xref: /illumos-gate/usr/src/cmd/mkmsgs/mkmsgs.c (revision f3041bfa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /*
34  * Create message files in a specific format.
35  * the gettxt message retrieval function must know the format of
36  * the data file created by this utility.
37  *
38  * 	FORMAT OF MESSAGE FILES
39 
40 	 __________________________
41 	|  Number of messages      |
42 	 --------------------------
43 	|  offset to the 1st mesg  |
44 	 --------------------------
45 	|  offset to the 2nd mesg  |
46 	 --------------------------
47 	|  offset to the 3rd mesg  |
48 	 --------------------------
49 	|          .		   |
50 	|	   .	           |
51 	|	   .		   |
52 	 --------------------------
53 	|  offset to the nth mesg  |
54 	 --------------------------
55 	|    message #1
56 	 --------------------------
57 	|    message #2
58 	 --------------------------
59 	|    message #3
60 	 --------------------------
61 		   .
62 		   .
63 		   .
64 	 --------------------------
65 	|    message #n
66 	 --------------------------
67 *
68 */
69 
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <unistd.h>
73 #include <string.h>
74 #include <sys/types.h>
75 #include <sys/stat.h>
76 #include <signal.h>
77 #include <errno.h>
78 #include <libgen.h>
79 
80 /*
81  * Definitions
82  */
83 
84 #define	LINESZ	2048	/* max line in input base */
85 #define STDERR  2
86 #define P_locale	"/usr/lib/locale/"	/* locale info directory */
87 #define L_locale	sizeof(P_locale)
88 #define MESSAGES	"/LC_MESSAGES/"		/* messages category */
89 
90 /*
91  * internal functions
92  */
93 
94 static	char	*syserr(void);		/* Returns description of error */
95 static	void	usage(void);		/* Displays valid invocations */
96 static	int	mymkdir(char *);	/* Creates sub-directories */
97 static	void	clean(int);		/* removes work file */
98 
99 /*
100  * static variables
101  */
102 
103 static	char	*cmdname;	/* Last qualifier of arg0 */
104 static	char    *workp;		/* name of the work file */
105 
106 int
107 main(argc, argv)
108 int argc;
109 char *argv[];
110 {
111 	int c;				/* contains option letter */
112 	char	*ifilep;		/* input file name */
113 	char	*ofilep;		/* output file name */
114 	char	*localep; 		/* locale name */
115 	char	*localedirp;    	/* full-path name of parent directory
116 				 	 * of the output file */
117 	char	*outfilep;		/* full-path name of output file */
118 	FILE *fp_inp; 			/* input file FILE pointer */
119 	FILE *fp_outp;			/* output file FILE pointer */
120 	char *bufinp, *bufworkp;	/* pointers to input and work areas */
121 	int  *bufoutp;			/* pointer to the output area */
122 	char *msgp;			/* pointer to the a message */
123 	int num_msgs;			/* number of messages in input file */
124 	int iflag;			/* -i option was specified */
125 	int oflag;			/* -o option was slecified */
126 	int nitems;			/* number of bytes to write */
127 	char *pathoutp;			/* full-path name of output file */
128 	struct stat buf;		/* buffer to stat the work file */
129 	unsigned size;			/* used for argument to malloc */
130 	int i;
131 
132 	/* Initializations */
133 
134 	localep = (char *)NULL;
135 	num_msgs = 0;
136 	iflag   = 0;
137 	oflag   = 0;
138 
139 	/* Get name of command */
140 
141 	if (cmdname = strrchr(argv[0], '/'))
142 		++cmdname;
143 	else
144 		cmdname = argv[0];
145 
146 	/* Check for invalid number of arguments */
147 
148 	if (argc < 3 && argc > 6)
149 		usage();
150 
151 	/* Get command line options */
152 
153 	while ((c = getopt(argc, argv, "oi:")) != EOF) {
154 		switch (c) {
155 		case 'o':
156 			oflag++;
157 			break;
158 		case 'i':
159 			iflag++;
160 			localep = optarg;
161 			break;
162 		case '?':
163 			usage();
164 			break;
165 		}
166 	}
167 
168 	/* Initialize pointers to input and output file names */
169 
170 	ifilep = argv[optind];
171 	ofilep = argv[optind + 1];
172 
173 	/* check for invalid invocations */
174 
175 	if (iflag && oflag && argc != 6)
176 		usage();
177 	if (iflag && ! oflag && argc != 5)
178 		usage();
179 	if (! iflag && oflag && argc != 4)
180 		usage();
181 	if (! iflag && ! oflag && argc != 3)
182 		usage();
183 
184 	/* Construct a  full-path to the output file */
185 
186 	if (localep) {
187 		size = L_locale + strlen(localep) +
188 			 sizeof(MESSAGES) + strlen(ofilep);
189 		if ((pathoutp = malloc(2 * (size + 1))) == NULL) {
190 			(void)fprintf(stderr, "%s: malloc error (size = %d)\n",
191 					cmdname, size);
192 			exit(1);
193 		}
194 		localedirp = pathoutp + size + 1;
195 		(void)strcpy(pathoutp, P_locale);
196 		(void)strcpy(&pathoutp[L_locale - 1], localep);
197 		(void)strcat(pathoutp, MESSAGES);
198 		(void)strcpy(localedirp, pathoutp);
199 		(void)strcat(pathoutp, ofilep);
200 	}
201 
202 	/* Check for overwrite error conditions */
203 
204 	if (! oflag) {
205 		if (iflag) {
206 			if (access(pathoutp, 0) == 0) {
207 				(void)fprintf(stderr, "%s: Message file \"%s\" already exists;\ndid not overwrite it\n", cmdname, pathoutp);
208 				if (localep)
209 					free(pathoutp);
210 				exit(1);
211 			}
212 		}
213 		else
214 			if (access(ofilep, 0) == 0) {
215 				(void)fprintf(stderr, "%s: Message file \"%s\" already exists;\ndid not overwrite it\n", cmdname, ofilep);
216 				if (localep)
217 					free(pathoutp);
218 				exit(1);
219 			}
220 	}
221 
222 	/* Open input file */
223 	if ((fp_inp = fopen(ifilep, "r")) == NULL) {
224 		(void)fprintf(stderr, "%s: %s: %s\n",
225 			cmdname, ifilep, syserr());
226 		exit(1);
227 	}
228 
229 	/* Allocate buffer for input and work areas */
230 
231 	if ((bufinp = malloc(2 * LINESZ)) == NULL) {
232 		(void)fprintf(stderr, "%s: malloc error (size = %d)\n",
233 					cmdname, 2 * LINESZ);
234 		exit(1);
235 	}
236 	bufworkp = bufinp + LINESZ;
237 
238 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
239 		(void)sigset(SIGINT, clean);
240 
241 	/* Open work file */
242 
243 	workp = tempnam(".", "xx");
244 	if ((fp_outp = fopen(workp, "a+")) == NULL) {
245 		(void)fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr());
246 		if (localep)
247 			free(pathoutp);
248 		free(bufinp);
249 		exit(1);
250 	}
251 
252 	/* Search for C-escape sequences in input file and
253 	 * replace them by the appropriate characters.
254 	 * The modified lines are copied to the work area
255 	 * and written to the work file */
256 
257 	for(;;) {
258 		if (!fgets(bufinp, LINESZ, fp_inp)) {
259 			if (!feof(fp_inp)) {
260 				(void)fprintf(stderr,"%s: %s: %s\n",
261 					cmdname, ifilep, syserr());
262 				free(bufinp);
263 				if (localep)
264 					free(pathoutp);
265 				exit(1);
266 			}
267 			break;
268 		}
269 		if(*(bufinp+strlen(bufinp)-1)  != '\n') {
270 			(void)fprintf(stderr, "%s: %s: data base file: error on line %d\n", cmdname, ifilep, num_msgs);
271 			free(bufinp);
272 			exit(1);
273 		}
274 		*(bufinp + strlen(bufinp) -1) = (char)0; /* delete newline */
275 		num_msgs++;
276 		(void)strccpy(bufworkp, bufinp);
277 		nitems = strlen(bufworkp) + 1;
278 		if (fwrite(bufworkp, sizeof(*bufworkp), nitems, fp_outp) != nitems) {
279 			(void)fprintf(stderr, "%s: %s: %s\n",
280 				cmdname, workp, syserr());
281 			exit(1);
282 		}
283 	}
284 	free(bufinp);
285 	(void)fclose(fp_outp);
286 
287 	/* Open and stat the work file */
288 
289 	if ((fp_outp = fopen(workp, "r")) == NULL) {
290 		(void)fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr());
291 		exit(1);
292 	}
293 	if ((stat(workp, &buf)) != 0) {
294 		(void)fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr());
295 	}
296 
297 	/* Find the size of the output message file
298 	 * and copy the control information and the messages
299 	 * to the output file */
300 
301 	size = sizeof(int) + num_msgs * sizeof(int) + buf.st_size;
302 
303 	if ( (bufoutp = (int *)malloc((uint)size)) == NULL ) {
304 		(void)fprintf(stderr, "%s: malloc error (size = %d)\n",
305 				cmdname, size);
306 		exit(1);
307 	}
308 	bufinp = (char *)bufoutp;
309 	if ( (fread(bufinp + sizeof(int) + num_msgs * sizeof(int), sizeof(*bufinp), buf.st_size, fp_outp)) != buf.st_size ) {
310 		free(bufinp);
311 		(void) fprintf(stderr, "%s: %s: %s\n", cmdname, workp, syserr());
312 	}
313 	(void) fclose(fp_outp);
314 	(void) unlink(workp);
315 	free(workp);
316 	msgp = bufinp + sizeof(int) + num_msgs * sizeof(int);
317 	*bufoutp = num_msgs;
318 	*(bufoutp + 1) = (bufinp + sizeof(int) + num_msgs * sizeof(int)) - bufinp;
319 
320 	for(i = 2; i <= num_msgs; i++) {
321 		*(bufoutp + i) = (msgp + strlen(msgp) + 1) - bufinp;
322 		msgp = msgp + strlen(msgp) + 1;
323 	}
324 
325 	if (iflag) {
326 		outfilep = pathoutp;
327 		if (mymkdir(localedirp) == 0) {
328 			free(bufinp);
329 			if (localep)
330 				free(pathoutp);
331 			exit(1);
332 		}
333 	}
334 	else
335 		outfilep = ofilep;
336 
337 	if ((fp_outp = fopen(outfilep, "w")) == NULL) {
338 		(void)fprintf(stderr, "%s: %s: %s\n",
339 				cmdname, outfilep, syserr());
340 		free(bufinp);
341 		if (localep)
342 			free(pathoutp);
343 		exit(1);
344 	}
345 
346 	if (fwrite((char *)bufinp, sizeof(*bufinp), size, fp_outp) != size) {
347 		(void)fprintf(stderr, "%s: %s: %s\n",
348 				cmdname, ofilep, syserr());
349 		free(bufinp);
350 		if (localep)
351 			free(pathoutp);
352 		exit(1);
353 	}
354 	free(bufinp);
355 	if (localep)
356 		free(pathoutp);
357 	return (0);
358 }
359 
360 /*
361  * syserr()
362  *
363  * Return a pointer to a system error message.
364  */
365 static char *
366 syserr()
367 {
368 	return (strerror(errno));
369 }
370 
371 static void
372 usage()
373 {
374 	(void)fprintf(stderr, "Usage: %s [-o] inputstrings outputmsgs\n",
375 				cmdname);
376 	(void)fprintf(stderr, "       %s [-o] [-i locale] inputstrings outputmsgs\n", cmdname);
377 	exit(1);
378 }
379 
380 static int
381 mymkdir(localdir)
382 char	*localdir;
383 {
384 	char	*dirp;
385 	char	*s1 = localdir;
386 	char	*path;
387 
388 	if ((path = malloc(strlen(localdir)+1)) == NULL)
389 		return(0);
390 	*path = '\0';
391 	while( (dirp = strtok(s1, "/")) != NULL ) {
392 		s1 = (char *)NULL;
393 		(void)strcat(path, "/");
394 		(void)strcat(path, dirp);
395 		if (access(path, 3) == 0)
396 			continue;
397 		if (mkdir(path, 0777) == -1) {
398 			(void)fprintf(stderr, "%s: %s: %s\n",
399 					cmdname, path, syserr());
400 			free(path);
401 			return(0);
402 		}
403 	}
404 	free(path);
405 	return(1);
406 }
407 
408 /* ARGSUSED */
409 static void
410 clean(int sig)
411 {
412 	(void)sigset(SIGINT, SIG_IGN);
413 	if (workp)
414 		(void) unlink(workp);
415 	exit(1);
416 }
417 
418