1 %{ 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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <limits.h> 32 #include <string.h> 33 #include <libintl.h> 34 #include <locale.h> 35 #include "genmsg.h" 36 #include "y.tab.h" 37 38 extern int is_cat_found; /* from main.c */ 39 extern void add_comment(Mode, char *); /* from util.c */ 40 41 int lineno = 1; 42 43 /* 44 * msg_line stores the line number where a msgid is to be replaced. 45 */ 46 int msg_line = 0; 47 48 int end_of_cat = TRUE; 49 50 /* 51 * In preprocessor mode, genmsg has to parse both the original 52 * soruce code and the code which a preprocessor generates. 53 * While genmsg is parsing the original source code, 'pound_is_mine' 54 * is set to TRUE. 55 */ 56 int pound_is_mine = FALSE; 57 58 void warning(char *); 59 60 #define NOLINEMSG -2 61 62 void set_linemsgid(int, int); 63 int get_linemsgid(int); 64 65 /* 66 * cat_field indicates which token is currently parsed by lex. 67 */ 68 #define CatdField 0 69 #define SetidField 1 70 #define MsgidField 2 71 #define StrField 3 72 73 static int cat_field; 74 75 /* 76 * This will be turned on when '-' is found in the catgets message 77 * number field. 78 */ 79 static int save_minus = FALSE; 80 81 static char *skip_quoted(int skip_ch); 82 static char *skip_comment(void); 83 static void parse_cppline(char *); 84 %} 85 %s CAT 86 %% 87 88 [0-9a-zA-Z\_\.]catgets { 89 if (IsActiveMode(ReplaceMode)) { 90 (void) fprintf(newfp, "%s", yytext); 91 } 92 } 93 94 catgets[0-9a-zA-Z\_\.] { 95 if (IsActiveMode(ReplaceMode)) { 96 (void) fprintf(newfp, "%s", yytext); 97 } 98 } 99 100 catgets { 101 if (end_of_cat) { 102 /* 103 * If the previous catgets 104 * state is on, turn it off 105 * first. 106 */ 107 BEGIN 0; 108 } 109 if (IsActiveMode(ReplaceMode)) { 110 (void) fprintf(newfp, "%s", yytext); 111 } 112 if (!IsActiveMode(ReplaceMode) || 113 !IsActiveMode(PreProcessMode)) { 114 BEGIN CAT; 115 end_of_cat = FALSE; 116 cat_field = CatdField; 117 return (CATGETS); 118 } 119 } 120 121 <CAT>\, { /* punctuation */ 122 cat_field++; 123 if (IsActiveMode(ReplaceMode)) { 124 (void) fprintf(newfp, "%c", yytext[0]); 125 } 126 if (end_of_cat) { 127 BEGIN 0; 128 } else { 129 return (yytext[0]); 130 } 131 } 132 133 <CAT>[+*/();>] { /* punctuation */ 134 if (IsActiveMode(ReplaceMode)) { 135 (void) fprintf(newfp, "%c", yytext[0]); 136 } 137 if (end_of_cat) { 138 BEGIN 0; 139 } else { 140 return (yytext[0]); 141 } 142 } 143 144 <CAT>const { 145 if (IsActiveMode(ReplaceMode)) { 146 (void) fprintf(newfp, "%s", yytext); 147 } 148 if (end_of_cat) { 149 BEGIN 0; 150 } else { 151 return (CONST); 152 } 153 } 154 155 <CAT>nl_catd { 156 if (IsActiveMode(ReplaceMode)) { 157 (void) fprintf(newfp, "%s", yytext); 158 } 159 if (end_of_cat) { 160 BEGIN 0; 161 } else { 162 return (CATD); 163 } 164 } 165 166 <CAT>char { 167 if (IsActiveMode(ReplaceMode)) { 168 (void) fprintf(newfp, "%s", yytext); 169 } 170 if (end_of_cat) { 171 BEGIN 0; 172 } else { 173 return (CHAR); 174 } 175 } 176 177 <CAT>int { 178 if (IsActiveMode(ReplaceMode)) { 179 (void) fprintf(newfp, "%s", yytext); 180 } 181 if (end_of_cat) { 182 BEGIN 0; 183 } else { 184 return (INT); 185 } 186 } 187 188 <CAT>\+\+ { 189 if (IsActiveMode(ReplaceMode)) { 190 (void) fprintf(newfp, "%s", yytext); 191 } 192 if (end_of_cat) { 193 BEGIN 0; 194 } else { 195 return (INC); 196 } 197 } 198 199 <CAT>\-\- { 200 if (IsActiveMode(ReplaceMode)) { 201 (void) fprintf(newfp, "%s", yytext); 202 } 203 if (end_of_cat) { 204 BEGIN 0; 205 } else { 206 return (INC); 207 } 208 } 209 210 <CAT>\" { /* extract quoted string */ 211 yylval.str = skip_quoted('"'); 212 if (IsActiveMode(ReplaceMode)) { 213 (void) fprintf(newfp, "\"%s\"", yylval.str); 214 } 215 if (end_of_cat) { /* just in case */ 216 BEGIN 0; 217 free(yylval.str); 218 } else { 219 return (QSTR); 220 } 221 } 222 223 <CAT>- { /* punctuation */ 224 if (IsActiveMode(ReplaceMode)) { 225 if (cat_field == MsgidField && 226 get_linemsgid(lineno) != NOLINEMSG) { 227 save_minus = TRUE; /* be replaced. */ 228 } else { 229 (void) fprintf(newfp, "%c", yytext[0]); 230 } 231 } 232 if (end_of_cat) { /* just in case */ 233 BEGIN 0; 234 } else { 235 return (yytext[0]); 236 } 237 } 238 239 <CAT>[0-9]+ { /* numbers */ 240 switch (cat_field) { 241 case SetidField: 242 yylval.id = atoi(yytext); 243 if (IsActiveMode(ReplaceMode)) { 244 (void) fprintf(newfp, "%s", yytext); 245 } 246 if (end_of_cat) { 247 BEGIN 0; 248 } else { 249 return (SETID); 250 } 251 break; 252 case MsgidField: 253 yylval.id = atoi(yytext); 254 if (IsActiveMode(ReplaceMode)) { 255 int id = get_linemsgid(lineno); 256 if (id == NOLINEMSG) { 257 (void) fprintf(newfp, "%s", 258 yytext); 259 } else if (id == NOMSGID && 260 IsActiveMode(ReverseMode)) { 261 (void) fprintf(newfp, "%d", 262 NOMSGID); 263 } else if (save_minus == TRUE && 264 yylval.id == 1) { 265 (void) fprintf(newfp, "%d", id); 266 } else { /* just in case */ 267 (void) fprintf(newfp, "%s", 268 yytext); 269 } 270 save_minus = FALSE; 271 } else { 272 msg_line = lineno; 273 } 274 if (end_of_cat) { 275 BEGIN 0; 276 } else { 277 return (MSGID); 278 } 279 break; 280 default: 281 yylval.id = atoi(yytext); 282 if (IsActiveMode(ReplaceMode)) { 283 (void) fprintf(newfp, "%s", yytext); 284 } 285 if (end_of_cat) { 286 BEGIN 0; 287 } else { 288 return (DIGIT); 289 } 290 } 291 } 292 293 <CAT>[a-zA-Z0-9_\&][a-zA-Z0-9_\>\&\.]* { 294 if (IsActiveMode(ReplaceMode)) { 295 (void) fprintf(newfp, "%s", yytext); 296 } 297 if (end_of_cat) { 298 BEGIN 0; 299 } else { 300 return (STR); 301 } 302 } 303 304 <CAT>\n { 305 lineno++; 306 if (IsActiveMode(ReplaceMode)) { 307 (void) fprintf(newfp, "\n"); 308 } 309 if (end_of_cat) { 310 BEGIN 0; 311 } 312 } 313 314 <CAT>. { /* not interested */ 315 if (IsActiveMode(ReplaceMode)) { 316 (void) fprintf(newfp, "%c", yytext[0]); 317 } 318 if (end_of_cat) { 319 BEGIN 0; 320 } 321 } 322 323 -((([ \t]+)1)|1) { /* -1 */ 324 if (end_of_cat == FALSE) { 325 REJECT; 326 } else if (IsActiveMode(ReplaceMode)) { 327 if (IsActiveMode(PreProcessMode)) { 328 int id = get_linemsgid(lineno); 329 if (id == NOLINEMSG) { 330 (void) fprintf(newfp, "%s", 331 yytext); 332 } else { /* could be -1. */ 333 (void) fprintf(newfp, "%d", id); 334 } 335 } else { 336 (void) fprintf(newfp, "%s", yytext); 337 } 338 } 339 } 340 341 [0-9]+ { 342 if (IsActiveMode(ReplaceMode)) { 343 if (IsActiveMode(PreProcessMode) && 344 IsActiveMode(ReverseMode)) { 345 int id = get_linemsgid(lineno); 346 if (id == NOLINEMSG) { 347 (void) fprintf(newfp, "%s", 348 yytext); 349 } else if (id == NOMSGID) { 350 (void) fprintf(newfp, "%d", id); 351 } 352 } else { 353 (void) fprintf(newfp, "%s", yytext); 354 } 355 } 356 } 357 358 ^#[ \t]*[0-9]+.*\n { /* pound for c-preprocessor */ 359 if (IsActiveMode(PreProcessMode)) { 360 if (IsActiveMode(ReplaceMode)) { 361 (void) fprintf(newfp, "%s", yytext); 362 } else { 363 parse_cppline(yytext); 364 } 365 } else if (IsActiveMode(ReplaceMode)) { 366 (void) fprintf(newfp, "%s", yytext); 367 } 368 lineno++; 369 } 370 371 "/*" { /* skip a comment block */ 372 char *comment = skip_comment(); 373 if (IsActiveMode(ReplaceMode)) { 374 (void) fprintf(newfp, "%s", comment); 375 } else { 376 if (IsActiveMode(MsgCommentMode)) { 377 add_comment(MsgCommentMode, comment); 378 } 379 if (IsActiveMode(SetCommentMode)) { 380 add_comment(SetCommentMode, comment); 381 } 382 } 383 free(comment); 384 } 385 386 "//".*\n { /* skip a c++ comment */ 387 if (IsActiveMode(ReplaceMode)) { 388 (void) fprintf(newfp, "%s", yytext); 389 } else { 390 if (IsActiveMode(MsgCommentMode)) { 391 add_comment(MsgCommentMode, yytext); 392 } 393 if (IsActiveMode(SetCommentMode)) { 394 add_comment(SetCommentMode, yytext); 395 } 396 } 397 lineno++; 398 } 399 400 \" { /* skip quoted string */ 401 char *qstr = skip_quoted('"'); 402 if (IsActiveMode(ReplaceMode)) { 403 (void) fprintf(newfp, "\"%s\"", qstr); 404 } 405 free(qstr); 406 } 407 408 \' { /* skip single-quoted character */ 409 char *qchr = skip_quoted('\''); 410 if (IsActiveMode(ReplaceMode)) { 411 (void) fprintf(newfp, "\'%s\'", qchr); 412 } 413 free(qchr); 414 } 415 416 \n { 417 if (IsActiveMode(ReplaceMode)) { 418 (void) fprintf(newfp, "\n"); 419 } 420 lineno++; 421 } 422 423 . { 424 if (IsActiveMode(ReplaceMode)) { 425 (void) fprintf(newfp, "%c", yytext[0]); 426 } 427 } 428 429 %% 430 431 static char * 432 skip_quoted(int skip_ch) 433 { 434 char *buf, *ptr; /* saved buffer and its pointer */ 435 int bsize = BUFSIZ; /* growing buffer size */ 436 int i = 0; /* counter */ 437 int c, old = 0; /* input character */ 438 439 if ((buf = ptr = malloc(bsize)) == NULL) { 440 prg_err(gettext("fatal: out of memory")); 441 exit(EXIT_FAILURE); 442 } 443 for (; ; i++) { 444 if (i == bsize) { 445 bsize += BUFSIZ; 446 if ((buf = realloc(buf, bsize)) == NULL) { 447 prg_err(gettext("fatal: out of memory")); 448 exit(EXIT_FAILURE); 449 } 450 ptr = buf + i; 451 } 452 c = input(); 453 if (c == skip_ch && old != '\\') { 454 break; 455 } else if (c == '\n') { 456 lineno++; 457 } else if (c == 0) { 458 if (skip_ch == '"') { 459 warning(gettext("warning: unmatched \"")); 460 } else if (skip_ch == '\'') { 461 warning(gettext("warning: unmatched '")); 462 } else { 463 /* Should not happen */ 464 warning(gettext( 465 "warning: unmatched character")); 466 } 467 break; 468 } 469 *ptr++ = c; 470 if (old == '\\') { 471 old = '\0'; 472 } else { 473 old = c; 474 } 475 } 476 *ptr = '\0'; 477 return (buf); 478 } 479 480 static char * 481 skip_comment(void) 482 { 483 char *buf, *ptr; /* saved buffer and its pointer */ 484 int bsize = BUFSIZ; /* growing buffer size */ 485 int i = 0; /* counter */ 486 int c, old = 0; /* input character */ 487 488 if ((buf = ptr = malloc(bsize)) == NULL) { 489 prg_err(gettext("fatal: out of memory")); 490 exit(EXIT_FAILURE); 491 } 492 *ptr++ = '/'; i++; 493 *ptr++ = '*'; i++; 494 for (; ; i++) { 495 if (i == bsize) { 496 bsize += BUFSIZ; 497 if ((buf = realloc(buf, bsize)) == NULL) { 498 prg_err(gettext("fatal: out of memory")); 499 exit(EXIT_FAILURE); 500 } 501 ptr = buf + i; 502 } 503 c = input(); 504 if (c == '/' && old == '*') { 505 *ptr++ = c; 506 break; 507 } else if (c == '\n') { 508 lineno++; 509 } else if (c == 0) { 510 warning(gettext("warning: unmatched /*")); 511 break; 512 } 513 *ptr++ = old = c; 514 } 515 *ptr = '\0'; 516 return (buf); 517 } 518 519 /* 520 * parse_cppline() parses the line control information that a C 521 * preprocessor generates to indicate the location in the original 522 * file. See the cpp man in the details. 523 */ 524 static void 525 parse_cppline(char *str) 526 { 527 int n, line, len; 528 char ch; 529 char file[BUFSIZ]; 530 char *altfile = NULL; 531 char *pfile; 532 533 len = strlen(str); 534 if (len >= sizeof (file)) { 535 if ((altfile = malloc(len + 1)) == NULL) { 536 prg_err(gettext("fatal: out of memory")); 537 exit(EXIT_FAILURE); 538 } 539 pfile = altfile; 540 } else { 541 pfile = file; 542 } 543 /* LINTED: E_SEC_SCANF_UNBOUNDED_COPY */ 544 n = sscanf(str, "%c%d%s", &ch, &line, pfile); 545 546 /* 'file' is a quoted string but 'srcfile' is not. */ 547 len = strlen(pfile) - 2; 548 549 pfile++; 550 if (n == 3 && (strncmp(pfile, srcfile, len) == 0)) { 551 pound_is_mine = TRUE; 552 lineno = line - 1; 553 } else if (n == 2 && (pound_is_mine == TRUE)) { 554 lineno = line - 1; 555 } else { 556 pound_is_mine = FALSE; 557 } 558 if (altfile) 559 free(altfile); 560 } 561 562 typedef struct { 563 int line; 564 int msgid; 565 } LineMsgID; 566 567 static LineMsgID line_msgid[NL_MSGMAX]; 568 static int line_msgcnt; 569 570 void 571 init_lex(void) 572 { 573 lineno = 1; 574 end_of_cat = TRUE; 575 pound_is_mine = FALSE; 576 } 577 578 void 579 init_linemsgid(void) 580 { 581 line_msgcnt = 0; 582 (void) memset(line_msgid, 0, sizeof (LineMsgID) * NL_MSGMAX); 583 } 584 585 void 586 set_linemsgid(int line, int msgid) 587 { 588 if (line_msgcnt >= NL_MSGMAX) { 589 return; /* oops */ 590 } 591 line_msgid[line_msgcnt].line = line; 592 line_msgid[line_msgcnt].msgid = msgid; 593 line_msgcnt++; 594 } 595 596 int 597 get_linemsgid(int line) 598 { 599 int i, left, right; 600 left = 0; 601 right = line_msgcnt - 1; 602 while (left <= right) { 603 i = (left + right) >> 1; 604 if (line < line_msgid[i].line) { 605 right = i - 1; 606 } else if (line > line_msgid[i].line) { 607 left = i + 1; 608 } else { 609 return (line_msgid[i].msgid); 610 } 611 } 612 return (NOLINEMSG); 613 } 614 615 void 616 yyerror(char *s) 617 { 618 if ((IsActiveMode(PreProcessMode) && pound_is_mine == FALSE) || 619 IsActiveMode(ReplaceMode)) { 620 return; 621 } 622 src_err(srcfile, lineno, gettext("%s before or at: %s"), s, yytext); 623 } 624 625 void 626 warning(char *s) 627 { 628 if ((IsActiveMode(PreProcessMode) && pound_is_mine == FALSE) || 629 IsActiveMode(ReplaceMode)) { 630 return; 631 } 632 src_err(srcfile, lineno, "%s", s); 633 } 634