Quick Search:

Mode

Context

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

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.170
 
1.171
 
MAIN:plunky:20121011100306
 
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 
 8686 /* include dirs */
 8787 struct incs {
 8888         struct incs *next;
 8989         usch *dir;
 9090         dev_t dev;
 9191         ino_t ino;
 9292 } *incdir[2];
 9393 
 9494 static struct symtab *filloc;
 9595 static struct symtab *linloc;
 9696 static struct symtab *pragloc;
 9797 int     trulvl;
 9898 int     flslvl;
 9999 int     elflvl;
 100100 int     elslvl;
 101101 usch *stringbuf = sbf;
 102102 
 103103 /*
 104104  * Macro replacement list syntax:
 105105  * - For object-type macros, replacement strings are stored as-is.
 106106  * - For function-type macros, macro args are substituted for the
 107107  *   character WARN followed by the argument number.
 108108  * - The value element points to the end of the string, to simplify
 109109  *   pushback onto the input queue.
 110110  *
 111111  * The first character (from the end) in the replacement list is
 112112  * the number of arguments:
 113113  *   VARG  - ends with ellipsis, next char is argcount without ellips.
 114114  *   OBJCT - object-type macro
 115115  *   0     - empty parenthesis, foo()
 116116  *   1->   - number of args.
 117117  *
 118118  * WARN is used:
 119119  *      - in stored replacement lists to tell that an argument comes
 120120  *      - When expanding replacement lists to tell that the list ended.
 121121  *
 122122  * To ensure that an already expanded identifier won't get expanded
 123123  * again a EBLOCK char + its number is stored directly before any
 124124  * expanded identifier.
 125125  */
 126126 
 127127 /* args for lookup() */
 128128 #define FIND    0
 129129 #define ENTER   1
 130130 
 131131 /*
 132132  * No-replacement array.  If a macro is found and exists in this array
 133133  * then no replacement shall occur.  This is a stack.
 134134  */
 135135 struct symtab *norep[RECMAX];   /* Symbol table index table */
 136136 int norepptr = 1;                       /* Top of index table */
 137137 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
 138138 int bidx;                       /* Top of bptr stack */
 139139 
 140140 static int readargs(struct symtab *sp, const usch **args);
 141141 static void exparg(int);
 142142 static void subarg(struct symtab *sp, const usch **args, int);
 143143 static void flbuf(void);
 144144 static void usage(void);
 145145 static usch *xstrdup(const usch *str);
 146146 static void addidir(char *idir, struct incs **ww);
 147147 
 148148 int
 149149 main(int argc, char **argv)
 150150 {
 151151         struct initar *it;
 152152         struct symtab *nl;
 153153         register int ch;
 154154         const usch *fn1, *fn2;
 155155         int dummy;
 156156 
 157157 #ifdef TIMING
 158158         struct timeval t1, t2;
 159159 
 160160         (void)gettimeofday(&t1, NULL);
 161161 #endif
 162162 
 163163         while ((ch = getopt(argc, argv, "CD:d:I:i:MPS:tU:Vvx:")) != -1) {
 164164                 switch (ch) {
 165165                 case 'C': /* Do not discard comments */
 166166                         Cflag++;
 167167                         break;
 168168 
 169169                 case 'D': /* define something */
 170170                 case 'i': /* include */
 171171                 case 'U': /* undef */
 172172                         /* XXX should not need malloc() here */
 173173                         if ((it = malloc(sizeof(struct initar))) == NULL)
 174174                                 error("couldn't apply -%c %s", ch, optarg);
 175175                         it->type = ch;
 176176                         it->str = optarg;
 177177                         it->next = initar;
 178178                         initar = it;
 179179                         break;
 180180 
 181181                 case 'd':
 182182                         while (*optarg) {
 183183                                 switch(*optarg) {
 184184                                 case 'M': /* display macro definitions */
 185185                                         dMflag = 1;
 186186                                         Mflag = 1;
 187187                                         break;
 188188 
 189189                                 default: /* ignore others */
 190190                                         break;
 191191                                 }
 192192                                 optarg++;
 193193                         }
 194194                         break;
 195195 
 196196                 case 'I':
 197197                 case 'S':
 198198                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
 199199                         break;
 200200 
 201201                 case 'M': /* Generate dependencies for make */
 202202                         Mflag++;
 203203                         break;
 204204 
 205205                 case 'P': /* Inhibit generation of line numbers */
 206206                         Pflag++;
 207207                         break;
 208208 
 209209                 case 't':
 210210                         tflag = 1;
 211211                         break;
 212212 
 213213 #ifdef PCC_DEBUG
 214214                 case 'V':
 215215                         dflag++;
 216216                         break;
 217217 #endif
 218218                 case 'v':
<>219 -                        dummy = write(2, versstr, sizeof(versstr));
  219+                        dummy = write(2, versstr, sizeof(versstr) - 1);
<_220220                         break;
 221221 
 222222                 case 'x':
 223223                         if (strcmp(optarg, "MP") == 0) {
 224224                                 MPflag++;
 225225                         } else if (strncmp(optarg, "MT,", 3) == 0 ||
 226226                             strncmp(optarg, "MQ,", 3) == 0) {
 227227                                 usch *cp, *fn;
 228228                                 fn = stringbuf;
 229229                                 for (cp = (usch *)&optarg[3]; *cp; cp++) {
 230230                                         if (*cp == '$' && optarg[1] == 'Q')
 231231                                                 savch('$');
 232232                                         savch(*cp);
 233233                                 }
 234234                                 savstr((const usch *)"");
 235235                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
 236236                                 savch(0);
 237237                                 Mxfile = fn;
 238238                         } else
 239239                                 usage();
 240240                         break;
 241241 
 242242                 case '?':
 243243                 default:
 244244                         usage();
 245245                 }
 246246         }
 247247 
 248248         argc -= optind;
 249249         argv += optind;
 250250 
 251251         filloc = lookup((const usch *)"__FILE__", ENTER);
 252252         linloc = lookup((const usch *)"__LINE__", ENTER);
 253253         filloc->value = linloc->value = stringbuf;
 254254         savch(OBJCT);
 255255 
 256256         /* create a complete macro for pragma */
 257257         pragloc = lookup((const usch *)"_Pragma", ENTER);
 258258         savch(0);
 259259         savstr((const usch *)"_Pragma(");
 260260         savch(0);
 261261         savch(WARN);
 262262         savch(')');
 263263         pragloc->value = stringbuf;
 264264         savch(1);
 265265 
 266266         if (tflag == 0) {
 267267                 time_t t = time(NULL);
 268268                 usch *n = (usch *)ctime(&t);
 269269 
 270270                 /*
 271271                  * Manually move in the predefined macros.
 272272                  */
 273273                 nl = lookup((const usch *)"__TIME__", ENTER);
 274274                 savch(0); savch('"');  n[19] = 0; savstr(&n[11]); savch('"');
 275275                 savch(OBJCT);
 276276                 nl->value = stringbuf-1;
 277277 
 278278                 nl = lookup((const usch *)"__DATE__", ENTER);
 279279                 savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
 280280                 savstr(&n[20]); savch('"'); savch(OBJCT);
 281281                 nl->value = stringbuf-1;
 282282 
 283283                 nl = lookup((const usch *)"__STDC__", ENTER);
 284284                 savch(0); savch('1'); savch(OBJCT);
 285285                 nl->value = stringbuf-1;
 286286 
 287287                 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
 288288                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
 289289                 nl->value = stringbuf-1;
 290290         }
 291291 
 292292         if (Mflag && !dMflag) {
 293293                 usch *c;
 294294 
 295295                 if (argc < 1)
 296296                         error("-M and no infile");
 297297                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
 298298                         c = (usch *)argv[0];
 299299                 else
 300300                         c++;
 301301                 Mfile = stringbuf;
 302302                 savstr(c); savch(0);
 303303                 if (MPflag) {
 304304                         MPfile = stringbuf;
 305305                         savstr(c); savch(0);
 306306                 }
 307307                 if (Mxfile)
 308308                         Mfile = Mxfile;
 309309                 if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
 310310                         error("-M and no extension: ");
 311311                 c[1] = 'o';
 312312                 c[2] = 0;
 313313         }
 314314 
 315315         if (argc == 2) {
 316316                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT, 0600)) < 0)
 317317                         error("Can't creat %s", argv[1]);
 318318         } else
 319319                 ofd = 1; /* stdout */
 320320         istty = isatty(ofd);
 321321 
 322322         if (argc && strcmp(argv[0], "-")) {
 323323                 fn1 = fn2 = (usch *)argv[0];
 324324         } else {
 325325                 fn1 = NULL;
 326326                 fn2 = (const usch *)"";
 327327         }
 328328         if (pushfile(fn1, fn2, 0, NULL))
 329329                 error("cannot open %s", argv[0]);
 330330 
 331331         flbuf();
 332332         close(ofd);
 333333 #ifdef TIMING
 334334         (void)gettimeofday(&t2, NULL);
 335335         t2.tv_sec -= t1.tv_sec;
 336336         t2.tv_usec -= t1.tv_usec;
 337337         if (t2.tv_usec < 0) {
 338338                 t2.tv_usec += 1000000;
 339339                 t2.tv_sec -= 1;
 340340         }
 341341         fprintf(stderr, "cpp total time: %ld s %ld us\n",
 342342              (long)t2.tv_sec, (long)t2.tv_usec);
 343343 #endif
 344344         return 0;
 345345 }
 346346 
 347347 static void
 348348 addidir(char *idir, struct incs **ww)
 349349 {
 350350         struct incs *w;
 351351         struct stat st;
 352352 
 353353         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
 354354                 return; /* ignore */
 355355         if (*ww != NULL) {
 356356                 for (w = *ww; w->next; w = w->next) {
 357357 #ifdef os_win32
 358358                         if (strcmp(w->dir, idir) == 0)
 359359                                 return;
 360360 #else
 361361                         if (w->dev == st.st_dev && w->ino == st.st_ino)
 362362                                 return;
 363363 #endif
 364364                 }
 365365 #ifdef os_win32
 366366                 if (strcmp(w->dir, idir) == 0)
 367367                         return;
 368368 #else
 369369                 if (w->dev == st.st_dev && w->ino == st.st_ino)
 370370                         return;
 371371 #endif
 372372                 ww = &w->next;
 373373         }
 374374         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
 375375                 error("couldn't add path %s", idir);
 376376         w->dir = (usch *)idir;
 377377         w->dev = st.st_dev;
 378378         w->ino = st.st_ino;
 379379         *ww = w;
 380380 }
 381381 
 382382 void
 383383 line(void)
 384384 {
 385385         static usch *lbuf;
 386386         static int llen;
 387387         usch *p;
 388388         int c;
 389389 
 390390         if ((c = yylex()) != NUMBER)
 391391                 goto bad;
 392392         ifiles->lineno = (int)(yylval.node.nd_val - 1);
 393393 
 394394         if ((c = yylex()) == '\n')
 395395                 return;
 396396 
 397397         if (c != STRING)
 398398                 goto bad;
 399399 
 400400         p = yytext;
 401401         if (*p++ == 'L')
 402402                 p++;
 403403         c = strlen((char *)p);
 404404         p[c - 1] = '\0';
 405405         if (llen < c) {
 406406                 /* XXX may lose heap space */
 407407                 lbuf = stringbuf;
 408408                 stringbuf += c;
 409409                 llen = c;
 410410                 if (stringbuf >= &sbf[SBSIZE]) {
 411411                         stringbuf = sbf; /* need space to write error message */
 412412                         error("line filename exceeds buffer size");
 413413                 }
 414414         }
 415415         memcpy(lbuf, p, c);
 416416         ifiles->fname = lbuf;
 417417         if (yylex() == '\n')
 418418                 return;
 419419 
 420420 bad:    error("bad line directive");
 421421 }
 422422 
 423423 /*
 424424  * Search for and include next file.
 425425  * Return 1 on success.
 426426  */
 427427 static int
 428428 fsrch(const usch *fn, int idx, struct incs *w)
 429429 {
 430430         int i;
 431431 
 432432         for (i = idx; i < 2; i++) {
 433433                 if (i > idx)
 434434                         w = incdir[i];
 435435                 for (; w; w = w->next) {
 436436                         usch *nm = stringbuf;
 437437 
 438438                         savstr(w->dir); savch('/');
 439439                         savstr(fn); savch(0);
 440440                         if (pushfile(nm, fn, i, w->next) == 0)
 441441                                 return 1;
 442442                         stringbuf = nm;
 443443                 }
 444444         }
 445445         return 0;
 446446 }
 447447 
 448448 static void
 449449 prem(void)
 450450 {
 451451         error("premature EOF");
 452452 }
 453453 
 454454 /*
 455455  * Include a file. Include order:
 456456  * - For <...> files, first search -I directories, then system directories.
 457457  * - For "..." files, first search "current" dir, then as <...> files.
 458458  */
 459459 void
 460460 include(void)
 461461 {
 462462         struct symtab *nl;
 463463         usch *osp;
 464464         usch *fn, *safefn;
 465465         int c;
 466466 
 467467         if (flslvl)
 468468                 return;
 469469         osp = stringbuf;
 470470 
 471471         while ((c = sloscan()) == WSPACE)
 472472                 ;
 473473         if (c == IDENT) {
 474474                 /* sloscan() will not expand idents */
 475475                 if ((nl = lookup(yytext, FIND)) == NULL)
 476476                         goto bad;
 477477                 if (kfind(nl))
 478478                         unpstr(stringbuf);
 479479                 else
 480480                         unpstr(nl->namep);
 481481                 stringbuf = osp;
 482482                 c = yylex();
 483483         }
 484484         if (c != STRING && c != '<')
 485485                 goto bad;
 486486 
 487487         if (c == '<') {
 488488                 fn = stringbuf;
 489489                 while ((c = sloscan()) != '>' && c != '\n') {
 490490                         if (c == '\n') /* XXX check - cannot reach */
 491491                                 goto bad;
 492492                         savstr(yytext);
 493493                 }
 494494                 savch('\0');
 495495                 while ((c = sloscan()) == WSPACE)
 496496                         ;
 497497                 if (c == 0)
 498498                         prem();
 499499                 if (c != '\n')
 500500                         goto bad;
 501501                 safefn = fn;
 502502         } else {
 503503                 usch *nm = stringbuf;
 504504 
 505505                 yytext[strlen((char *)yytext)-1] = 0;
 506506                 fn = &yytext[1];
 507507                 /* first try to open file relative to previous file */
 508508                 /* but only if it is not an absolute path */
 509509                 if (*fn != '/') {
 510510                         savstr(ifiles->orgfn);
 511511                         if ((stringbuf =
 512512                             (usch *)strrchr((char *)nm, '/')) == NULL)
 513513                                 stringbuf = nm;
 514514                         else
 515515                                 stringbuf++;
 516516                 }
 517517                 safefn = stringbuf;
 518518                 savstr(fn); savch(0);
 519519                 c = yylex();
 520520                 if (c == 0)
 521521                         prem();
 522522                 if (c != '\n')
 523523                         goto bad;
 524524                 if (pushfile(nm, safefn, 0, NULL) == 0)
 525525                         goto okret;
 526526                 /* XXX may lose stringbuf space */
 527527         }
 528528 
 529529         if (fsrch(safefn, 0, incdir[0]))
 530530                 goto okret;
 531531 
 532532         error("cannot find '%s'", safefn);
 533533         /* error() do not return */
 534534 
 535535 bad:    error("bad include");
 536536         /* error() do not return */
 537537 okret:
 538538         prtline();
 539539 }
 540540 
 541541 void
 542542 include_next(void)
 543543 {
 544544         struct symtab *nl;
 545545         usch *osp;
 546546         usch *fn;
 547547         int c;
 548548 
 549549         if (flslvl)
 550550                 return;
 551551         osp = stringbuf;
 552552         while ((c = sloscan()) == WSPACE)
 553553                 ;
 554554         if (c == IDENT) {
 555555                 /* sloscan() will not expand idents */
 556556                 if ((nl = lookup(yytext, FIND)) == NULL)
 557557                         goto bad;
 558558                 if (kfind(nl))
 559559                         unpstr(stringbuf);
 560560                 else
 561561                         unpstr(nl->namep);
 562562                 stringbuf = osp;
 563563                 c = yylex();
 564564         }
 565565         if (c != STRING && c != '<')
 566566                 goto bad;
 567567 
 568568         fn = stringbuf;
 569569         if (c == STRING) {
 570570                 savstr(&yytext[1]);
 571571                 stringbuf[-1] = 0;
 572572         } else { /* < > */
 573573                 while ((c = sloscan()) != '>') {
 574574                         if (c == '\n')
 575575                                 goto bad;
 576576                         savstr(yytext);
 577577                 }
 578578                 savch('\0');
 579579         }
 580580         while ((c = sloscan()) == WSPACE)
 581581                 ;
 582582         if (c != '\n')
 583583                 goto bad;
 584584 
 585585         if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
 586586                 error("cannot find '%s'", fn);
 587587         prtline();
 588588         return;
 589589 
 590590 bad:    error("bad include");
 591591         /* error() do not return */
 592592 }
 593593 
 594594 static int
 595595 definp(void)
 596596 {
 597597         int c;
 598598 
 599599         do
 600600                 c = sloscan();
 601601         while (c == WSPACE);
 602602         return c;
 603603 }
 604604 
 605605 void
 606606 getcmnt(void)
 607607 {
 608608         int c;
 609609 
 610610         savstr(yytext);
 611611         savch(cinput()); /* Lost * */
 612612         for (;;) {
 613613                 c = cinput();
 614614                 if (c == '*') {
 615615                         c = cinput();
 616616                         if (c == '/') {
 617617                                 savstr((const usch *)"*/");
 618618                                 return;
 619619                         }
 620620                         cunput(c);
 621621                         c = '*';
 622622                 }
 623623                 savch(c);
 624624         }
 625625 }
 626626 
 627627 /*
 628628  * Compare two replacement lists, taking in account comments etc.
 629629  */
 630630 static int
 631631 cmprepl(const usch *o, const usch *n)
 632632 {
 633633         for (; *o; o--, n--) {
 634634                 /* comment skip */
 635635                 if (*o == '/' && o[-1] == '*') {
 636636                         while (*o != '*' || o[-1] != '/')
 637637                                 o--;
 638638                         o -= 2;
 639639                 }
 640640                 if (*n == '/' && n[-1] == '*') {
 641641                         while (*n != '*' || n[-1] != '/')
 642642                                 n--;
 643643                         n -= 2;
 644644                 }
 645645                 while (*o == ' ' || *o == '\t')
 646646                         o--;
 647647                 while (*n == ' ' || *n == '\t')
 648648                         n--;
 649649                 if (*o != *n)
 650650                         return 1;
 651651         }
 652652         return 0;
 653653 }
 654654 
 655655 static int
 656656 isell(void)
 657657 {
 658658         int ch;
 659659 
 660660         if ((ch = cinput()) != '.') {
 661661                 cunput(ch);
 662662                 return 0;
 663663         }
 664664         if ((ch = cinput()) != '.') {
 665665                 cunput(ch);
 666666                 cunput('.');
 667667                 return 0;
 668668         }
 669669         return 1;
 670670 }
 671671 
 672672 void
 673673 define(void)
 674674 {
 675675         struct symtab *np;
 676676         usch *args[MAXARGS+1], *ubuf, *sbeg;
 677677         int c, i, redef;
 678678         int mkstr = 0, narg = -1;
 679679         int ellips = 0;
 680680 #ifdef GCC_COMPAT
 681681         usch *gccvari = NULL;
 682682         int wascon;
 683683 #endif
 684684 
 685685         if (flslvl)
 686686                 return;
 687687         if (sloscan() != WSPACE || sloscan() != IDENT)
 688688                 goto bad;
 689689 
 690690         np = lookup(yytext, ENTER);
 691691         redef = np->value != NULL;
 692692 
 693693         defining = readmac = 1;
 694694         sbeg = stringbuf;
 695695         if ((c = sloscan()) == '(') {
 696696                 narg = 0;
 697697                 /* function-like macros, deal with identifiers */
 698698                 c = definp();
 699699                 for (;;) {
 700700                         if (c == ')')
 701701                                 break;
 702702                         if (c == '.' && isell()) {
 703703                                 ellips = 1;
 704704                                 if (definp() != ')')
 705705                                         goto bad;
 706706                                 break;
 707707                         }
 708708                         if (c == IDENT) {
 709709                                 /* make sure there is no arg of same name */
 710710                                 for (i = 0; i < narg; i++)
 711711                                         if (!strcmp((char *) args[i], (char *)yytext))
 712712                                                 error("Duplicate macro "
 713713                                                   "parameter \"%s\"", yytext);
 714714                                 if (narg == MAXARGS)
 715715                                         error("Too many macro args");
 716716                                 args[narg++] = xstrdup(yytext);
 717717                                 if ((c = definp()) == ',') {
 718718                                         if ((c = definp()) == ')')
 719719                                                 goto bad;
 720720                                         continue;
 721721                                 }
 722722 #ifdef GCC_COMPAT
 723723                                 if (c == '.' && isell()) {
 724724                                         if (definp() != ')')
 725725                                                 goto bad;
 726726                                         gccvari = args[--narg];
 727727                                         break;
 728728                                 }
 729729 #endif
 730730                                 if (c == ')')
 731731                                         break;
 732732                         }
 733733                         goto bad;
 734734                 }
 735735                 c = sloscan();
 736736         } else if (c == '\n') {
 737737                 /* #define foo */
 738738                 ;
 739739         } else if (c == 0) {
 740740                 prem();
 741741         } else if (c != WSPACE)
 742742                 goto bad;
 743743 
 744744         while (c == WSPACE)
 745745                 c = sloscan();
 746746 
 747747         /* replacement list cannot start with ## operator */
 748748         if (c == '#') {
 749749                 if ((c = sloscan()) == '#')
 750750                         goto bad;
 751751                 savch('\0');
 752752 #ifdef GCC_COMPAT
 753753                 wascon = 0;
 754754 #endif
 755755                 goto in2;
 756756         }
 757757 
 758758         /* parse replacement-list, substituting arguments */
 759759         savch('\0');
 760760         while (c != '\n') {
 761761 #ifdef GCC_COMPAT
 762762                 wascon = 0;
 763763 loop:
 764764 #endif
 765765                 switch (c) {
 766766                 case WSPACE:
 767767                         /* remove spaces if it surrounds a ## directive */
 768768                         ubuf = stringbuf;
 769769                         savstr(yytext);
 770770                         c = sloscan();
 771771                         if (c == '#') {
 772772                                 if ((c = sloscan()) != '#')
 773773                                         goto in2;
 774774                                 stringbuf = ubuf;
 775775                                 savch(CONC);
 776776                                 if ((c = sloscan()) == WSPACE)
 777777                                         c = sloscan();
 778778 #ifdef GCC_COMPAT
 779779                                 if (c == '\n')
 780780                                         break;
 781781                                 wascon = 1;
 782782                                 goto loop;
 783783 #endif
 784784                         }
 785785                         continue;
 786786 
 787787                 case '#':
 788788                         c = sloscan();
 789789                         if (c == '#') {
 790790                                 /* concat op */
 791791                                 savch(CONC);
 792792                                 if ((c = sloscan()) == WSPACE)
 793793                                         c = sloscan();
 794794 #ifdef GCC_COMPAT
 795795                                 if (c == '\n')
 796796                                         break;
 797797                                 wascon = 1;
 798798                                 goto loop;
 799799 #else
 800800                                 continue;
 801801 #endif
 802802                         }
 803803 in2:                    if (narg < 0) {
 804804                                 /* no meaning in object-type macro */
 805805                                 savch('#');
 806806                                 continue;
 807807                         }
 808808                         /* remove spaces between # and arg */
 809809                         savch(SNUFF);
 810810                         if (c == WSPACE)
 811811                                 c = sloscan(); /* whitespace, ignore */
 812812                         mkstr = 1;
 813813                         if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
 814814                                 continue;
 815815 
 816816                         /* FALLTHROUGH */
 817817                 case IDENT:
 818818                         if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
 819819                                 if (ellips == 0)
 820820                                         error("unwanted %s", yytext);
 821821 #ifdef GCC_COMPAT
 822822                                 savch(wascon ? GCCARG : VARG);
 823823 #else
 824824                                 savch(VARG);
 825825 #endif
 826826 
 827827                                 savch(WARN);
 828828                                 if (mkstr)
 829829                                         savch(SNUFF), mkstr = 0;
 830830                                 break;
 831831                         }
 832832                         if (narg < 0)
 833833                                 goto id; /* just add it if object */
 834834                         /* check if its an argument */
 835835                         for (i = 0; i < narg; i++)
 836836                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
 837837                                         break;
 838838                         if (i == narg) {
 839839 #ifdef GCC_COMPAT
 840840                                 if (gccvari &&
 841841                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
 842842                                         savch(wascon ? GCCARG : VARG);
 843843                                         savch(WARN);
 844844                                         if (mkstr)
 845845                                                 savch(SNUFF), mkstr = 0;
 846846                                         break;
 847847                                 }
 848848 #endif
 849849                                 if (mkstr)
 850850                                         error("not argument");
 851851                                 goto id;
 852852                         }
 853853                         savch(i);
 854854                         savch(WARN);
 855855                         if (mkstr)
 856856                                 savch(SNUFF), mkstr = 0;
 857857                         break;
 858858 
 859859                 case CMNT: /* save comments */
 860860                         getcmnt();
 861861                         break;
 862862 
 863863                 case 0:
 864864                         prem();
 865865 
 866866                 default:
 867867 id:                     savstr(yytext);
 868868                         break;
 869869                 }
 870870                 c = sloscan();
 871871         }
 872872         defining = readmac = 0;
 873873         /* remove trailing whitespace */
 874874         while (stringbuf > sbeg) {
 875875                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
 876876                         stringbuf--;
 877877                 /* replacement list cannot end with ## operator */
 878878                 else if (stringbuf[-1] == CONC)
 879879                         goto bad;
 880880                 else
 881881                         break;
 882882         }
 883883 #ifdef GCC_COMPAT
 884884         if (gccvari) {
 885885                 savch(narg);
 886886                 savch(VARG);
 887887         } else
 888888 #endif
 889889         if (ellips) {
 890890                 savch(narg);
 891891                 savch(VARG);
 892892         } else
 893893                 savch(narg < 0 ? OBJCT : narg);
 894894         if (redef && ifiles->idx != SYSINC) {
 895895                 if (cmprepl(np->value, stringbuf-1)) {
 896896                         sbeg = stringbuf;
 897897                         np->value = stringbuf-1;
 898898                         warning("%s redefined\nprevious define: %s:%d",
 899899                             np->namep, np->file, np->line);
 900900                 }
 901901                 stringbuf = sbeg/* forget this space */
 902902         } else
 903903                 np->value = stringbuf-1;
 904904 
 905905 #ifdef PCC_DEBUG
 906906         if (dflag) {
 907907                 const usch *w = np->value;
 908908 
 909909                 printf("!define: ");
 910910                 if (*w == OBJCT)
 911911                         printf("[object]");
 912912                 else if (*w == VARG)
 913913                         printf("[VARG%d]", *--w);
 914914                 while (*--w) {
 915915                         switch (*w) {
 916916                         case WARN: printf("<%d>", *--w); break;
 917917                         case CONC: printf("<##>"); break;
 918918                         case SNUFF: printf("<\">"); break;
 919919                         default: putchar(*w); break;
 920920                         }
 921921                 }
 922922                 putchar('\n');
 923923         }
 924924 #endif
 925925         for (i = 0; i < narg; i++)
 926926                 free(args[i]);
 927927         return;
 928928 
 929929 bad:    error("bad define");
 930930 }
 931931 
 932932 void
 933933 xwarning(usch *s)
 934934 {
 935935         usch *t;
 936936         usch *sb = stringbuf;
 937937         int dummy;
 938938 
 939939         flbuf();
 940940         savch(0);
 941941         if (ifiles != NULL) {
 942942                 t = sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
 943943                 dummy = write (2, t, strlen((char *)t));
 944944         }
 945945         dummy = write (2, s, strlen((char *)s));
 946946         dummy = write (2, "\n", 1);
 947947         stringbuf = sb;
 948948 }
 949949 
 950950 void
 951951 xerror(usch *s)
 952952 {
 953953         usch *t;
 954954         int dummy;
 955955 
 956956         flbuf();
 957957         savch(0);
 958958         if (ifiles != NULL) {
 959959                 t = sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
 960960                 dummy = write (2, t, strlen((char *)t));
 961961         }
 962962         dummy = write (2, s, strlen((char *)s));
 963963         dummy = write (2, "\n", 1);
 964964         exit(1);
 965965 }
 966966 
 967967 static void
 968968 sss(void)
 969969 {
 970970         savch(EBLOCK);
 971971         savch(cinput());
 972972         savch(cinput());
 973973 }
 974974 
 975975 static int
 976976 addmac(struct symtab *sp)
 977977 {
 978978         int c, i;
 979979 
 980980         /* Check if it exists; then save some space */
 981981         /* May be more difficult to debug cpp */
 982982         for (i = 1; i < norepptr; i++)
 983983                 if (norep[i] == sp)
 984984                         return i;
 985985         if (norepptr >= RECMAX)
 986986                 error("too many macros");
 987987         /* check norepptr */
 988988         if ((norepptr & 255) == 0)
 989989                 norepptr++;
 990990         if (((norepptr >> 8) & 255) == 0)
 991991                 norepptr += 256;
 992992         c = norepptr;
 993993         norep[norepptr++] = sp;
 994994         return c;
 995995 }
 996996 
 997997 static void
 998998 doblk(void)
 999999 {
 10001000         int c;
 10011001 
 10021002         do {
 10031003                 donex();
 10041004         } while ((c = sloscan()) == EBLOCK);
 10051005         if (c == IDENT)
 10061006                 return;
 10071007         error("EBLOCK sync error");
 10081008 }
 10091009 
 10101010 /* Block next nr in lex buffer to expand */
 10111011 int
 10121012 donex(void)
 10131013 {
 10141014         int n, i;
 10151015 
 10161016         if (bidx == RECMAX)
 10171017                 error("too deep macro recursion");
 10181018         n = cinput();
 10191019         n = MKB(n, cinput());
 10201020         for (i = 0; i < bidx; i++)
 10211021                 if (bptr[i] == n)
 10221022                         return n; /* already blocked */
 10231023         bptr[bidx++] = n;
 10241024         /* XXX - check for sp buffer overflow */
 10251025 #ifdef PCC_DEBUG
 10261026         if (dflag>1) {
 10271027                 printf("donex %d (%d) blocking:\n", bidx, n);
 10281028                 printf("donex %s(%d) blocking:", norep[n]->namep, n);
 10291029                 for (i = bidx-1; i >= 0; i--)
 10301030                         printf(" '%s'", norep[bptr[i]]->namep);
 10311031                 printf("\n");
 10321032         }
 10331033 #endif
 10341034         return n;
 10351035 }
 10361036 
 10371037 /*
 10381038  * store a character into the "define" buffer.
 10391039  */
 10401040 void
 10411041 savch(int c)
 10421042 {
 10431043         if (stringbuf-sbf < SBSIZE) {
 10441044                 *stringbuf++ = (usch)c;
 10451045         } else {
 10461046                 stringbuf = sbf; /* need space to write error message */
 10471047                 error("Too much defining");
 10481048         }
 10491049 }
 10501050 
 10511051 /*
 10521052  * convert _Pragma to #pragma for output.
 10531053  * Syntax is already correct.
 10541054  */
 10551055 static void
 10561056 pragoper(void)
 10571057 {
 10581058         usch *s;
 10591059         int t;
 10601060 
 10611061         while ((t = sloscan()) != '(')
 10621062                 ;
 10631063 
 10641064         while ((t = sloscan()) == WSPACE)
 10651065                 ;
 10661066         if (t != STRING)
 10671067                 error("pragma must have string argument");
 10681068         savstr((const usch *)"\n#pragma ");
 10691069         s = yytext;
 10701070         if (*s == 'L')
 10711071                 s++;
 10721072         for (; *s; s++) {
 10731073                 if (*s == EBLOCK) {
 10741074                         s+=2;
 10751075                         continue;
 10761076                 }
 10771077                 if (*s == '\"')
 10781078                         continue;
 10791079                 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
 10801080                         s++;
 10811081                 savch(*s);
 10821082         }
 10831083         sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
 10841084         while ((t = sloscan()) == WSPACE)
 10851085                 ;
 10861086         if (t != ')')
 10871087                 error("pragma syntax error");
 10881088 }
 10891089 
 10901090 /*
 10911091  * Return true if it is OK to expand this symbol.
 10921092  */
 10931093 static int
 10941094 okexp(struct symtab *sp)
 10951095 {
 10961096         int i;
 10971097 
 10981098         if (sp == NULL)
 10991099                 return 0;
 11001100         for (i = 0; i < bidx; i++)
 11011101                 if (norep[bptr[i]] == sp)
 11021102                         return 0;
 11031103         return 1;
 11041104 }
 11051105 
 11061106 /*
 11071107  * Insert block(s) before each expanded name.
 11081108  * Input is in lex buffer, output on lex buffer.
 11091109  */
 11101110 static void
 11111111 insblock(int bnr)
 11121112 {
 11131113         usch *bp = stringbuf;
 11141114         int c, i;
 11151115  
 11161116         IMP("IB");
 11171117         readmac++;
 11181118         while ((c = sloscan()) != WARN) {
 11191119                 if (c == EBLOCK) {
 11201120                         sss();
 11211121                         continue;
 11221122                 }
 11231123                 if (c == CMNT) {
 11241124                         getcmnt();
 11251125                         continue;
 11261126                 }
 11271127                 if (c == IDENT) {
 11281128                         savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
 11291129                         for (i = 0; i < bidx; i++)
 11301130                                 savch(EBLOCK), savch(bptr[i] & 255),
 11311131                                     savch(bptr[i] >> 8);
 11321132                 }
 11331133                 savstr(yytext);
 11341134                 if (c == '\n')
 11351135                         (void)cinput();
 11361136         }
 11371137         savch(0);
 11381138         cunput(WARN);
 11391139         unpstr(bp);
 11401140         stringbuf = bp;
 11411141         readmac--;
 11421142         IMP("IBRET");
 11431143 }
 11441144 
 11451145 /* Delete next WARN on the input stream */
 11461146 static void
 11471147 delwarn(void)
 11481148 {
 11491149         usch *bp = stringbuf;
 11501150         int c;
 11511151  
 11521152         IMP("DELWARN");
 11531153         while ((c = sloscan()) != WARN) {
 11541154                 if (c == CMNT) {
 11551155                         getcmnt();
 11561156                 } else if (c == EBLOCK) {
 11571157                         sss();
 11581158                 } else if (c == '\n') {
 11591159                         putch(cinput());
 11601160                 } else
 11611161                         savstr(yytext);
 11621162         }
 11631163         if (stringbuf[-1] == '/')
 11641164                 savch(PHOLD); /* avoid creating comments */
 11651165         savch(0);
 11661166         unpstr(bp);
 11671167         stringbuf = bp;
 11681168         IMP("DELWRET");
 11691169 }
 11701170 
 11711171 /*
 11721172  * Handle defined macro keywords found on input stream.
 11731173  * When finished print out the full expanded line.
 11741174  * Everything on lex buffer except for the symtab.
 11751175  */
 11761176 int
 11771177 kfind(struct symtab *sp)
 11781178 {
 11791179         struct symtab *nl;
 11801180         const usch *argary[MAXARGS+1], *cbp;
 11811181         usch *sbp;
 11821182         int c, o, chkf;
 11831183 
 11841184         DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
 11851185         IMP("KFIND");
 11861186         if (*sp->value == OBJCT) {
 11871187                 if (sp == filloc) {
 11881188                         unpstr(sheap("\"%s\"", ifiles->fname));
 11891189                         return 1;
 11901190                 } else if (sp == linloc) {
 11911191                         unpstr(sheap("%d", ifiles->lineno));
 11921192                         return 1;
 11931193                 }
 11941194                 IMP("END1");
 11951195                 cunput(WARN);
 11961196                 for (cbp = sp->value-1; *cbp; cbp--)
 11971197                         cunput(*cbp);
 11981198                 insblock(addmac(sp));
 11991199                 IMP("ENDX");
 12001200                 exparg(1);
 12011201 
 12021202 upp:            sbp = stringbuf;
 12031203                 chkf = 1;
 12041204                 if (obufp != 0)
 12051205                         lastoch = outbuf[obufp-1];
 12061206                 if (iswsnl(lastoch))
 12071207                         chkf = 0;
 12081208                 if (Cflag)
 12091209                         readmac++;
 12101210                 while ((c = sloscan()) != WARN) {
 12111211                         switch (c) {
 12121212                         case CMNT:
 12131213                                 getcmnt();
 12141214                                 break;
 12151215 
 12161216                         case STRING:
 12171217                                 /* Remove embedded directives */
 12181218                                 for (cbp = yytext; *cbp; cbp++) {
 12191219                                         if (*cbp == EBLOCK)
 12201220                                                 cbp+=2;
 12211221                                         else if (*cbp != CONC)
 12221222                                                 savch(*cbp);
 12231223                                 }
 12241224                                 break;
 12251225 
 12261226                         case EBLOCK:
 12271227                                 doblk();
 12281228                                 /* FALLTHROUGH */
 12291229                         case IDENT:
 12301230                                 /*
 12311231                                  * Tricky: if this is the last identifier
 12321232                                  * in the expanded list, and it is defined
 12331233                                  * as a function-like macro, then push it
 12341234                                  * back on the input stream and let fastscan
 12351235                                  * handle it as a new macro.
 12361236                                  * BUT: if this macro is blocked then this
 12371237                                  * should not be done.
 12381238                                  */
 12391239                                 nl = lookup(yytext, FIND);
 12401240                                 o = okexp(nl);
 12411241                                 bidx = 0;
 12421242                                 /* Deal with pragmas here */
 12431243                                 if (nl == pragloc) {
 12441244                                         pragoper();
 12451245                                         break;
 12461246                                 }
 12471247                                 if (nl == NULL || !o || *nl->value == OBJCT) {
 12481248                                         /* Not fun-like macro */
 12491249                                         savstr(yytext);
 12501250                                         break;
 12511251                                 }
 12521252                                 c = cinput();
 12531253                                 if (c == WARN) {
 12541254                                         /* succeeded, push back */
 12551255                                         unpstr(yytext);
 12561256                                 } else {
 12571257                                         savstr(yytext);
 12581258                                 }
 12591259                                 cunput(c);
 12601260                                 break;
 12611261 
 12621262                         default:
 12631263                                 if (chkf && c < 127)
 12641264                                         putch(' ');
 12651265                                 savstr(yytext);
 12661266                                 break;
 12671267                         }
 12681268                         chkf = 0;
 12691269                 }
 12701270                 if (Cflag)
 12711271                         readmac--;
 12721272                 IMP("END2");
 12731273                 norepptr = 1;
 12741274                 savch(0);
 12751275                 stringbuf = sbp;
 12761276                 return 1;
 12771277         }
 12781278         /* Is a function-like macro */
 12791279 
 12801280         /* Search for '(' */
 12811281         sbp = stringbuf;
 12821282         while (iswsnl(c = cinput()))
 12831283                 savch(c);
 12841284         savch(0);
 12851285         stringbuf = sbp;
 12861286         if (c != '(') {
 12871287                 cunput(c);
 12881288                 unpstr(sbp);
 12891289                 return 0; /* Failed */
 12901290         }
 12911291 
 12921292         /* Found one, output \n to be in sync */
 12931293         for (; *sbp; sbp++) {
 12941294                 if (*sbp == '\n')
 12951295                         putch('\n'), ifiles->lineno++;
 12961296         }
 12971297 
 12981298         /* fetch arguments */
 12991299         if (Cflag)
 13001300                 readmac++;
 13011301         if (readargs(sp, argary))
 13021302                 error("readargs");
 13031303 
 13041304         c = addmac(sp);
 13051305         sbp = stringbuf;
 13061306         cunput(WARN);
 13071307 
 13081308         IMP("KEXP");
 13091309         subarg(sp, argary, 1);
 13101310         IMP("KNEX");
 13111311         insblock(c);
 13121312         IMP("KBLK");
 13131313 
 13141314         stringbuf = sbp;
 13151315 
 13161316         exparg(1);
 13171317         if (Cflag)
 13181318                 readmac--;
 13191319 
 13201320         IMP("END");
 13211321 
 13221322         goto upp;
 13231323 
 13241324 }
 13251325 
 13261326 /*
 13271327  * Replace and push-back on input stream the eventual replaced macro.
 13281328  * The check for whether it can expand or not should already have been done.
 13291329  * Blocks for this identifier will be added via insblock() after expansion.
 13301330  */
 13311331 int
 13321332 submac(struct symtab *sp, int lvl)
 13331333 {
 13341334         const usch *argary[MAXARGS+1];
 13351335         const usch *cp;
 13361336         usch *bp;
 13371337         int ch;
 13381338 
 13391339         DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
 13401340         if (*sp->value == OBJCT) {
 13411341                 if (sp == filloc) {
 13421342                         unpstr(sheap("\"%s\"", ifiles->fname));
 13431343                         return 1;
 13441344                 } else if (sp == linloc) {
 13451345                         unpstr(sheap("%d", ifiles->lineno));
 13461346                         return 1;
 13471347                 }
 13481348 
 13491349                 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
 13501350                 /* expand object-type macros */
 13511351                 ch = addmac(sp);
 13521352                 cunput(WARN);
 13531353 
 13541354                 for (cp = sp->value-1; *cp; cp--)
 13551355                         cunput(*cp);
 13561356                 insblock(ch);
 13571357                 delwarn();
 13581358                 return 1;
 13591359         }
 13601360 
 13611361         /*
 13621362          * Function-like macro; see if it is followed by a (
 13631363          * Be careful about the expand/noexpand balance.
 13641364          * Store read data on heap meanwhile.
 13651365          * For directive        #define foo() kaka
 13661366          * If input is          <NEX><NEX>foo<EXP>()<EXP> then
 13671367          * output should be     <NEX><NEX><EXP>kaka<EXP>.
 13681368          */
 13691369         bp = stringbuf;
 13701370         while (iswsnl(ch = cinput()))
 13711371                 savch(ch);
 13721372         savch(0);
 13731373         stringbuf = bp;
 13741374         if (ch != '(') {
 13751375                 cunput(ch);
 13761376                 unpstr(bp);
 13771377                 return 0; /* Failed */
 13781378         }
 13791379 
 13801380         /* no \n should be here */
 13811381 
 13821382         /*
 13831383          * A function-like macro has been found.  Read in the arguments,
 13841384          * expand them and push-back everything for another scan.
 13851385          */
 13861386         DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
 13871387         savch(0);
 13881388         if (readargs(sp, argary)) {
 13891389                 /* Bailed out in the middle of arg list */
 13901390                 unpstr(bp);
 13911391                 DDPRINT(("%d:noreadargs\n", lvl));
 13921392                 stringbuf = bp;
 13931393                 return 0;
 13941394         }
 13951395 
 13961396         /* when all args are read from input stream */
 13971397         ch = addmac(sp);
 13981398 
 13991399         DDPRINT(("%d:submac pre\n", lvl));
 14001400         cunput(WARN);
 14011401 
 14021402         subarg(sp, argary, lvl+1);
 14031403 
 14041404         DDPRINT(("%d:submac post\n", lvl));
 14051405         insblock(ch);
 14061406         delwarn();
 14071407 
 14081408         stringbuf = bp; /* Reset heap */
 14091409         DPRINT(("%d:Return submac\n", lvl));
 14101410         IMP("SM1");
 14111411         return 1;
 14121412 }
 14131413 
 14141414 static int
 14151415 isdir(void)
 14161416 {
 14171417         usch *bp = stringbuf;
 14181418         usch ch;
 14191419 
 14201420         while ((ch = cinput()) == ' ' || ch == '\t')
 14211421                 *stringbuf++ = ch;
 14221422         *stringbuf++ = ch;
 14231423         *stringbuf++ = 0;
 14241424         stringbuf = bp;
 14251425         if (ch == '#')
 14261426                 return 1;
 14271427         unpstr(bp);
 14281428         return 0;
 14291429 }
 14301430 
 14311431 /*
 14321432  * Deal with directives inside a macro.
 14331433  * Doing so is really ugly but gcc allows it, so...
 14341434  */
 14351435 static void
 14361436 chkdir(void)
 14371437 {
 14381438         usch ch;
 14391439 
 14401440         for (;;) {
 14411441                 if (isdir())
 14421442                         ppdir();
 14431443                 if (flslvl == 0)
 14441444                         return;
 14451445                 while ((ch = cinput()) != '\n')
 14461446                         ;
 14471447                 ifiles->lineno++;
 14481448                 putch('\n');
 14491449         }
 14501450 }
 14511451 
 14521452 /*
 14531453  * Read arguments and put in argument array.
 14541454  * If WARN is encountered return 1, otherwise 0.
 14551455  */
 14561456 int
 14571457 readargs(struct symtab *sp, const usch **args)
 14581458 {
 14591459         const usch *vp = sp->value;
 14601460         int c, i, plev, narg, ellips = 0;
 14611461         int warn;
 14621462 
 14631463         DPRINT(("readargs\n"));
 14641464 
 14651465         narg = *vp--;
 14661466         if (narg == VARG) {
 14671467                 narg = *vp--;
 14681468                 ellips = 1;
 14691469         }
 14701470 
 14711471         IMP("RDA1");
 14721472         /*
 14731473          * read arguments and store them on heap.
 14741474          */
 14751475         warn = 0;
 14761476         c = '(';
 14771477         for (i = 0; i < narg && c != ')'; i++) {
 14781478                 args[i] = stringbuf;
 14791479                 plev = 0;
 14801480                 while ((c = sloscan()) == WSPACE || c == '\n')
 14811481                         if (c == '\n') {
 14821482                                 ifiles->lineno++;
 14831483                                 putch(cinput());
 14841484                                 chkdir();
 14851485                         }
 14861486                 for (;;) {
 14871487                         while (c == EBLOCK) {
 14881488                                 sss();
 14891489                                 c = sloscan();
 14901490                         }
 14911491                         if (c == WARN) {
 14921492                                 warn++;
 14931493                                 goto oho;
 14941494                         }
 14951495                         if (plev == 0 && (c == ')' || c == ','))
 14961496                                 break;
 14971497                         if (c == '(')
 14981498                                 plev++;
 14991499                         if (c == ')')
 15001500                                 plev--;
 15011501                         savstr(yytext);
 15021502 oho:                    while ((c = sloscan()) == '\n') {
 15031503                                 ifiles->lineno++;
 15041504                                 putch(cinput());
 15051505                                 chkdir();
 15061506                                 savch(' ');
 15071507                         }
 15081508                         while (c == CMNT) {
 15091509                                 getcmnt();
 15101510                                 c = sloscan();
 15111511                         }
 15121512                         if (c == 0)
 15131513                                 error("eof in macro");
 15141514                 }
 15151515                 while (args[i] < stringbuf &&
 15161516                     iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
 15171517                         stringbuf--;
 15181518                 savch('\0');
 15191519 #ifdef PCC_DEBUG
 15201520                 if (dflag) {
 15211521                         printf("readargs: save arg %d '", i);
 15221522                         prline(args[i]);
 15231523                         printf("'\n");
 15241524                 }
 15251525 #endif
 15261526         }
 15271527 
 15281528         IMP("RDA2");
 15291529         /* Handle varargs readin */
 15301530         if (ellips)
 15311531                 args[i] = (const usch *)"";
 15321532         if (ellips && c != ')') {
 15331533                 args[i] = stringbuf;
 15341534                 plev = 0;
 15351535                 while ((c = sloscan()) == WSPACE || c == '\n')
 15361536                         if (c == '\n')
 15371537                                 cinput();
 15381538                 for (;;) {
 15391539                         if (plev == 0 && c == ')')
 15401540                                 break;
 15411541                         if (c == '(')
 15421542                                 plev++;
 15431543                         if (c == ')')
 15441544                                 plev--;
 15451545                         if (c == EBLOCK) {
 15461546                                 sss();
 15471547                         } else
 15481548                                 savstr(yytext);
 15491549                         while ((c = sloscan()) == '\n') {
 15501550                                 ifiles->lineno++;
 15511551                                 cinput();
 15521552                                 chkdir();
 15531553                                 savch(' ');
 15541554                         }
 15551555                 }
 15561556                 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
 15571557                         stringbuf--;
 15581558                 savch('\0');
 15591559                 
 15601560         }
 15611561         if (narg == 0 && ellips == 0)
 15621562                 while ((c = sloscan()) == WSPACE || c == '\n')
 15631563                         if (c == '\n')
 15641564                                 cinput();
 15651565 
 15661566         if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
 15671567                 error("wrong arg count");
 15681568         while (warn)
 15691569                 cunput(WARN), warn--;
 15701570         return 0;
 15711571 }
 15721572 
 15731573 /*
 15741574  * expand a function-like macro.
 15751575  * vp points to end of replacement-list
 15761576  * reads function arguments from sloscan()
 15771577  * result is pushed-back for more scanning.
 15781578  */
 15791579 void
 15801580 subarg(struct symtab *nl, const usch **args, int lvl)
 15811581 {
 15821582         int narg, instr, snuff;
 15831583         const usch *sp, *bp, *ap, *vp;
 15841584 
 15851585         DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
 15861586         vp = nl->value;
 15871587         narg = *vp--;
 15881588         if (narg == VARG)
 15891589                 narg = *vp--;
 15901590 
 15911591         sp = vp;
 15921592         instr = snuff = 0;
 15931593 #ifdef PCC_DEBUG
 15941594         if (dflag>1) {
 15951595                 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
 15961596                 prrep(vp);
 15971597                 printf("'\n");
 15981598         }
 15991599 #endif
 16001600 
 16011601         /*
 16021602          * push-back replacement-list onto lex buffer while replacing
 16031603          * arguments.  Arguments are macro-expanded if required.
 16041604          */
 16051605         while (*sp != 0) {
 16061606                 if (*sp == SNUFF)
 16071607                         cunput('\"'), snuff ^= 1;
 16081608                 else if (*sp == CONC)
 16091609                         ;
 16101610                 else if (*sp == WARN) {
 16111611 
 16121612                         if (sp[-1] == VARG) {
 16131613                                 bp = ap = args[narg];
 16141614                                 sp--;
 16151615 #ifdef GCC_COMPAT
 16161616                         } else if (sp[-1] == GCCARG) {
 16171617                                 ap = args[narg];
 16181618                                 if (ap[0] == 0)
 16191619                                         ap = (const usch *)"0";
 16201620                                 bp = ap;
 16211621                                 sp--;
 16221622 #endif
 16231623                         } else
 16241624                                 bp = ap = args[(int)*--sp];
 16251625 #ifdef PCC_DEBUG
 16261626                         if (dflag>1){
 16271627                                 printf("%d:subarg GOTwarn; arglist '", lvl);
 16281628                                 prline(bp);
 16291629                                 printf("'\n");
 16301630                         }
 16311631 #endif
 16321632                         if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
 16331633                                 /*
 16341634                                  * Expand an argument; 6.10.3.1:
 16351635                                  * "A parameter in the replacement list,
 16361636                                  *  is replaced by the corresponding argument
 16371637                                  *  after all macros contained therein have
 16381638                                  *  been expanded.".
 16391639                                  */
 16401640                                 cunput(WARN);
 16411641                                 unpstr(bp);
 16421642                                 exparg(lvl+1);
 16431643                                 delwarn();
 16441644                         } else {
 16451645                         while (*bp)
 16461646                                 bp++;
 16471647                         while (bp > ap) {
 16481648                                 bp--;
 16491649                                 if (snuff && !instr && iswsnl(*bp)) {
 16501650                                         while (iswsnl(*bp))
 16511651                                                 bp--;
 16521652                                         cunput(' ');
 16531653                                 }
 16541654 
 16551655                                 cunput(*bp);
 16561656                                 if ((*bp == '\'' || *bp == '"')
 16571657                                      && bp[-1] != '\\' && snuff) {
 16581658                                         instr ^= 1;
 16591659                                         if (instr == 0 && *bp == '"')
 16601660                                                 cunput('\\');
 16611661                                 }
 16621662                                 if (instr && (*bp == '\\' || *bp == '"'))
 16631663                                         cunput('\\');
 16641664                         }
 16651665                         }
 16661666                 } else
 16671667                         cunput(*sp);
 16681668                 sp--;
 16691669         }
 16701670         DPRINT(("%d:Return subarg\n", lvl));
 16711671         IMP("SUBARG");
 16721672 }
 16731673 
 16741674 /*
 16751675  * Do a (correct) expansion of a WARN-terminated buffer of tokens.
 16761676  * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
 16771677  * Expansion blocking is not altered here unless when tokens are
 16781678  * concatenated, in which case they are removed.
 16791679  */
 16801680 void
 16811681 exparg(int lvl)
 16821682 {
 16831683         struct symtab *nl;
 16841684         int c, i, gmult;
 16851685         usch *och;
 16861686         usch *osb = stringbuf;
 16871687         int anychange;
 16881688 
 16891689         DPRINT(("%d:exparg\n", lvl));
 16901690         IMP("EXPARG");
 16911691 
 16921692         readmac++;
 16931693 rescan:
 16941694         anychange = 0;
 16951695         while ((c = sloscan()) != WARN) {
 16961696                 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
 16971697                 IMP("EA0");
 16981698                 bidx = 0;
 16991699                 switch (c) {
 17001700 
 17011701                 case EBLOCK:
 17021702                         doblk();
 17031703                         /* FALLTHROUGH */
 17041704                 case IDENT:
 17051705                         /*
 17061706                          * Handle argument concatenation here.
 17071707                          * In case of concatenation, add all blockings.
 17081708                          */
 17091709                         DDPRINT(("%d:exparg ident %d\n", lvl, c));
 17101710                         och = stringbuf;
 17111711                         gmult = 0;
 17121712 
 17131713 sav:                    savstr(yytext);
 17141714 
 17151715                         if ((c = cinput()) == EBLOCK) {
 17161716                                 /* yep, are concatenating; add blocks */
 17171717                                 gmult = 1;
 17181718                                 do {
 17191719                                         donex();
 17201720                                 } while ((c = sloscan()) == EBLOCK);
 17211721                                 goto sav;
 17221722                         }
 17231723                         cunput(c);
 17241724 
 17251725                         DPRINT(("%d:exparg: str '%s'\n", lvl, och));
 17261726                         IMP("EA1");
 17271727                         /* see if ident is expandable */
 17281728                         if ((nl = lookup(och, FIND)) && okexp(nl)) {
 17291729                                 /* Save blocks */
 17301730                                 int donothing;
 17311731                                 unsigned short *svidx =
 17321732                                     malloc(sizeof(int)*(bidx+1));
 17331733                                 int svbidx = bidx;
 17341734 
 17351735                                 for (i = 0; i < bidx; i++)
 17361736                                         svidx[i] = bptr[i];
 17371737                                 if (submac(nl, lvl+1)) {
 17381738                                         /* Could expand, result on lexbuffer */
 17391739                                         stringbuf = och; /* clear saved name */
 17401740                                         anychange = 1;
 17411741                                 }
 17421742                                 donothing = 0;
 17431743                                 c = cinput();
 17441744                                 if (c == 'L') {
 17451745                                         int c2 = cinput();
 17461746                                         if (c2 == '\"' || c2 == '\'')
 17471747                                                 donothing = 1;
 17481748                                         cunput(c2);
 17491749                                 }
 17501750                                 cunput(c);
 17511751 
 17521752                                 if (donothing == 0)
 17531753                                     if (((spechr[c] & C_ID) && c > 63) ||
 17541754                                     c == EBLOCK) {
 17551755                                         for (i = 0; i < svbidx; i++) {
 17561756                                                 cunput(svidx[i] >> 8);
 17571757                                                 cunput(svidx[i] & 255);
 17581758                                                 cunput(EBLOCK);
 17591759                                         }
 17601760                                 }
 17611761                                 free(svidx);
 17621762                         } else if (bidx) {
 17631763                                 /* must restore blocks */
 17641764                                 if (gmult) {
 17651765                                         unpstr(och);
 17661766                                         if (sloscan() != IDENT)
 17671767                                                 error("exparg sync error");
 17681768                                 }
 17691769                                 stringbuf = och;
 17701770                                 for (i = 0; i < bidx; i++)
 17711771                                         savch(EBLOCK), savch(bptr[i] & 255),
 17721772                                             savch(bptr[i] >> 8);
 17731773                                 savstr(yytext);
 17741774                         }
 17751775                         bidx = 0;
 17761776                         IMP("EA2");
 17771777                         break;
 17781778 
 17791779                 case CMNT:
 17801780                         getcmnt();
 17811781                         break;
 17821782 
 17831783                 case '\n':
 17841784                         cinput();
 17851785                         savch(' ');
 17861786                         break;
 17871787 
 17881788                 default:
 17891789                         savstr(yytext);
 17901790                         break;
 17911791                 }
 17921792         }
 17931793         *stringbuf = 0;
 17941794         cunput(WARN);
 17951795         unpstr(osb);
 17961796         DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
 17971797         IMP("EXPRET");
 17981798         stringbuf = osb;
 17991799         if (anychange)
 18001800                 goto rescan;
 18011801         readmac--;
 18021802 }
 18031803 
 18041804 #ifdef PCC_DEBUG
 18051805 static void
 18061806 imp(const char *str)
 18071807 {
 18081808         printf("%s (%d) '", str, bidx);
 18091809         prline(ifiles->curptr);
 18101810         printf("'\n");
 18111811 }
 18121812 
 18131813 static void
 18141814 prrep(const usch *s)
 18151815 {
 18161816         while (*s) {
 18171817                 switch (*s) {
 18181818                 case WARN: printf("<ARG(%d)>", *--s); break;
 18191819                 case CONC: printf("<CONC>"); break;
 18201820                 case SNUFF: printf("<SNUFF>"); break;
 18211821                 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
 18221822                 default: printf("%c", *s); break;
 18231823                 }
 18241824                 s--;
 18251825         }
 18261826 }
 18271827 
 18281828 static void
 18291829 prline(const usch *s)
 18301830 {
 18311831         while (*s) {
 18321832                 switch (*s) {
 18331833                 case WARN: printf("<WARN>"); break;
 18341834                 case CONC: printf("<CONC>"); break;
 18351835                 case SNUFF: printf("<SNUFF>"); break;
 18361836                 case PHOLD: printf("<PHOLD>"); break;
 18371837                 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
 18381838                 case '\n': printf("<NL>"); break;
 18391839                 default: printf("%c", *s); break;
 18401840                 }
 18411841                 s++;
 18421842         }
 18431843 }
 18441844 #endif
 18451845 
 18461846 usch *
 18471847 savstr(const usch *str)
 18481848 {
 18491849         usch *rv = stringbuf;
 18501850 
 18511851         do {
 18521852                 if (stringbuf >= &sbf[SBSIZE])   {
 18531853                         stringbuf = sbf; /* need space to write error message */
 18541854                         error("out of macro space!");
 18551855                 }
 18561856         } while ((*stringbuf++ = *str++));
 18571857         stringbuf--;
 18581858         return rv;
 18591859 }
 18601860 
 18611861 void
 18621862 unpstr(const usch *c)
 18631863 {
 18641864         const usch *d = c;
 18651865 
 18661866 #if 0
 18671867         if (dflag>1) {
 18681868                 printf("Xunpstr: '");
 18691869                 prline(c);
 18701870                 printf("'\n");
 18711871         }
 18721872 #endif
 18731873         while (*d) {
 18741874                 if (*d == EBLOCK)
 18751875                         d += 2;
 18761876                 d++;
 18771877         }
 18781878         while (d > c) {
 18791879                 cunput(*--d);
 18801880         }
 18811881 }
 18821882 
 18831883 static void
 18841884 flbuf(void)
 18851885 {
 18861886         if (obufp == 0)
 18871887                 return;
 18881888         if (Mflag == 0 && write(ofd, outbuf, obufp) < 0)
 18891889                 error("obuf write error");
 18901890         lastoch = outbuf[obufp-1];
 18911891         obufp = 0;
 18921892 }
 18931893 
 18941894 void
 18951895 putch(int ch)
 18961896 {
 18971897         outbuf[obufp++] = (usch)ch;
 18981898         if (obufp == CPPBUF || (istty && ch == '\n'))
 18991899                 flbuf();
 19001900 }
 19011901 
 19021902 void
 19031903 putstr(const usch *s)
 19041904 {
 19051905         for (; *s; s++) {
 19061906                 if (*s == PHOLD)
 19071907                         continue;
 19081908                 outbuf[obufp++] = *s;
 19091909                 if (obufp == CPPBUF || (istty && *s == '\n'))
 19101910                         flbuf();
 19111911         }
 19121912 }
 19131913 
 19141914 /*
 19151915  * convert a number to an ascii string. Store it on the heap.
 19161916  */
 19171917 static void
 19181918 num2str(int num)
 19191919 {
 19201920         static usch buf[12];
 19211921         usch *b = buf;
 19221922         int m = 0;
 19231923         
 19241924         if (num < 0)
 19251925                 num = -num, m = 1;
 19261926         do {
 19271927                 *b++ = (usch)(num % 10 + '0');
 19281928                 num /= 10;
 19291929         } while (num);
 19301930         if (m)
 19311931                 *b++ = '-';
 19321932         while (b > buf)
 19331933                 savch(*--b);
 19341934 }
 19351935 
 19361936 /*
 19371937  * similar to sprintf, but only handles %s and %d.
 19381938  * saves result on heap.
 19391939  */
 19401940 usch *
 19411941 sheap(const char *fmt, ...)
 19421942 {
 19431943         va_list ap;
 19441944         usch *op = stringbuf;
 19451945 
 19461946         va_start(ap, fmt);
 19471947         for (; *fmt; fmt++) {
 19481948                 if (*fmt == '%') {
 19491949                         fmt++;
 19501950                         switch (*fmt) {
 19511951                         case 's':
 19521952                                 savstr(va_arg(ap, usch *));
 19531953                                 break;
 19541954                         case 'd':
 19551955                                 num2str(va_arg(ap, int));
 19561956                                 break;
 19571957                         case 'c':
 19581958                                 savch(va_arg(ap, int));
 19591959                                 break;
 19601960                         default:
 19611961                                 break; /* cannot call error() here */
 19621962                         }
 19631963                 } else
 19641964                         savch(*fmt);
 19651965         }
 19661966         va_end(ap);
 19671967         *stringbuf = 0;
 19681968         return op;
 19691969 }
 19701970 
 19711971 static void
 19721972 usage(void)
 19731973 {
 19741974         error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
 19751975 }
 19761976 
 19771977 #ifdef notyet
 19781978 /*
 19791979  * Symbol table stuff.
 19801980  * The data structure used is a patricia tree implementation using only
 19811981  * bytes to store offsets. 
 19821982  * The information stored is (lower address to higher):
 19831983  *
 19841984  *      unsigned char bitno[2]; bit number in the string
 19851985  *      unsigned char left[3];  offset from base to left element
 19861986  *      unsigned char right[3]; offset from base to right element
 19871987  */
 19881988 #endif
 19891989 
 19901990 /*
 19911991  * This patricia implementation is more-or-less the same as
 19921992  * used in ccom for string matching.
 19931993  */
 19941994 struct tree {
 19951995         int bitno;
 19961996         struct tree *lr[2];
 19971997 };
 19981998 
 19991999 #define BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
 20002000 #define LEFT_IS_LEAF            0x80000000
 20012001 #define RIGHT_IS_LEAF           0x40000000
 20022002 #define IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
 20032003 #define IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
 20042004 #define P_BIT(key, bit)         (key[bit >> 3] >> (bit & 7)) & 1
 20052005 #define CHECKBITS               8
 20062006 
 20072007 static struct tree *sympole;
 20082008 static int numsyms;
 20092009 
 20102010 /*
 20112011  * Allocate a symtab struct and store the string.
 20122012  */
 20132013 static struct symtab *
 20142014 getsymtab(const usch *str)
 20152015 {
 20162016         struct symtab *sp = malloc(sizeof(struct symtab));
 20172017 
 20182018         if (sp == NULL)
 20192019                 error("getsymtab: couldn't allocate symtab");
 20202020         sp->namep = savstr(str);
 20212021         savch('\0');
 20222022         sp->value = NULL;
 20232023         sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
 20242024         sp->line = ifiles ? ifiles->lineno : 0;
 20252025         return sp;
 20262026 }
 20272027 
 20282028 /*
 20292029  * Do symbol lookup in a patricia tree.
 20302030  * Only do full string matching, no pointer optimisations.
 20312031  */
 20322032 struct symtab *
 20332033 lookup(const usch *key, int enterf)
 20342034 {
 20352035         struct symtab *sp;
 20362036         struct tree *w, *new, *last;
 20372037         int len, cix, bit, fbit, svbit, ix, bitno;
 20382038         const usch *k, *m;
 20392039 
 20402040         /* Count full string length */
 20412041         for (k = key, len = 0; *k; k++, len++)
 20422042                 ;
 20432043 
 20442044         switch (numsyms) {
 20452045         case 0: /* no symbols yet */
 20462046                 if (enterf != ENTER)
 20472047                         return NULL;
 20482048                 sympole = (struct tree *)getsymtab(key);
 20492049                 numsyms++;
 20502050                 return (struct symtab *)sympole;
 20512051 
 20522052         case 1:
 20532053                 w = sympole;
 20542054                 svbit = 0; /* XXX gcc */
 20552055                 break;
 20562056 
 20572057         default:
 20582058                 w = sympole;
 20592059                 bitno = len * CHECKBITS;
 20602060                 for (;;) {
 20612061                         bit = BITNO(w->bitno);
 20622062                         fbit = bit > bitno ? 0 : P_BIT(key, bit);
 20632063                         svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
 20642064                             IS_LEFT_LEAF(w->bitno);
 20652065                         w = w->lr[fbit];
 20662066                         if (svbit)
 20672067                                 break;
 20682068                 }
 20692069         }
 20702070 
 20712071         sp = (struct symtab *)w;
 20722072 
 20732073         m = sp->namep;
 20742074         k = key;
 20752075 
 20762076         /* Check for correct string and return */
 20772077         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
 20782078                 ;
 20792079         if (*m == 0 && *k == 0) {
 20802080                 if (enterf != ENTER && sp->value == NULL)
 20812081                         return NULL;
 20822082                 return sp;
 20832083         }
 20842084 
 20852085         if (enterf != ENTER)
 20862086                 return NULL; /* no string found and do not enter */
 20872087 
 20882088         ix = *m ^ *k;
 20892089         while ((ix & 1) == 0)
 20902090                 ix >>= 1, cix++;
 20912091 
 20922092         /* Create new node */
 20932093         if ((new = malloc(sizeof *new)) == NULL)
 20942094                 error("getree: couldn't allocate tree");
 20952095         bit = P_BIT(key, cix);
 20962096         new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 20972097         new->lr[bit] = (struct tree *)getsymtab(key);
 20982098 
 20992099         if (numsyms++ == 1) {
 21002100                 new->lr[!bit] = sympole;
 21012101                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21022102                 sympole = new;
 21032103                 return (struct symtab *)new->lr[bit];
 21042104         }
 21052105 
 21062106         w = sympole;
 21072107         last = NULL;
 21082108         for (;;) {
 21092109                 fbit = w->bitno;
 21102110                 bitno = BITNO(w->bitno);
 21112111                 if (bitno == cix)
 21122112                         error("bitno == cix");
 21132113                 if (bitno > cix)
 21142114                         break;
 21152115                 svbit = P_BIT(key, bitno);
 21162116                 last = w;
 21172117                 w = w->lr[svbit];
 21182118                 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
 21192119                         break;
 21202120         }
 21212121 
 21222122         new->lr[!bit] = w;
 21232123         if (last == NULL) {
 21242124                 sympole = new;
 21252125         } else {
 21262126                 last->lr[svbit] = new;
 21272127                 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21282128         }
 21292129         if (bitno < cix)
 21302130                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21312131         return (struct symtab *)new->lr[bit];
 21322132 }
 21332133 
 21342134 static usch *
 21352135 xstrdup(const usch *str)
 21362136 {
 21372137         size_t len = strlen((const char *)str)+1;
 21382138         usch *rv;
 21392139 
 21402140         if ((rv = malloc(len)) == NULL)
 21412141                 error("xstrdup: out of mem");
 21422142         strlcpy((char *)rv, (const char *)str, len);
 21432143         return rv;
 21442144 }
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-08-23 20:11 +0200