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