Quick Search:

Mode

Context

Displaying the whole file. None | Less | More | Full

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.183
 
1.184
 
MAIN:plunky:20121031115454
 
cpp.c
_>11 /*      $Id$    */
 22 
 33 /*
 44  * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
 55  * All rights reserved.
 66  *
 77  * Redistribution and use in source and binary forms, with or without
 88  * modification, are permitted provided that the following conditions
 99  * are met:
 1010  * 1. Redistributions of source code must retain the above copyright
 1111  *    notice, this list of conditions and the following disclaimer.
 1212  * 2. Redistributions in binary form must reproduce the above copyright
 1313  *    notice, this list of conditions and the following disclaimer in the
 1414  *    documentation and/or other materials provided with the distribution.
 1515  *
 1616  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 1717  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 1818  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 1919  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 2020  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 2121  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 2222  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 2323  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 2424  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 2525  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 2626  */
 2727 
 2828 /*
 2929  * The C preprocessor.
 3030  * This code originates from the V6 preprocessor with some additions
 3131  * from V7 cpp, and at last ansi/c99 support.
 3232  */
 3333 
 3434 #include "config.h"
 3535 
 3636 #include <sys/stat.h>
 3737 
 3838 #include <fcntl.h>
 3939 #ifdef HAVE_UNISTD_H
 4040 #include <unistd.h>
 4141 #endif
 4242 #include <stdio.h>
 4343 #include <stdarg.h>
 4444 #include <stdlib.h>
 4545 #include <string.h>
 4646 #include <time.h>
 4747 
 4848 #include "compat.h"
 4949 #include "cpp.h"
 5050 #include "cpy.h"
 5151 
 5252 #ifndef S_ISDIR
 5353 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
 5454 #endif
 5555 
 5656 #define SBSIZE  1000000
 5757 
 5858 static const char versstr[] = "PCC preprocessor version " VERSSTR "\n";
 5959 
 6060 static usch     sbf[SBSIZE];
 6161 /* C command */
 6262 
 6363 int tflag;      /* traditional cpp syntax */
 6464 #ifdef PCC_DEBUG
 6565 int dflag;      /* debug printouts */
 6666 static void imp(const char *);
 6767 static void prline(const usch *s);
 6868 static void prrep(const usch *s);
 6969 #define DPRINT(x) if (dflag) printf x
 7070 #define DDPRINT(x) if (dflag > 1) printf x
 7171 #define IMP(x) if (dflag > 1) imp(x)
 7272 #else
 7373 #define DPRINT(x)
 7474 #define DDPRINT(x)
 7575 #define IMP(x)
 7676 #endif
 7777 
 7878 int ofd;
 7979 usch outbuf[CPPBUF];
 8080 int obufp, istty;
 8181 int Cflag, Mflag, dMflag, Pflag, MPflag;
 8282 usch *Mfile, *MPfile, *Mxfile;
 8383 struct initar *initar;
 8484 int readmac, lastoch;
 8585 int defining;
 8686 
 8787 /* include dirs */
 8888 struct incs {
 8989         struct incs *next;
 9090         usch *dir;
 9191         dev_t dev;
 9292         ino_t ino;
 9393 } *incdir[2];
 9494 
 9595 static struct symtab *filloc;
 9696 static struct symtab *linloc;
 9797 static struct symtab *pragloc;
 9898 int     trulvl;
 9999 int     flslvl;
 100100 int     elflvl;
 101101 int     elslvl;
 102102 usch *stringbuf = sbf;
 103103 
 104104 /*
 105105  * Macro replacement list syntax:
 106106  * - For object-type macros, replacement strings are stored as-is.
 107107  * - For function-type macros, macro args are substituted for the
 108108  *   character WARN followed by the argument number.
 109109  * - The value element points to the end of the string, to simplify
 110110  *   pushback onto the input queue.
 111111  *
 112112  * The first character (from the end) in the replacement list is
 113113  * the number of arguments:
 114114  *   VARG  - ends with ellipsis, next char is argcount without ellips.
 115115  *   OBJCT - object-type macro
 116116  *   0     - empty parenthesis, foo()
 117117  *   1->   - number of args.
 118118  *
 119119  * WARN is used:
 120120  *      - in stored replacement lists to tell that an argument comes
 121121  *      - When expanding replacement lists to tell that the list ended.
 122122  *
 123123  * To ensure that an already expanded identifier won't get expanded
 124124  * again a EBLOCK char + its number is stored directly before any
 125125  * expanded identifier.
 126126  */
 127127 
 128128 /* args for lookup() */
 129129 #define FIND    0
 130130 #define ENTER   1
 131131 
 132132 /*
 133133  * No-replacement array.  If a macro is found and exists in this array
 134134  * then no replacement shall occur.  This is a stack.
 135135  */
 136136 struct symtab *norep[RECMAX];   /* Symbol table index table */
 137137 int norepptr = 1;                       /* Top of index table */
 138138 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
 139139 int bidx;                       /* Top of bptr stack */
 140140 
 141141 static int readargs(struct symtab *sp, const usch **args);
 142142 static void exparg(int);
 143143 static void subarg(struct symtab *sp, const usch **args, int);
 144144 static void flbuf(void);
 145145 static void usage(void);
 146146 static usch *xstrdup(const usch *str);
 147147 static void addidir(char *idir, struct incs **ww);
 148148 static void vsheap(const char *, va_list);
 149149 
 150150 int
 151151 main(int argc, char **argv)
 152152 {
 153153         struct initar *it;
 154154         struct symtab *nl;
 155155         register int ch;
 156156         const usch *fn1, *fn2;
 157157 
 158158 #ifdef TIMING
 159159         struct timeval t1, t2;
 160160 
 161161         (void)gettimeofday(&t1, NULL);
 162162 #endif
 163163 
 164164         while ((ch = getopt(argc, argv, "CD:d:I:i:MPS:tU:Vvx:")) != -1) {
 165165                 switch (ch) {
 166166                 case 'C': /* Do not discard comments */
 167167                         Cflag++;
 168168                         break;
 169169 
 170170                 case 'D': /* define something */
 171171                 case 'i': /* include */
 172172                 case 'U': /* undef */
 173173                         /* XXX should not need malloc() here */
 174174                         if ((it = malloc(sizeof(struct initar))) == NULL)
 175175                                 error("couldn't apply -%c %s", ch, optarg);
 176176                         it->type = ch;
 177177                         it->str = optarg;
 178178                         it->next = initar;
 179179                         initar = it;
 180180                         break;
 181181 
 182182                 case 'd':
 183183                         while (*optarg) {
 184184                                 switch(*optarg) {
 185185                                 case 'M': /* display macro definitions */
 186186                                         dMflag = 1;
 187187                                         Mflag = 1;
 188188                                         break;
 189189 
 190190                                 default: /* ignore others */
 191191                                         break;
 192192                                 }
 193193                                 optarg++;
 194194                         }
 195195                         break;
 196196 
 197197                 case 'I':
 198198                 case 'S':
 199199                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
 200200                         break;
 201201 
 202202                 case 'M': /* Generate dependencies for make */
 203203                         Mflag++;
 204204                         break;
 205205 
 206206                 case 'P': /* Inhibit generation of line numbers */
 207207                         Pflag++;
 208208                         break;
 209209 
 210210                 case 't':
 211211                         tflag = 1;
 212212                         break;
 213213 
 214214 #ifdef PCC_DEBUG
 215215                 case 'V':
 216216                         dflag++;
 217217                         break;
 218218 #endif
 219219                 case 'v':
 220220                         xwrite(2, versstr, sizeof(versstr) - 1);
 221221                         break;
 222222 
 223223                 case 'x':
 224224                         if (strcmp(optarg, "MP") == 0) {
 225225                                 MPflag++;
 226226                         } else if (strncmp(optarg, "MT,", 3) == 0 ||
 227227                             strncmp(optarg, "MQ,", 3) == 0) {
 228228                                 usch *cp, *fn;
 229229                                 fn = stringbuf;
 230230                                 for (cp = (usch *)&optarg[3]; *cp; cp++) {
 231231                                         if (*cp == '$' && optarg[1] == 'Q')
 232232                                                 savch('$');
 233233                                         savch(*cp);
 234234                                 }
 235235                                 savstr((const usch *)"");
 236236                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
 237237                                 savch(0);
 238238                                 Mxfile = fn;
 239239                         } else
 240240                                 usage();
 241241                         break;
 242242 
 243243                 case '?':
 244244                 default:
 245245                         usage();
 246246                 }
 247247         }
 248248 
 249249         argc -= optind;
 250250         argv += optind;
 251251 
 252252         filloc = lookup((const usch *)"__FILE__", ENTER);
 253253         linloc = lookup((const usch *)"__LINE__", ENTER);
 254254         filloc->value = linloc->value = stringbuf;
 255255         savch(OBJCT);
 256256 
 257257         /* create a complete macro for pragma */
 258258         pragloc = lookup((const usch *)"_Pragma", ENTER);
 259259         savch(0);
 260260         savstr((const usch *)"_Pragma(");
 261261         savch(0);
 262262         savch(WARN);
 263263         savch(')');
 264264         pragloc->value = stringbuf;
 265265         savch(1);
 266266 
 267267         if (tflag == 0) {
 268268                 time_t t = time(NULL);
 269269                 usch *n = (usch *)ctime(&t);
 270270 
 271271                 /*
 272272                  * Manually move in the predefined macros.
 273273                  */
 274274                 nl = lookup((const usch *)"__TIME__", ENTER);
 275275                 savch(0); savch('"');  n[19] = 0; savstr(&n[11]); savch('"');
 276276                 savch(OBJCT);
 277277                 nl->value = stringbuf-1;
 278278 
 279279                 nl = lookup((const usch *)"__DATE__", ENTER);
 280280                 savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
 281281                 savstr(&n[20]); savch('"'); savch(OBJCT);
 282282                 nl->value = stringbuf-1;
 283283 
 284284                 nl = lookup((const usch *)"__STDC__", ENTER);
 285285                 savch(0); savch('1'); savch(OBJCT);
 286286                 nl->value = stringbuf-1;
 287287 
 288288                 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
 289289                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
 290290                 nl->value = stringbuf-1;
 291291         }
 292292 
 293293         if (Mflag && !dMflag) {
 294294                 usch *c;
 295295 
 296296                 if (argc < 1)
 297297                         error("-M and no infile");
 298298                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
 299299                         c = (usch *)argv[0];
 300300                 else
 301301                         c++;
 302302                 Mfile = stringbuf;
 303303                 savstr(c); savch(0);
 304304                 if (MPflag) {
 305305                         MPfile = stringbuf;
 306306                         savstr(c); savch(0);
 307307                 }
 308308                 if (Mxfile)
 309309                         Mfile = Mxfile;
 310310                 if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
 311311                         error("-M and no extension: ");
 312312                 c[1] = 'o';
 313313                 c[2] = 0;
 314314         }
 315315 
 316316         if (argc == 2) {
 317317                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
 318318                         error("Can't creat %s", argv[1]);
 319319         } else
 320320                 ofd = 1; /* stdout */
 321321         istty = isatty(ofd);
 322322 
 323323         if (argc && strcmp(argv[0], "-")) {
 324324                 fn1 = fn2 = (usch *)argv[0];
 325325         } else {
 326326                 fn1 = NULL;
 327327                 fn2 = (const usch *)"";
 328328         }
 329329         if (pushfile(fn1, fn2, 0, NULL))
 330330                 error("cannot open %s", argv[0]);
 331331 
 332332         flbuf();
 333333         close(ofd);
 334334 #ifdef TIMING
 335335         (void)gettimeofday(&t2, NULL);
 336336         t2.tv_sec -= t1.tv_sec;
 337337         t2.tv_usec -= t1.tv_usec;
 338338         if (t2.tv_usec < 0) {
 339339                 t2.tv_usec += 1000000;
 340340                 t2.tv_sec -= 1;
 341341         }
 342342         fprintf(stderr, "cpp total time: %ld s %ld us\n",
 343343              (long)t2.tv_sec, (long)t2.tv_usec);
 344344 #endif
 345345         return 0;
 346346 }
 347347 
 348348 static void
 349349 addidir(char *idir, struct incs **ww)
 350350 {
 351351         struct incs *w;
 352352         struct stat st;
 353353 
 354354         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
 355355                 return; /* ignore */
 356356         if (*ww != NULL) {
 357357                 for (w = *ww; w->next; w = w->next) {
 358358 #ifdef os_win32
 359359                         if (strcmp(w->dir, idir) == 0)
 360360                                 return;
 361361 #else
 362362                         if (w->dev == st.st_dev && w->ino == st.st_ino)
 363363                                 return;
 364364 #endif
 365365                 }
 366366 #ifdef os_win32
 367367                 if (strcmp(w->dir, idir) == 0)
 368368                         return;
 369369 #else
 370370                 if (w->dev == st.st_dev && w->ino == st.st_ino)
 371371                         return;
 372372 #endif
 373373                 ww = &w->next;
 374374         }
 375375         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
 376376                 error("couldn't add path %s", idir);
 377377         w->dir = (usch *)idir;
 378378         w->dev = st.st_dev;
 379379         w->ino = st.st_ino;
 380380         *ww = w;
 381381 }
 382382 
 383383 void
 384384 line(void)
 385385 {
 386386         static usch *lbuf;
 387387         static int llen;
 388388         usch *p;
 389389         int c;
 390390 
 391391         if ((c = yylex()) != NUMBER)
 392392                 goto bad;
 393393         ifiles->lineno = (int)(yylval.node.nd_val - 1);
 394394 
 395395         if ((c = yylex()) == '\n')
 396396                 goto okret;
 397397 
 398398         if (c != STRING)
 399399                 goto bad;
 400400 
 401401         p = yytext;
 402402         if (*p++ == 'L')
 403403                 p++;
 404404         c = strlen((char *)p);
 405405         p[c - 1] = '\0';
 406406         if (llen < c) {
 407407                 /* XXX may lose heap space */
 408408                 lbuf = stringbuf;
 409409                 stringbuf += c;
 410410                 llen = c;
 411411                 if (stringbuf >= &sbf[SBSIZE]) {
 412412                         stringbuf = sbf; /* need space to write error message */
 413413                         error("#line filename exceeds buffer size");
 414414                 }
 415415         }
 416416         memcpy(lbuf, p, c);
 417417         ifiles->fname = lbuf;
 418418         if (yylex() != '\n')
 419419                 goto bad;
 420420 
 421421 okret:  prtline();
 422422         return;
 423423 
 424424 bad:    error("bad #line");
 425425 }
 426426 
 427427 /*
 428428  * Search for and include next file.
 429429  * Return 1 on success.
 430430  */
 431431 static int
 432432 fsrch(const usch *fn, int idx, struct incs *w)
 433433 {
 434434         int i;
 435435 
 436436         for (i = idx; i < 2; i++) {
 437437                 if (i > idx)
 438438                         w = incdir[i];
 439439                 for (; w; w = w->next) {
 440440                         usch *nm = stringbuf;
 441441 
 442442                         savstr(w->dir); savch('/');
 443443                         savstr(fn); savch(0);
 444444                         if (pushfile(nm, fn, i, w->next) == 0)
 445445                                 return 1;
 446446                         stringbuf = nm;
 447447                 }
 448448         }
 449449         return 0;
 450450 }
 451451 
 452452 static void
 453453 prem(void)
 454454 {
 455455         error("premature EOF");
 456456 }
 457457 
 458458 /*
 459459  * Include a file. Include order:
 460460  * - For <...> files, first search -I directories, then system directories.
 461461  * - For "..." files, first search "current" dir, then as <...> files.
 462462  */
 463463 void
 464464 include(void)
 465465 {
 466466         struct symtab *nl;
 467467         usch *osp;
 468468         usch *fn, *safefn;
 469469         int c;
 470470 
 471471         if (flslvl)
 472472                 return;
 473473         osp = stringbuf;
 474474 
 475475         while ((c = sloscan()) == WSPACE)
 476476                 ;
 477477         if (c == IDENT) {
 478478                 /* sloscan() will not expand idents */
 479479                 if ((nl = lookup(yytext, FIND)) == NULL)
 480480                         goto bad;
 481481                 if (kfind(nl))
 482482                         unpstr(stringbuf);
 483483                 else
 484484                         unpstr(nl->namep);
 485485                 stringbuf = osp;
 486486                 c = yylex();
 487487         }
 488488 
 489489         if (c == '<') {
 490490                 fn = stringbuf;
 491491                 while ((c = sloscan()) != '>') {
 492492                         if (c == 0)
 493493                                 prem();
 494494                         if (c == '\n')
 495495                                 goto bad;
 496496                         savstr(yytext);
 497497                 }
 498498                 savch('\0');
 499499                 while ((c = sloscan()) == WSPACE)
 500500                         ;
 501501                 if (c == 0)
 502502                         prem();
 503503                 if (c != '\n')
 504504                         goto bad;
 505505                 safefn = fn;
 506506         } else if (c == STRING) {
 507507                 usch *nm = stringbuf;
 508508 
 509509                 fn = yytext;
 510510                 if (*fn++ == 'L')
 511511                         fn++;
 512512                 fn[strlen((char *)fn) - 1] = 0;
 513513                 /* first try to open file relative to previous file */
 514514                 /* but only if it is not an absolute path */
 515515                 if (*fn != '/') {
 516516                         savstr(ifiles->orgfn);
 517517                         if ((stringbuf =
 518518                             (usch *)strrchr((char *)nm, '/')) == NULL)
 519519                                 stringbuf = nm;
 520520                         else
 521521                                 stringbuf++;
 522522                 }
 523523                 safefn = stringbuf;
 524524                 savstr(fn); savch(0);
 525525                 c = yylex();
 526526                 if (c == 0)
 527527                         prem();
 528528                 if (c != '\n')
 529529                         goto bad;
 530530                 if (pushfile(nm, safefn, 0, NULL) == 0)
 531531                         goto okret;
 532532                 /* XXX may lose stringbuf space */
 533533         } else
 534534                 goto bad;
 535535 
 536536         if (fsrch(safefn, 0, incdir[0]))
 537537                 goto okret;
 538538 
 539539         error("cannot find '%s'", safefn);
 540540         /* error() do not return */
 541541 
 542542 bad:    error("bad #include");
 543543         /* error() do not return */
 544544 okret:
 545545         prtline();
 546546 }
 547547 
 548548 void
 549549 include_next(void)
 550550 {
 551551         struct symtab *nl;
 552552         usch *osp;
 553553         usch *fn;
 554554         int c;
 555555 
 556556         if (flslvl)
 557557                 return;
 558558         osp = stringbuf;
 559559         while ((c = sloscan()) == WSPACE)
 560560                 ;
 561561         if (c == IDENT) {
 562562                 /* sloscan() will not expand idents */
 563563                 if ((nl = lookup(yytext, FIND)) == NULL)
 564564                         goto bad;
 565565                 if (kfind(nl))
 566566                         unpstr(stringbuf);
 567567                 else
 568568                         unpstr(nl->namep);
 569569                 stringbuf = osp;
 570570                 c = yylex();
 571571         }
 572572         if (c != STRING && c != '<')
 573573                 goto bad;
 574574 
 575575         fn = stringbuf;
 576576         if (c == STRING) {
 577577                 savstr(&yytext[1]);
 578578                 stringbuf[-1] = 0;
 579579         } else { /* < > */
 580580                 while ((c = sloscan()) != '>') {
 581581                         if (c == '\n')
 582582                                 goto bad;
 583583                         savstr(yytext);
 584584                 }
 585585                 savch('\0');
 586586         }
 587587         while ((c = sloscan()) == WSPACE)
 588588                 ;
 589589         if (c != '\n')
 590590                 goto bad;
 591591 
 592592         if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
 593593                 error("cannot find '%s'", fn);
 594594         prtline();
 595595         return;
 596596 
 597597 bad:    error("bad #include_next");
 598598         /* error() do not return */
 599599 }
 600600 
 601601 static int
 602602 definp(void)
 603603 {
 604604         int c;
 605605 
 606606         do
 607607                 c = sloscan();
 608608         while (c == WSPACE);
 609609         return c;
 610610 }
 611611 
 612612 void
 613613 getcmnt(void)
 614614 {
 615615         int c;
 616616 
 617617         savstr(yytext);
 618618         savch(cinput()); /* Lost * */
 619619         for (;;) {
 620620                 c = cinput();
 621621                 if (c == '*') {
 622622                         c = cinput();
 623623                         if (c == '/') {
 624624                                 savstr((const usch *)"*/");
 625625                                 return;
 626626                         }
 627627                         cunput(c);
 628628                         c = '*';
 629629                 }
 630630                 savch(c);
 631631         }
 632632 }
 633633 
 634634 /*
 635635  * Compare two replacement lists, taking in account comments etc.
 636636  */
 637637 static int
 638638 cmprepl(const usch *o, const usch *n)
 639639 {
 640640         for (; *o; o--, n--) {
 641641                 /* comment skip */
 642642                 if (*o == '/' && o[-1] == '*') {
 643643                         while (*o != '*' || o[-1] != '/')
 644644                                 o--;
 645645                         o -= 2;
 646646                 }
 647647                 if (*n == '/' && n[-1] == '*') {
 648648                         while (*n != '*' || n[-1] != '/')
 649649                                 n--;
 650650                         n -= 2;
 651651                 }
 652652                 while (*o == ' ' || *o == '\t')
 653653                         o--;
 654654                 while (*n == ' ' || *n == '\t')
 655655                         n--;
 656656                 if (*o != *n)
 657657                         return 1;
 658658         }
 659659         return 0;
 660660 }
 661661 
 662662 static int
 663663 isell(void)
 664664 {
 665665         int ch;
 666666 
 667667         if ((ch = cinput()) != '.') {
 668668                 cunput(ch);
 669669                 return 0;
 670670         }
 671671         if ((ch = cinput()) != '.') {
 672672                 cunput(ch);
 673673                 cunput('.');
 674674                 return 0;
 675675         }
 676676         return 1;
 677677 }
 678678 
 679679 void
 680680 define(void)
 681681 {
 682682         struct symtab *np;
 683683         usch *args[MAXARGS+1], *ubuf, *sbeg;
 684684         int c, i, redef;
 685685         int mkstr = 0, narg = -1;
 686686         int ellips = 0;
 687687 #ifdef GCC_COMPAT
 688688         usch *gccvari = NULL;
 689689         int wascon;
 690690 #endif
 691691 
 692692         if (flslvl)
 693693                 return;
 694694         if (sloscan() != WSPACE || sloscan() != IDENT)
 695695                 goto bad;
 696696 
 697697         np = lookup(yytext, ENTER);
 698698         redef = np->value != NULL;
 699699 
 700700         defining = readmac = 1;
 701701         sbeg = stringbuf;
 702702         if ((c = sloscan()) == '(') {
 703703                 narg = 0;
 704704                 /* function-like macros, deal with identifiers */
 705705                 c = definp();
 706706                 for (;;) {
 707707                         if (c == ')')
 708708                                 break;
 709709                         if (c == '.' && isell()) {
 710710                                 ellips = 1;
 711711                                 if (definp() != ')')
 712712                                         goto bad;
 713713                                 break;
 714714                         }
 715715                         if (c == IDENT) {
 716716                                 /* make sure there is no arg of same name */
 717717                                 for (i = 0; i < narg; i++)
 718718                                         if (!strcmp((char *) args[i], (char *)yytext))
 719719                                                 error("Duplicate macro "
 720720                                                   "parameter \"%s\"", yytext);
 721721                                 if (narg == MAXARGS)
 722722                                         error("Too many macro args");
 723723                                 args[narg++] = xstrdup(yytext);
 724724                                 if ((c = definp()) == ',') {
 725725                                         if ((c = definp()) == ')')
 726726                                                 goto bad;
 727727                                         continue;
 728728                                 }
 729729 #ifdef GCC_COMPAT
 730730                                 if (c == '.' && isell()) {
 731731                                         if (definp() != ')')
 732732                                                 goto bad;
 733733                                         gccvari = args[--narg];
 734734                                         break;
 735735                                 }
 736736 #endif
 737737                                 if (c == ')')
 738738                                         break;
 739739                         }
 740740                         goto bad;
 741741                 }
 742742                 c = sloscan();
 743743         } else if (c == '\n') {
 744744                 /* #define foo */
 745745                 ;
 746746         } else if (c == 0) {
 747747                 prem();
 748748         } else if (c != WSPACE)
 749749                 goto bad;
 750750 
 751751         while (c == WSPACE)
 752752                 c = sloscan();
 753753 
 754754         /* replacement list cannot start with ## operator */
 755755         if (c == '#') {
 756756                 if ((c = sloscan()) == '#')
 757757                         goto bad;
 758758                 savch('\0');
 759759 #ifdef GCC_COMPAT
 760760                 wascon = 0;
 761761 #endif
 762762                 goto in2;
 763763         }
 764764 
 765765         /* parse replacement-list, substituting arguments */
 766766         savch('\0');
 767767         while (c != '\n') {
 768768 #ifdef GCC_COMPAT
 769769                 wascon = 0;
 770770 loop:
 771771 #endif
 772772                 switch (c) {
 773773                 case WSPACE:
 774774                         /* remove spaces if it surrounds a ## directive */
 775775                         ubuf = stringbuf;
 776776                         savstr(yytext);
 777777                         c = sloscan();
 778778                         if (c == '#') {
 779779                                 if ((c = sloscan()) != '#')
 780780                                         goto in2;
 781781                                 stringbuf = ubuf;
 782782                                 savch(CONC);
 783783                                 if ((c = sloscan()) == WSPACE)
 784784                                         c = sloscan();
 785785 #ifdef GCC_COMPAT
 786786                                 if (c == '\n')
 787787                                         break;
 788788                                 wascon = 1;
 789789                                 goto loop;
 790790 #endif
 791791                         }
 792792                         continue;
 793793 
 794794                 case '#':
 795795                         c = sloscan();
 796796                         if (c == '#') {
 797797                                 /* concat op */
 798798                                 savch(CONC);
 799799                                 if ((c = sloscan()) == WSPACE)
 800800                                         c = sloscan();
 801801 #ifdef GCC_COMPAT
 802802                                 if (c == '\n')
 803803                                         break;
 804804                                 wascon = 1;
 805805                                 goto loop;
 806806 #else
 807807                                 continue;
 808808 #endif
 809809                         }
 810810 in2:                    if (narg < 0) {
 811811                                 /* no meaning in object-type macro */
 812812                                 savch('#');
 813813                                 continue;
 814814                         }
 815815                         /* remove spaces between # and arg */
 816816                         savch(SNUFF);
 817817                         if (c == WSPACE)
 818818                                 c = sloscan(); /* whitespace, ignore */
 819819                         mkstr = 1;
 820820                         if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
 821821                                 continue;
 822822 
 823823                         /* FALLTHROUGH */
 824824                 case IDENT:
 825825                         if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
 826826                                 if (ellips == 0)
 827827                                         error("unwanted %s", yytext);
 828828 #ifdef GCC_COMPAT
 829829                                 savch(wascon ? GCCARG : VARG);
 830830 #else
 831831                                 savch(VARG);
 832832 #endif
 833833 
 834834                                 savch(WARN);
 835835                                 if (mkstr)
 836836                                         savch(SNUFF), mkstr = 0;
 837837                                 break;
 838838                         }
 839839                         if (narg < 0)
 840840                                 goto id; /* just add it if object */
 841841                         /* check if its an argument */
 842842                         for (i = 0; i < narg; i++)
 843843                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
 844844                                         break;
 845845                         if (i == narg) {
 846846 #ifdef GCC_COMPAT
 847847                                 if (gccvari &&
 848848                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
 849849                                         savch(wascon ? GCCARG : VARG);
 850850                                         savch(WARN);
 851851                                         if (mkstr)
 852852                                                 savch(SNUFF), mkstr = 0;
 853853                                         break;
 854854                                 }
 855855 #endif
 856856                                 if (mkstr)
 857857                                         error("not argument");
 858858                                 goto id;
 859859                         }
 860860                         savch(i);
 861861                         savch(WARN);
 862862                         if (mkstr)
 863863                                 savch(SNUFF), mkstr = 0;
 864864                         break;
 865865 
 866866                 case CMNT: /* save comments */
 867867                         getcmnt();
 868868                         break;
 869869 
 870870                 case 0:
 871871                         prem();
 872872 
 873873                 default:
 874874 id:                     savstr(yytext);
 875875                         break;
 876876                 }
 877877                 c = sloscan();
 878878         }
 879879         defining = readmac = 0;
 880880         /* remove trailing whitespace */
 881881         while (stringbuf > sbeg) {
 882882                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
 883883                         stringbuf--;
 884884                 /* replacement list cannot end with ## operator */
 885885                 else if (stringbuf[-1] == CONC)
 886886                         goto bad;
 887887                 else
 888888                         break;
 889889         }
 890890 #ifdef GCC_COMPAT
 891891         if (gccvari) {
 892892                 savch(narg);
 893893                 savch(VARG);
 894894         } else
 895895 #endif
 896896         if (ellips) {
 897897                 savch(narg);
 898898                 savch(VARG);
 899899         } else
 900900                 savch(narg < 0 ? OBJCT : narg);
 901901         if (redef && ifiles->idx != SYSINC) {
 902902                 if (cmprepl(np->value, stringbuf-1)) {
 903903                         sbeg = stringbuf;
 904904                         np->value = stringbuf-1;
 905905                         warning("%s redefined (previously defined at \"%s\" line %d)",
 906906                             np->namep, np->file, np->line);
 907907                 }
 908908                 stringbuf = sbeg/* forget this space */
 909909         } else
 910910                 np->value = stringbuf-1;
 911911 
 912912 #ifdef PCC_DEBUG
 913913         if (dflag) {
 914914                 const usch *w = np->value;
 915915 
 916916                 printf("!define: ");
 917917                 if (*w == OBJCT)
 918918                         printf("[object]");
 919919                 else if (*w == VARG)
 920920                         printf("[VARG%d]", *--w);
 921921                 while (*--w) {
 922922                         switch (*w) {
 923923                         case WARN: printf("<%d>", *--w); break;
 924924                         case CONC: printf("<##>"); break;
 925925                         case SNUFF: printf("<\">"); break;
 926926                         default: putchar(*w); break;
 927927                         }
 928928                 }
 929929                 putchar('\n');
 930930         }
 931931 #endif
 932932         for (i = 0; i < narg; i++)
 933933                 free(args[i]);
 934934         return;
 935935 
 936936 bad:    error("bad #define");
 937937 }
 938938 
 939939 void
 940940 warning(const char *fmt, ...)
 941941 {
 942942         va_list ap;
 943943         usch *sb;
 944944 
 945945         flbuf();
 946946         savch(0);
 947947 
 948948         sb = stringbuf;
 949949         if (ifiles != NULL)
 950950                 sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
 951951 
 952952         va_start(ap, fmt);
 953953         vsheap(fmt, ap);
 954954         va_end(ap);
 955955         savch('\n');
 956956         xwrite(2, sb, stringbuf - sb);
 957957         stringbuf = sb;
 958958 }
 959959 
 960960 void
 961961 error(const char *fmt, ...)
 962962 {
 963963         va_list ap;
 964964         usch *sb;
 965965 
 966966         flbuf();
 967967         savch(0);
 968968 
 969969         sb = stringbuf;
 970970         if (ifiles != NULL)
 971971                 sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
 972972 
 973973         va_start(ap, fmt);
 974974         vsheap(fmt, ap);
 975975         va_end(ap);
 976976         savch('\n');
 977977         xwrite(2, sb, stringbuf - sb);
 978978         stringbuf = sb;
 979979 
 980980         exit(1);
 981981 }
 982982 
 983983 static void
 984984 sss(void)
 985985 {
 986986         savch(EBLOCK);
 987987         savch(cinput());
 988988         savch(cinput());
 989989 }
 990990 
 991991 static int
 992992 addmac(struct symtab *sp)
 993993 {
 994994         int c, i;
 995995 
 996996         /* Check if it exists; then save some space */
 997997         /* May be more difficult to debug cpp */
 998998         for (i = 1; i < norepptr; i++)
 999999                 if (norep[i] == sp)
 10001000                         return i;
 10011001         if (norepptr >= RECMAX)
 10021002                 error("too many macros");
 10031003         /* check norepptr */
 10041004         if ((norepptr & 255) == 0)
 10051005                 norepptr++;
 10061006         if (((norepptr >> 8) & 255) == 0)
 10071007                 norepptr += 256;
 10081008         c = norepptr;
 10091009         norep[norepptr++] = sp;
 10101010         return c;
 10111011 }
 10121012 
 10131013 static void
 10141014 doblk(void)
 10151015 {
 10161016         int c;
 10171017 
 10181018         do {
 10191019                 donex();
 10201020         } while ((c = sloscan()) == EBLOCK);
 10211021         if (c == IDENT)
 10221022                 return;
 10231023         error("EBLOCK sync error");
 10241024 }
 10251025 
 10261026 /* Block next nr in lex buffer to expand */
 10271027 int
 10281028 donex(void)
 10291029 {
 10301030         int n, i;
 10311031 
 10321032         if (bidx == RECMAX)
 10331033                 error("too deep macro recursion");
 10341034         n = cinput();
 10351035         n = MKB(n, cinput());
 10361036         for (i = 0; i < bidx; i++)
 10371037                 if (bptr[i] == n)
 10381038                         return n; /* already blocked */
 10391039         bptr[bidx++] = n;
 10401040         /* XXX - check for sp buffer overflow */
 10411041 #ifdef PCC_DEBUG
 10421042         if (dflag>1) {
 10431043                 printf("donex %d (%d) blocking:\n", bidx, n);
 10441044                 printf("donex %s(%d) blocking:", norep[n]->namep, n);
 10451045                 for (i = bidx-1; i >= 0; i--)
 10461046                         printf(" '%s'", norep[bptr[i]]->namep);
 10471047                 printf("\n");
 10481048         }
 10491049 #endif
 10501050         return n;
 10511051 }
 10521052 
 10531053 /*
 10541054  * store a character into the "define" buffer.
 10551055  */
 10561056 void
 10571057 savch(int c)
 10581058 {
 10591059         if (stringbuf >= &sbf[SBSIZE]) {
 10601060                 stringbuf = sbf; /* need space to write error message */
 10611061                 error("out of macro space!");
 10621062         }
 10631063         *stringbuf++ = (usch)c;
 10641064 }
 10651065 
 10661066 /*
 10671067  * convert _Pragma() to #pragma for output.
 10681068  * Syntax is already correct.
 10691069  */
 10701070 static void
 10711071 pragoper(void)
 10721072 {
 10731073         usch *s;
 10741074         int t;
 10751075 
 10761076         while ((t = sloscan()) != '(')
 10771077                 ;
 10781078 
 10791079         while ((t = sloscan()) == WSPACE)
 10801080                 ;
 10811081         if (t != STRING)
 10821082                 error("_Pragma() must have string argument");
 10831083         savstr((const usch *)"\n#pragma ");
 10841084         s = yytext;
 10851085         if (*s == 'L')
 10861086                 s++;
 10871087         for (; *s; s++) {
 10881088                 if (*s == EBLOCK) {
 10891089                         s+=2;
 10901090                         continue;
 10911091                 }
 10921092                 if (*s == '\"')
 10931093                         continue;
 10941094                 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
 10951095                         s++;
 10961096                 savch(*s);
 10971097         }
 10981098         sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
 10991099         while ((t = sloscan()) == WSPACE)
 11001100                 ;
 11011101         if (t != ')')
 11021102                 error("_Pragma() syntax error");
 11031103 }
 11041104 
 11051105 /*
 11061106  * Return true if it is OK to expand this symbol.
 11071107  */
 11081108 static int
 11091109 okexp(struct symtab *sp)
 11101110 {
 11111111         int i;
 11121112 
 11131113         if (sp == NULL)
 11141114                 return 0;
 11151115         for (i = 0; i < bidx; i++)
 11161116                 if (norep[bptr[i]] == sp)
 11171117                         return 0;
 11181118         return 1;
 11191119 }
 11201120 
 11211121 /*
 11221122  * Insert block(s) before each expanded name.
 11231123  * Input is in lex buffer, output on lex buffer.
 11241124  */
 11251125 static void
 11261126 insblock(int bnr)
 11271127 {
 11281128         usch *bp = stringbuf;
 11291129         int c, i;
 11301130  
 11311131         IMP("IB");
 11321132         readmac++;
 11331133         while ((c = sloscan()) != WARN) {
 11341134                 if (c == EBLOCK) {
 11351135                         sss();
 11361136                         continue;
 11371137                 }
 11381138                 if (c == CMNT) {
 11391139                         getcmnt();
 11401140                         continue;
 11411141                 }
 11421142                 if (c == IDENT) {
 11431143                         savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
 11441144                         for (i = 0; i < bidx; i++)
 11451145                                 savch(EBLOCK), savch(bptr[i] & 255),
 11461146                                     savch(bptr[i] >> 8);
 11471147                 }
 11481148                 savstr(yytext);
 11491149                 if (c == '\n')
 11501150                         (void)cinput();
 11511151         }
 11521152         savch(0);
 11531153         cunput(WARN);
 11541154         unpstr(bp);
 11551155         stringbuf = bp;
 11561156         readmac--;
 11571157         IMP("IBRET");
 11581158 }
 11591159 
 11601160 /* Delete next WARN on the input stream */
 11611161 static void
 11621162 delwarn(void)
 11631163 {
 11641164         usch *bp = stringbuf;
 11651165         int c;
 11661166  
 11671167         IMP("DELWARN");
 11681168         while ((c = sloscan()) != WARN) {
 11691169                 if (c == CMNT) {
 11701170                         getcmnt();
 11711171                 } else if (c == EBLOCK) {
 11721172                         sss();
 11731173                 } else if (c == '\n') {
 11741174                         putch(cinput());
 11751175                 } else
 11761176                         savstr(yytext);
 11771177         }
 11781178         if (stringbuf[-1] == '/')
 11791179                 savch(PHOLD); /* avoid creating comments */
 11801180         savch(0);
 11811181         unpstr(bp);
 11821182         stringbuf = bp;
 11831183         IMP("DELWRET");
 11841184 }
 11851185 
 11861186 /*
 11871187  * Handle defined macro keywords found on input stream.
 11881188  * When finished print out the full expanded line.
 11891189  * Everything on lex buffer except for the symtab.
 11901190  */
 11911191 int
 11921192 kfind(struct symtab *sp)
 11931193 {
 11941194         struct symtab *nl;
 11951195         const usch *argary[MAXARGS+1], *cbp;
 11961196         usch *sbp;
 11971197         int c, o, chkf;
 11981198 
 11991199         DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
 12001200         IMP("KFIND");
 12011201         if (*sp->value == OBJCT) {
 12021202                 if (sp == filloc) {
 12031203                         unpstr(sheap("\"%s\"", ifiles->fname));
 12041204                         return 1;
 12051205                 } else if (sp == linloc) {
 12061206                         unpstr(sheap("%d", ifiles->lineno));
 12071207                         return 1;
 12081208                 }
 12091209                 IMP("END1");
 12101210                 cunput(WARN);
 12111211                 for (cbp = sp->value-1; *cbp; cbp--)
 12121212                         cunput(*cbp);
 12131213                 insblock(addmac(sp));
 12141214                 IMP("ENDX");
 12151215                 exparg(1);
 12161216 
 12171217 upp:            sbp = stringbuf;
 12181218                 chkf = 1;
 12191219                 if (obufp != 0)
 12201220                         lastoch = outbuf[obufp-1];
 12211221                 if (iswsnl(lastoch))
 12221222                         chkf = 0;
 12231223                 if (Cflag)
 12241224                         readmac++;
 12251225                 while ((c = sloscan()) != WARN) {
 12261226                         switch (c) {
 12271227                         case CMNT:
 12281228                                 getcmnt();
 12291229                                 break;
 12301230 
 12311231                         case STRING:
 12321232                                 /* Remove embedded directives */
 12331233                                 for (cbp = yytext; *cbp; cbp++) {
 12341234                                         if (*cbp == EBLOCK)
 12351235                                                 cbp+=2;
 12361236                                         else if (*cbp != CONC)
 12371237                                                 savch(*cbp);
 12381238                                 }
 12391239                                 break;
 12401240 
 12411241                         case EBLOCK:
 12421242                                 doblk();
 12431243                                 /* FALLTHROUGH */
 12441244                         case IDENT:
 12451245                                 /*
 12461246                                  * Tricky: if this is the last identifier
 12471247                                  * in the expanded list, and it is defined
 12481248                                  * as a function-like macro, then push it
 12491249                                  * back on the input stream and let fastscan
 12501250                                  * handle it as a new macro.
 12511251                                  * BUT: if this macro is blocked then this
 12521252                                  * should not be done.
 12531253                                  */
 12541254                                 nl = lookup(yytext, FIND);
 12551255                                 o = okexp(nl);
 12561256                                 bidx = 0;
 12571257                                 /* Deal with pragmas here */
 12581258                                 if (nl == pragloc) {
 12591259                                         pragoper();
 12601260                                         break;
 12611261                                 }
 12621262                                 if (nl == NULL || !o || *nl->value == OBJCT) {
 12631263                                         /* Not fun-like macro */
 12641264                                         savstr(yytext);
 12651265                                         break;
 12661266                                 }
 12671267                                 c = cinput();
 12681268                                 if (c == WARN) {
 12691269                                         /* succeeded, push back */
 12701270                                         unpstr(yytext);
 12711271                                 } else {
 12721272                                         savstr(yytext);
 12731273                                 }
 12741274                                 cunput(c);
 12751275                                 break;
 12761276 
 12771277                         default:
 12781278                                 if (chkf && c < 127)
 12791279                                         putch(' ');
 12801280                                 savstr(yytext);
 12811281                                 break;
 12821282                         }
 12831283                         chkf = 0;
 12841284                 }
 12851285                 if (Cflag)
 12861286                         readmac--;
 12871287                 IMP("END2");
 12881288                 norepptr = 1;
 12891289                 savch(0);
 12901290                 stringbuf = sbp;
 12911291                 return 1;
 12921292         }
 12931293         /* Is a function-like macro */
 12941294 
 12951295         /* Search for '(' */
 12961296         sbp = stringbuf;
 12971297         while (iswsnl(c = cinput()))
 12981298                 savch(c);
 12991299         savch(0);
 13001300         stringbuf = sbp;
 13011301         if (c != '(') {
 13021302                 cunput(c);
 13031303                 unpstr(sbp);
 13041304                 return 0; /* Failed */
 13051305         }
 13061306 
 13071307         /* Found one, output \n to be in sync */
 13081308         for (; *sbp; sbp++) {
 13091309                 if (*sbp == '\n')
 13101310                         putch('\n'), ifiles->lineno++;
 13111311         }
 13121312 
 13131313         /* fetch arguments */
 13141314         if (Cflag)
 13151315                 readmac++;
 13161316         if (readargs(sp, argary))
 13171317                 error("readargs");
 13181318 
 13191319         c = addmac(sp);
 13201320         sbp = stringbuf;
 13211321         cunput(WARN);
 13221322 
 13231323         IMP("KEXP");
 13241324         subarg(sp, argary, 1);
 13251325         IMP("KNEX");
 13261326         insblock(c);
 13271327         IMP("KBLK");
 13281328 
 13291329         stringbuf = sbp;
 13301330 
 13311331         exparg(1);
 13321332         if (Cflag)
 13331333                 readmac--;
 13341334 
 13351335         IMP("END");
 13361336 
 13371337         goto upp;
 13381338 
 13391339 }
 13401340 
 13411341 /*
 13421342  * Replace and push-back on input stream the eventual replaced macro.
 13431343  * The check for whether it can expand or not should already have been done.
 13441344  * Blocks for this identifier will be added via insblock() after expansion.
 13451345  */
 13461346 int
 13471347 submac(struct symtab *sp, int lvl)
 13481348 {
 13491349         const usch *argary[MAXARGS+1];
 13501350         const usch *cp;
 13511351         usch *bp;
 13521352         int ch;
 13531353 
 13541354         DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
 13551355         if (*sp->value == OBJCT) {
 13561356                 if (sp == filloc) {
 13571357                         unpstr(sheap("\"%s\"", ifiles->fname));
 13581358                         return 1;
 13591359                 } else if (sp == linloc) {
 13601360                         unpstr(sheap("%d", ifiles->lineno));
 13611361                         return 1;
 13621362                 }
 13631363 
 13641364                 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
 13651365                 /* expand object-type macros */
 13661366                 ch = addmac(sp);
 13671367                 cunput(WARN);
 13681368 
 13691369                 for (cp = sp->value-1; *cp; cp--)
 13701370                         cunput(*cp);
 13711371                 insblock(ch);
 13721372                 delwarn();
 13731373                 return 1;
 13741374         }
 13751375 
 13761376         /*
 13771377          * Function-like macro; see if it is followed by a (
 13781378          * Be careful about the expand/noexpand balance.
 13791379          * Store read data on heap meanwhile.
 13801380          * For directive        #define foo() kaka
 13811381          * If input is          <NEX><NEX>foo<EXP>()<EXP> then
 13821382          * output should be     <NEX><NEX><EXP>kaka<EXP>.
 13831383          */
 13841384         bp = stringbuf;
 13851385         while (iswsnl(ch = cinput()))
 13861386                 savch(ch);
 13871387         savch(0);
 13881388         stringbuf = bp;
 13891389         if (ch != '(') {
 13901390                 cunput(ch);
 13911391                 unpstr(bp);
 13921392                 return 0; /* Failed */
 13931393         }
 13941394 
 13951395         /* no \n should be here */
 13961396 
 13971397         /*
 13981398          * A function-like macro has been found.  Read in the arguments,
 13991399          * expand them and push-back everything for another scan.
 14001400          */
 14011401         DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
 14021402         savch(0);
 14031403         if (readargs(sp, argary)) {
 14041404                 /* Bailed out in the middle of arg list */
 14051405                 unpstr(bp);
 14061406                 DDPRINT(("%d:noreadargs\n", lvl));
 14071407                 stringbuf = bp;
 14081408                 return 0;
 14091409         }
 14101410 
 14111411         /* when all args are read from input stream */
 14121412         ch = addmac(sp);
 14131413 
 14141414         DDPRINT(("%d:submac pre\n", lvl));
 14151415         cunput(WARN);
 14161416 
 14171417         subarg(sp, argary, lvl+1);
 14181418 
 14191419         DDPRINT(("%d:submac post\n", lvl));
 14201420         insblock(ch);
 14211421         delwarn();
 14221422 
 14231423         stringbuf = bp; /* Reset heap */
 14241424         DPRINT(("%d:Return submac\n", lvl));
 14251425         IMP("SM1");
 14261426         return 1;
 14271427 }
 14281428 
 14291429 static int
 14301430 isdir(void)
 14311431 {
 14321432         usch *bp = stringbuf;
 14331433         usch ch;
 14341434 
 14351435         while ((ch = cinput()) == ' ' || ch == '\t')
 14361436                 *stringbuf++ = ch;
 14371437         *stringbuf++ = ch;
 14381438         *stringbuf++ = 0;
 14391439         stringbuf = bp;
 14401440         if (ch == '#')
 14411441                 return 1;
 14421442         unpstr(bp);
 14431443         return 0;
 14441444 }
 14451445 
 14461446 /*
 14471447  * Deal with directives inside a macro.
 14481448  * Doing so is really ugly but gcc allows it, so...
 14491449  */
 14501450 static void
 14511451 chkdir(void)
 14521452 {
 14531453         usch ch;
 14541454 
 14551455         for (;;) {
 14561456                 if (isdir())
 14571457                         ppdir();
 14581458                 if (flslvl == 0)
 14591459                         return;
 14601460                 while ((ch = cinput()) != '\n')
 14611461                         ;
 14621462                 ifiles->lineno++;
 14631463                 putch('\n');
 14641464         }
 14651465 }
 14661466 
 14671467 /*
 14681468  * Read arguments and put in argument array.
 14691469  * If WARN is encountered return 1, otherwise 0.
 14701470  */
 14711471 int
 14721472 readargs(struct symtab *sp, const usch **args)
 14731473 {
 14741474         const usch *vp = sp->value;
 14751475         int c, i, plev, narg, ellips = 0;
 14761476         int warn;
 14771477 
 14781478         DPRINT(("readargs\n"));
 14791479 
 14801480         narg = *vp--;
 14811481         if (narg == VARG) {
 14821482                 narg = *vp--;
 14831483                 ellips = 1;
 14841484         }
 14851485 
 14861486         IMP("RDA1");
 14871487         /*
 14881488          * read arguments and store them on heap.
 14891489          */
 14901490         warn = 0;
 14911491         c = '(';
 14921492         for (i = 0; i < narg && c != ')'; i++) {
 14931493                 args[i] = stringbuf;
 14941494                 plev = 0;
 14951495                 while ((c = sloscan()) == WSPACE || c == '\n')
 14961496                         if (c == '\n') {
 14971497                                 ifiles->lineno++;
 14981498                                 putch(cinput());
 14991499                                 chkdir();
 15001500                         }
 15011501                 for (;;) {
 15021502                         while (c == EBLOCK) {
 15031503                                 sss();
 15041504                                 c = sloscan();
 15051505                         }
 15061506                         if (c == WARN) {
 15071507                                 warn++;
 15081508                                 goto oho;
 15091509                         }
 15101510                         if (plev == 0 && (c == ')' || c == ','))
 15111511                                 break;
 15121512                         if (c == '(')
 15131513                                 plev++;
 15141514                         if (c == ')')
 15151515                                 plev--;
 15161516                         savstr(yytext);
 15171517 oho:                    while ((c = sloscan()) == '\n') {
 15181518                                 ifiles->lineno++;
 15191519                                 putch(cinput());
 15201520                                 chkdir();
 15211521                                 savch(' ');
 15221522                         }
 15231523                         while (c == CMNT) {
 15241524                                 getcmnt();
 15251525                                 c = sloscan();
 15261526                         }
 15271527                         if (c == 0)
 15281528                                 error("eof in macro");
 15291529                 }
 15301530                 while (args[i] < stringbuf &&
 15311531                     iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
 15321532                         stringbuf--;
 15331533                 savch('\0');
 15341534 #ifdef PCC_DEBUG
 15351535                 if (dflag) {
 15361536                         printf("readargs: save arg %d '", i);
 15371537                         prline(args[i]);
 15381538                         printf("'\n");
 15391539                 }
 15401540 #endif
 15411541         }
 15421542 
 15431543         IMP("RDA2");
 15441544         /* Handle varargs readin */
 15451545         if (ellips)
 15461546                 args[i] = (const usch *)"";
 15471547         if (ellips && c != ')') {
 15481548                 args[i] = stringbuf;
 15491549                 plev = 0;
 15501550                 while ((c = sloscan()) == WSPACE || c == '\n')
 15511551                         if (c == '\n')
 15521552                                 cinput();
 15531553                 for (;;) {
 15541554                         if (plev == 0 && c == ')')
 15551555                                 break;
 15561556                         if (c == '(')
 15571557                                 plev++;
 15581558                         if (c == ')')
 15591559                                 plev--;
 15601560                         if (c == EBLOCK) {
 15611561                                 sss();
 15621562                         } else
 15631563                                 savstr(yytext);
 15641564                         while ((c = sloscan()) == '\n') {
 15651565                                 ifiles->lineno++;
 15661566                                 cinput();
 15671567                                 chkdir();
 15681568                                 savch(' ');
 15691569                         }
 15701570                 }
 15711571                 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
 15721572                         stringbuf--;
 15731573                 savch('\0');
 15741574                 
 15751575         }
 15761576         if (narg == 0 && ellips == 0)
 15771577                 while ((c = sloscan()) == WSPACE || c == '\n')
 15781578                         if (c == '\n')
 15791579                                 cinput();
 15801580 
 15811581         if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
 15821582                 error("wrong arg count");
 15831583         while (warn)
 15841584                 cunput(WARN), warn--;
 15851585         return 0;
 15861586 }
 15871587 
 15881588 /*
 15891589  * expand a function-like macro.
 15901590  * vp points to end of replacement-list
 15911591  * reads function arguments from sloscan()
 15921592  * result is pushed-back for more scanning.
 15931593  */
 15941594 void
 15951595 subarg(struct symtab *nl, const usch **args, int lvl)
 15961596 {
 15971597         int narg, instr, snuff;
 15981598         const usch *sp, *bp, *ap, *vp;
 15991599 
 16001600         DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
 16011601         vp = nl->value;
 16021602         narg = *vp--;
 16031603         if (narg == VARG)
 16041604                 narg = *vp--;
 16051605 
 16061606         sp = vp;
 16071607         instr = snuff = 0;
 16081608 #ifdef PCC_DEBUG
 16091609         if (dflag>1) {
 16101610                 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
 16111611                 prrep(vp);
 16121612                 printf("'\n");
 16131613         }
 16141614 #endif
 16151615 
 16161616         /*
 16171617          * push-back replacement-list onto lex buffer while replacing
 16181618          * arguments.  Arguments are macro-expanded if required.
 16191619          */
 16201620         while (*sp != 0) {
 16211621                 if (*sp == SNUFF)
 16221622                         cunput('\"'), snuff ^= 1;
 16231623                 else if (*sp == CONC)
 16241624                         ;
 16251625                 else if (*sp == WARN) {
 16261626 
 16271627                         if (sp[-1] == VARG) {
 16281628                                 bp = ap = args[narg];
 16291629                                 sp--;
 16301630 #ifdef GCC_COMPAT
 16311631                         } else if (sp[-1] == GCCARG) {
 16321632                                 ap = args[narg];
 16331633                                 if (ap[0] == 0)
 16341634                                         ap = (const usch *)"0";
 16351635                                 bp = ap;
 16361636                                 sp--;
 16371637 #endif
 16381638                         } else
 16391639                                 bp = ap = args[(int)*--sp];
 16401640 #ifdef PCC_DEBUG
 16411641                         if (dflag>1){
 16421642                                 printf("%d:subarg GOTwarn; arglist '", lvl);
 16431643                                 prline(bp);
 16441644                                 printf("'\n");
 16451645                         }
 16461646 #endif
 16471647                         if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
 16481648                                 /*
 16491649                                  * Expand an argument; 6.10.3.1:
 16501650                                  * "A parameter in the replacement list,
 16511651                                  *  is replaced by the corresponding argument
 16521652                                  *  after all macros contained therein have
 16531653                                  *  been expanded.".
 16541654                                  */
 16551655                                 cunput(WARN);
 16561656                                 unpstr(bp);
 16571657                                 exparg(lvl+1);
 16581658                                 delwarn();
 16591659                         } else {
 16601660                         while (*bp)
 16611661                                 bp++;
 16621662                         while (bp > ap) {
 16631663                                 bp--;
 16641664                                 if (snuff && !instr && iswsnl(*bp)) {
 16651665                                         while (iswsnl(*bp))
 16661666                                                 bp--;
 16671667                                         cunput(' ');
 16681668                                 }
 16691669 
 16701670                                 cunput(*bp);
 16711671                                 if ((*bp == '\'' || *bp == '"')
 16721672                                      && bp[-1] != '\\' && snuff) {
 16731673                                         instr ^= 1;
 16741674                                         if (instr == 0 && *bp == '"')
 16751675                                                 cunput('\\');
 16761676                                 }
 16771677                                 if (instr && (*bp == '\\' || *bp == '"'))
 16781678                                         cunput('\\');
 16791679                         }
 16801680                         }
 16811681                 } else
 16821682                         cunput(*sp);
 16831683                 sp--;
 16841684         }
 16851685         DPRINT(("%d:Return subarg\n", lvl));
 16861686         IMP("SUBARG");
 16871687 }
 16881688 
 16891689 /*
 16901690  * Do a (correct) expansion of a WARN-terminated buffer of tokens.
 16911691  * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
 16921692  * Expansion blocking is not altered here unless when tokens are
 16931693  * concatenated, in which case they are removed.
 16941694  */
 16951695 void
 16961696 exparg(int lvl)
 16971697 {
 16981698         struct symtab *nl;
 16991699         int c, i, gmult;
 17001700         usch *och;
 17011701         usch *osb = stringbuf;
 17021702         int anychange;
 17031703 
 17041704         DPRINT(("%d:exparg\n", lvl));
 17051705         IMP("EXPARG");
 17061706 
 17071707         readmac++;
 17081708 rescan:
 17091709         anychange = 0;
 17101710         while ((c = sloscan()) != WARN) {
 17111711                 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
 17121712                 IMP("EA0");
 17131713                 bidx = 0;
 17141714                 switch (c) {
 17151715 
 17161716                 case EBLOCK:
 17171717                         doblk();
 17181718                         /* FALLTHROUGH */
 17191719                 case IDENT:
 17201720                         /*
 17211721                          * Handle argument concatenation here.
 17221722                          * In case of concatenation, add all blockings.
 17231723                          */
 17241724                         DDPRINT(("%d:exparg ident %d\n", lvl, c));
 17251725                         och = stringbuf;
 17261726                         gmult = 0;
 17271727 
 17281728 sav:                    savstr(yytext);
 17291729 
 17301730                         if ((c = cinput()) == EBLOCK) {
 17311731                                 /* yep, are concatenating; add blocks */
 17321732                                 gmult = 1;
 17331733                                 do {
 17341734                                         donex();
 17351735                                 } while ((c = sloscan()) == EBLOCK);
 17361736                                 goto sav;
 17371737                         }
 17381738                         cunput(c);
 17391739 
 17401740                         DPRINT(("%d:exparg: str '%s'\n", lvl, och));
 17411741                         IMP("EA1");
 17421742                         /* see if ident is expandable */
 17431743                         if ((nl = lookup(och, FIND)) && okexp(nl)) {
 17441744                                 /* Save blocks */
 17451745                                 int donothing;
 17461746                                 unsigned short *svidx =
 17471747                                     malloc(sizeof(int)*(bidx+1));
 17481748                                 int svbidx = bidx;
 17491749 
 17501750                                 for (i = 0; i < bidx; i++)
 17511751                                         svidx[i] = bptr[i];
 17521752                                 if (submac(nl, lvl+1)) {
 17531753                                         /* Could expand, result on lexbuffer */
 17541754                                         stringbuf = och; /* clear saved name */
 17551755                                         anychange = 1;
 17561756                                 }
 17571757                                 donothing = 0;
 17581758                                 c = cinput();
 17591759                                 if (c == 'L') {
 17601760                                         int c2 = cinput();
 17611761                                         if (c2 == '\"' || c2 == '\'')
 17621762                                                 donothing = 1;
 17631763                                         cunput(c2);
 17641764                                 }
 17651765                                 cunput(c);
 17661766 
 17671767                                 if (donothing == 0)
<>1768 -                                    if (((spechr[c] & C_ID) && c > 63) ||
 1769 -                                    c == EBLOCK) {
  1768+                                    if ((spechr[c] & C_ID0) || c == EBLOCK) {
<_17701769                                         for (i = 0; i < svbidx; i++) {
 17711770                                                 cunput(svidx[i] >> 8);
 17721771                                                 cunput(svidx[i] & 255);
 17731772                                                 cunput(EBLOCK);
 17741773                                         }
 17751774                                 }
 17761775                                 free(svidx);
 17771776                         } else if (bidx) {
 17781777                                 /* must restore blocks */
 17791778                                 if (gmult) {
 17801779                                         unpstr(och);
 17811780                                         if (sloscan() != IDENT)
 17821781                                                 error("exparg sync error");
 17831782                                 }
 17841783                                 stringbuf = och;
 17851784                                 for (i = 0; i < bidx; i++)
 17861785                                         savch(EBLOCK), savch(bptr[i] & 255),
 17871786                                             savch(bptr[i] >> 8);
 17881787                                 savstr(yytext);
 17891788                         }
 17901789                         bidx = 0;
 17911790                         IMP("EA2");
 17921791                         break;
 17931792 
 17941793                 case CMNT:
 17951794                         getcmnt();
 17961795                         break;
 17971796 
 17981797                 case '\n':
 17991798                         cinput();
 18001799                         savch(' ');
 18011800                         break;
 18021801 
 18031802                 default:
 18041803                         savstr(yytext);
 18051804                         break;
 18061805                 }
 18071806         }
 18081807         *stringbuf = 0;
 18091808         cunput(WARN);
 18101809         unpstr(osb);
 18111810         DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
 18121811         IMP("EXPRET");
 18131812         stringbuf = osb;
 18141813         if (anychange)
 18151814                 goto rescan;
 18161815         readmac--;
 18171816 }
 18181817 
 18191818 #ifdef PCC_DEBUG
 18201819 static void
 18211820 imp(const char *str)
 18221821 {
 18231822         printf("%s (%d) '", str, bidx);
 18241823         prline(ifiles->curptr);
 18251824         printf("'\n");
 18261825 }
 18271826 
 18281827 static void
 18291828 prrep(const usch *s)
 18301829 {
 18311830         while (*s) {
 18321831                 switch (*s) {
 18331832                 case WARN: printf("<ARG(%d)>", *--s); break;
 18341833                 case CONC: printf("<CONC>"); break;
 18351834                 case SNUFF: printf("<SNUFF>"); break;
 18361835                 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
 18371836                 default: printf("%c", *s); break;
 18381837                 }
 18391838                 s--;
 18401839         }
 18411840 }
 18421841 
 18431842 static void
 18441843 prline(const usch *s)
 18451844 {
 18461845         while (*s) {
 18471846                 switch (*s) {
 18481847                 case WARN: printf("<WARN>"); break;
 18491848                 case CONC: printf("<CONC>"); break;
 18501849                 case SNUFF: printf("<SNUFF>"); break;
 18511850                 case PHOLD: printf("<PHOLD>"); break;
 18521851                 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
 18531852                 case '\n': printf("<NL>"); break;
 18541853                 default: printf("%c", *s); break;
 18551854                 }
 18561855                 s++;
 18571856         }
 18581857 }
 18591858 #endif
 18601859 
 18611860 usch *
 18621861 savstr(const usch *str)
 18631862 {
 18641863         usch *rv = stringbuf;
 18651864 
 18661865         do {
 18671866                 if (stringbuf >= &sbf[SBSIZE])   {
 18681867                         stringbuf = sbf; /* need space to write error message */
 18691868                         error("out of macro space!");
 18701869                 }
 18711870         } while ((*stringbuf++ = *str++));
 18721871         stringbuf--;
 18731872         return rv;
 18741873 }
 18751874 
 18761875 void
 18771876 unpstr(const usch *c)
 18781877 {
 18791878         const usch *d = c;
 18801879 
 18811880 #if 0
 18821881         if (dflag>1) {
 18831882                 printf("Xunpstr: '");
 18841883                 prline(c);
 18851884                 printf("'\n");
 18861885         }
 18871886 #endif
 18881887         while (*d) {
 18891888                 if (*d == EBLOCK)
 18901889                         d += 2;
 18911890                 d++;
 18921891         }
 18931892         while (d > c) {
 18941893                 cunput(*--d);
 18951894         }
 18961895 }
 18971896 
 18981897 static void
 18991898 flbuf(void)
 19001899 {
 19011900         if (obufp == 0)
 19021901                 return;
 19031902         if (Mflag == 0)
 19041903                 xwrite(ofd, outbuf, obufp);
 19051904         lastoch = outbuf[obufp-1];
 19061905         obufp = 0;
 19071906 }
 19081907 
 19091908 void
 19101909 putch(int ch)
 19111910 {
 19121911         outbuf[obufp++] = (usch)ch;
 19131912         if (obufp == CPPBUF || (istty && ch == '\n'))
 19141913                 flbuf();
 19151914 }
 19161915 
 19171916 void
 19181917 putstr(const usch *s)
 19191918 {
 19201919         for (; *s; s++) {
 19211920                 if (*s == PHOLD)
 19221921                         continue;
 19231922                 outbuf[obufp++] = *s;
 19241923                 if (obufp == CPPBUF || (istty && *s == '\n'))
 19251924                         flbuf();
 19261925         }
 19271926 }
 19281927 
 19291928 /*
 19301929  * convert a number to an ascii string. Store it on the heap.
 19311930  */
 19321931 static void
 19331932 num2str(int num)
 19341933 {
 19351934         static usch buf[12];
 19361935         usch *b = buf;
 19371936         int m = 0;
 19381937         
 19391938         if (num < 0)
 19401939                 num = -num, m = 1;
 19411940         do {
 19421941                 *b++ = (usch)(num % 10 + '0');
 19431942                 num /= 10;
 19441943         } while (num);
 19451944         if (m)
 19461945                 *b++ = '-';
 19471946         while (b > buf)
 19481947                 savch(*--b);
 19491948 }
 19501949 
 19511950 /*
 19521951  * similar to sprintf, but only handles %c, %s and %d.
 19531952  * saves result on heap.
 19541953  */
 19551954 static void
 19561955 vsheap(const char *fmt, va_list ap)
 19571956 {
 19581957         for (; *fmt; fmt++) {
 19591958                 if (*fmt == '%') {
 19601959                         fmt++;
 19611960                         switch (*fmt) {
 19621961                         case 's':
 19631962                                 savstr(va_arg(ap, usch *));
 19641963                                 break;
 19651964                         case 'd':
 19661965                                 num2str(va_arg(ap, int));
 19671966                                 break;
 19681967                         case 'c':
 19691968                                 savch(va_arg(ap, int));
 19701969                                 break;
 19711970                         default:
 19721971                                 error("bad sheap");
 19731972                         }
 19741973                 } else
 19751974                         savch(*fmt);
 19761975         }
 19771976         *stringbuf = 0;
 19781977 }
 19791978 
 19801979 usch *
 19811980 sheap(const char *fmt, ...)
 19821981 {
 19831982         va_list ap;
 19841983         usch *op = stringbuf;
 19851984 
 19861985         va_start(ap, fmt);
 19871986         vsheap(fmt, ap);
 19881987         va_end(ap);
 19891988 
 19901989         return op;
 19911990 }
 19921991 
 19931992 static void
 19941993 usage(void)
 19951994 {
 19961995         error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
 19971996 }
 19981997 
 19991998 #ifdef notyet
 20001999 /*
 20012000  * Symbol table stuff.
 20022001  * The data structure used is a patricia tree implementation using only
 20032002  * bytes to store offsets. 
 20042003  * The information stored is (lower address to higher):
 20052004  *
 20062005  *      unsigned char bitno[2]; bit number in the string
 20072006  *      unsigned char left[3];  offset from base to left element
 20082007  *      unsigned char right[3]; offset from base to right element
 20092008  */
 20102009 #endif
 20112010 
 20122011 /*
 20132012  * This patricia implementation is more-or-less the same as
 20142013  * used in ccom for string matching.
 20152014  */
 20162015 struct tree {
 20172016         int bitno;
 20182017         struct tree *lr[2];
 20192018 };
 20202019 
 20212020 #define BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
 20222021 #define LEFT_IS_LEAF            0x80000000
 20232022 #define RIGHT_IS_LEAF           0x40000000
 20242023 #define IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
 20252024 #define IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
 20262025 #define P_BIT(key, bit)         (key[bit >> 3] >> (bit & 7)) & 1
 20272026 #define CHECKBITS               8
 20282027 
 20292028 static struct tree *sympole;
 20302029 static int numsyms;
 20312030 
 20322031 /*
 20332032  * Allocate a symtab struct and store the string.
 20342033  */
 20352034 static struct symtab *
 20362035 getsymtab(const usch *str)
 20372036 {
 20382037         struct symtab *sp = malloc(sizeof(struct symtab));
 20392038 
 20402039         if (sp == NULL)
 20412040                 error("getsymtab: couldn't allocate symtab");
 20422041         sp->namep = savstr(str);
 20432042         savch('\0');
 20442043         sp->value = NULL;
 20452044         sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
 20462045         sp->line = ifiles ? ifiles->lineno : 0;
 20472046         return sp;
 20482047 }
 20492048 
 20502049 /*
 20512050  * Do symbol lookup in a patricia tree.
 20522051  * Only do full string matching, no pointer optimisations.
 20532052  */
 20542053 struct symtab *
 20552054 lookup(const usch *key, int enterf)
 20562055 {
 20572056         struct symtab *sp;
 20582057         struct tree *w, *new, *last;
 20592058         int len, cix, bit, fbit, svbit, ix, bitno;
 20602059         const usch *k, *m;
 20612060 
 20622061         /* Count full string length */
 20632062         for (k = key, len = 0; *k; k++, len++)
 20642063                 ;
 20652064 
 20662065         switch (numsyms) {
 20672066         case 0: /* no symbols yet */
 20682067                 if (enterf != ENTER)
 20692068                         return NULL;
 20702069                 sympole = (struct tree *)getsymtab(key);
 20712070                 numsyms++;
 20722071                 return (struct symtab *)sympole;
 20732072 
 20742073         case 1:
 20752074                 w = sympole;
 20762075                 svbit = 0; /* XXX gcc */
 20772076                 break;
 20782077 
 20792078         default:
 20802079                 w = sympole;
 20812080                 bitno = len * CHECKBITS;
 20822081                 for (;;) {
 20832082                         bit = BITNO(w->bitno);
 20842083                         fbit = bit > bitno ? 0 : P_BIT(key, bit);
 20852084                         svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
 20862085                             IS_LEFT_LEAF(w->bitno);
 20872086                         w = w->lr[fbit];
 20882087                         if (svbit)
 20892088                                 break;
 20902089                 }
 20912090         }
 20922091 
 20932092         sp = (struct symtab *)w;
 20942093 
 20952094         m = sp->namep;
 20962095         k = key;
 20972096 
 20982097         /* Check for correct string and return */
 20992098         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
 21002099                 ;
 21012100         if (*m == 0 && *k == 0) {
 21022101                 if (enterf != ENTER && sp->value == NULL)
 21032102                         return NULL;
 21042103                 return sp;
 21052104         }
 21062105 
 21072106         if (enterf != ENTER)
 21082107                 return NULL; /* no string found and do not enter */
 21092108 
 21102109         ix = *m ^ *k;
 21112110         while ((ix & 1) == 0)
 21122111                 ix >>= 1, cix++;
 21132112 
 21142113         /* Create new node */
 21152114         if ((new = malloc(sizeof *new)) == NULL)
 21162115                 error("getree: couldn't allocate tree");
 21172116         bit = P_BIT(key, cix);
 21182117         new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21192118         new->lr[bit] = (struct tree *)getsymtab(key);
 21202119 
 21212120         if (numsyms++ == 1) {
 21222121                 new->lr[!bit] = sympole;
 21232122                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21242123                 sympole = new;
 21252124                 return (struct symtab *)new->lr[bit];
 21262125         }
 21272126 
 21282127         w = sympole;
 21292128         last = NULL;
 21302129         for (;;) {
 21312130                 fbit = w->bitno;
 21322131                 bitno = BITNO(w->bitno);
 21332132                 if (bitno == cix)
 21342133                         error("bitno == cix");
 21352134                 if (bitno > cix)
 21362135                         break;
 21372136                 svbit = P_BIT(key, bitno);
 21382137                 last = w;
 21392138                 w = w->lr[svbit];
 21402139                 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
 21412140                         break;
 21422141         }
 21432142 
 21442143         new->lr[!bit] = w;
 21452144         if (last == NULL) {
 21462145                 sympole = new;
 21472146         } else {
 21482147                 last->lr[svbit] = new;
 21492148                 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21502149         }
 21512150         if (bitno < cix)
 21522151                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21532152         return (struct symtab *)new->lr[bit];
 21542153 }
 21552154 
 21562155 static usch *
 21572156 xstrdup(const usch *str)
 21582157 {
 21592158         usch *rv;
 21602159 
 21612160         if ((rv = (usch *)strdup((const char *)str)) == NULL)
 21622161                 error("xstrdup: out of mem");
 21632162         return rv;
 21642163 }
 21652164 
 21662165 void
 21672166 xwrite(int fd, const void *buf, unsigned int len)
 21682167 {
 21692168         if (write(fd, buf, len) != (int)len) {
 21702169                 if (fd == 2)
 21712170                         exit(2);
 21722171                 error("write error");
 21732172         }
 21742173 }
FishEye: Open Source License registered to PCC.
Your maintenance has expired. You can renew your license at http://www.atlassian.com/fisheye/renew
Atlassian FishEye, CVS analysis. (Version:1.6.3 Build:build-336 2008-11-04) - Administration - Page generated 2014-09-19 05:47 +0200