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