ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/cddl/contrib/opensolaris/cmd/sgs/tools/common/sgsmsg.c
Revision: 10228
Committed: Sat Jun 2 16:07:17 2018 UTC (5 years, 11 months ago) by laffer1
Content type: text/plain
File size: 28932 byte(s)
Log Message:
sync

File Contents

# Content
1 /* $MidnightBSD$ */
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance 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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * sgsmsg generates several message files from an input template file. Messages
27 * are constructed for use with gettext(3i) - the default - or catgets(3c). The
28 * files generate are:
29 *
30 * msg.h a header file containing definitions for each message. The -h
31 * option triggers the creation of these definitions and specifies
32 * the name to use.
33 *
34 * msg.c a data array of message strings. The msg.h definitions are
35 * offsets into this array. The -d option triggers the creation of
36 * these definitions and specifies the name to use.
37 *
38 * messages a message file suitable for catgets(3c) or gettext(3i) use. The
39 * -m option triggers this output and specifies the filename to be
40 * used.
41 *
42 * The template file is processed based on the first character of each line:
43 *
44 * # or $ entries are copied (as is) to the message file (messages).
45 *
46 * @ token(s) entries are translated. Two translations are possible dependent
47 * on whether one or more tokens are supplied:
48 *
49 * A single token is interpreted as one of two reserved message
50 * output indicators, or a message identifier. The reserved output
51 * indicator _START_ enables output to the message file - Note that
52 * the occurance of any other @ token will also enable message
53 * output. The reserved output indicator _END_ disables output to
54 * the message file. The use of these two indicators provides for
55 * only those message strings that require translation to be output
56 * to the message file.
57 *
58 * Besides the reserved output indicators, a single token is taken
59 * to be a message identifier which will be subsituted for a
60 * `setid' for catgets(3c) output, or a `domain' name for
61 * gettext(3i) output. This value is determine by substituting the
62 * token for the associated definition found in the message
63 * identifier file (specified with the -i option).
64 *
65 * Multiple tokens are taken to be a message definition followed by
66 * the associated message string. The message string is copied to
67 * the data array being built in msg.c. The index into this array
68 * becomes the `message' identifier created in the msg.h file.
69 */
70 #pragma ident "%Z%%M% %I% %E% SMI"
71
72 #include <fcntl.h>
73 #include <stdlib.h>
74 #include <stdio.h>
75 #include <unistd.h>
76 #include <limits.h>
77 #include <string.h>
78 #include <ctype.h>
79 #include <errno.h>
80 #include <sys/param.h>
81
82 #include <sgs.h>
83 #include <_string_table.h>
84
85 /*
86 * Define any error message strings.
87 */
88 static const char
89 * Errmsg_malt = "sgsmsg: file %s: line %d: malformed input "
90 "at line\n",
91 * Errmsg_nmem = "sgsmsg: memory allocation failed: %s\n",
92 * Errmsg_opne = "sgsmsg: file %s: open failed: %s\n",
93 * Errmsg_wrte = "sgsmsg: file %s: write failed: %s\n",
94 * Errmsg_read = "sgsmsg: file %s: read failed %s\n",
95 * Errmsg_stnw = "sgsmsg: st_new(): failed: %s\n",
96 * Errmsg_stin = "sgsmsg: Str_tbl insert failed: %s\n",
97 * Errmsg_mnfn = "sgsmsg: message not found in Str_tbl: %s\n",
98 * Errmsg_use = "usage: sgsmsg [-clv] [-d mesgdata] [-h mesgdefs] "
99 "[-m messages] [-n name] [-i mesgident] file ...\n";
100
101 /*
102 * Define all output filenames and associated descriptors.
103 */
104 static FILE *fddefs, *fddata, *fdmsgs, *fdmids, *fddesc;
105 static char *fldefs, *fldata, *flmsgs, *flmids, *fldesc;
106 static FILE *fdlint;
107 static char fllint[MAXPATHLEN];
108
109 static uint_t vflag; /* verbose flag */
110 static Str_tbl *stp; /* string table */
111
112 /*
113 * Define any default strings.
114 */
115 static const char
116 *nmlint = "/tmp/sgsmsg.lint",
117 *interface = "sgs_msg",
118 *start = "_START_",
119 *end = "_END_";
120
121 /*
122 * Define any default flags and data items.
123 */
124 static int cflag = 0, lflag = 0, prtmsgs = 0, line, ptr = 1, msgid = 0;
125 static char *mesgid = 0, *setid = 0, *domain = 0;
126
127 typedef struct msg_string {
128 char *ms_defn;
129 char *ms_message;
130 struct msg_string *ms_next;
131 } msg_string;
132
133 static msg_string *msg_head;
134 static msg_string *msg_tail;
135
136 /*
137 * message_append() is responsible for both inserting strings into
138 * the master Str_tbl as well as maintaining a list of the
139 * DEFINITIONS associated with each string.
140 *
141 * The list of strings is traversed at the end once the full
142 * Str_tbl has been constructed - and string offsets can be
143 * assigned.
144 */
145 static void
146 message_append(const char *defn, const char *message)
147 {
148 msg_string *msg;
149 if ((msg = calloc(sizeof (msg_string), 1)) == 0) {
150 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
151 exit(1);
152 }
153
154 /*
155 * Initialize the string table.
156 */
157 if ((stp == 0) && ((stp = st_new(FLG_STNEW_COMPRESS)) == NULL)) {
158 (void) fprintf(stderr, Errmsg_stnw, strerror(errno));
159 exit(1);
160 }
161
162
163 if ((msg->ms_defn = strdup(defn)) == 0) {
164 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
165 exit(1);
166 }
167 if ((msg->ms_message = strdup(message)) == 0) {
168 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
169 exit(1);
170 }
171
172 if (st_insert(stp, msg->ms_message) == -1) {
173 (void) fprintf(stderr, Errmsg_stin,
174 message);
175 exit(1);
176 }
177
178 if (msg_head == 0) {
179 msg_head = msg_tail = msg;
180 return;
181 }
182 msg_tail->ms_next = msg;
183 msg_tail = msg;
184 }
185
186 /*
187 * Initialize a setid value. Given a setid definition determine its numeric
188 * value from the specified message identifier file (specified with the -i
189 * option). Return a pointer to the numeric string.
190 */
191 static int
192 getmesgid(char *id)
193 {
194 char *buffer, *token, *_mesgid = 0, *_setid = 0, *_domain = 0;
195
196 /*
197 * If we're being asked to interpret a message id but the user didn't
198 * provide the required message identifier file (-i option) we're in
199 * trouble.
200 */
201 if (flmids == 0) {
202 (void) fprintf(stderr, "sgsmsg: file %s: line %d: mesgid %s: "
203 "unable to process mesgid\n\t"
204 "no message identifier file specified "
205 "(see -i option)\n", fldesc, line, id);
206 return (1);
207 }
208
209 if ((buffer = malloc(LINE_MAX)) == 0) {
210 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
211 return (1);
212 }
213
214 /*
215 * Read the message identifier file and locate the required mesgid.
216 */
217 rewind(fdmids);
218 while (fgets(buffer, LINE_MAX, fdmids) != NULL) {
219 if ((token = strstr(buffer, id)) == NULL)
220 continue;
221
222 /*
223 * Establish individual strings for the mesgid, setid and domain
224 * values.
225 */
226 _mesgid = token;
227 while (!(isspace(*token)))
228 token++;
229 *token++ = 0;
230
231 while (isspace(*token))
232 token++;
233 _setid = token;
234 while (!(isspace(*token)))
235 token++;
236 *token++ = 0;
237
238 while (isspace(*token))
239 token++;
240 _domain = token;
241 while (!(isspace(*token)))
242 token++;
243 *token = 0;
244 break;
245 }
246
247 /*
248 * Did we find a match?
249 */
250 if ((_mesgid == 0) || (_setid == 0) || (_domain == 0)) {
251 (void) fprintf(stderr, "sgsmsg: file %s: line %d: mesgid %s: "
252 "unable to process mesgid\n\t"
253 "identifier does not exist in file %s\n",
254 fldesc, line, id, flmids);
255 return (1);
256 }
257
258 /*
259 * Have we been here before?
260 */
261 if (mesgid) {
262 if (cflag == 1) {
263 /*
264 * If we're being asked to process more than one mesgid
265 * warn the user that only one mesgid can be used for
266 * the catgets(3c) call.
267 */
268 (void) fprintf(stderr, "sgsmsg: file %s: line %d: "
269 "setid %s: warning: multiple mesgids "
270 "encountered\n\t"
271 "last setting used in messaging code\n",
272 fldesc, line, id);
273 }
274 }
275
276 mesgid = _mesgid;
277 setid = _setid;
278 domain = _domain;
279
280 /*
281 * Generate the message file output (insure output flag is enabled).
282 */
283 if (prtmsgs != -1)
284 prtmsgs = 1;
285 if (fdmsgs && (prtmsgs == 1)) {
286 if (cflag == 1) {
287 if (fprintf(fdmsgs, "$quote \"\n$set %s\n",
288 setid) < 0) {
289 (void) fprintf(stderr, Errmsg_wrte, flmsgs,
290 strerror(errno));
291 return (1);
292 }
293 } else {
294 if (fprintf(fdmsgs, "domain\t\"%s\"\n", domain) < 0) {
295 (void) fprintf(stderr, Errmsg_wrte, flmsgs,
296 strerror(errno));
297 return (1);
298 }
299 }
300 }
301
302 /*
303 * For catgets(3c) output generate a setid definition in the message
304 * definition file.
305 */
306 if (fddefs && (cflag == 1) &&
307 (fprintf(fddefs, "#define\t%s\t%s\n\n", mesgid, setid) < 0)) {
308 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
309 return (1);
310 }
311
312 return (0);
313 }
314
315 /*
316 * Dump contents of String Table to standard out
317 */
318 static void
319 dump_stringtab(Str_tbl *stp)
320 {
321 uint_t cnt;
322
323 if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) {
324 (void) printf("string table full size: %ld: uncompressed\n",
325 stp->st_fullstrsize);
326 return;
327 }
328
329 (void) printf("string table full size: %ld compressed down to: %ld\n\n",
330 stp->st_fullstrsize, stp->st_strsize);
331 (void) printf("string table compression information [%d buckets]:\n",
332 stp->st_hbckcnt);
333
334 for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) {
335 Str_hash *sthash = stp->st_hashbcks[cnt];
336
337 if (sthash == 0)
338 continue;
339
340 (void) printf(" bucket: [%d]\n", cnt);
341
342 while (sthash) {
343 size_t stroff = sthash->hi_mstr->sm_strlen -
344 sthash->hi_strlen;
345
346 if (stroff == 0) {
347 (void) printf(" [%ld]: '%s' <master>\n",
348 sthash->hi_refcnt, sthash->hi_mstr->sm_str);
349 } else {
350 (void) printf(" [%ld]: '%s' <suffix of: "
351 "'%s'>\n", sthash->hi_refcnt,
352 &sthash->hi_mstr->sm_str[stroff],
353 sthash->hi_mstr->sm_str);
354 }
355 sthash = sthash->hi_next;
356 }
357 }
358 }
359
360 /*
361 * Initialize the message definition header file stream.
362 */
363 static int
364 init_defs(void)
365 {
366 static char guard[FILENAME_MAX + 6];
367 char *optr;
368 const char *iptr, *_ptr;
369
370 /*
371 * Establish a header guard name using the files basename.
372 */
373 for (iptr = 0, _ptr = fldefs; _ptr && (*_ptr != '\0'); _ptr++) {
374 if (*_ptr == '/')
375 iptr = _ptr + 1;
376 }
377 if (iptr == 0)
378 iptr = fldefs;
379
380 optr = guard;
381 for (*optr++ = '_'; iptr && (*iptr != '\0'); iptr++, optr++) {
382 if (*iptr == '.') {
383 *optr++ = '_';
384 *optr++ = 'D';
385 *optr++ = 'O';
386 *optr++ = 'T';
387 *optr = '_';
388 } else
389 *optr = toupper(*iptr);
390 }
391
392 if (fprintf(fddefs, "#ifndef\t%s\n#define\t%s\n\n", guard, guard) < 0) {
393 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
394 return (1);
395 }
396
397 if (fprintf(fddefs, "#ifndef\t__lint\n\n") < 0) {
398 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
399 return (1);
400 }
401
402 /*
403 * add "typedef int Msg;"
404 */
405 if (fprintf(fddefs, "typedef int\tMsg;\n\n") < 0) {
406 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
407 return (1);
408 }
409
410 /*
411 * If the associated data array is global define a prototype.
412 * Define a macro to access the array elements.
413 */
414 if (lflag == 0) {
415 if (fprintf(fddefs, "extern\tconst char\t__%s[];\n\n",
416 interface) < 0) {
417 (void) fprintf(stderr, Errmsg_wrte, fldefs,
418 strerror(errno));
419 return (1);
420 }
421 }
422 if (fprintf(fddefs, "#define\tMSG_ORIG(x)\t&__%s[x]\n\n",
423 interface) < 0) {
424 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
425 return (1);
426 }
427
428 /*
429 * Generate a prototype to access the associated data array.
430 */
431 if (fprintf(fddefs, "extern\tconst char *\t_%s(Msg);\n\n",
432 interface) < 0) {
433 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
434 return (1);
435 }
436 if (fprintf(fddefs, "#define\tMSG_INTL(x)\t_%s(x)\n\n",
437 interface) < 0) {
438 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
439 return (1);
440 }
441
442 return (0);
443 }
444
445
446 /*
447 * Finish the message definition header file.
448 */
449 static int
450 fini_defs(void)
451 {
452 if (fprintf(fddefs, "\n#else\t/* __lint */\n\n") < 0) {
453 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
454 return (1);
455 }
456
457 /*
458 * When __lint is defined, Msg is a char *. This allows lint to
459 * check our format strings against it's arguments.
460 */
461 if (fprintf(fddefs, "\ntypedef char *\tMsg;\n\n") < 0) {
462 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
463 return (1);
464 }
465
466 if (fprintf(fddefs, "extern\tconst char *\t_%s(Msg);\n\n",
467 interface) < 0) {
468 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
469 return (1);
470 }
471
472 if (lflag == 0) {
473 if (fprintf(fddefs, "extern\tconst char\t__%s[];\n\n",
474 interface) < 0) {
475 (void) fprintf(stderr, Errmsg_wrte, fldefs,
476 strerror(errno));
477 return (1);
478 }
479 }
480
481 if (fprintf(fddefs,
482 "#define MSG_ORIG(x)\tx\n#define MSG_INTL(x)\tx\n") < 0) {
483 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
484 return (1);
485 }
486
487 /*
488 * Copy the temporary lint defs file into the new header.
489 */
490 if (fdlint) {
491 long size;
492 char *buf;
493
494 size = ftell(fdlint);
495 (void) rewind(fdlint);
496
497 if ((buf = malloc(size)) == 0) {
498 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
499 return (1);
500 }
501 if (fread(buf, size, 1, fdlint) == 0) {
502 (void) fprintf(stderr, Errmsg_read, fllint,
503 strerror(errno));
504 return (1);
505 }
506 if (fwrite(buf, size, 1, fddefs) == 0) {
507 (void) fprintf(stderr, Errmsg_wrte, fldefs,
508 strerror(errno));
509 return (1);
510 }
511 (void) free(buf);
512 }
513
514 if (fprintf(fddefs, "\n#endif\t/* __lint */\n") < 0) {
515 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
516 return (1);
517 }
518
519 if (fprintf(fddefs, "\n#endif\n") < 0) {
520 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
521 return (1);
522 }
523
524 return (0);
525 }
526
527 /*
528 * The entire messaging file has been scanned - and all strings have been
529 * inserted into the string_table. We can now walk the message queue
530 * and create the '#define <DEFN>' for each string - with the strings
531 * assigned offset into the string_table.
532 */
533 static int
534 output_defs(void)
535 {
536 msg_string *msg;
537 size_t stbufsize;
538 char *stbuf;
539
540 stbufsize = st_getstrtab_sz(stp);
541 if ((stbuf = malloc(stbufsize)) == 0) {
542 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
543 exit(1);
544 }
545 (void) st_setstrbuf(stp, stbuf, stbufsize);
546 for (msg = msg_head; msg; msg = msg->ms_next) {
547 size_t stoff;
548 if ((st_setstring(stp, msg->ms_message, &stoff)) == -1) {
549 (void) fprintf(stderr, Errmsg_mnfn, msg->ms_message);
550 return (1);
551 }
552 if (fprintf(fddefs, "\n#define\t%s\t%ld\n",
553 msg->ms_defn, stoff) < 0) {
554 (void) fprintf(stderr, Errmsg_wrte,
555 fldefs, strerror(errno));
556 return (1);
557 }
558 if (fddefs && fprintf(fddefs, "#define\t%s_SIZE\t%d\n",
559 msg->ms_defn, strlen(msg->ms_message)) < 0) {
560 (void) fprintf(stderr, Errmsg_wrte,
561 fldefs, strerror(errno));
562 return (1);
563 }
564 }
565 return (0);
566 }
567
568
569 /*
570 * Finish off the data structure definition.
571 */
572 static int
573 output_data(void)
574 {
575 size_t stbufsize;
576 size_t ndx;
577 size_t column = 1;
578 const char *stbuf;
579 const char *fmtstr;
580
581 stbufsize = st_getstrtab_sz(stp);
582 stbuf = st_getstrbuf(stp);
583
584 assert(stbuf);
585
586 /*
587 * Determine from the local flag whether the data declaration should
588 * be static.
589 */
590 if (lflag)
591 fmtstr = (const char *)"static const";
592 else
593 fmtstr = (const char *)"const";
594
595 if (fprintf(fddata, "\n%s char __%s[%ld] = { ",
596 fmtstr, interface, stbufsize) < 0) {
597 (void) fprintf(stderr, Errmsg_wrte, fldata, strerror(errno));
598 return (1);
599 }
600
601 for (ndx = 0; ndx < (stbufsize - 1); ndx++) {
602 if (column == 1) {
603 if (fddata && fprintf(fddata,
604 "\n/* %4ld */ 0x%.2x,", ndx,
605 (unsigned char)stbuf[ndx]) < 0) {
606 (void) fprintf(stderr, Errmsg_wrte,
607 fldata, strerror(errno));
608 return (1);
609 }
610 } else {
611 if (fddata && fprintf(fddata, " 0x%.2x,",
612 (unsigned char)stbuf[ndx]) < 0) {
613 (void) fprintf(stderr, Errmsg_wrte,
614 fldata, strerror(errno));
615 return (1);
616 }
617 }
618
619 if (column++ == 10)
620 column = 1;
621 }
622
623 if (column == 1)
624 fmtstr = "\n\t0x%.2x };\n";
625 else
626 fmtstr = " 0x%.2x };\n";
627
628 if (fprintf(fddata, fmtstr, (unsigned char)stbuf[stbufsize - 1]) < 0) {
629 (void) fprintf(stderr, Errmsg_wrte, fldata, strerror(errno));
630 return (1);
631 }
632
633 return (0);
634 }
635
636 static int
637 file()
638 {
639 char buffer[LINE_MAX], * token;
640 uint_t bufsize;
641 char *token_buffer;
642 int escape = 0;
643
644 if ((token_buffer = malloc(LINE_MAX)) == 0) {
645 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
646 return (1);
647 }
648 bufsize = LINE_MAX;
649
650 line = 1;
651
652 while ((token = fgets(buffer, LINE_MAX, fddesc)) != NULL) {
653 char defn[PATH_MAX], * _defn, * str;
654 int len;
655
656 switch (*token) {
657 case '#':
658 case '$':
659 if (escape) {
660 (void) fprintf(stderr, Errmsg_malt, fldesc,
661 line);
662 return (1);
663 }
664
665 /*
666 * If a msgid has been output a msgstr must follow
667 * before we digest the new token. A msgid is only set
668 * if fdmsgs is in use.
669 */
670 if (msgid) {
671 msgid = 0;
672 if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
673 (void) fprintf(stderr, Errmsg_wrte,
674 flmsgs, strerror(errno));
675 return (1);
676 }
677 }
678
679 /*
680 * Pass lines directly through to the output message
681 * file.
682 */
683 if (fdmsgs && (prtmsgs == 1)) {
684 char comment;
685
686 if (cflag == 0)
687 comment = '#';
688 else
689 comment = '$';
690
691 if (fprintf(fdmsgs, "%c%s", comment,
692 ++token) < 0) {
693 (void) fprintf(stderr, Errmsg_wrte,
694 flmsgs, strerror(errno));
695 return (1);
696 }
697 }
698 break;
699
700 case '@':
701 if (escape) {
702 (void) fprintf(stderr, Errmsg_malt, fldesc,
703 line);
704 return (1);
705 }
706
707 /*
708 * If a msgid has been output a msgstr must follow
709 * before we digest the new token.
710 */
711 if (msgid) {
712 msgid = 0;
713 if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
714 (void) fprintf(stderr, Errmsg_wrte,
715 flmsgs, strerror(errno));
716 return (1);
717 }
718 }
719
720 /*
721 * Determine whether we have one or more tokens.
722 */
723 token++;
724 while (isspace(*token)) /* rid any whitespace */
725 token++;
726 _defn = token; /* definition start */
727 while (!(isspace(*token)))
728 token++;
729 *token++ = 0;
730
731 while (isspace(*token)) /* rid any whitespace */
732 token++;
733
734 /*
735 * Determine whether the single token is one of the
736 * reserved message output delimiters otherwise
737 * translate it as a message identifier.
738 */
739 if (*token == 0) {
740 if (strcmp(_defn, start) == 0)
741 prtmsgs = 1;
742 else if (strcmp(_defn, end) == 0)
743 prtmsgs = -1;
744 else if (getmesgid(_defn) == 1)
745 return (1);
746 break;
747 }
748
749 /*
750 * Multiple tokens are translated by taking the first
751 * token as the message definition, and the rest of the
752 * line as the message itself. A message line ending
753 * with an escape ('\') is expected to be continued on
754 * the next line.
755 */
756 if (prtmsgs != -1)
757 prtmsgs = 1;
758 if (fdmsgs && (prtmsgs == 1)) {
759 /*
760 * For catgets(3c) make sure a message
761 * identifier has been established (this is
762 * normally a domain for gettext(3i), but for
763 * sgsmsg use this could be argued as being
764 * redundent). Also make sure that the message
765 * definitions haven't exceeeded the maximum
766 * value allowed by gencat(1) before generating
767 * any message file entries.
768 */
769 if (cflag == 1) {
770 if (setid == 0) {
771 (void) fprintf(stderr, "file "
772 "%s: no message identifier "
773 "has been established\n",
774 fldesc);
775 return (1);
776 }
777 if (ptr > NL_MSGMAX) {
778 (void) fprintf(stderr, "file "
779 "%s: message definition "
780 "(%d) exceeds allowable "
781 "limit (NL_MSGMAX)\n",
782 fldesc, ptr);
783 return (1);
784 }
785 }
786
787 /*
788 * For catgets(3c) write the definition and the
789 * message string to the message file. For
790 * gettext(3i) write the message string as a
791 * mesgid - indicate a mesgid has been output
792 * so that a msgstr can follow.
793 */
794 if (cflag == 1) {
795 if (fprintf(fdmsgs, "%d\t%s", ptr,
796 token) < 0) {
797 (void) fprintf(stderr,
798 Errmsg_wrte, flmsgs,
799 strerror(errno));
800 return (1);
801 }
802 } else {
803 if (fprintf(fdmsgs, "msgid\t\"") < 0) {
804 (void) fprintf(stderr,
805 Errmsg_wrte, flmsgs,
806 strerror(errno));
807 return (1);
808 }
809 msgid = 1;
810 }
811 }
812
813 /*
814 * The message itself is a quoted string as this makes
815 * embedding spaces at the start (or the end) of the
816 * string very easy.
817 */
818 if (*token != '"') {
819 (void) fprintf(stderr, Errmsg_malt, fldesc,
820 line);
821 return (1);
822 }
823
824 (void) strcpy(defn, _defn);
825
826 /*
827 * Write the tag to the lint definitions.
828 */
829 if (fdlint) {
830 if (fprintf(fdlint, "\n#define\t%s\t",
831 _defn) < 0) {
832 (void) fprintf(stderr, Errmsg_wrte,
833 fllint, strerror(errno));
834 return (1);
835 }
836 }
837
838 len = 0;
839
840 /*
841 * Write each character of the message string to the
842 * data array. Translate any escaped characters - use
843 * the same specially recognized characters as defined
844 * by gencat(1).
845 */
846 message:
847 if (*token == '"') {
848 if (fdlint &&
849 (fprintf(fdlint, "%c", *token) < 0)) {
850 (void) fprintf(stderr, Errmsg_wrte,
851 fllint, strerror(errno));
852 return (1);
853 }
854 token++;
855 }
856 while (*token) {
857 char _token;
858
859 if ((*token == '\\') && (escape == 0)) {
860 escape = 1;
861 if (fdlint && (*(token + 1) != '\n') &&
862 fprintf(fdlint, "%c", *token) < 0) {
863 (void) fprintf(stderr,
864 Errmsg_wrte, fllint,
865 strerror(errno));
866 return (1);
867 }
868 token++;
869 continue;
870 }
871 if (escape) {
872 if (*token == 'n')
873 _token = '\n';
874 else if (*token == 't')
875 _token = '\t';
876 else if (*token == 'v')
877 _token = '\v';
878 else if (*token == 'b')
879 _token = '\b';
880 else if (*token == 'f')
881 _token = '\f';
882 else if (*token == '\\')
883 _token = '\\';
884 else if (*token == '"')
885 _token = '"';
886 else if (*token == '\n')
887 break;
888 else
889 _token = *token;
890
891 if (fdmsgs && (prtmsgs == 1) &&
892 (fprintf(fdmsgs, "\\") < 0)) {
893 (void) fprintf(stderr,
894 Errmsg_wrte, flmsgs,
895 strerror(errno));
896 return (1);
897 }
898 } else {
899 /*
900 * If this is the trailing quote then
901 * thats the last of the message string.
902 * Eat up any remaining white space and
903 * unless an escape character is found
904 * terminate the data string with a 0.
905 */
906 /* BEGIN CSTYLED */
907 if (*token == '"') {
908 if (fdlint && (fprintf(fdlint,
909 "%c", *token) < 0)) {
910 (void) fprintf(stderr,
911 Errmsg_wrte, fllint,
912 strerror(errno));
913 return (1);
914 }
915
916 if (fdmsgs && (prtmsgs == 1) &&
917 (fprintf(fdmsgs, "%c",
918 *token) < 0)) {
919 (void) fprintf(stderr,
920 Errmsg_wrte, flmsgs,
921 strerror(errno));
922 return (1);
923 }
924
925 while (*++token) {
926 if (*token == '\n')
927 break;
928 }
929 _token = '\0';
930 } else
931 _token = *token;
932 /* END CSTYLED */
933 }
934
935 if (fdmsgs && (prtmsgs == 1) &&
936 (fprintf(fdmsgs, "%c", *token) < 0)) {
937 (void) fprintf(stderr, Errmsg_wrte,
938 flmsgs, strerror(errno));
939 return (1);
940 }
941
942 if (fdlint && fprintf(fdlint,
943 "%c", *token) < 0) {
944 (void) fprintf(stderr, Errmsg_wrte,
945 fllint, strerror(errno));
946 return (1);
947 }
948
949 if (len >= bufsize) {
950 bufsize += LINE_MAX;
951 if ((token_buffer = realloc(
952 token_buffer, bufsize)) == 0) {
953 (void) fprintf(stderr,
954 Errmsg_nmem,
955 strerror(errno));
956 return (1);
957 }
958 }
959 token_buffer[len] = _token;
960 ptr++, token++, len++;
961 escape = 0;
962
963 if (_token == '\0')
964 break;
965 }
966
967 /*
968 * After the complete message string has been processed
969 * (including its continuation beyond one line), create
970 * a string size definition.
971 */
972 if (escape == 0) {
973 const char *form = "#define\t%s_SIZE\t%d\n";
974
975 token_buffer[len] = '\0';
976
977 message_append(defn, token_buffer);
978
979 if (fdlint && fprintf(fdlint, form, defn,
980 (len - 1)) < 0) {
981 (void) fprintf(stderr, Errmsg_wrte,
982 fllint, strerror(errno));
983 return (1);
984 }
985 }
986 break;
987
988 default:
989 /*
990 * Empty lines are passed through to the message file.
991 */
992 while (isspace(*token))
993 token++;
994
995 if (*token == 0) {
996 if (msgid || (fdmsgs && (prtmsgs == 1))) {
997 /*
998 * If a msgid has been output a msgstr
999 * must follow before we digest the new
1000 * token.
1001 */
1002 if (msgid) {
1003 msgid = 0;
1004 str = "msgstr\t\"\"\n\n";
1005 } else
1006 str = "\n";
1007
1008 if (fprintf(fdmsgs, str) < 0) {
1009 (void) fprintf(stderr,
1010 Errmsg_wrte, flmsgs,
1011 strerror(errno));
1012 return (1);
1013 }
1014 }
1015 break;
1016 }
1017
1018 /*
1019 * If an escape is in effect then any tokens are taken
1020 * to be message continuations.
1021 */
1022 if (escape) {
1023 escape = 0;
1024 goto message;
1025 }
1026
1027 (void) fprintf(stderr, "file %s: line %d: invalid "
1028 "input does not start with #, $ or @\n", fldesc,
1029 line);
1030 return (1);
1031 }
1032 line++;
1033 }
1034
1035 free(token_buffer);
1036
1037 return (0);
1038 }
1039
1040 int
1041 main(int argc, char ** argv)
1042 {
1043 opterr = 0;
1044 while ((line = getopt(argc, argv, "cd:h:lm:n:i:v")) != EOF) {
1045 switch (line) {
1046 case 'c': /* catgets instead of gettext */
1047 cflag = 1;
1048 break;
1049 case 'd': /* new message data filename */
1050 fldata = optarg; /* (msg.c is default) */
1051 break;
1052 case 'h': /* new message defs filename */
1053 fldefs = optarg; /* (msg.h is default) */
1054 break;
1055 case 'i': /* input message ids from */
1056 flmids = optarg; /* from this file */
1057 break;
1058 case 'l': /* define message data arrays */
1059 lflag = 1; /* to be local (static) */
1060 break;
1061 case 'm': /* generate message database */
1062 flmsgs = optarg; /* to this file */
1063 break;
1064 case 'n': /* new data array and func */
1065 interface = optarg; /* name (msg is default) */
1066 break;
1067 case 'v':
1068 vflag = 1; /* set verbose flag */
1069 break;
1070 case '?':
1071 (void) fprintf(stderr, Errmsg_use, argv[0]);
1072 exit(1);
1073 default:
1074 break;
1075 }
1076 }
1077
1078 /*
1079 * Validate the we have been given at least one input file.
1080 */
1081 if ((argc - optind) < 1) {
1082 (void) fprintf(stderr, Errmsg_use);
1083 exit(1);
1084 }
1085
1086 /*
1087 * Open all the required output files.
1088 */
1089 if (fldefs) {
1090 if ((fddefs = fopen(fldefs, "w+")) == NULL) {
1091 (void) fprintf(stderr, Errmsg_opne, fldefs,
1092 strerror(errno));
1093 return (1);
1094 }
1095 }
1096 if (fldata) {
1097 if (fldefs && (strcmp(fldefs, fldata) == 0))
1098 fddata = fddefs;
1099 else if ((fddata = fopen(fldata, "w+")) == NULL) {
1100 (void) fprintf(stderr, Errmsg_opne, fldata,
1101 strerror(errno));
1102 return (1);
1103 }
1104 }
1105 if (fddefs && fddata) {
1106 (void) sprintf(fllint, "%s.%d", nmlint, (int)getpid());
1107 if ((fdlint = fopen(fllint, "w+")) == NULL) {
1108 (void) fprintf(stderr, Errmsg_opne, fllint,
1109 strerror(errno));
1110 return (1);
1111 }
1112 }
1113 if (flmsgs) {
1114 if ((fdmsgs = fopen(flmsgs, "w+")) == NULL) {
1115 (void) fprintf(stderr, Errmsg_opne, flmsgs,
1116 strerror(errno));
1117 return (1);
1118 }
1119 }
1120 if (flmids) {
1121 if ((fdmids = fopen(flmids, "r")) == NULL) {
1122 (void) fprintf(stderr, Errmsg_opne, flmids,
1123 strerror(errno));
1124 return (1);
1125 }
1126 }
1127
1128
1129 /*
1130 * Initialize the message definition and message data streams.
1131 */
1132 if (fddefs) {
1133 if (init_defs())
1134 return (1);
1135 }
1136
1137 /*
1138 * Read the input message file, and for each line process accordingly.
1139 */
1140 for (; optind < argc; optind++) {
1141 int err;
1142
1143 fldesc = argv[optind];
1144
1145 if ((fddesc = fopen(fldesc, "r")) == NULL) {
1146 (void) fprintf(stderr, Errmsg_opne, fldesc,
1147 strerror(errno));
1148 return (1);
1149 }
1150 err = file();
1151 (void) fclose(fddesc);
1152
1153 if (err != 0)
1154 return (1);
1155 }
1156
1157 /*
1158 * If a msgid has been output a msgstr must follow before we end the
1159 * file.
1160 */
1161 if (msgid) {
1162 msgid = 0;
1163 if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
1164 (void) fprintf(stderr, Errmsg_wrte, flmsgs,
1165 strerror(errno));
1166 return (1);
1167 }
1168 }
1169
1170 if (fdmids)
1171 (void) fclose(fdmids);
1172 if (fdmsgs)
1173 (void) fclose(fdmsgs);
1174
1175 if (fddefs) {
1176 if (output_defs())
1177 return (1);
1178 }
1179
1180 /*
1181 * Finish off any generated data and header file.
1182 */
1183 if (fldata) {
1184 if (output_data())
1185 return (1);
1186 }
1187 if (fddefs) {
1188 if (fini_defs())
1189 return (1);
1190 }
1191
1192 if (vflag)
1193 dump_stringtab(stp);
1194
1195 /*
1196 * Close up everything and go home.
1197 */
1198 if (fddata)
1199 (void) fclose(fddata);
1200 if (fddefs && (fddefs != fddata))
1201 (void) fclose(fddefs);
1202 if (fddefs && fddata) {
1203 (void) fclose(fdlint);
1204 (void) unlink(fllint);
1205 }
1206
1207 if (stp)
1208 st_destroy(stp);
1209
1210 return (0);
1211 }

Properties

Name Value
svn:keywords MidnightBSD=%H