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