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