1 /*- 2 * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by David A. Holland. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <stdint.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include "union.h" 36 #include "array.h" 37 #include "mode.h" 38 #include "place.h" 39 #include "macro.h" 40 #include "output.h" 41 42 struct expansionitem { 43 enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype; 44 union { 45 char *ei_string; /* for EI_STRING */ 46 unsigned ei_param; /* for EI_PARAM */ 47 } UN; 48 }; 49 DECLARRAY(expansionitem, static UNUSED); 50 DEFARRAY(expansionitem, static); 51 52 #ifdef NEED_UNION_ACCESSORS 53 #define ei_string un.ei_string 54 #define ei_param un.ei_param 55 #endif 56 57 58 struct macro { 59 struct place defplace; 60 struct place expansionplace; 61 unsigned hash; 62 char *name; 63 bool hasparams; 64 struct stringarray params; 65 struct expansionitemarray expansion; 66 bool inuse; 67 }; 68 DECLARRAY(macro, static UNUSED); 69 DEFARRAY(macro, static); 70 DECLARRAY(macroarray, static UNUSED); 71 DEFARRAY(macroarray, static); 72 73 static struct macroarrayarray macros; 74 static unsigned total_macros; 75 static unsigned hashmask; 76 77 //////////////////////////////////////////////////////////// 78 // macro structure ops 79 80 static 81 struct expansionitem * 82 expansionitem_create_string(const char *string) 83 { 84 struct expansionitem *ei; 85 86 ei = domalloc(sizeof(*ei)); 87 ei->itemtype = EI_STRING; 88 ei->ei_string = dostrdup(string); 89 return ei; 90 } 91 92 static 93 struct expansionitem * 94 expansionitem_create_stringlen(const char *string, size_t len) 95 { 96 struct expansionitem *ei; 97 98 ei = domalloc(sizeof(*ei)); 99 ei->itemtype = EI_STRING; 100 ei->ei_string = dostrndup(string, len); 101 return ei; 102 } 103 104 static 105 struct expansionitem * 106 expansionitem_create_param(unsigned param) 107 { 108 struct expansionitem *ei; 109 110 ei = domalloc(sizeof(*ei)); 111 ei->itemtype = EI_PARAM; 112 ei->ei_param = param; 113 return ei; 114 } 115 116 static 117 struct expansionitem * 118 expansionitem_create_file(void) 119 { 120 struct expansionitem *ei; 121 122 ei = domalloc(sizeof(*ei)); 123 ei->itemtype = EI_FILE; 124 return ei; 125 } 126 127 static 128 struct expansionitem * 129 expansionitem_create_line(void) 130 { 131 struct expansionitem *ei; 132 133 ei = domalloc(sizeof(*ei)); 134 ei->itemtype = EI_LINE; 135 return ei; 136 } 137 138 static 139 void 140 expansionitem_destroy(struct expansionitem *ei) 141 { 142 switch (ei->itemtype) { 143 case EI_STRING: 144 dostrfree(ei->ei_string); 145 break; 146 case EI_PARAM: 147 case EI_FILE: 148 case EI_LINE: 149 break; 150 } 151 dofree(ei, sizeof(*ei)); 152 } 153 154 static 155 bool 156 expansionitem_eq(const struct expansionitem *ei1, 157 const struct expansionitem *ei2) 158 { 159 if (ei1->itemtype != ei2->itemtype) { 160 return false; 161 } 162 switch (ei1->itemtype) { 163 case EI_STRING: 164 if (strcmp(ei1->ei_string, ei2->ei_string) != 0) { 165 return false; 166 } 167 break; 168 case EI_PARAM: 169 if (ei1->ei_param != ei2->ei_param) { 170 return false; 171 } 172 break; 173 case EI_FILE: 174 case EI_LINE: 175 break; 176 } 177 return true; 178 } 179 180 static 181 struct macro * 182 macro_create(struct place *p1, const char *name, unsigned hash, 183 struct place *p2) 184 { 185 struct macro *m; 186 187 m = domalloc(sizeof(*m)); 188 m->defplace = *p1; 189 m->expansionplace = *p2; 190 m->hash = hash; 191 m->name = dostrdup(name); 192 m->hasparams = false; 193 stringarray_init(&m->params); 194 expansionitemarray_init(&m->expansion); 195 m->inuse = false; 196 return m; 197 } 198 199 DESTROYALL_ARRAY(expansionitem, ); 200 201 static 202 void 203 macro_destroy(struct macro *m) 204 { 205 expansionitemarray_destroyall(&m->expansion); 206 expansionitemarray_cleanup(&m->expansion); 207 dostrfree(m->name); 208 dofree(m, sizeof(*m)); 209 } 210 211 static 212 bool 213 macro_eq(const struct macro *m1, const struct macro *m2) 214 { 215 unsigned num1, num2, i; 216 struct expansionitem *ei1, *ei2; 217 const char *p1, *p2; 218 219 if (strcmp(m1->name, m2->name) != 0) { 220 return false; 221 } 222 223 if (m1->hasparams != m2->hasparams) { 224 return false; 225 } 226 227 num1 = expansionitemarray_num(&m1->expansion); 228 num2 = expansionitemarray_num(&m2->expansion); 229 if (num1 != num2) { 230 return false; 231 } 232 233 for (i=0; i<num1; i++) { 234 ei1 = expansionitemarray_get(&m1->expansion, i); 235 ei2 = expansionitemarray_get(&m2->expansion, i); 236 if (!expansionitem_eq(ei1, ei2)) { 237 return false; 238 } 239 } 240 241 num1 = stringarray_num(&m1->params); 242 num2 = stringarray_num(&m2->params); 243 if (num1 != num2) { 244 return false; 245 } 246 247 for (i=0; i<num1; i++) { 248 p1 = stringarray_get(&m1->params, i); 249 p2 = stringarray_get(&m2->params, i); 250 if (strcmp(p1, p2) != 0) { 251 return false; 252 } 253 } 254 return true; 255 } 256 257 //////////////////////////////////////////////////////////// 258 // macro table 259 260 /* 261 * Unless I've screwed up, this is something called Fletcher's Checksum 262 * that showed up in Dr. Dobbs in, according to my notes, May 1992. The 263 * implementation is new. 264 */ 265 static 266 unsigned 267 hashfunc(const char *s, size_t len) 268 { 269 uint16_t x1, x2, a; 270 size_t i; 271 272 x1 = (uint16_t) (len >> 16); 273 x2 = (uint16_t) (len); 274 if (x1==0) { 275 x1++; 276 } 277 if (x2==0) { 278 x2++; 279 } 280 281 for (i=0; i<len; i+=2) { 282 if (i==len-1) { 283 a = (unsigned char)s[i]; 284 /* don't run off the end of the array */ 285 } 286 else { 287 a = (unsigned char)s[i] + 288 ((uint16_t)(unsigned char)s[i+1] << 8); 289 } 290 x1 += a; 291 if (x1 < a) { 292 x1++; 293 } 294 x2 += x1; 295 if (x2 < x1) { 296 x2++; 297 } 298 } 299 300 x1 ^= 0xffff; 301 x2 ^= 0xffff; 302 return ((uint32_t)x2)*65535U + x1; 303 } 304 305 static 306 void 307 macrotable_init(void) 308 { 309 unsigned i; 310 311 macroarrayarray_init(¯os); 312 macroarrayarray_setsize(¯os, 4); 313 for (i=0; i<4; i++) { 314 macroarrayarray_set(¯os, i, NULL); 315 } 316 total_macros = 0; 317 hashmask = 0x3; 318 } 319 320 DESTROYALL_ARRAY(macro, ); 321 322 static 323 void 324 macrotable_cleanup(void) 325 { 326 struct macroarray *bucket; 327 unsigned numbuckets, i; 328 329 numbuckets = macroarrayarray_num(¯os); 330 for (i=0; i<numbuckets; i++) { 331 bucket = macroarrayarray_get(¯os, i); 332 if (bucket != NULL) { 333 macroarray_destroyall(bucket); 334 macroarray_destroy(bucket); 335 } 336 } 337 macroarrayarray_setsize(¯os, 0); 338 macroarrayarray_cleanup(¯os); 339 } 340 341 static 342 struct macro * 343 macrotable_findlen(const char *name, size_t len, bool remove_it) 344 { 345 unsigned hash; 346 struct macroarray *bucket; 347 struct macro *m, *m2; 348 unsigned i, num; 349 size_t mlen; 350 351 hash = hashfunc(name, len); 352 bucket = macroarrayarray_get(¯os, hash & hashmask); 353 if (bucket == NULL) { 354 return NULL; 355 } 356 num = macroarray_num(bucket); 357 for (i=0; i<num; i++) { 358 m = macroarray_get(bucket, i); 359 if (hash != m->hash) { 360 continue; 361 } 362 mlen = strlen(m->name); 363 if (len == mlen && !memcmp(name, m->name, len)) { 364 if (remove_it) { 365 if (i < num-1) { 366 m2 = macroarray_get(bucket, num-1); 367 macroarray_set(bucket, i, m2); 368 } 369 macroarray_setsize(bucket, num-1); 370 total_macros--; 371 } 372 return m; 373 } 374 } 375 return NULL; 376 } 377 378 static 379 struct macro * 380 macrotable_find(const char *name, bool remove_it) 381 { 382 return macrotable_findlen(name, strlen(name), remove_it); 383 } 384 385 static 386 void 387 macrotable_rehash(void) 388 { 389 struct macroarray *newbucket, *oldbucket; 390 struct macro *m; 391 unsigned newmask, tossbit; 392 unsigned numbuckets, i; 393 unsigned oldnum, j, k; 394 395 numbuckets = macroarrayarray_num(¯os); 396 macroarrayarray_setsize(¯os, numbuckets*2); 397 398 assert(hashmask == numbuckets - 1); 399 newmask = (hashmask << 1) | 1U; 400 tossbit = newmask & ~hashmask; 401 hashmask = newmask; 402 403 for (i=0; i<numbuckets; i++) { 404 newbucket = NULL; 405 oldbucket = macroarrayarray_get(¯os, i); 406 if (oldbucket == NULL) { 407 macroarrayarray_set(¯os, numbuckets + i, NULL); 408 continue; 409 } 410 oldnum = macroarray_num(oldbucket); 411 for (j=0; j<oldnum; j++) { 412 m = macroarray_get(oldbucket, j); 413 if (m->hash & tossbit) { 414 if (newbucket == NULL) { 415 newbucket = macroarray_create(); 416 } 417 macroarray_set(oldbucket, j, NULL); 418 macroarray_add(newbucket, m, NULL); 419 } 420 } 421 for (j=k=0; j<oldnum; j++) { 422 m = macroarray_get(oldbucket, j); 423 if (m != NULL) { 424 if (k < j) { 425 macroarray_set(oldbucket, k, m); 426 } 427 k++; 428 } 429 } 430 macroarray_setsize(oldbucket, k); 431 macroarrayarray_set(¯os, numbuckets + i, newbucket); 432 } 433 } 434 435 static 436 void 437 macrotable_add(struct macro *m) 438 { 439 unsigned hash; 440 struct macroarray *bucket; 441 unsigned numbuckets; 442 443 numbuckets = macroarrayarray_num(¯os); 444 if (total_macros > 0 && total_macros / numbuckets > 9) { 445 macrotable_rehash(); 446 } 447 448 hash = hashfunc(m->name, strlen(m->name)); 449 bucket = macroarrayarray_get(¯os, hash & hashmask); 450 if (bucket == NULL) { 451 bucket = macroarray_create(); 452 macroarrayarray_set(¯os, hash & hashmask, bucket); 453 } 454 macroarray_add(bucket, m, NULL); 455 total_macros++; 456 } 457 458 //////////////////////////////////////////////////////////// 459 // external macro definition interface 460 461 static 462 struct macro * 463 macro_define_common_start(struct place *p1, const char *macro, 464 struct place *p2) 465 { 466 struct macro *m; 467 unsigned hash; 468 469 if (!is_identifier(macro)) { 470 complain(p1, "Invalid macro name %s", macro); 471 complain_fail(); 472 } 473 474 hash = hashfunc(macro, strlen(macro)); 475 m = macro_create(p1, macro, hash, p2); 476 return m; 477 } 478 479 static 480 void 481 macro_define_common_end(struct macro *m) 482 { 483 struct macro *oldm; 484 bool ok; 485 486 oldm = macrotable_find(m->name, false); 487 if (oldm != NULL) { 488 ok = macro_eq(m, oldm); 489 if (ok) { 490 /* in traditional cpp this is silent */ 491 //complain(&m->defplace, 492 // "Warning: redefinition of %s", m->name); 493 //complain(&oldm->defplace, 494 // "Previous definition was here"); 495 //if (mode.werror) { 496 // complain_fail(); 497 //} 498 } else { 499 complain(&m->defplace, 500 "Warning: non-identical redefinition of %s", 501 m->name); 502 complain(&oldm->defplace, 503 "Previous definition was here"); 504 /* in traditional cpp this is not fatal */ 505 if (mode.werror) { 506 complain_fail(); 507 } 508 } 509 macro_destroy(m); 510 return; 511 } 512 macrotable_add(m); 513 } 514 515 static 516 void 517 macro_parse_parameters(struct macro *m, struct place *p, const char *params) 518 { 519 size_t len; 520 const char *s; 521 char *param; 522 523 while (params != NULL) { 524 len = strspn(params, ws); 525 params += len; 526 place_addcolumns(p, len); 527 s = strchr(params, ','); 528 if (s) { 529 len = s-params; 530 param = dostrndup(params, len); 531 s++; 532 } else { 533 len = strlen(params); 534 param = dostrndup(params, len); 535 } 536 notrailingws(param, strlen(param)); 537 if (!is_identifier(param)) { 538 complain(p, "Invalid macro parameter name %s", param); 539 complain_fail(); 540 } else { 541 stringarray_add(&m->params, param, NULL); 542 } 543 params = s; 544 place_addcolumns(p, len); 545 } 546 } 547 548 static 549 bool 550 isparam(struct macro *m, const char *name, size_t len, unsigned *num_ret) 551 { 552 unsigned num, i; 553 const char *param; 554 555 num = stringarray_num(&m->params); 556 for (i=0; i<num; i++) { 557 param = stringarray_get(&m->params, i); 558 if (strlen(param) == len && !memcmp(name, param, len)) { 559 *num_ret = i; 560 return true; 561 } 562 } 563 return false; 564 } 565 566 static 567 void 568 macro_parse_expansion(struct macro *m, const char *buf) 569 { 570 size_t blockstart, wordstart, pos; 571 struct expansionitem *ei; 572 unsigned param; 573 574 pos = blockstart = 0; 575 while (buf[pos] != '\0') { 576 pos += strspn(buf+pos, ws); 577 if (strchr(alnum, buf[pos])) { 578 wordstart = pos; 579 pos += strspn(buf+pos, alnum); 580 if (isparam(m, buf+wordstart, pos-wordstart, ¶m)) { 581 if (wordstart > blockstart) { 582 ei = expansionitem_create_stringlen( 583 buf + blockstart, 584 wordstart - blockstart); 585 expansionitemarray_add(&m->expansion, 586 ei, NULL); 587 } 588 ei = expansionitem_create_param(param); 589 expansionitemarray_add(&m->expansion, ei,NULL); 590 blockstart = pos; 591 continue; 592 } 593 continue; 594 } 595 pos++; 596 } 597 if (pos > blockstart) { 598 ei = expansionitem_create_stringlen(buf + blockstart, 599 pos - blockstart); 600 expansionitemarray_add(&m->expansion, ei, NULL); 601 } 602 } 603 604 void 605 macro_define_plain(struct place *p1, const char *macro, 606 struct place *p2, const char *expansion) 607 { 608 struct macro *m; 609 struct expansionitem *ei; 610 611 m = macro_define_common_start(p1, macro, p2); 612 ei = expansionitem_create_string(expansion); 613 expansionitemarray_add(&m->expansion, ei, NULL); 614 macro_define_common_end(m); 615 } 616 617 void 618 macro_define_params(struct place *p1, const char *macro, 619 struct place *p2, const char *params, 620 struct place *p3, const char *expansion) 621 { 622 struct macro *m; 623 624 m = macro_define_common_start(p1, macro, p3); 625 m->hasparams = true; 626 macro_parse_parameters(m, p2, params); 627 macro_parse_expansion(m, expansion); 628 macro_define_common_end(m); 629 } 630 631 void 632 macro_define_magic(struct place *p, const char *macro) 633 { 634 struct macro *m; 635 struct expansionitem *ei; 636 637 m = macro_define_common_start(p, macro, p); 638 if (!strcmp(macro, "__FILE__")) { 639 ei = expansionitem_create_file(); 640 } 641 else { 642 assert(!strcmp(macro, "__LINE__")); 643 ei = expansionitem_create_line(); 644 } 645 expansionitemarray_add(&m->expansion, ei, NULL); 646 macro_define_common_end(m); 647 } 648 649 void 650 macro_undef(const char *macro) 651 { 652 struct macro *m; 653 654 m = macrotable_find(macro, true); 655 if (m) { 656 macro_destroy(m); 657 } 658 } 659 660 bool 661 macro_isdefined(const char *macro) 662 { 663 struct macro *m; 664 665 m = macrotable_find(macro, false); 666 return m != NULL; 667 } 668 669 //////////////////////////////////////////////////////////// 670 // macro expansion 671 672 struct expstate { 673 bool honordefined; 674 enum { ES_NORMAL, ES_WANTLPAREN, ES_NOARG, ES_HAVEARG } state; 675 struct macro *curmacro; 676 struct stringarray args; 677 unsigned argparens; 678 679 bool tobuf; 680 char *buf; 681 size_t bufpos, bufmax; 682 }; 683 684 static struct expstate mainstate; 685 686 static void doexpand(struct expstate *es, struct place *p, 687 const char *buf, size_t len); 688 689 static 690 void 691 expstate_init(struct expstate *es, bool tobuf, bool honordefined) 692 { 693 es->honordefined = honordefined; 694 es->state = ES_NORMAL; 695 es->curmacro = NULL; 696 stringarray_init(&es->args); 697 es->argparens = 0; 698 es->tobuf = tobuf; 699 es->buf = NULL; 700 es->bufpos = 0; 701 es->bufmax = 0; 702 } 703 704 static 705 void 706 expstate_cleanup(struct expstate *es) 707 { 708 assert(es->state == ES_NORMAL); 709 stringarray_cleanup(&es->args); 710 if (es->buf) { 711 dofree(es->buf, es->bufmax); 712 } 713 } 714 715 static 716 void 717 expstate_destroyargs(struct expstate *es) 718 { 719 unsigned i, num; 720 721 num = stringarray_num(&es->args); 722 for (i=0; i<num; i++) { 723 dostrfree(stringarray_get(&es->args, i)); 724 } 725 stringarray_setsize(&es->args, 0); 726 } 727 728 static 729 void 730 expand_send(struct expstate *es, struct place *p, const char *buf, size_t len) 731 { 732 size_t oldmax; 733 734 if (es->tobuf) { 735 assert(es->bufpos <= es->bufmax); 736 if (es->bufpos + len > es->bufmax) { 737 oldmax = es->bufmax; 738 if (es->bufmax == 0) { 739 es->bufmax = 64; 740 } 741 while (es->bufpos + len > es->bufmax) { 742 es->bufmax *= 2; 743 } 744 es->buf = dorealloc(es->buf, oldmax, es->bufmax); 745 } 746 memcpy(es->buf + es->bufpos, buf, len); 747 es->bufpos += len; 748 assert(es->bufpos <= es->bufmax); 749 } else { 750 output(p, buf, len); 751 } 752 } 753 754 static 755 void 756 expand_send_eof(struct expstate *es, struct place *p) 757 { 758 if (es->tobuf) { 759 expand_send(es, p, "", 1); 760 es->bufpos--; 761 } else { 762 output_eof(); 763 } 764 } 765 766 static 767 void 768 expand_newarg(struct expstate *es, const char *buf, size_t len) 769 { 770 char *text; 771 772 text = dostrndup(buf, len); 773 stringarray_add(&es->args, text, NULL); 774 } 775 776 static 777 void 778 expand_appendarg(struct expstate *es, const char *buf, size_t len) 779 { 780 unsigned num; 781 char *text; 782 size_t oldlen; 783 784 num = stringarray_num(&es->args); 785 assert(num > 0); 786 787 text = stringarray_get(&es->args, num - 1); 788 oldlen = strlen(text); 789 text = dorealloc(text, oldlen + 1, oldlen + len + 1); 790 memcpy(text + oldlen, buf, len); 791 text[oldlen+len] = '\0'; 792 stringarray_set(&es->args, num - 1, text); 793 } 794 795 static 796 char * 797 expand_substitute(struct place *p, struct expstate *es) 798 { 799 struct expansionitem *ei; 800 unsigned i, num; 801 size_t len; 802 char *arg; 803 char *ret; 804 unsigned numargs, numparams; 805 char numbuf[64]; 806 807 numargs = stringarray_num(&es->args); 808 numparams = stringarray_num(&es->curmacro->params); 809 810 if (numargs == 0 && numparams == 1) { 811 /* no arguments <=> one empty argument */ 812 stringarray_add(&es->args, dostrdup(""), NULL); 813 numargs++; 814 } 815 if (numargs != numparams) { 816 complain(p, "Wrong number of arguments for macro %s; " 817 "found %u, expected %u", 818 es->curmacro->name, numargs, numparams); 819 complain_fail(); 820 while (numargs < numparams) { 821 stringarray_add(&es->args, dostrdup(""), NULL); 822 numargs++; 823 } 824 } 825 826 len = 0; 827 num = expansionitemarray_num(&es->curmacro->expansion); 828 for (i=0; i<num; i++) { 829 ei = expansionitemarray_get(&es->curmacro->expansion, i); 830 switch (ei->itemtype) { 831 case EI_STRING: 832 len += strlen(ei->ei_string); 833 break; 834 case EI_PARAM: 835 arg = stringarray_get(&es->args, ei->ei_param); 836 len += strlen(arg); 837 break; 838 case EI_FILE: 839 len += strlen(place_getname(p)) + 2; 840 break; 841 case EI_LINE: 842 len += snprintf(numbuf, sizeof(numbuf), "%u", p->line); 843 break; 844 } 845 } 846 847 ret = domalloc(len+1); 848 *ret = '\0'; 849 for (i=0; i<num; i++) { 850 ei = expansionitemarray_get(&es->curmacro->expansion, i); 851 switch (ei->itemtype) { 852 case EI_STRING: 853 strlcat(ret, ei->ei_string, len + 1); 854 break; 855 case EI_PARAM: 856 arg = stringarray_get(&es->args, ei->ei_param); 857 strlcat(ret, arg, len + 1); 858 break; 859 case EI_FILE: 860 strlcat(ret, "\"", len + 1); 861 strlcat(ret, place_getname(p), len + 1); 862 strlcat(ret, "\"", len + 1); 863 break; 864 case EI_LINE: 865 snprintf(numbuf, sizeof(numbuf), "%u", p->line); 866 strlcat(ret, numbuf, len + 1); 867 break; 868 } 869 } 870 871 return ret; 872 } 873 874 static 875 void 876 expand_domacro(struct expstate *es, struct place *p) 877 { 878 struct macro *m; 879 const char *name, *val; 880 char *newbuf, *newbuf2; 881 882 if (es->curmacro == NULL) { 883 /* defined() */ 884 if (stringarray_num(&es->args) != 1) { 885 complain(p, "Too many arguments for defined()"); 886 complain_fail(); 887 expand_send(es, p, "0", 1); 888 return; 889 } 890 name = stringarray_get(&es->args, 0); 891 m = macrotable_find(name, false); 892 val = (m != NULL) ? "1" : "0"; 893 debuglog(p, "defined(%s): %s", name, val); 894 expand_send(es, p, val, 1); 895 expstate_destroyargs(es); 896 return; 897 } 898 899 m = es->curmacro; 900 assert(m->inuse == false); 901 m->inuse = true; 902 903 debuglog(p, "Expanding macro %s", m->name); 904 newbuf = expand_substitute(p, es); 905 debuglog(p, "Substituting for %s: %s", m->name, newbuf); 906 907 newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false); 908 dostrfree(newbuf); 909 expstate_destroyargs(es); 910 debuglog(p, "Complete expansion for %s: %s", m->name, newbuf2); 911 912 doexpand(es, p, newbuf2, strlen(newbuf2)); 913 dostrfree(newbuf2); 914 915 m->inuse = false; 916 } 917 918 /* 919 * The traditional behavior if a function-like macro appears without 920 * arguments is to pretend it isn't a macro; that is, just emit its 921 * name. 922 */ 923 static 924 void 925 expand_missingargs(struct expstate *es, struct place *p, bool needspace) 926 { 927 if (es->curmacro == NULL) { 928 /* defined */ 929 expand_send(es, p, "defined", 7); 930 return; 931 } 932 expand_send(es, p, es->curmacro->name, strlen(es->curmacro->name)); 933 /* send a space in case we ate whitespace after the macro name */ 934 if (needspace) { 935 expand_send(es, p, " ", 1); 936 } 937 } 938 939 static 940 void 941 expand_got_ws(struct expstate *es, struct place *p, 942 const char *buf, size_t len) 943 { 944 switch (es->state) { 945 case ES_NORMAL: 946 expand_send(es, p, buf, len); 947 break; 948 case ES_WANTLPAREN: 949 /* XXX notyet */ 950 //expand_send(es, p, buf, len); 951 break; 952 case ES_NOARG: 953 expand_newarg(es, buf, len); 954 es->state = ES_HAVEARG; 955 break; 956 case ES_HAVEARG: 957 expand_appendarg(es, buf, len); 958 break; 959 } 960 } 961 962 static 963 void 964 expand_got_word(struct expstate *es, struct place *p, 965 const char *buf, size_t len) 966 { 967 struct macro *m; 968 969 switch (es->state) { 970 case ES_NORMAL: 971 if (es->honordefined && 972 len == 7 && !memcmp(buf, "defined", 7)) { 973 es->curmacro = NULL; 974 es->state = ES_WANTLPAREN; 975 break; 976 } 977 m = macrotable_findlen(buf, len, false); 978 if (m == NULL || m->inuse) { 979 expand_send(es, p, buf, len); 980 } else if (!m->hasparams) { 981 es->curmacro = m; 982 expand_domacro(es, p); 983 } else { 984 es->curmacro = m; 985 es->state = ES_WANTLPAREN; 986 } 987 break; 988 case ES_WANTLPAREN: 989 if (es->curmacro != NULL) { 990 expand_missingargs(es, p, true); 991 es->state = ES_NORMAL; 992 /* try again */ 993 expand_got_word(es, p, buf, len); 994 } else { 995 /* "defined foo" means "defined(foo)" */ 996 expand_newarg(es, buf, len); 997 es->state = ES_NORMAL; 998 expand_domacro(es, p); 999 } 1000 break; 1001 case ES_NOARG: 1002 expand_newarg(es, buf, len); 1003 es->state = ES_HAVEARG; 1004 break; 1005 case ES_HAVEARG: 1006 expand_appendarg(es, buf, len); 1007 break; 1008 } 1009 } 1010 1011 static 1012 void 1013 expand_got_lparen(struct expstate *es, struct place *p, 1014 const char *buf, size_t len) 1015 { 1016 switch (es->state) { 1017 case ES_NORMAL: 1018 expand_send(es, p, buf, len); 1019 break; 1020 case ES_WANTLPAREN: 1021 es->state = ES_NOARG; 1022 break; 1023 case ES_NOARG: 1024 expand_newarg(es, buf, len); 1025 es->state = ES_HAVEARG; 1026 es->argparens++; 1027 break; 1028 case ES_HAVEARG: 1029 expand_appendarg(es, buf, len); 1030 es->argparens++; 1031 break; 1032 } 1033 } 1034 1035 static 1036 void 1037 expand_got_rparen(struct expstate *es, struct place *p, 1038 const char *buf, size_t len) 1039 { 1040 switch (es->state) { 1041 case ES_NORMAL: 1042 expand_send(es, p, buf, len); 1043 break; 1044 case ES_WANTLPAREN: 1045 expand_missingargs(es, p, false); 1046 es->state = ES_NORMAL; 1047 /* try again */ 1048 expand_got_rparen(es, p, buf, len); 1049 break; 1050 case ES_NOARG: 1051 assert(es->argparens == 0); 1052 if (stringarray_num(&es->args) > 0) { 1053 /* we are after a comma; enter an empty argument */ 1054 expand_newarg(es, buf, 0); 1055 } 1056 es->state = ES_NORMAL; 1057 expand_domacro(es, p); 1058 break; 1059 case ES_HAVEARG: 1060 if (es->argparens > 0) { 1061 es->argparens--; 1062 expand_appendarg(es, buf, len); 1063 } else { 1064 es->state = ES_NORMAL; 1065 expand_domacro(es, p); 1066 } 1067 break; 1068 } 1069 } 1070 1071 static 1072 void 1073 expand_got_comma(struct expstate *es, struct place *p, 1074 const char *buf, size_t len) 1075 { 1076 switch (es->state) { 1077 case ES_NORMAL: 1078 expand_send(es, p, buf, len); 1079 break; 1080 case ES_WANTLPAREN: 1081 expand_missingargs(es, p, false); 1082 es->state = ES_NORMAL; 1083 /* try again */ 1084 expand_got_comma(es, p, buf, len); 1085 break; 1086 case ES_NOARG: 1087 assert(es->argparens == 0); 1088 expand_newarg(es, buf, 0); 1089 break; 1090 case ES_HAVEARG: 1091 if (es->argparens > 0) { 1092 expand_appendarg(es, buf, len); 1093 } else { 1094 es->state = ES_NOARG; 1095 } 1096 break; 1097 } 1098 } 1099 1100 static 1101 void 1102 expand_got_other(struct expstate *es, struct place *p, 1103 const char *buf, size_t len) 1104 { 1105 switch (es->state) { 1106 case ES_NORMAL: 1107 expand_send(es, p, buf, len); 1108 break; 1109 case ES_WANTLPAREN: 1110 expand_missingargs(es, p, false); 1111 es->state = ES_NORMAL; 1112 /* try again */ 1113 expand_got_other(es, p, buf, len); 1114 break; 1115 case ES_NOARG: 1116 expand_newarg(es, buf, len); 1117 es->state = ES_HAVEARG; 1118 break; 1119 case ES_HAVEARG: 1120 expand_appendarg(es, buf, len); 1121 break; 1122 } 1123 } 1124 1125 static 1126 void 1127 expand_got_eof(struct expstate *es, struct place *p) 1128 { 1129 switch (es->state) { 1130 case ES_NORMAL: 1131 break; 1132 case ES_WANTLPAREN: 1133 expand_missingargs(es, p, false); 1134 break; 1135 case ES_NOARG: 1136 case ES_HAVEARG: 1137 if (es->curmacro) { 1138 complain(p, "Unclosed argument list for macro %s", 1139 es->curmacro->name); 1140 } else { 1141 complain(p, "Unclosed argument list for defined()"); 1142 } 1143 complain_fail(); 1144 expstate_destroyargs(es); 1145 break; 1146 } 1147 expand_send_eof(es, p); 1148 es->state = ES_NORMAL; 1149 es->curmacro = NULL; 1150 es->argparens = 0; 1151 } 1152 1153 static 1154 void 1155 doexpand(struct expstate *es, struct place *p, const char *buf, size_t len) 1156 { 1157 char *s; 1158 size_t x; 1159 bool inquote = false; 1160 char quote = '\0'; 1161 1162 while (len > 0) { 1163 x = strspn(buf, ws); 1164 if (x > len) { 1165 /* XXX gross, need strnspn */ 1166 x = len; 1167 } 1168 1169 if (x > 0) { 1170 expand_got_ws(es, p, buf, x); 1171 buf += x; 1172 len -= x; 1173 continue; 1174 } 1175 1176 x = strspn(buf, alnum); 1177 if (x > len) { 1178 /* XXX gross, need strnspn */ 1179 x = len; 1180 } 1181 1182 if (!inquote && x > 0) { 1183 expand_got_word(es, p, buf, x); 1184 buf += x; 1185 len -= x; 1186 continue; 1187 } 1188 1189 if (!inquote && len > 1 && buf[0] == '/' && buf[1] == '*') { 1190 s = strstr(buf, "*/"); 1191 if (s) { 1192 x = s - buf; 1193 } else { 1194 x = len; 1195 } 1196 expand_got_ws(es, p, buf, x); 1197 buf += x; 1198 len -= x; 1199 continue; 1200 } 1201 1202 if (!inquote && buf[0] == '(') { 1203 expand_got_lparen(es, p, buf, 1); 1204 buf++; 1205 len--; 1206 continue; 1207 } 1208 1209 if (!inquote && buf[0] == ')') { 1210 expand_got_rparen(es, p, buf, 1); 1211 buf++; 1212 len--; 1213 continue; 1214 } 1215 1216 if (!inquote && buf[0] == ',') { 1217 expand_got_comma(es, p, buf, 1); 1218 buf++; 1219 len--; 1220 continue; 1221 } 1222 1223 if (len > 1 && buf[0] == '\\' && 1224 (buf[1] == '"' || buf[1] == '\'')) { 1225 expand_got_other(es, p, buf, 2); 1226 buf += 2; 1227 len -= 2; 1228 continue; 1229 } 1230 if (!inquote && (buf[0] == '"' || buf[0] == '\'')) { 1231 inquote = true; 1232 quote = buf[0]; 1233 } else if (inquote && buf[0] == quote) { 1234 inquote = false; 1235 } 1236 1237 expand_got_other(es, p, buf, 1); 1238 buf++; 1239 len--; 1240 } 1241 } 1242 1243 char * 1244 macroexpand(struct place *p, const char *buf, size_t len, bool honordefined) 1245 { 1246 struct expstate es; 1247 char *ret; 1248 1249 expstate_init(&es, true, honordefined); 1250 doexpand(&es, p, buf, len); 1251 expand_got_eof(&es, p); 1252 1253 /* trim to fit, so the malloc debugging won't complain */ 1254 es.buf = dorealloc(es.buf, es.bufmax, strlen(es.buf) + 1); 1255 1256 ret = es.buf; 1257 es.buf = NULL; 1258 es.bufpos = es.bufmax = 0; 1259 1260 expstate_cleanup(&es); 1261 1262 return ret; 1263 } 1264 1265 void 1266 macro_sendline(struct place *p, const char *buf, size_t len) 1267 { 1268 doexpand(&mainstate, p, buf, len); 1269 switch (mainstate.state) { 1270 case ES_NORMAL: 1271 /* 1272 * If we were sent a blank line, don't emit a newline 1273 * for it. This matches the prior behavior of tradcpp. 1274 */ 1275 if (len > 0) { 1276 output(p, "\n", 1); 1277 } 1278 break; 1279 case ES_WANTLPAREN: 1280 case ES_NOARG: 1281 case ES_HAVEARG: 1282 /* 1283 * Apparently to match gcc's -traditional behavior we 1284 * need to emit a space for each newline that appears 1285 * while processing macro args. 1286 */ 1287 expand_got_ws(&mainstate, p, " ", 1); 1288 break; 1289 } 1290 } 1291 1292 void 1293 macro_sendeof(struct place *p) 1294 { 1295 expand_got_eof(&mainstate, p); 1296 } 1297 1298 //////////////////////////////////////////////////////////// 1299 // module initialization 1300 1301 void 1302 macros_init(void) 1303 { 1304 macrotable_init(); 1305 expstate_init(&mainstate, false, false); 1306 } 1307 1308 void 1309 macros_cleanup(void) 1310 { 1311 expstate_cleanup(&mainstate); 1312 macrotable_cleanup(); 1313 } 1314