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