1 #ifdef _MSC_VER 2 # define _POSIX_ 3 #endif 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #ifdef __hpux 8 # define _HPUX_SOURCE 9 #endif 10 #if defined(__IBMC__) || defined(__EMX__) 11 # define PATH_MAX _MAX_PATH 12 #endif 13 #include <limits.h> 14 15 #include "cpp.h" 16 17 #define NCONCAT 16384 18 19 /* 20 * do a macro definition. tp points to the name being defined in the line 21 */ 22 void 23 dodefine(Tokenrow * trp) 24 { 25 Token *tp; 26 Nlist *np; 27 Source *s; 28 Tokenrow *def, *args; 29 static uchar location[(PATH_MAX + 8) * NINC], *cp; 30 31 tp = trp->tp + 1; 32 if (tp >= trp->lp || tp->type != NAME) 33 { 34 error(ERROR, "#defined token is not a name"); 35 return; 36 } 37 np = lookup(tp, 1); 38 if (np->flag & ISUNCHANGE) 39 { 40 error(ERROR, "#defined token %t can't be redefined", tp); 41 return; 42 } 43 /* collect arguments */ 44 tp += 1; 45 args = NULL; 46 if (tp < trp->lp && tp->type == LP && tp->wslen == 0) 47 { 48 /* macro with args */ 49 int narg = 0; 50 51 tp += 1; 52 args = new(Tokenrow); 53 maketokenrow(2, args); 54 if (tp->type != RP) 55 { 56 int err = 0; 57 58 for (;;) 59 { 60 Token *atp; 61 62 if (tp->type != NAME) 63 { 64 err++; 65 break; 66 } 67 if (narg >= args->max) 68 growtokenrow(args); 69 for (atp = args->bp; atp < args->lp; atp++) 70 if (atp->len == tp->len 71 && strncmp((char *) atp->t, (char *) tp->t, tp->len) == 0) 72 error(ERROR, "Duplicate macro argument"); 73 *args->lp++ = *tp; 74 narg++; 75 tp += 1; 76 if (tp->type == RP) 77 break; 78 if (tp->type != COMMA) 79 { 80 err++; 81 break; 82 } 83 tp += 1; 84 } 85 if (err) 86 { 87 error(ERROR, "Syntax error in macro parameters"); 88 return; 89 } 90 } 91 tp += 1; 92 } 93 trp->tp = tp; 94 if (((trp->lp) - 1)->type == NL) 95 trp->lp -= 1; 96 def = normtokenrow(trp); 97 if (np->flag & ISDEFINED) 98 { 99 if (comparetokens(def, np->vp) 100 || (np->ap == NULL) != (args == NULL) 101 || (np->ap && comparetokens(args, np->ap))) 102 { 103 if ( np->loc ) 104 error(ERROR, 105 "Macro redefinition of %t (already defined at %s)", 106 trp->bp + 2, np->loc); 107 else 108 error(ERROR, 109 "Macro redefinition of %t (already defined at %s)", 110 trp->bp + 2, "commandline" ); 111 } 112 } 113 if (args) 114 { 115 Tokenrow *tap; 116 117 tap = normtokenrow(args); 118 dofree(args->bp); 119 args = tap; 120 } 121 np->ap = args; 122 np->vp = def; 123 np->flag |= ISDEFINED; 124 125 /* build location string of macro definition */ 126 for (cp = location, s = cursource; s; s = s->next) 127 if (*s->filename) 128 { 129 if (cp != location) 130 *cp++ = ' '; 131 sprintf((char *)cp, "%s:%d", s->filename, s->line); 132 cp += strlen((char *)cp); 133 } 134 135 np->loc = newstring(location, strlen((char *)location), 0); 136 137 if (Mflag) 138 { 139 if (np->ap) 140 error(INFO, "Macro definition of %s(%r) [%r]", np->name, np->ap, np->vp); 141 else 142 error(INFO, "Macro definition of %s [%r]", np->name, np->vp); 143 } 144 } 145 146 /* 147 * Definition received via -D or -U 148 */ 149 void 150 doadefine(Tokenrow * trp, int type) 151 { 152 Nlist *np; 153 static uchar onestr[2] = "1"; 154 static Token onetoken[1] = {{NUMBER, 0, 0, 1, onestr, 0}}; 155 static Tokenrow onetr = {onetoken, onetoken, onetoken + 1, 1}; 156 157 trp->tp = trp->bp; 158 if (type == 'U') 159 { 160 if (trp->lp - trp->tp != 2 || trp->tp->type != NAME) 161 goto syntax; 162 if ((np = lookup(trp->tp, 0)) == NULL) 163 return; 164 np->flag &= ~ISDEFINED; 165 return; 166 } 167 168 if (type == 'A') 169 { 170 if (trp->tp >= trp->lp || trp->tp->type != NAME) 171 goto syntax; 172 trp->tp->type = ARCHITECTURE; 173 np = lookup(trp->tp, 1); 174 np->flag |= ISARCHITECTURE; 175 trp->tp += 1; 176 if (trp->tp >= trp->lp || trp->tp->type == END) 177 { 178 np->vp = &onetr; 179 return; 180 } 181 else 182 error(FATAL, "Illegal -A argument %r", trp); 183 } 184 185 if (trp->tp >= trp->lp || trp->tp->type != NAME) 186 goto syntax; 187 np = lookup(trp->tp, 1); 188 np->flag |= ISDEFINED; 189 trp->tp += 1; 190 if (trp->tp >= trp->lp || trp->tp->type == END) 191 { 192 np->vp = &onetr; 193 return; 194 } 195 if (trp->tp->type != ASGN) 196 goto syntax; 197 trp->tp += 1; 198 if ((trp->lp - 1)->type == END) 199 trp->lp -= 1; 200 np->vp = normtokenrow(trp); 201 return; 202 syntax: 203 error(FATAL, "Illegal -D or -U argument %r", trp); 204 } 205 206 207 208 /* 209 * Do macro expansion in a row of tokens. 210 * Flag is NULL if more input can be gathered. 211 */ 212 void 213 expandrow(Tokenrow * trp, char *flag) 214 { 215 Token * tp; 216 Nlist * np; 217 218 MacroValidatorList validators; 219 mvl_init(&validators); 220 /* Sets all token-identifiers to 0 because tokens may not be initialised (never use C!) */ 221 tokenrow_zeroTokenIdentifiers(trp); 222 223 if (flag) 224 setsource(flag, -1, -1, "", 0); 225 for (tp = trp->tp; tp < trp->lp;) 226 { 227 mvl_check(&validators, tp); 228 229 if (tp->type != NAME 230 || quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0) == 0 231 || (np = lookup(tp, 0)) == NULL 232 || (np->flag & (ISDEFINED | ISMAC)) == 0 233 || (np->flag & ISACTIVE) != 0) 234 { 235 tp++; 236 continue; 237 } 238 trp->tp = tp; 239 if (np->val == KDEFINED) 240 { 241 tp->type = DEFINED; 242 if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) 243 (tp + 1)->type = NAME1; 244 else 245 if ((tp + 3) < trp->lp && (tp + 1)->type == LP 246 && (tp + 2)->type == NAME && (tp + 3)->type == RP) 247 (tp + 2)->type = NAME1; 248 else 249 error(ERROR, "Incorrect syntax for `defined'"); 250 tp++; 251 continue; 252 } 253 else 254 if (np->val == KMACHINE) 255 { 256 if (((tp - 1) >= trp->bp) && ((tp - 1)->type == SHARP)) 257 { 258 tp->type = ARCHITECTURE; 259 if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) 260 (tp + 1)->type = NAME2; 261 else 262 if ((tp + 3) < trp->lp && (tp + 1)->type == LP 263 && (tp + 2)->type == NAME && (tp + 3)->type == RP) 264 (tp + 2)->type = NAME2; 265 else 266 error(ERROR, "Incorrect syntax for `#machine'"); 267 } 268 tp++; 269 continue; 270 } 271 272 if (np->flag & ISMAC) 273 builtin(trp, np->val); 274 else 275 expand(trp, np, &validators); 276 tp = trp->tp; 277 } // end for 278 if (flag) 279 unsetsource(); 280 281 mvl_destruct(&validators); 282 } 283 284 /* 285 * Expand the macro whose name is np, at token trp->tp, in the tokenrow. 286 * Return trp->tp at the first token next to be expanded 287 * (ordinarily the beginning of the expansion) 288 * I.e.: the same position as before! 289 * Only one expansion is performed, then we return to the expandrow() 290 * loop and start at same position. 291 */ 292 void 293 expand(Tokenrow * trp, Nlist * np, MacroValidatorList * pValidators) 294 { 295 // Token * pOldNextTp; 296 Tokenrow ntr; 297 int ntokc, narg, i; 298 Tokenrow *atr[NARG + 1]; 299 300 if (Mflag == 2) 301 { 302 if (np->ap) 303 error(INFO, "Macro expansion of %t with %s(%r)", trp->tp, np->name, np->ap); 304 else 305 error(INFO, "Macro expansion of %t with %s", trp->tp, np->name); 306 } 307 308 copytokenrow(&ntr, np->vp); /* copy macro value */ 309 if (np->ap == NULL) /* parameterless */ 310 ntokc = 1; 311 else 312 { 313 ntokc = gatherargs(trp, atr, &narg); 314 if (narg < 0) 315 { /* not actually a call (no '(') */ 316 trp->tp++; 317 return; 318 } 319 if (narg != rowlen(np->ap)) 320 { 321 error(ERROR, "Disagreement in number of macro arguments"); 322 trp->tp += ntokc; 323 return; 324 } 325 326 /** If gatherargs passed a macro validating token, this token 327 must become valid here. 328 trp->tp+0 was checked in expandrow(), so we dont need to do it 329 again here: 330 */ 331 for (i = 1; i < ntokc; i++) 332 { 333 mvl_check(pValidators,trp->tp+i); 334 } 335 336 substargs(np, &ntr, atr); /* put args into replacement */ 337 for (i = 0; i < narg; i++) 338 { 339 dofree(atr[i]->bp); 340 dofree(atr[i]); 341 } 342 } 343 344 /* old 345 np->flag |= ISACTIVE; 346 */ 347 348 /* rh 349 */ 350 doconcat(&ntr); /* execute ## operators */ 351 ntr.tp = ntr.bp; 352 makespace(&ntr, trp->tp); 353 354 /* old 355 // expandrow(&ntr, "<expand>"); 356 // insertrow(trp, ntokc, &ntr); 357 // dofree(ntr.bp); 358 // np->flag &= ~ISACTIVE; 359 */ 360 361 /* NP 362 // Replace macro by its value: 363 */ 364 // pOldNextTp = trp->tp+ntokc; 365 tokenrow_zeroTokenIdentifiers(&ntr); 366 insertrow(trp, ntokc, &ntr); 367 /* Reassign old macro validators: 368 */ 369 // mvl_move(pValidators, trp->tp - pOldNextTp); 370 371 /* add validator for just invalidated macro: 372 */ 373 np->flag |= ISACTIVE; 374 if (trp->tp != trp->lp) 375 { /* tp is a valid pointer: */ 376 mvl_add(pValidators,np,trp->tp); 377 } 378 else 379 { /* tp is == lp, therefore does not point to valid memory: */ 380 mvl_add(pValidators,np,0); 381 } 382 /* reset trp->tp to original position: 383 */ 384 trp->tp -= ntr.lp - ntr.bp; /* so the result will be tested for macros from the same position again */ 385 386 dofree(ntr.bp); 387 388 return; 389 } 390 391 /* 392 * Gather an arglist, starting in trp with tp pointing at the macro name. 393 * Return total number of tokens passed, stash number of args found. 394 * trp->tp is not changed relative to the tokenrow. 395 */ 396 int 397 gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg) 398 { 399 int parens = 1; 400 int ntok = 0; 401 Token *bp, *lp; 402 Tokenrow ttr; 403 int ntokp; 404 int needspace; 405 406 *narg = -1; /* means that there is no macro 407 * call */ 408 /* look for the ( */ 409 for (;;) 410 { 411 trp->tp++; 412 ntok++; 413 if (trp->tp >= trp->lp) 414 { 415 gettokens(trp, 0); 416 if ((trp->lp - 1)->type == END) 417 { 418 trp->lp -= 1; 419 trp->tp -= ntok; 420 return ntok; 421 } 422 } 423 if (trp->tp->type == LP) 424 break; 425 if (trp->tp->type != NL) 426 return ntok; 427 } 428 *narg = 0; 429 ntok++; 430 ntokp = ntok; 431 trp->tp++; 432 /* search for the terminating ), possibly extending the row */ 433 needspace = 0; 434 while (parens > 0) 435 { 436 if (trp->tp >= trp->lp) 437 gettokens(trp, 0); 438 if (needspace) 439 { 440 needspace = 0; 441 /* makespace(trp); [rh] */ 442 } 443 if (trp->tp->type == END) 444 { 445 trp->lp -= 1; 446 trp->tp -= ntok; 447 error(ERROR, "EOF in macro arglist"); 448 return ntok; 449 } 450 if (trp->tp->type == NL) 451 { 452 trp->tp += 1; 453 adjustrow(trp, -1); 454 trp->tp -= 1; 455 /* makespace(trp); [rh] */ 456 needspace = 1; 457 continue; 458 } 459 if (trp->tp->type == LP) 460 parens++; 461 else 462 if (trp->tp->type == RP) 463 parens--; 464 trp->tp++; 465 ntok++; 466 } 467 trp->tp -= ntok; 468 /* Now trp->tp won't move underneath us */ 469 lp = bp = trp->tp + ntokp; 470 for (; parens >= 0; lp++) 471 { 472 if (lp->type == LP) 473 { 474 parens++; 475 continue; 476 } 477 if (lp->type == RP) 478 parens--; 479 if (lp->type == DSHARP) 480 lp->type = DSHARP1; /* ## not special in arg */ 481 if ((lp->type == COMMA && parens == 0) || 482 ( parens < 0 && ((lp - 1)->type != LP))) 483 { 484 if (*narg >= NARG - 1) 485 error(FATAL, "Sorry, too many macro arguments"); 486 ttr.bp = ttr.tp = bp; 487 ttr.lp = lp; 488 atr[(*narg)++] = normtokenrow(&ttr); 489 bp = lp + 1; 490 } 491 } 492 return ntok; 493 } 494 495 /* 496 * substitute the argument list into the replacement string 497 * This would be simple except for ## and # 498 */ 499 void 500 substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr) 501 { 502 Tokenrow tatr; 503 Token *tp; 504 int ntok, argno; 505 506 for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;) 507 { 508 if (rtr->tp->type == SHARP) 509 { /* string operator */ 510 tp = rtr->tp; 511 rtr->tp += 1; 512 if ((argno = lookuparg(np, rtr->tp)) < 0) 513 { 514 error(ERROR, "# not followed by macro parameter"); 515 continue; 516 } 517 ntok = 1 + (rtr->tp - tp); 518 rtr->tp = tp; 519 insertrow(rtr, ntok, stringify(atr[argno])); 520 continue; 521 } 522 if (rtr->tp->type == NAME 523 && (argno = lookuparg(np, rtr->tp)) >= 0) 524 { 525 if (((rtr->tp + 1) < rtr->lp && (rtr->tp + 1)->type == DSHARP) 526 || (rtr->tp != rtr->bp && (rtr->tp - 1)->type == DSHARP)) 527 { 528 copytokenrow(&tatr, atr[argno]); 529 makespace(&tatr, rtr->tp); 530 insertrow(rtr, 1, &tatr); 531 dofree(tatr.bp); 532 } 533 else 534 { 535 copytokenrow(&tatr, atr[argno]); 536 makespace(&tatr, rtr->tp); 537 expandrow(&tatr, "<macro>"); 538 insertrow(rtr, 1, &tatr); 539 dofree(tatr.bp); 540 } 541 continue; 542 } 543 rtr->tp++; 544 } 545 } 546 547 /* 548 * Evaluate the ## operators in a tokenrow 549 */ 550 void 551 doconcat(Tokenrow * trp) 552 { 553 Token *ltp, *ntp; 554 Tokenrow ntr; 555 int len; 556 557 for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++) 558 { 559 if (trp->tp->type == DSHARP1) 560 trp->tp->type = DSHARP; 561 else 562 if (trp->tp->type == DSHARP) 563 { 564 int i; 565 char tt[NCONCAT]; 566 567 ltp = trp->tp - 1; 568 ntp = trp->tp + 1; 569 570 if (ltp < trp->bp || ntp >= trp->lp) 571 { 572 error(ERROR, "## occurs at border of replacement"); 573 continue; 574 } 575 576 ntp = ltp; 577 i = 1; 578 len = 0; 579 580 do 581 { 582 if (len + ntp->len + ntp->wslen > sizeof(tt)) 583 { 584 error(ERROR, "## string concatination buffer overrun"); 585 break; 586 } 587 588 if (ntp != trp->tp + 1) 589 { 590 strncpy((char *) tt + len, (char *) ntp->t - ntp->wslen, 591 ntp->len + ntp->wslen); 592 len += ntp->len + ntp->wslen; 593 } 594 else // Leerzeichen um ## herum entfernen: 595 { 596 strncpy((char *) tt + len, (char *) ntp->t, ntp->len); 597 len += ntp->len; 598 } 599 600 ntp = trp->tp + i; 601 i++; 602 } 603 while (ntp < trp->lp); 604 605 tt[len] = '\0'; 606 setsource("<##>", -1, -1, tt, 0); 607 maketokenrow(3, &ntr); 608 gettokens(&ntr, 1); 609 unsetsource(); 610 if (ntr.bp->type == UNCLASS) 611 error(WARNING, "Bad token %r produced by ##", &ntr); 612 while ((ntr.lp-1)->len == 0 && ntr.lp != ntr.bp) 613 ntr.lp--; 614 615 doconcat(&ntr); 616 trp->tp = ltp; 617 makespace(&ntr, ltp); 618 insertrow(trp, ntp - ltp, &ntr); 619 dofree(ntr.bp); 620 trp->tp--; 621 } 622 } 623 } 624 625 /* 626 * tp is a potential parameter name of macro mac; 627 * look it up in mac's arglist, and if found, return the 628 * corresponding index in the argname array. Return -1 if not found. 629 */ 630 int 631 lookuparg(Nlist * mac, Token * tp) 632 { 633 Token *ap; 634 635 if (tp->type != NAME || mac->ap == NULL) 636 return -1; 637 for (ap = mac->ap->bp; ap < mac->ap->lp; ap++) 638 { 639 if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0) 640 return ap - mac->ap->bp; 641 } 642 return -1; 643 } 644 645 /* 646 * Return a quoted version of the tokenrow (from # arg) 647 */ 648 #define STRLEN 512 649 Tokenrow * 650 stringify(Tokenrow * vp) 651 { 652 static Token t = {STRING, 0, 0, 0, NULL, 0}; 653 static Tokenrow tr = {&t, &t, &t + 1, 1}; 654 Token *tp; 655 uchar s[STRLEN]; 656 uchar *sp = s, *cp; 657 int i, instring; 658 659 *sp++ = '"'; 660 for (tp = vp->bp; tp < vp->lp; tp++) 661 { 662 instring = tp->type == STRING || tp->type == CCON; 663 if (sp + 2 * tp->len + tp->wslen >= &s[STRLEN - 10]) 664 { 665 error(ERROR, "Stringified macro arg is too long"); 666 break; 667 } 668 669 // Change by np 31.10.2001, #93725 - begin 670 if ( tp->wslen > 0 ) 671 *sp++ = ' '; 672 // change end. 673 674 for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++) 675 { 676 if (instring && (*cp == '"' || *cp == '\\')) 677 *sp++ = '\\'; 678 *sp++ = *cp++; 679 } 680 } 681 *sp++ = '"'; 682 *sp = '\0'; 683 sp = s; 684 t.len = strlen((char *) sp); 685 t.t = newstring(sp, t.len, 0); 686 return &tr; 687 } 688 689 /* 690 * expand a builtin name 691 */ 692 void 693 builtin(Tokenrow * trp, int biname) 694 { 695 char *op; 696 Token *tp; 697 Source *s; 698 699 tp = trp->tp; 700 trp->tp++; 701 /* need to find the real source */ 702 s = cursource; 703 while (s && s->fd == -1) 704 s = s->next; 705 if (s == NULL) 706 s = cursource; 707 /* most are strings */ 708 tp->type = STRING; 709 if (tp->wslen) 710 { 711 *outptr++ = ' '; 712 tp->wslen = 1; 713 } 714 op = outptr; 715 *op++ = '"'; 716 switch (biname) 717 { 718 719 case KLINENO: 720 tp->type = NUMBER; 721 op = outnum(op - 1, s->line); 722 break; 723 724 case KFILE: 725 { 726 char *src = s->filename; 727 728 while ((*op++ = *src++) != 0) 729 if (src[-1] == '\\') 730 *op++ = '\\'; 731 op--; 732 break; 733 } 734 735 case KDATE: 736 strncpy(op, curtime + 4, 7); 737 strncpy(op + 7, curtime + 20, 4); 738 op += 11; 739 break; 740 741 case KTIME: 742 strncpy(op, curtime + 11, 8); 743 op += 8; 744 break; 745 746 default: 747 error(ERROR, "cpp botch: unknown internal macro"); 748 return; 749 } 750 if (tp->type == STRING) 751 *op++ = '"'; 752 tp->t = (uchar *) outptr; 753 tp->len = op - outptr; 754 outptr = op; 755 } 756 757