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