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
main(argc,argv)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 *
syserr()366 syserr()
367 {
368 return (strerror(errno));
369 }
370
371 static void
usage()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
mymkdir(localdir)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
clean(int sig)410 clean(int sig)
411 {
412 (void)sigset(SIGINT, SIG_IGN);
413 if (workp)
414 (void) unlink(workp);
415 exit(1);
416 }
417
418