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