parse.c revision b2f5b1db
1/* 2 3Copyright (c) 1993, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27#include "def.h" 28 29static int deftype (char *line, struct filepointer *filep, 30 struct inclist *file_red, struct inclist *file, 31 int parse_it); 32static int zero_value(char *filename, char *exp, struct filepointer *filep, 33 struct inclist *file_red); 34static int merge2defines(struct inclist *file1, struct inclist *file2); 35 36static int 37gobble(struct filepointer *filep, struct inclist *file, 38 struct inclist *file_red) 39{ 40 char *line; 41 int type; 42 43 while ((line = getnextline(filep))) { 44 switch(type = deftype(line, filep, file_red, file, FALSE)) { 45 case IF: 46 case IFFALSE: 47 case IFGUESSFALSE: 48 case IFDEF: 49 case IFNDEF: 50 type = gobble(filep, file, file_red); 51 while ((type == ELIF) || (type == ELIFFALSE) || 52 (type == ELIFGUESSFALSE)) 53 type = gobble(filep, file, file_red); 54 if (type == ELSE) 55 (void)gobble(filep, file, file_red); 56 break; 57 case ELSE: 58 case ENDIF: 59 debug(0,("%s, line %d: #%s\n", 60 file->i_file, filep->f_line, 61 directives[type])); 62 return(type); 63 case DEFINE: 64 case UNDEF: 65 case INCLUDE: 66 case INCLUDEDOT: 67 case PRAGMA: 68 case ERROR: 69 case IDENT: 70 case SCCS: 71 case EJECT: 72 case WARNING: 73 case INCLUDENEXT: 74 case INCLUDENEXTDOT: 75 break; 76 case ELIF: 77 case ELIFFALSE: 78 case ELIFGUESSFALSE: 79 return(type); 80 case -1: 81 warning("%s", file_red->i_file); 82 if (file_red != file) 83 warning1(" (reading %s)", file->i_file); 84 warning1(", line %ld: unknown directive == \"%s\"\n", 85 filep->f_line, line); 86 break; 87 } 88 } 89 return(-1); 90} 91 92/* 93 * Decide what type of # directive this line is. 94 */ 95static int 96deftype (char *line, struct filepointer *filep, 97 struct inclist *file_red, struct inclist *file, int parse_it) 98{ 99 register char *p; 100 char *directive, savechar, *q; 101 register int ret; 102 103 /* 104 * Parse the directive... 105 */ 106 directive=line+1; 107 while (*directive == ' ' || *directive == '\t') 108 directive++; 109 110 p = directive; 111 while ((*p == '_') || (*p >= 'a' && *p <= 'z')) 112 p++; 113 savechar = *p; 114 *p = '\0'; 115 ret = match(directive, directives); 116 *p = savechar; 117 118 /* If we don't recognize this compiler directive or we happen to just 119 * be gobbling up text while waiting for an #endif or #elif or #else 120 * in the case of an #elif we must check the zero_value and return an 121 * ELIF or an ELIFFALSE. 122 */ 123 124 if (ret == ELIF && !parse_it) 125 { 126 while (*p == ' ' || *p == '\t') 127 p++; 128 /* 129 * parse an expression. 130 */ 131 debug(0,("%s, line %d: #elif %s ", 132 file->i_file, filep->f_line, p)); 133 ret = zero_value(file->i_file, p, filep, file_red); 134 if (ret != IF) 135 { 136 debug(0,("false...\n")); 137 if (ret == IFFALSE) 138 return(ELIFFALSE); 139 else 140 return(ELIFGUESSFALSE); 141 } 142 else 143 { 144 debug(0,("true...\n")); 145 return(ELIF); 146 } 147 } 148 149 if (ret < 0 || ! parse_it) 150 return(ret); 151 152 /* 153 * now decide how to parse the directive, and do it. 154 */ 155 while (*p == ' ' || *p == '\t') 156 p++; 157 q = p + strlen(p); 158 do { 159 q--; 160 } while (*q == ' ' || *q == '\t'); 161 q[1] = '\0'; 162 switch (ret) { 163 case IF: 164 /* 165 * parse an expression. 166 */ 167 ret = zero_value(file->i_file, p, filep, file_red); 168 debug(0,("%s, line %d: %s #if %s\n", 169 file->i_file, filep->f_line, ret?"false":"true", p)); 170 break; 171 case IFDEF: 172 case IFNDEF: 173 debug(0,("%s, line %d: #%s %s\n", 174 file->i_file, filep->f_line, directives[ret], p)); 175 case UNDEF: 176 /* 177 * separate the name of a single symbol. 178 */ 179 while (isalnum(*p) || *p == '_') 180 *line++ = *p++; 181 *line = '\0'; 182 break; 183 case INCLUDE: 184 case INCLUDENEXT: 185 debug(2,("%s, line %d: #include%s %s\n", 186 file->i_file, filep->f_line, 187 (ret == INCLUDE) ? "" : "_next", p)); 188 189 /* Support ANSI macro substitution */ 190 while (1) { 191 struct symtab **sym; 192 193 if (!*p || *p == '"' || *p == '<') 194 break; 195 196 sym = isdefined(p, file_red, NULL); 197 if (!sym) 198 break; 199 200 p = (*sym)->s_value; 201 debug(3,("%s : #includes SYMBOL %s = %s\n", 202 file->i_incstring, 203 (*sym) -> s_name, 204 (*sym) -> s_value)); 205 /* mark file as having included a 'soft include' */ 206 file->i_flags |= INCLUDED_SYM; 207 } 208 209 /* 210 * Separate the name of the include file. 211 */ 212 while (*p && *p != '"' && *p != '<') 213 p++; 214 if (! *p) 215 return(-2); 216 if (*p++ == '"') { 217 if (ret == INCLUDE) 218 ret = INCLUDEDOT; 219 else 220 ret = INCLUDENEXTDOT; 221 while (*p && *p != '"') 222 *line++ = *p++; 223 } else 224 while (*p && *p != '>') 225 *line++ = *p++; 226 *line = '\0'; 227 break; 228 case DEFINE: 229 /* 230 * copy the definition back to the beginning of the line. 231 */ 232 memmove (line, p, strlen(p) + 1); 233 break; 234 case ELSE: 235 case ENDIF: 236 case ELIF: 237 case PRAGMA: 238 case ERROR: 239 case IDENT: 240 case SCCS: 241 case EJECT: 242 case WARNING: 243 debug(0,("%s, line %d: #%s\n", 244 file->i_file, filep->f_line, directives[ret])); 245 /* 246 * nothing to do. 247 */ 248 break; 249 } 250 return(ret); 251} 252 253struct symtab ** 254fdefined(const char *symbol, struct inclist *file, struct inclist **srcfile) 255{ 256 struct inclist **ip; 257 struct symtab **val; 258 int i; 259 static int recurse_lvl = 0; 260 261 if (file->i_flags & DEFCHECKED) 262 return(NULL); 263 debug(2,("Looking for %s in %s\n", symbol, file->i_file)); 264 file->i_flags |= DEFCHECKED; 265 if ((val = slookup(symbol, file))) 266 debug(1,("%s defined in %s as %s\n", 267 symbol, file->i_file, (*val)->s_value)); 268 if (val == NULL && file->i_list) 269 { 270 for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++) 271 if (file->i_merged[i]==FALSE) { 272 val = fdefined(symbol, *ip, srcfile); 273 file->i_merged[i]=merge2defines(file,*ip); 274 if (val!=NULL) break; 275 } 276 } 277 else if (val != NULL && srcfile != NULL) *srcfile = file; 278 recurse_lvl--; 279 file->i_flags &= ~DEFCHECKED; 280 281 return(val); 282} 283 284struct symtab ** 285isdefined(const char *symbol, struct inclist *file, struct inclist **srcfile) 286{ 287 struct symtab **val; 288 289 if ((val = slookup(symbol, &maininclist))) { 290 debug(1,("%s defined on command line\n", symbol)); 291 if (srcfile != NULL) *srcfile = &maininclist; 292 return(val); 293 } 294 if ((val = fdefined(symbol, file, srcfile))) 295 return(val); 296 debug(1,("%s not defined in %s\n", symbol, file->i_file)); 297 return(NULL); 298} 299 300/* 301 * Return type based on if the #if expression evaluates to 0 302 */ 303static int 304zero_value(char *filename, 305 char *exp, 306 struct filepointer *filep, 307 struct inclist *file_red) 308{ 309 if (cppsetup(filename, exp, filep, file_red)) 310 return(IFFALSE); 311 else 312 return(IF); 313} 314 315void 316define2(const char *name, const char *val, struct inclist *file) 317{ 318 int first, last, below; 319 register struct symtab **sp = NULL, **dest; 320 struct symtab *stab; 321 322 /* Make space if it's needed */ 323 if (file->i_defs == NULL) 324 { 325 file->i_defs = malloc(sizeof (struct symtab*) * SYMTABINC); 326 file->i_ndefs = 0; 327 } 328 else if (!(file->i_ndefs % SYMTABINC)) 329 file->i_defs = realloc(file->i_defs, 330 sizeof(struct symtab*)*(file->i_ndefs+SYMTABINC)); 331 332 if (file->i_defs == NULL) 333 fatalerr("malloc()/realloc() failure in insert_defn()\n"); 334 335 below = first = 0; 336 last = file->i_ndefs - 1; 337 while (last >= first) 338 { 339 /* Fast inline binary search */ 340 register const char *s1; 341 register const char *s2; 342 register int middle = (first + last) / 2; 343 344 /* Fast inline strchr() */ 345 s1 = name; 346 s2 = file->i_defs[middle]->s_name; 347 while (*s1++ == *s2++) 348 if (s2[-1] == '\0') break; 349 350 /* If exact match, set sp and break */ 351 if (*--s1 == *--s2) 352 { 353 sp = file->i_defs + middle; 354 break; 355 } 356 357 /* If name > i_defs[middle] ... */ 358 if (*s1 > *s2) 359 { 360 below = first; 361 first = middle + 1; 362 } 363 /* else ... */ 364 else 365 { 366 below = last = middle - 1; 367 } 368 } 369 370 /* Search is done. If we found an exact match to the symbol name, 371 just replace its s_value */ 372 if (sp != NULL) 373 { 374 debug(1,("redefining %s from %s to %s in file %s\n", 375 name, (*sp)->s_value, val, file->i_file)); 376 free((*sp)->s_value); 377 (*sp)->s_value = strdup(val); 378 return; 379 } 380 381 sp = file->i_defs + file->i_ndefs++; 382 dest = file->i_defs + below + 1; 383 while (sp > dest) 384 { 385 *sp = sp[-1]; 386 sp--; 387 } 388 stab = malloc(sizeof (struct symtab)); 389 if (stab == NULL) 390 fatalerr("malloc()/realloc() failure in insert_defn()\n"); 391 392 debug(1,("defining %s to %s in file %s\n", name, val, file->i_file)); 393 stab->s_name = strdup(name); 394 stab->s_value = strdup(val); 395 *sp = stab; 396} 397 398void 399define(char *def, struct inclist *file) 400{ 401 char *val; 402 403 /* Separate symbol name and its value */ 404 val = def; 405 while (isalnum(*val) || *val == '_') 406 val++; 407 if (*val) 408 *val++ = '\0'; 409 while (*val == ' ' || *val == '\t') 410 val++; 411 412 if (!*val) 413 define2(def, "1", file); 414 else 415 define2(def, val, file); 416} 417 418struct symtab ** 419slookup(const char *symbol, struct inclist *file) 420{ 421 register int first = 0; 422 register int last; 423 424 if (file == NULL) 425 return NULL; 426 427 last = file->i_ndefs - 1; 428 429 while (last >= first) 430 { 431 /* Fast inline binary search */ 432 register const char *s1; 433 register const char *s2; 434 register int middle = (first + last) / 2; 435 436 /* Fast inline strchr() */ 437 s1 = symbol; 438 s2 = file->i_defs[middle]->s_name; 439 while (*s1++ == *s2++) 440 if (s2[-1] == '\0') break; 441 442 /* If exact match, we're done */ 443 if (*--s1 == *--s2) 444 { 445 return file->i_defs + middle; 446 } 447 448 /* If symbol > i_defs[middle] ... */ 449 if (*s1 > *s2) 450 { 451 first = middle + 1; 452 } 453 /* else ... */ 454 else 455 { 456 last = middle - 1; 457 } 458 } 459 return(NULL); 460} 461 462static int 463merge2defines(struct inclist *file1, struct inclist *file2) 464{ 465 int i; 466 467 if ((file1==NULL) || (file2==NULL) || 468 !(file2->i_flags & FINISHED)) 469 return 0; 470 471 for (i=0; i < file2->i_listlen; i++) 472 if (file2->i_merged[i]==FALSE) 473 return 0; 474 475 { 476 int first1 = 0; 477 int last1 = file1->i_ndefs - 1; 478 479 int first2 = 0; 480 int last2 = file2->i_ndefs - 1; 481 482 int first=0; 483 struct symtab** i_defs = NULL; 484 int deflen=file1->i_ndefs+file2->i_ndefs; 485 486 debug(2,("merging %s into %s\n", 487 file2->i_file, file1->i_file)); 488 489 if (deflen>0) 490 { 491 /* make sure deflen % SYMTABINC == 0 is still true */ 492 deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC; 493 i_defs = malloc(deflen*sizeof(struct symtab*)); 494 if (i_defs==NULL) return 0; 495 } 496 497 while ((last1 >= first1) && (last2 >= first2)) 498 { 499 const char *s1 = file1->i_defs[first1]->s_name; 500 const char *s2 = file2->i_defs[first2]->s_name; 501 502 if (strcmp(s1,s2) < 0) 503 i_defs[first++]=file1->i_defs[first1++]; 504 else if (strcmp(s1,s2) > 0) 505 i_defs[first++]=file2->i_defs[first2++]; 506 else /* equal */ 507 { 508 i_defs[first++]=file2->i_defs[first2++]; 509 first1++; 510 } 511 } 512 while (last1 >= first1) 513 { 514 i_defs[first++]=file1->i_defs[first1++]; 515 } 516 while (last2 >= first2) 517 { 518 i_defs[first++]=file2->i_defs[first2++]; 519 } 520 521 if (file1->i_defs) free(file1->i_defs); 522 file1->i_defs=i_defs; 523 file1->i_ndefs=first; 524 525 return 1; 526 } 527} 528 529void 530undefine(const char *symbol, struct inclist *file) 531{ 532 register struct symtab **ptr; 533 struct inclist *srcfile; 534 while ((ptr = isdefined(symbol, file, &srcfile)) != NULL) 535 { 536 srcfile->i_ndefs--; 537 for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++) 538 *ptr = ptr[1]; 539 } 540} 541 542int 543find_includes(struct filepointer *filep, struct inclist *file, 544 struct inclist *file_red, int recursion, boolean failOK) 545{ 546 struct inclist *inclistp; 547 const char **includedirsp; 548 register char *line; 549 register int type; 550 boolean recfailOK; 551 552 while ((line = getnextline(filep))) { 553 switch(type = deftype(line, filep, file_red, file, TRUE)) { 554 case IF: 555 doif: 556 type = find_includes(filep, file, 557 file_red, recursion+1, failOK); 558 while ((type == ELIF) || (type == ELIFFALSE) || 559 (type == ELIFGUESSFALSE)) 560 type = gobble(filep, file, file_red); 561 if (type == ELSE) 562 gobble(filep, file, file_red); 563 break; 564 case IFFALSE: 565 case IFGUESSFALSE: 566 doiffalse: 567 if (type == IFGUESSFALSE || type == ELIFGUESSFALSE) 568 recfailOK = TRUE; 569 else 570 recfailOK = failOK; 571 type = gobble(filep, file, file_red); 572 if (type == ELSE) 573 find_includes(filep, file, 574 file_red, recursion+1, recfailOK); 575 else 576 if (type == ELIF) 577 goto doif; 578 else 579 if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE)) 580 goto doiffalse; 581 break; 582 case IFDEF: 583 case IFNDEF: 584 if ((type == IFDEF && isdefined(line, file_red, NULL)) 585 || (type == IFNDEF && !isdefined(line, file_red, NULL))) { 586 debug(1,(type == IFNDEF ? 587 "line %d: %s !def'd in %s via %s%s\n" : "", 588 filep->f_line, line, 589 file->i_file, file_red->i_file, ": doit")); 590 type = find_includes(filep, file, 591 file_red, recursion+1, failOK); 592 while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE) 593 type = gobble(filep, file, file_red); 594 if (type == ELSE) 595 gobble(filep, file, file_red); 596 } 597 else { 598 debug(1,(type == IFDEF ? 599 "line %d: %s !def'd in %s via %s%s\n" : "", 600 filep->f_line, line, 601 file->i_file, file_red->i_file, ": gobble")); 602 type = gobble(filep, file, file_red); 603 if (type == ELSE) 604 find_includes(filep, file, 605 file_red, recursion+1, failOK); 606 else if (type == ELIF) 607 goto doif; 608 else if (type == ELIFFALSE || type == ELIFGUESSFALSE) 609 goto doiffalse; 610 } 611 break; 612 case ELSE: 613 case ELIFFALSE: 614 case ELIFGUESSFALSE: 615 case ELIF: 616 if (!recursion) 617 gobble(filep, file, file_red); 618 case ENDIF: 619 if (recursion) 620 return(type); 621 case DEFINE: 622 define(line, file); 623 break; 624 case UNDEF: 625 if (!*line) { 626 warning("%s", file_red->i_file); 627 if (file_red != file) 628 warning1(" (reading %s)", file->i_file); 629 warning1(", line %ld: incomplete undef == \"%s\"\n", 630 filep->f_line, line); 631 break; 632 } 633 undefine(line, file_red); 634 break; 635 case INCLUDE: 636 case INCLUDEDOT: 637 case INCLUDENEXT: 638 case INCLUDENEXTDOT: 639 inclistp = inclistnext; 640 includedirsp = includedirsnext; 641 debug(2,("%s, reading %s, includes %s\n", 642 file_red->i_file, file->i_file, line)); 643 add_include(filep, file, file_red, line, type, failOK); 644 inclistnext = inclistp; 645 includedirsnext = includedirsp; 646 break; 647 case ERROR: 648 case WARNING: 649 warning("%s", file_red->i_file); 650 if (file_red != file) 651 warning1(" (reading %s)", file->i_file); 652 warning1(", line %ld: %s\n", 653 filep->f_line, line); 654 break; 655 656 case PRAGMA: 657 case IDENT: 658 case SCCS: 659 case EJECT: 660 break; 661 case -1: 662 warning("%s", file_red->i_file); 663 if (file_red != file) 664 warning1(" (reading %s)", file->i_file); 665 warning1(", line %ld: unknown directive == \"%s\"\n", 666 filep->f_line, line); 667 break; 668 case -2: 669 warning("%s", file_red->i_file); 670 if (file_red != file) 671 warning1(" (reading %s)", file->i_file); 672 warning1(", line %ld: incomplete include == \"%s\"\n", 673 filep->f_line, line); 674 break; 675 } 676 } 677 file->i_flags |= FINISHED; 678 debug(2,("finished with %s\n", file->i_file)); 679 return(-1); 680} 681