Quick Search:

Mode

Context

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

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.180
 
1.181
 
MAIN:plunky:20121029170535
 
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')
<>396 -                return;
  396+                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;
<>418 -        if (yylex() == '\n')
 419 -                return;
  418+        if (yylex() != '\n')
  419+                goto bad;
420420 
<> 421+okret:  prtline();
  422+        return;
  423+
<_421424 bad:    error("bad line directive");
 422425 }
 423426 
 424427 /*
 425428  * Search for and include next file.
 426429  * Return 1 on success.
 427430  */
 428431 static int
 429432 fsrch(const usch *fn, int idx, struct incs *w)
 430433 {
 431434         int i;
 432435 
 433436         for (i = idx; i < 2; i++) {
 434437                 if (i > idx)
 435438                         w = incdir[i];
 436439                 for (; w; w = w->next) {
 437440                         usch *nm = stringbuf;
 438441 
 439442                         savstr(w->dir); savch('/');
 440443                         savstr(fn); savch(0);
 441444                         if (pushfile(nm, fn, i, w->next) == 0)
 442445                                 return 1;
 443446                         stringbuf = nm;
 444447                 }
 445448         }
 446449         return 0;
 447450 }
 448451 
 449452 static void
 450453 prem(void)
 451454 {
 452455         error("premature EOF");
 453456 }
 454457 
 455458 /*
 456459  * Include a file. Include order:
 457460  * - For <...> files, first search -I directories, then system directories.
 458461  * - For "..." files, first search "current" dir, then as <...> files.
 459462  */
 460463 void
 461464 include(void)
 462465 {
 463466         struct symtab *nl;
 464467         usch *osp;
 465468         usch *fn, *safefn;
 466469         int c;
 467470 
 468471         if (flslvl)
 469472                 return;
 470473         osp = stringbuf;
 471474 
 472475         while ((c = sloscan()) == WSPACE)
 473476                 ;
 474477         if (c == IDENT) {
 475478                 /* sloscan() will not expand idents */
 476479                 if ((nl = lookup(yytext, FIND)) == NULL)
 477480                         goto bad;
 478481                 if (kfind(nl))
 479482                         unpstr(stringbuf);
 480483                 else
 481484                         unpstr(nl->namep);
 482485                 stringbuf = osp;
 483486                 c = yylex();
 484487         }
 485488         if (c != STRING && c != '<')
 486489                 goto bad;
 487490 
 488491         if (c == '<') {
 489492                 fn = stringbuf;
 490493                 while ((c = sloscan()) != '>' && c != '\n') {
 491494                         if (c == '\n') /* XXX check - cannot reach */
 492495                                 goto bad;
 493496                         savstr(yytext);
 494497                 }
 495498                 savch('\0');
 496499                 while ((c = sloscan()) == WSPACE)
 497500                         ;
 498501                 if (c == 0)
 499502                         prem();
 500503                 if (c != '\n')
 501504                         goto bad;
 502505                 safefn = fn;
 503506         } else {
 504507                 usch *nm = stringbuf;
 505508 
 506509                 yytext[strlen((char *)yytext)-1] = 0;
 507510                 fn = &yytext[1];
 508511                 /* first try to open file relative to previous file */
 509512                 /* but only if it is not an absolute path */
 510513                 if (*fn != '/') {
 511514                         savstr(ifiles->orgfn);
 512515                         if ((stringbuf =
 513516                             (usch *)strrchr((char *)nm, '/')) == NULL)
 514517                                 stringbuf = nm;
 515518                         else
 516519                                 stringbuf++;
 517520                 }
 518521                 safefn = stringbuf;
 519522                 savstr(fn); savch(0);
 520523                 c = yylex();
 521524                 if (c == 0)
 522525                         prem();
 523526                 if (c != '\n')
 524527                         goto bad;
 525528                 if (pushfile(nm, safefn, 0, NULL) == 0)
 526529                         goto okret;
 527530                 /* XXX may lose stringbuf space */
 528531         }
 529532 
 530533         if (fsrch(safefn, 0, incdir[0]))
 531534                 goto okret;
 532535 
 533536         error("cannot find '%s'", safefn);
 534537         /* error() do not return */
 535538 
 536539 bad:    error("bad include");
 537540         /* error() do not return */
 538541 okret:
 539542         prtline();
 540543 }
 541544 
 542545 void
 543546 include_next(void)
 544547 {
 545548         struct symtab *nl;
 546549         usch *osp;
 547550         usch *fn;
 548551         int c;
 549552 
 550553         if (flslvl)
 551554                 return;
 552555         osp = stringbuf;
 553556         while ((c = sloscan()) == WSPACE)
 554557                 ;
 555558         if (c == IDENT) {
 556559                 /* sloscan() will not expand idents */
 557560                 if ((nl = lookup(yytext, FIND)) == NULL)
 558561                         goto bad;
 559562                 if (kfind(nl))
 560563                         unpstr(stringbuf);
 561564                 else
 562565                         unpstr(nl->namep);
 563566                 stringbuf = osp;
 564567                 c = yylex();
 565568         }
 566569         if (c != STRING && c != '<')
 567570                 goto bad;
 568571 
 569572         fn = stringbuf;
 570573         if (c == STRING) {
 571574                 savstr(&yytext[1]);
 572575                 stringbuf[-1] = 0;
 573576         } else { /* < > */
 574577                 while ((c = sloscan()) != '>') {
 575578                         if (c == '\n')
 576579                                 goto bad;
 577580                         savstr(yytext);
 578581                 }
 579582                 savch('\0');
 580583         }
 581584         while ((c = sloscan()) == WSPACE)
 582585                 ;
 583586         if (c != '\n')
 584587                 goto bad;
 585588 
 586589         if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
 587590                 error("cannot find '%s'", fn);
 588591         prtline();
 589592         return;
 590593 
 591594 bad:    error("bad include");
 592595         /* error() do not return */
 593596 }
 594597 
 595598 static int
 596599 definp(void)
 597600 {
 598601         int c;
 599602 
 600603         do
 601604                 c = sloscan();
 602605         while (c == WSPACE);
 603606         return c;
 604607 }
 605608 
 606609 void
 607610 getcmnt(void)
 608611 {
 609612         int c;
 610613 
 611614         savstr(yytext);
 612615         savch(cinput()); /* Lost * */
 613616         for (;;) {
 614617                 c = cinput();
 615618                 if (c == '*') {
 616619                         c = cinput();
 617620                         if (c == '/') {
 618621                                 savstr((const usch *)"*/");
 619622                                 return;
 620623                         }
 621624                         cunput(c);
 622625                         c = '*';
 623626                 }
 624627                 savch(c);
 625628         }
 626629 }
 627630 
 628631 /*
 629632  * Compare two replacement lists, taking in account comments etc.
 630633  */
 631634 static int
 632635 cmprepl(const usch *o, const usch *n)
 633636 {
 634637         for (; *o; o--, n--) {
 635638                 /* comment skip */
 636639                 if (*o == '/' && o[-1] == '*') {
 637640                         while (*o != '*' || o[-1] != '/')
 638641                                 o--;
 639642                         o -= 2;
 640643                 }
 641644                 if (*n == '/' && n[-1] == '*') {
 642645                         while (*n != '*' || n[-1] != '/')
 643646                                 n--;
 644647                         n -= 2;
 645648                 }
 646649                 while (*o == ' ' || *o == '\t')
 647650                         o--;
 648651                 while (*n == ' ' || *n == '\t')
 649652                         n--;
 650653                 if (*o != *n)
 651654                         return 1;
 652655         }
 653656         return 0;
 654657 }
 655658 
 656659 static int
 657660 isell(void)
 658661 {
 659662         int ch;
 660663 
 661664         if ((ch = cinput()) != '.') {
 662665                 cunput(ch);
 663666                 return 0;
 664667         }
 665668         if ((ch = cinput()) != '.') {
 666669                 cunput(ch);
 667670                 cunput('.');
 668671                 return 0;
 669672         }
 670673         return 1;
 671674 }
 672675 
 673676 void
 674677 define(void)
 675678 {
 676679         struct symtab *np;
 677680         usch *args[MAXARGS+1], *ubuf, *sbeg;
 678681         int c, i, redef;
 679682         int mkstr = 0, narg = -1;
 680683         int ellips = 0;
 681684 #ifdef GCC_COMPAT
 682685         usch *gccvari = NULL;
 683686         int wascon;
 684687 #endif
 685688 
 686689         if (flslvl)
 687690                 return;
 688691         if (sloscan() != WSPACE || sloscan() != IDENT)
 689692                 goto bad;
 690693 
 691694         np = lookup(yytext, ENTER);
 692695         redef = np->value != NULL;
 693696 
 694697         defining = readmac = 1;
 695698         sbeg = stringbuf;
 696699         if ((c = sloscan()) == '(') {
 697700                 narg = 0;
 698701                 /* function-like macros, deal with identifiers */
 699702                 c = definp();
 700703                 for (;;) {
 701704                         if (c == ')')
 702705                                 break;
 703706                         if (c == '.' && isell()) {
 704707                                 ellips = 1;
 705708                                 if (definp() != ')')
 706709                                         goto bad;
 707710                                 break;
 708711                         }
 709712                         if (c == IDENT) {
 710713                                 /* make sure there is no arg of same name */
 711714                                 for (i = 0; i < narg; i++)
 712715                                         if (!strcmp((char *) args[i], (char *)yytext))
 713716                                                 error("Duplicate macro "
 714717                                                   "parameter \"%s\"", yytext);
 715718                                 if (narg == MAXARGS)
 716719                                         error("Too many macro args");
 717720                                 args[narg++] = xstrdup(yytext);
 718721                                 if ((c = definp()) == ',') {
 719722                                         if ((c = definp()) == ')')
 720723                                                 goto bad;
 721724                                         continue;
 722725                                 }
 723726 #ifdef GCC_COMPAT
 724727                                 if (c == '.' && isell()) {
 725728                                         if (definp() != ')')
 726729                                                 goto bad;
 727730                                         gccvari = args[--narg];
 728731                                         break;
 729732                                 }
 730733 #endif
 731734                                 if (c == ')')
 732735                                         break;
 733736                         }
 734737                         goto bad;
 735738                 }
 736739                 c = sloscan();
 737740         } else if (c == '\n') {
 738741                 /* #define foo */
 739742                 ;
 740743         } else if (c == 0) {
 741744                 prem();
 742745         } else if (c != WSPACE)
 743746                 goto bad;
 744747 
 745748         while (c == WSPACE)
 746749                 c = sloscan();
 747750 
 748751         /* replacement list cannot start with ## operator */
 749752         if (c == '#') {
 750753                 if ((c = sloscan()) == '#')
 751754                         goto bad;
 752755                 savch('\0');
 753756 #ifdef GCC_COMPAT
 754757                 wascon = 0;
 755758 #endif
 756759                 goto in2;
 757760         }
 758761 
 759762         /* parse replacement-list, substituting arguments */
 760763         savch('\0');
 761764         while (c != '\n') {
 762765 #ifdef GCC_COMPAT
 763766                 wascon = 0;
 764767 loop:
 765768 #endif
 766769                 switch (c) {
 767770                 case WSPACE:
 768771                         /* remove spaces if it surrounds a ## directive */
 769772                         ubuf = stringbuf;
 770773                         savstr(yytext);
 771774                         c = sloscan();
 772775                         if (c == '#') {
 773776                                 if ((c = sloscan()) != '#')
 774777                                         goto in2;
 775778                                 stringbuf = ubuf;
 776779                                 savch(CONC);
 777780                                 if ((c = sloscan()) == WSPACE)
 778781                                         c = sloscan();
 779782 #ifdef GCC_COMPAT
 780783                                 if (c == '\n')
 781784                                         break;
 782785                                 wascon = 1;
 783786                                 goto loop;
 784787 #endif
 785788                         }
 786789                         continue;
 787790 
 788791                 case '#':
 789792                         c = sloscan();
 790793                         if (c == '#') {
 791794                                 /* concat op */
 792795                                 savch(CONC);
 793796                                 if ((c = sloscan()) == WSPACE)
 794797                                         c = sloscan();
 795798 #ifdef GCC_COMPAT
 796799                                 if (c == '\n')
 797800                                         break;
 798801                                 wascon = 1;
 799802                                 goto loop;
 800803 #else
 801804                                 continue;
 802805 #endif
 803806                         }
 804807 in2:                    if (narg < 0) {
 805808                                 /* no meaning in object-type macro */
 806809                                 savch('#');
 807810                                 continue;
 808811                         }
 809812                         /* remove spaces between # and arg */
 810813                         savch(SNUFF);
 811814                         if (c == WSPACE)
 812815                                 c = sloscan(); /* whitespace, ignore */
 813816                         mkstr = 1;
 814817                         if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
 815818                                 continue;
 816819 
 817820                         /* FALLTHROUGH */
 818821                 case IDENT:
 819822                         if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
 820823                                 if (ellips == 0)
 821824                                         error("unwanted %s", yytext);
 822825 #ifdef GCC_COMPAT
 823826                                 savch(wascon ? GCCARG : VARG);
 824827 #else
 825828                                 savch(VARG);
 826829 #endif
 827830 
 828831                                 savch(WARN);
 829832                                 if (mkstr)
 830833                                         savch(SNUFF), mkstr = 0;
 831834                                 break;
 832835                         }
 833836                         if (narg < 0)
 834837                                 goto id; /* just add it if object */
 835838                         /* check if its an argument */
 836839                         for (i = 0; i < narg; i++)
 837840                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
 838841                                         break;
 839842                         if (i == narg) {
 840843 #ifdef GCC_COMPAT
 841844                                 if (gccvari &&
 842845                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
 843846                                         savch(wascon ? GCCARG : VARG);
 844847                                         savch(WARN);
 845848                                         if (mkstr)
 846849                                                 savch(SNUFF), mkstr = 0;
 847850                                         break;
 848851                                 }
 849852 #endif
 850853                                 if (mkstr)
 851854                                         error("not argument");
 852855                                 goto id;
 853856                         }
 854857                         savch(i);
 855858                         savch(WARN);
 856859                         if (mkstr)
 857860                                 savch(SNUFF), mkstr = 0;
 858861                         break;
 859862 
 860863                 case CMNT: /* save comments */
 861864                         getcmnt();
 862865                         break;
 863866 
 864867                 case 0:
 865868                         prem();
 866869 
 867870                 default:
 868871 id:                     savstr(yytext);
 869872                         break;
 870873                 }
 871874                 c = sloscan();
 872875         }
 873876         defining = readmac = 0;
 874877         /* remove trailing whitespace */
 875878         while (stringbuf > sbeg) {
 876879                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
 877880                         stringbuf--;
 878881                 /* replacement list cannot end with ## operator */
 879882                 else if (stringbuf[-1] == CONC)
 880883                         goto bad;
 881884                 else
 882885                         break;
 883886         }
 884887 #ifdef GCC_COMPAT
 885888         if (gccvari) {
 886889                 savch(narg);
 887890                 savch(VARG);
 888891         } else
 889892 #endif
 890893         if (ellips) {
 891894                 savch(narg);
 892895                 savch(VARG);
 893896         } else
 894897                 savch(narg < 0 ? OBJCT : narg);
 895898         if (redef && ifiles->idx != SYSINC) {
 896899                 if (cmprepl(np->value, stringbuf-1)) {
 897900                         sbeg = stringbuf;
 898901                         np->value = stringbuf-1;
 899902                         warning("%s redefined (previously defined at \"%s\" line %d)",
 900903                             np->namep, np->file, np->line);
 901904                 }
 902905                 stringbuf = sbeg/* forget this space */
 903906         } else
 904907                 np->value = stringbuf-1;
 905908 
 906909 #ifdef PCC_DEBUG
 907910         if (dflag) {
 908911                 const usch *w = np->value;
 909912 
 910913                 printf("!define: ");
 911914                 if (*w == OBJCT)
 912915                         printf("[object]");
 913916                 else if (*w == VARG)
 914917                         printf("[VARG%d]", *--w);
 915918                 while (*--w) {
 916919                         switch (*w) {
 917920                         case WARN: printf("<%d>", *--w); break;
 918921                         case CONC: printf("<##>"); break;
 919922                         case SNUFF: printf("<\">"); break;
 920923                         default: putchar(*w); break;
 921924                         }
 922925                 }
 923926                 putchar('\n');
 924927         }
 925928 #endif
 926929         for (i = 0; i < narg; i++)
 927930                 free(args[i]);
 928931         return;
 929932 
 930933 bad:    error("bad define");
 931934 }
 932935 
 933936 void
 934937 warning(const char *fmt, ...)
 935938 {
 936939         va_list ap;
 937940         usch *sb;
 938941 
 939942         flbuf();
 940943         savch(0);
 941944 
 942945         sb = stringbuf;
 943946         if (ifiles != NULL)
 944947                 sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
 945948 
 946949         va_start(ap, fmt);
 947950         vsheap(fmt, ap);
 948951         va_end(ap);
 949952         savch('\n');
 950953         xwrite(2, sb, stringbuf - sb);
 951954         stringbuf = sb;
 952955 }
 953956 
 954957 void
 955958 error(const char *fmt, ...)
 956959 {
 957960         va_list ap;
 958961         usch *sb;
 959962 
 960963         flbuf();
 961964         savch(0);
 962965 
 963966         sb = stringbuf;
 964967         if (ifiles != NULL)
 965968                 sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
 966969 
 967970         va_start(ap, fmt);
 968971         vsheap(fmt, ap);
 969972         va_end(ap);
 970973         savch('\n');
 971974         xwrite(2, sb, stringbuf - sb);
 972975         stringbuf = sb;
 973976 
 974977         exit(1);
 975978 }
 976979 
 977980 static void
 978981 sss(void)
 979982 {
 980983         savch(EBLOCK);
 981984         savch(cinput());
 982985         savch(cinput());
 983986 }
 984987 
 985988 static int
 986989 addmac(struct symtab *sp)
 987990 {
 988991         int c, i;
 989992 
 990993         /* Check if it exists; then save some space */
 991994         /* May be more difficult to debug cpp */
 992995         for (i = 1; i < norepptr; i++)
 993996                 if (norep[i] == sp)
 994997                         return i;
 995998         if (norepptr >= RECMAX)
 996999                 error("too many macros");
 9971000         /* check norepptr */
 9981001         if ((norepptr & 255) == 0)
 9991002                 norepptr++;
 10001003         if (((norepptr >> 8) & 255) == 0)
 10011004                 norepptr += 256;
 10021005         c = norepptr;
 10031006         norep[norepptr++] = sp;
 10041007         return c;
 10051008 }
 10061009 
 10071010 static void
 10081011 doblk(void)
 10091012 {
 10101013         int c;
 10111014 
 10121015         do {
 10131016                 donex();
 10141017         } while ((c = sloscan()) == EBLOCK);
 10151018         if (c == IDENT)
 10161019                 return;
 10171020         error("EBLOCK sync error");
 10181021 }
 10191022 
 10201023 /* Block next nr in lex buffer to expand */
 10211024 int
 10221025 donex(void)
 10231026 {
 10241027         int n, i;
 10251028 
 10261029         if (bidx == RECMAX)
 10271030                 error("too deep macro recursion");
 10281031         n = cinput();
 10291032         n = MKB(n, cinput());
 10301033         for (i = 0; i < bidx; i++)
 10311034                 if (bptr[i] == n)
 10321035                         return n; /* already blocked */
 10331036         bptr[bidx++] = n;
 10341037         /* XXX - check for sp buffer overflow */
 10351038 #ifdef PCC_DEBUG
 10361039         if (dflag>1) {
 10371040                 printf("donex %d (%d) blocking:\n", bidx, n);
 10381041                 printf("donex %s(%d) blocking:", norep[n]->namep, n);
 10391042                 for (i = bidx-1; i >= 0; i--)
 10401043                         printf(" '%s'", norep[bptr[i]]->namep);
 10411044                 printf("\n");
 10421045         }
 10431046 #endif
 10441047         return n;
 10451048 }
 10461049 
 10471050 /*
 10481051  * store a character into the "define" buffer.
 10491052  */
 10501053 void
 10511054 savch(int c)
 10521055 {
 10531056         if (stringbuf >= &sbf[SBSIZE]) {
 10541057                 stringbuf = sbf; /* need space to write error message */
 10551058                 error("out of macro space!");
 10561059         }
 10571060         *stringbuf++ = (usch)c;
 10581061 }
 10591062 
 10601063 /*
 10611064  * convert _Pragma() to #pragma for output.
 10621065  * Syntax is already correct.
 10631066  */
 10641067 static void
 10651068 pragoper(void)
 10661069 {
 10671070         usch *s;
 10681071         int t;
 10691072 
 10701073         while ((t = sloscan()) != '(')
 10711074                 ;
 10721075 
 10731076         while ((t = sloscan()) == WSPACE)
 10741077                 ;
 10751078         if (t != STRING)
 10761079                 error("_Pragma() must have string argument");
 10771080         savstr((const usch *)"\n#pragma ");
 10781081         s = yytext;
 10791082         if (*s == 'L')
 10801083                 s++;
 10811084         for (; *s; s++) {
 10821085                 if (*s == EBLOCK) {
 10831086                         s+=2;
 10841087                         continue;
 10851088                 }
 10861089                 if (*s == '\"')
 10871090                         continue;
 10881091                 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
 10891092                         s++;
 10901093                 savch(*s);
 10911094         }
 10921095         sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
 10931096         while ((t = sloscan()) == WSPACE)
 10941097                 ;
 10951098         if (t != ')')
 10961099                 error("_Pragma() syntax error");
 10971100 }
 10981101 
 10991102 /*
 11001103  * Return true if it is OK to expand this symbol.
 11011104  */
 11021105 static int
 11031106 okexp(struct symtab *sp)
 11041107 {
 11051108         int i;
 11061109 
 11071110         if (sp == NULL)
 11081111                 return 0;
 11091112         for (i = 0; i < bidx; i++)
 11101113                 if (norep[bptr[i]] == sp)
 11111114                         return 0;
 11121115         return 1;
 11131116 }
 11141117 
 11151118 /*
 11161119  * Insert block(s) before each expanded name.
 11171120  * Input is in lex buffer, output on lex buffer.
 11181121  */
 11191122 static void
 11201123 insblock(int bnr)
 11211124 {
 11221125         usch *bp = stringbuf;
 11231126         int c, i;
 11241127  
 11251128         IMP("IB");
 11261129         readmac++;
 11271130         while ((c = sloscan()) != WARN) {
 11281131                 if (c == EBLOCK) {
 11291132                         sss();
 11301133                         continue;
 11311134                 }
 11321135                 if (c == CMNT) {
 11331136                         getcmnt();
 11341137                         continue;
 11351138                 }
 11361139                 if (c == IDENT) {
 11371140                         savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
 11381141                         for (i = 0; i < bidx; i++)
 11391142                                 savch(EBLOCK), savch(bptr[i] & 255),
 11401143                                     savch(bptr[i] >> 8);
 11411144                 }
 11421145                 savstr(yytext);
 11431146                 if (c == '\n')
 11441147                         (void)cinput();
 11451148         }
 11461149         savch(0);
 11471150         cunput(WARN);
 11481151         unpstr(bp);
 11491152         stringbuf = bp;
 11501153         readmac--;
 11511154         IMP("IBRET");
 11521155 }
 11531156 
 11541157 /* Delete next WARN on the input stream */
 11551158 static void
 11561159 delwarn(void)
 11571160 {
 11581161         usch *bp = stringbuf;
 11591162         int c;
 11601163  
 11611164         IMP("DELWARN");
 11621165         while ((c = sloscan()) != WARN) {
 11631166                 if (c == CMNT) {
 11641167                         getcmnt();
 11651168                 } else if (c == EBLOCK) {
 11661169                         sss();
 11671170                 } else if (c == '\n') {
 11681171                         putch(cinput());
 11691172                 } else
 11701173                         savstr(yytext);
 11711174         }
 11721175         if (stringbuf[-1] == '/')
 11731176                 savch(PHOLD); /* avoid creating comments */
 11741177         savch(0);
 11751178         unpstr(bp);
 11761179         stringbuf = bp;
 11771180         IMP("DELWRET");
 11781181 }
 11791182 
 11801183 /*
 11811184  * Handle defined macro keywords found on input stream.
 11821185  * When finished print out the full expanded line.
 11831186  * Everything on lex buffer except for the symtab.
 11841187  */
 11851188 int
 11861189 kfind(struct symtab *sp)
 11871190 {
 11881191         struct symtab *nl;
 11891192         const usch *argary[MAXARGS+1], *cbp;
 11901193         usch *sbp;
 11911194         int c, o, chkf;
 11921195 
 11931196         DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
 11941197         IMP("KFIND");
 11951198         if (*sp->value == OBJCT) {
 11961199                 if (sp == filloc) {
 11971200                         unpstr(sheap("\"%s\"", ifiles->fname));
 11981201                         return 1;
 11991202                 } else if (sp == linloc) {
 12001203                         unpstr(sheap("%d", ifiles->lineno));
 12011204                         return 1;
 12021205                 }
 12031206                 IMP("END1");
 12041207                 cunput(WARN);
 12051208                 for (cbp = sp->value-1; *cbp; cbp--)
 12061209                         cunput(*cbp);
 12071210                 insblock(addmac(sp));
 12081211                 IMP("ENDX");
 12091212                 exparg(1);
 12101213 
 12111214 upp:            sbp = stringbuf;
 12121215                 chkf = 1;
 12131216                 if (obufp != 0)
 12141217                         lastoch = outbuf[obufp-1];
 12151218                 if (iswsnl(lastoch))
 12161219                         chkf = 0;
 12171220                 if (Cflag)
 12181221                         readmac++;
 12191222                 while ((c = sloscan()) != WARN) {
 12201223                         switch (c) {
 12211224                         case CMNT:
 12221225                                 getcmnt();
 12231226                                 break;
 12241227 
 12251228                         case STRING:
 12261229                                 /* Remove embedded directives */
 12271230                                 for (cbp = yytext; *cbp; cbp++) {
 12281231                                         if (*cbp == EBLOCK)
 12291232                                                 cbp+=2;
 12301233                                         else if (*cbp != CONC)
 12311234                                                 savch(*cbp);
 12321235                                 }
 12331236                                 break;
 12341237 
 12351238                         case EBLOCK:
 12361239                                 doblk();
 12371240                                 /* FALLTHROUGH */
 12381241                         case IDENT:
 12391242                                 /*
 12401243                                  * Tricky: if this is the last identifier
 12411244                                  * in the expanded list, and it is defined
 12421245                                  * as a function-like macro, then push it
 12431246                                  * back on the input stream and let fastscan
 12441247                                  * handle it as a new macro.
 12451248                                  * BUT: if this macro is blocked then this
 12461249                                  * should not be done.
 12471250                                  */
 12481251                                 nl = lookup(yytext, FIND);
 12491252                                 o = okexp(nl);
 12501253                                 bidx = 0;
 12511254                                 /* Deal with pragmas here */
 12521255                                 if (nl == pragloc) {
 12531256                                         pragoper();
 12541257                                         break;
 12551258                                 }
 12561259                                 if (nl == NULL || !o || *nl->value == OBJCT) {
 12571260                                         /* Not fun-like macro */
 12581261                                         savstr(yytext);
 12591262                                         break;
 12601263                                 }
 12611264                                 c = cinput();
 12621265                                 if (c == WARN) {
 12631266                                         /* succeeded, push back */
 12641267                                         unpstr(yytext);
 12651268                                 } else {
 12661269                                         savstr(yytext);
 12671270                                 }
 12681271                                 cunput(c);
 12691272                                 break;
 12701273 
 12711274                         default:
 12721275                                 if (chkf && c < 127)
 12731276                                         putch(' ');
 12741277                                 savstr(yytext);
 12751278                                 break;
 12761279                         }
 12771280                         chkf = 0;
 12781281                 }
 12791282                 if (Cflag)
 12801283                         readmac--;
 12811284                 IMP("END2");
 12821285                 norepptr = 1;
 12831286                 savch(0);
 12841287                 stringbuf = sbp;
 12851288                 return 1;
 12861289         }
 12871290         /* Is a function-like macro */
 12881291 
 12891292         /* Search for '(' */
 12901293         sbp = stringbuf;
 12911294         while (iswsnl(c = cinput()))
 12921295                 savch(c);
 12931296         savch(0);
 12941297         stringbuf = sbp;
 12951298         if (c != '(') {
 12961299                 cunput(c);
 12971300                 unpstr(sbp);
 12981301                 return 0; /* Failed */
 12991302         }
 13001303 
 13011304         /* Found one, output \n to be in sync */
 13021305         for (; *sbp; sbp++) {
 13031306                 if (*sbp == '\n')
 13041307                         putch('\n'), ifiles->lineno++;
 13051308         }
 13061309 
 13071310         /* fetch arguments */
 13081311         if (Cflag)
 13091312                 readmac++;
 13101313         if (readargs(sp, argary))
 13111314                 error("readargs");
 13121315 
 13131316         c = addmac(sp);
 13141317         sbp = stringbuf;
 13151318         cunput(WARN);
 13161319 
 13171320         IMP("KEXP");
 13181321         subarg(sp, argary, 1);
 13191322         IMP("KNEX");
 13201323         insblock(c);
 13211324         IMP("KBLK");
 13221325 
 13231326         stringbuf = sbp;
 13241327 
 13251328         exparg(1);
 13261329         if (Cflag)
 13271330                 readmac--;
 13281331 
 13291332         IMP("END");
 13301333 
 13311334         goto upp;
 13321335 
 13331336 }
 13341337 
 13351338 /*
 13361339  * Replace and push-back on input stream the eventual replaced macro.
 13371340  * The check for whether it can expand or not should already have been done.
 13381341  * Blocks for this identifier will be added via insblock() after expansion.
 13391342  */
 13401343 int
 13411344 submac(struct symtab *sp, int lvl)
 13421345 {
 13431346         const usch *argary[MAXARGS+1];
 13441347         const usch *cp;
 13451348         usch *bp;
 13461349         int ch;
 13471350 
 13481351         DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
 13491352         if (*sp->value == OBJCT) {
 13501353                 if (sp == filloc) {
 13511354                         unpstr(sheap("\"%s\"", ifiles->fname));
 13521355                         return 1;
 13531356                 } else if (sp == linloc) {
 13541357                         unpstr(sheap("%d", ifiles->lineno));
 13551358                         return 1;
 13561359                 }
 13571360 
 13581361                 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
 13591362                 /* expand object-type macros */
 13601363                 ch = addmac(sp);
 13611364                 cunput(WARN);
 13621365 
 13631366                 for (cp = sp->value-1; *cp; cp--)
 13641367                         cunput(*cp);
 13651368                 insblock(ch);
 13661369                 delwarn();
 13671370                 return 1;
 13681371         }
 13691372 
 13701373         /*
 13711374          * Function-like macro; see if it is followed by a (
 13721375          * Be careful about the expand/noexpand balance.
 13731376          * Store read data on heap meanwhile.
 13741377          * For directive        #define foo() kaka
 13751378          * If input is          <NEX><NEX>foo<EXP>()<EXP> then
 13761379          * output should be     <NEX><NEX><EXP>kaka<EXP>.
 13771380          */
 13781381         bp = stringbuf;
 13791382         while (iswsnl(ch = cinput()))
 13801383                 savch(ch);
 13811384         savch(0);
 13821385         stringbuf = bp;
 13831386         if (ch != '(') {
 13841387                 cunput(ch);
 13851388                 unpstr(bp);
 13861389                 return 0; /* Failed */
 13871390         }
 13881391 
 13891392         /* no \n should be here */
 13901393 
 13911394         /*
 13921395          * A function-like macro has been found.  Read in the arguments,
 13931396          * expand them and push-back everything for another scan.
 13941397          */
 13951398         DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
 13961399         savch(0);
 13971400         if (readargs(sp, argary)) {
 13981401                 /* Bailed out in the middle of arg list */
 13991402                 unpstr(bp);
 14001403                 DDPRINT(("%d:noreadargs\n", lvl));
 14011404                 stringbuf = bp;
 14021405                 return 0;
 14031406         }
 14041407 
 14051408         /* when all args are read from input stream */
 14061409         ch = addmac(sp);
 14071410 
 14081411         DDPRINT(("%d:submac pre\n", lvl));
 14091412         cunput(WARN);
 14101413 
 14111414         subarg(sp, argary, lvl+1);
 14121415 
 14131416         DDPRINT(("%d:submac post\n", lvl));
 14141417         insblock(ch);
 14151418         delwarn();
 14161419 
 14171420         stringbuf = bp; /* Reset heap */
 14181421         DPRINT(("%d:Return submac\n", lvl));
 14191422         IMP("SM1");
 14201423         return 1;
 14211424 }
 14221425 
 14231426 static int
 14241427 isdir(void)
 14251428 {
 14261429         usch *bp = stringbuf;
 14271430         usch ch;
 14281431 
 14291432         while ((ch = cinput()) == ' ' || ch == '\t')
 14301433                 *stringbuf++ = ch;
 14311434         *stringbuf++ = ch;
 14321435         *stringbuf++ = 0;
 14331436         stringbuf = bp;
 14341437         if (ch == '#')
 14351438                 return 1;
 14361439         unpstr(bp);
 14371440         return 0;
 14381441 }
 14391442 
 14401443 /*
 14411444  * Deal with directives inside a macro.
 14421445  * Doing so is really ugly but gcc allows it, so...
 14431446  */
 14441447 static void
 14451448 chkdir(void)
 14461449 {
 14471450         usch ch;
 14481451 
 14491452         for (;;) {
 14501453                 if (isdir())
 14511454                         ppdir();
 14521455                 if (flslvl == 0)
 14531456                         return;
 14541457                 while ((ch = cinput()) != '\n')
 14551458                         ;
 14561459                 ifiles->lineno++;
 14571460                 putch('\n');
 14581461         }
 14591462 }
 14601463 
 14611464 /*
 14621465  * Read arguments and put in argument array.
 14631466  * If WARN is encountered return 1, otherwise 0.
 14641467  */
 14651468 int
 14661469 readargs(struct symtab *sp, const usch **args)
 14671470 {
 14681471         const usch *vp = sp->value;
 14691472         int c, i, plev, narg, ellips = 0;
 14701473         int warn;
 14711474 
 14721475         DPRINT(("readargs\n"));
 14731476 
 14741477         narg = *vp--;
 14751478         if (narg == VARG) {
 14761479                 narg = *vp--;
 14771480                 ellips = 1;
 14781481         }
 14791482 
 14801483         IMP("RDA1");
 14811484         /*
 14821485          * read arguments and store them on heap.
 14831486          */
 14841487         warn = 0;
 14851488         c = '(';
 14861489         for (i = 0; i < narg && c != ')'; i++) {
 14871490                 args[i] = stringbuf;
 14881491                 plev = 0;
 14891492                 while ((c = sloscan()) == WSPACE || c == '\n')
 14901493                         if (c == '\n') {
 14911494                                 ifiles->lineno++;
 14921495                                 putch(cinput());
 14931496                                 chkdir();
 14941497                         }
 14951498                 for (;;) {
 14961499                         while (c == EBLOCK) {
 14971500                                 sss();
 14981501                                 c = sloscan();
 14991502                         }
 15001503                         if (c == WARN) {
 15011504                                 warn++;
 15021505                                 goto oho;
 15031506                         }
 15041507                         if (plev == 0 && (c == ')' || c == ','))
 15051508                                 break;
 15061509                         if (c == '(')
 15071510                                 plev++;
 15081511                         if (c == ')')
 15091512                                 plev--;
 15101513                         savstr(yytext);
 15111514 oho:                    while ((c = sloscan()) == '\n') {
 15121515                                 ifiles->lineno++;
 15131516                                 putch(cinput());
 15141517                                 chkdir();
 15151518                                 savch(' ');
 15161519                         }
 15171520                         while (c == CMNT) {
 15181521                                 getcmnt();
 15191522                                 c = sloscan();
 15201523                         }
 15211524                         if (c == 0)
 15221525                                 error("eof in macro");
 15231526                 }
 15241527                 while (args[i] < stringbuf &&
 15251528                     iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
 15261529                         stringbuf--;
 15271530                 savch('\0');
 15281531 #ifdef PCC_DEBUG
 15291532                 if (dflag) {
 15301533                         printf("readargs: save arg %d '", i);
 15311534                         prline(args[i]);
 15321535                         printf("'\n");
 15331536                 }
 15341537 #endif
 15351538         }
 15361539 
 15371540         IMP("RDA2");
 15381541         /* Handle varargs readin */
 15391542         if (ellips)
 15401543                 args[i] = (const usch *)"";
 15411544         if (ellips && c != ')') {
 15421545                 args[i] = stringbuf;
 15431546                 plev = 0;
 15441547                 while ((c = sloscan()) == WSPACE || c == '\n')
 15451548                         if (c == '\n')
 15461549                                 cinput();
 15471550                 for (;;) {
 15481551                         if (plev == 0 && c == ')')
 15491552                                 break;
 15501553                         if (c == '(')
 15511554                                 plev++;
 15521555                         if (c == ')')
 15531556                                 plev--;
 15541557                         if (c == EBLOCK) {
 15551558                                 sss();
 15561559                         } else
 15571560                                 savstr(yytext);
 15581561                         while ((c = sloscan()) == '\n') {
 15591562                                 ifiles->lineno++;
 15601563                                 cinput();
 15611564                                 chkdir();
 15621565                                 savch(' ');
 15631566                         }
 15641567                 }
 15651568                 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
 15661569                         stringbuf--;
 15671570                 savch('\0');
 15681571                 
 15691572         }
 15701573         if (narg == 0 && ellips == 0)
 15711574                 while ((c = sloscan()) == WSPACE || c == '\n')
 15721575                         if (c == '\n')
 15731576                                 cinput();
 15741577 
 15751578         if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
 15761579                 error("wrong arg count");
 15771580         while (warn)
 15781581                 cunput(WARN), warn--;
 15791582         return 0;
 15801583 }
 15811584 
 15821585 /*
 15831586  * expand a function-like macro.
 15841587  * vp points to end of replacement-list
 15851588  * reads function arguments from sloscan()
 15861589  * result is pushed-back for more scanning.
 15871590  */
 15881591 void
 15891592 subarg(struct symtab *nl, const usch **args, int lvl)
 15901593 {
 15911594         int narg, instr, snuff;
 15921595         const usch *sp, *bp, *ap, *vp;
 15931596 
 15941597         DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
 15951598         vp = nl->value;
 15961599         narg = *vp--;
 15971600         if (narg == VARG)
 15981601                 narg = *vp--;
 15991602 
 16001603         sp = vp;
 16011604         instr = snuff = 0;
 16021605 #ifdef PCC_DEBUG
 16031606         if (dflag>1) {
 16041607                 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
 16051608                 prrep(vp);
 16061609                 printf("'\n");
 16071610         }
 16081611 #endif
 16091612 
 16101613         /*
 16111614          * push-back replacement-list onto lex buffer while replacing
 16121615          * arguments.  Arguments are macro-expanded if required.
 16131616          */
 16141617         while (*sp != 0) {
 16151618                 if (*sp == SNUFF)
 16161619                         cunput('\"'), snuff ^= 1;
 16171620                 else if (*sp == CONC)
 16181621                         ;
 16191622                 else if (*sp == WARN) {
 16201623 
 16211624                         if (sp[-1] == VARG) {
 16221625                                 bp = ap = args[narg];
 16231626                                 sp--;
 16241627 #ifdef GCC_COMPAT
 16251628                         } else if (sp[-1] == GCCARG) {
 16261629                                 ap = args[narg];
 16271630                                 if (ap[0] == 0)
 16281631                                         ap = (const usch *)"0";
 16291632                                 bp = ap;
 16301633                                 sp--;
 16311634 #endif
 16321635                         } else
 16331636                                 bp = ap = args[(int)*--sp];
 16341637 #ifdef PCC_DEBUG
 16351638                         if (dflag>1){
 16361639                                 printf("%d:subarg GOTwarn; arglist '", lvl);
 16371640                                 prline(bp);
 16381641                                 printf("'\n");
 16391642                         }
 16401643 #endif
 16411644                         if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
 16421645                                 /*
 16431646                                  * Expand an argument; 6.10.3.1:
 16441647                                  * "A parameter in the replacement list,
 16451648                                  *  is replaced by the corresponding argument
 16461649                                  *  after all macros contained therein have
 16471650                                  *  been expanded.".
 16481651                                  */
 16491652                                 cunput(WARN);
 16501653                                 unpstr(bp);
 16511654                                 exparg(lvl+1);
 16521655                                 delwarn();
 16531656                         } else {
 16541657                         while (*bp)
 16551658                                 bp++;
 16561659                         while (bp > ap) {
 16571660                                 bp--;
 16581661                                 if (snuff && !instr && iswsnl(*bp)) {
 16591662                                         while (iswsnl(*bp))
 16601663                                                 bp--;
 16611664                                         cunput(' ');
 16621665                                 }
 16631666 
 16641667                                 cunput(*bp);
 16651668                                 if ((*bp == '\'' || *bp == '"')
 16661669                                      && bp[-1] != '\\' && snuff) {
 16671670                                         instr ^= 1;
 16681671                                         if (instr == 0 && *bp == '"')
 16691672                                                 cunput('\\');
 16701673                                 }
 16711674                                 if (instr && (*bp == '\\' || *bp == '"'))
 16721675                                         cunput('\\');
 16731676                         }
 16741677                         }
 16751678                 } else
 16761679                         cunput(*sp);
 16771680                 sp--;
 16781681         }
 16791682         DPRINT(("%d:Return subarg\n", lvl));
 16801683         IMP("SUBARG");
 16811684 }
 16821685 
 16831686 /*
 16841687  * Do a (correct) expansion of a WARN-terminated buffer of tokens.
 16851688  * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
 16861689  * Expansion blocking is not altered here unless when tokens are
 16871690  * concatenated, in which case they are removed.
 16881691  */
 16891692 void
 16901693 exparg(int lvl)
 16911694 {
 16921695         struct symtab *nl;
 16931696         int c, i, gmult;
 16941697         usch *och;
 16951698         usch *osb = stringbuf;
 16961699         int anychange;
 16971700 
 16981701         DPRINT(("%d:exparg\n", lvl));
 16991702         IMP("EXPARG");
 17001703 
 17011704         readmac++;
 17021705 rescan:
 17031706         anychange = 0;
 17041707         while ((c = sloscan()) != WARN) {
 17051708                 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
 17061709                 IMP("EA0");
 17071710                 bidx = 0;
 17081711                 switch (c) {
 17091712 
 17101713                 case EBLOCK:
 17111714                         doblk();
 17121715                         /* FALLTHROUGH */
 17131716                 case IDENT:
 17141717                         /*
 17151718                          * Handle argument concatenation here.
 17161719                          * In case of concatenation, add all blockings.
 17171720                          */
 17181721                         DDPRINT(("%d:exparg ident %d\n", lvl, c));
 17191722                         och = stringbuf;
 17201723                         gmult = 0;
 17211724 
 17221725 sav:                    savstr(yytext);
 17231726 
 17241727                         if ((c = cinput()) == EBLOCK) {
 17251728                                 /* yep, are concatenating; add blocks */
 17261729                                 gmult = 1;
 17271730                                 do {
 17281731                                         donex();
 17291732                                 } while ((c = sloscan()) == EBLOCK);
 17301733                                 goto sav;
 17311734                         }
 17321735                         cunput(c);
 17331736 
 17341737                         DPRINT(("%d:exparg: str '%s'\n", lvl, och));
 17351738                         IMP("EA1");
 17361739                         /* see if ident is expandable */
 17371740                         if ((nl = lookup(och, FIND)) && okexp(nl)) {
 17381741                                 /* Save blocks */
 17391742                                 int donothing;
 17401743                                 unsigned short *svidx =
 17411744                                     malloc(sizeof(int)*(bidx+1));
 17421745                                 int svbidx = bidx;
 17431746 
 17441747                                 for (i = 0; i < bidx; i++)
 17451748                                         svidx[i] = bptr[i];
 17461749                                 if (submac(nl, lvl+1)) {
 17471750                                         /* Could expand, result on lexbuffer */
 17481751                                         stringbuf = och; /* clear saved name */
 17491752                                         anychange = 1;
 17501753                                 }
 17511754                                 donothing = 0;
 17521755                                 c = cinput();
 17531756                                 if (c == 'L') {
 17541757                                         int c2 = cinput();
 17551758                                         if (c2 == '\"' || c2 == '\'')
 17561759                                                 donothing = 1;
 17571760                                         cunput(c2);
 17581761                                 }
 17591762                                 cunput(c);
 17601763 
 17611764                                 if (donothing == 0)
 17621765                                     if (((spechr[c] & C_ID) && c > 63) ||
 17631766                                     c == EBLOCK) {
 17641767                                         for (i = 0; i < svbidx; i++) {
 17651768                                                 cunput(svidx[i] >> 8);
 17661769                                                 cunput(svidx[i] & 255);
 17671770                                                 cunput(EBLOCK);
 17681771                                         }
 17691772                                 }
 17701773                                 free(svidx);
 17711774                         } else if (bidx) {
 17721775                                 /* must restore blocks */
 17731776                                 if (gmult) {
 17741777                                         unpstr(och);
 17751778                                         if (sloscan() != IDENT)
 17761779                                                 error("exparg sync error");
 17771780                                 }
 17781781                                 stringbuf = och;
 17791782                                 for (i = 0; i < bidx; i++)
 17801783                                         savch(EBLOCK), savch(bptr[i] & 255),
 17811784                                             savch(bptr[i] >> 8);
 17821785                                 savstr(yytext);
 17831786                         }
 17841787                         bidx = 0;
 17851788                         IMP("EA2");
 17861789                         break;
 17871790 
 17881791                 case CMNT:
 17891792                         getcmnt();
 17901793                         break;
 17911794 
 17921795                 case '\n':
 17931796                         cinput();
 17941797                         savch(' ');
 17951798                         break;
 17961799 
 17971800                 default:
 17981801                         savstr(yytext);
 17991802                         break;
 18001803                 }
 18011804         }
 18021805         *stringbuf = 0;
 18031806         cunput(WARN);
 18041807         unpstr(osb);
 18051808         DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
 18061809         IMP("EXPRET");
 18071810         stringbuf = osb;
 18081811         if (anychange)
 18091812                 goto rescan;
 18101813         readmac--;
 18111814 }
 18121815 
 18131816 #ifdef PCC_DEBUG
 18141817 static void
 18151818 imp(const char *str)
 18161819 {
 18171820         printf("%s (%d) '", str, bidx);
 18181821         prline(ifiles->curptr);
 18191822         printf("'\n");
 18201823 }
 18211824 
 18221825 static void
 18231826 prrep(const usch *s)
 18241827 {
 18251828         while (*s) {
 18261829                 switch (*s) {
 18271830                 case WARN: printf("<ARG(%d)>", *--s); break;
 18281831                 case CONC: printf("<CONC>"); break;
 18291832                 case SNUFF: printf("<SNUFF>"); break;
 18301833                 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
 18311834                 default: printf("%c", *s); break;
 18321835                 }
 18331836                 s--;
 18341837         }
 18351838 }
 18361839 
 18371840 static void
 18381841 prline(const usch *s)
 18391842 {
 18401843         while (*s) {
 18411844                 switch (*s) {
 18421845                 case WARN: printf("<WARN>"); break;
 18431846                 case CONC: printf("<CONC>"); break;
 18441847                 case SNUFF: printf("<SNUFF>"); break;
 18451848                 case PHOLD: printf("<PHOLD>"); break;
 18461849                 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
 18471850                 case '\n': printf("<NL>"); break;
 18481851                 default: printf("%c", *s); break;
 18491852                 }
 18501853                 s++;
 18511854         }
 18521855 }
 18531856 #endif
 18541857 
 18551858 usch *
 18561859 savstr(const usch *str)
 18571860 {
 18581861         usch *rv = stringbuf;
 18591862 
 18601863         do {
 18611864                 if (stringbuf >= &sbf[SBSIZE])   {
 18621865                         stringbuf = sbf; /* need space to write error message */
 18631866                         error("out of macro space!");
 18641867                 }
 18651868         } while ((*stringbuf++ = *str++));
 18661869         stringbuf--;
 18671870         return rv;
 18681871 }
 18691872 
 18701873 void
 18711874 unpstr(const usch *c)
 18721875 {
 18731876         const usch *d = c;
 18741877 
 18751878 #if 0
 18761879         if (dflag>1) {
 18771880                 printf("Xunpstr: '");
 18781881                 prline(c);
 18791882                 printf("'\n");
 18801883         }
 18811884 #endif
 18821885         while (*d) {
 18831886                 if (*d == EBLOCK)
 18841887                         d += 2;
 18851888                 d++;
 18861889         }
 18871890         while (d > c) {
 18881891                 cunput(*--d);
 18891892         }
 18901893 }
 18911894 
 18921895 static void
 18931896 flbuf(void)
 18941897 {
 18951898         if (obufp == 0)
 18961899                 return;
 18971900         if (Mflag == 0)
 18981901                 xwrite(ofd, outbuf, obufp);
 18991902         lastoch = outbuf[obufp-1];
 19001903         obufp = 0;
 19011904 }
 19021905 
 19031906 void
 19041907 putch(int ch)
 19051908 {
 19061909         outbuf[obufp++] = (usch)ch;
 19071910         if (obufp == CPPBUF || (istty && ch == '\n'))
 19081911                 flbuf();
 19091912 }
 19101913 
 19111914 void
 19121915 putstr(const usch *s)
 19131916 {
 19141917         for (; *s; s++) {
 19151918                 if (*s == PHOLD)
 19161919                         continue;
 19171920                 outbuf[obufp++] = *s;
 19181921                 if (obufp == CPPBUF || (istty && *s == '\n'))
 19191922                         flbuf();
 19201923         }
 19211924 }
 19221925 
 19231926 /*
 19241927  * convert a number to an ascii string. Store it on the heap.
 19251928  */
 19261929 static void
 19271930 num2str(int num)
 19281931 {
 19291932         static usch buf[12];
 19301933         usch *b = buf;
 19311934         int m = 0;
 19321935         
 19331936         if (num < 0)
 19341937                 num = -num, m = 1;
 19351938         do {
 19361939                 *b++ = (usch)(num % 10 + '0');
 19371940                 num /= 10;
 19381941         } while (num);
 19391942         if (m)
 19401943                 *b++ = '-';
 19411944         while (b > buf)
 19421945                 savch(*--b);
 19431946 }
 19441947 
 19451948 /*
 19461949  * similar to sprintf, but only handles %c, %s and %d.
 19471950  * saves result on heap.
 19481951  */
 19491952 static void
 19501953 vsheap(const char *fmt, va_list ap)
 19511954 {
 19521955         for (; *fmt; fmt++) {
 19531956                 if (*fmt == '%') {
 19541957                         fmt++;
 19551958                         switch (*fmt) {
 19561959                         case 's':
 19571960                                 savstr(va_arg(ap, usch *));
 19581961                                 break;
 19591962                         case 'd':
 19601963                                 num2str(va_arg(ap, int));
 19611964                                 break;
 19621965                         case 'c':
 19631966                                 savch(va_arg(ap, int));
 19641967                                 break;
 19651968                         default:
 19661969                                 error("bad sheap");
 19671970                         }
 19681971                 } else
 19691972                         savch(*fmt);
 19701973         }
 19711974         *stringbuf = 0;
 19721975 }
 19731976 
 19741977 usch *
 19751978 sheap(const char *fmt, ...)
 19761979 {
 19771980         va_list ap;
 19781981         usch *op = stringbuf;
 19791982 
 19801983         va_start(ap, fmt);
 19811984         vsheap(fmt, ap);
 19821985         va_end(ap);
 19831986 
 19841987         return op;
 19851988 }
 19861989 
 19871990 static void
 19881991 usage(void)
 19891992 {
 19901993         error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
 19911994 }
 19921995 
 19931996 #ifdef notyet
 19941997 /*
 19951998  * Symbol table stuff.
 19961999  * The data structure used is a patricia tree implementation using only
 19972000  * bytes to store offsets. 
 19982001  * The information stored is (lower address to higher):
 19992002  *
 20002003  *      unsigned char bitno[2]; bit number in the string
 20012004  *      unsigned char left[3];  offset from base to left element
 20022005  *      unsigned char right[3]; offset from base to right element
 20032006  */
 20042007 #endif
 20052008 
 20062009 /*
 20072010  * This patricia implementation is more-or-less the same as
 20082011  * used in ccom for string matching.
 20092012  */
 20102013 struct tree {
 20112014         int bitno;
 20122015         struct tree *lr[2];
 20132016 };
 20142017 
 20152018 #define BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
 20162019 #define LEFT_IS_LEAF            0x80000000
 20172020 #define RIGHT_IS_LEAF           0x40000000
 20182021 #define IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
 20192022 #define IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
 20202023 #define P_BIT(key, bit)         (key[bit >> 3] >> (bit & 7)) & 1
 20212024 #define CHECKBITS               8
 20222025 
 20232026 static struct tree *sympole;
 20242027 static int numsyms;
 20252028 
 20262029 /*
 20272030  * Allocate a symtab struct and store the string.
 20282031  */
 20292032 static struct symtab *
 20302033 getsymtab(const usch *str)
 20312034 {
 20322035         struct symtab *sp = malloc(sizeof(struct symtab));
 20332036 
 20342037         if (sp == NULL)
 20352038                 error("getsymtab: couldn't allocate symtab");
 20362039         sp->namep = savstr(str);
 20372040         savch('\0');
 20382041         sp->value = NULL;
 20392042         sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
 20402043         sp->line = ifiles ? ifiles->lineno : 0;
 20412044         return sp;
 20422045 }
 20432046 
 20442047 /*
 20452048  * Do symbol lookup in a patricia tree.
 20462049  * Only do full string matching, no pointer optimisations.
 20472050  */
 20482051 struct symtab *
 20492052 lookup(const usch *key, int enterf)
 20502053 {
 20512054         struct symtab *sp;
 20522055         struct tree *w, *new, *last;
 20532056         int len, cix, bit, fbit, svbit, ix, bitno;
 20542057         const usch *k, *m;
 20552058 
 20562059         /* Count full string length */
 20572060         for (k = key, len = 0; *k; k++, len++)
 20582061                 ;
 20592062 
 20602063         switch (numsyms) {
 20612064         case 0: /* no symbols yet */
 20622065                 if (enterf != ENTER)
 20632066                         return NULL;
 20642067                 sympole = (struct tree *)getsymtab(key);
 20652068                 numsyms++;
 20662069                 return (struct symtab *)sympole;
 20672070 
 20682071         case 1:
 20692072                 w = sympole;
 20702073                 svbit = 0; /* XXX gcc */
 20712074                 break;
 20722075 
 20732076         default:
 20742077                 w = sympole;
 20752078                 bitno = len * CHECKBITS;
 20762079                 for (;;) {
 20772080                         bit = BITNO(w->bitno);
 20782081                         fbit = bit > bitno ? 0 : P_BIT(key, bit);
 20792082                         svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
 20802083                             IS_LEFT_LEAF(w->bitno);
 20812084                         w = w->lr[fbit];
 20822085                         if (svbit)
 20832086                                 break;
 20842087                 }
 20852088         }
 20862089 
 20872090         sp = (struct symtab *)w;
 20882091 
 20892092         m = sp->namep;
 20902093         k = key;
 20912094 
 20922095         /* Check for correct string and return */
 20932096         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
 20942097                 ;
 20952098         if (*m == 0 && *k == 0) {
 20962099                 if (enterf != ENTER && sp->value == NULL)
 20972100                         return NULL;
 20982101                 return sp;
 20992102         }
 21002103 
 21012104         if (enterf != ENTER)
 21022105                 return NULL; /* no string found and do not enter */
 21032106 
 21042107         ix = *m ^ *k;
 21052108         while ((ix & 1) == 0)
 21062109                 ix >>= 1, cix++;
 21072110 
 21082111         /* Create new node */
 21092112         if ((new = malloc(sizeof *new)) == NULL)
 21102113                 error("getree: couldn't allocate tree");
 21112114         bit = P_BIT(key, cix);
 21122115         new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21132116         new->lr[bit] = (struct tree *)getsymtab(key);
 21142117 
 21152118         if (numsyms++ == 1) {
 21162119                 new->lr[!bit] = sympole;
 21172120                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21182121                 sympole = new;
 21192122                 return (struct symtab *)new->lr[bit];
 21202123         }
 21212124 
 21222125         w = sympole;
 21232126         last = NULL;
 21242127         for (;;) {
 21252128                 fbit = w->bitno;
 21262129                 bitno = BITNO(w->bitno);
 21272130                 if (bitno == cix)
 21282131                         error("bitno == cix");
 21292132                 if (bitno > cix)
 21302133                         break;
 21312134                 svbit = P_BIT(key, bitno);
 21322135                 last = w;
 21332136                 w = w->lr[svbit];
 21342137                 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
 21352138                         break;
 21362139         }
 21372140 
 21382141         new->lr[!bit] = w;
 21392142         if (last == NULL) {
 21402143                 sympole = new;
 21412144         } else {
 21422145                 last->lr[svbit] = new;
 21432146                 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21442147         }
 21452148         if (bitno < cix)
 21462149                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21472150         return (struct symtab *)new->lr[bit];
 21482151 }
 21492152 
 21502153 static usch *
 21512154 xstrdup(const usch *str)
 21522155 {
 21532156         usch *rv;
 21542157 
 21552158         if ((rv = (usch *)strdup((const char *)str)) == NULL)
 21562159                 error("xstrdup: out of mem");
 21572160         return rv;
 21582161 }
 21592162 
 21602163 void
 21612164 xwrite(int fd, const void *buf, unsigned int len)
 21622165 {
 21632166         if (write(fd, buf, len) != (int)len) {
 21642167                 if (fd == 2)
 21652168                         exit(2);
 21662169                 error("write error");
 21672170         }
 21682171 }
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-10-31 12:29 +0100