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