Quick Search:

Mode

Context

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

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.186
 
1.187
 
MAIN:plunky:20121108111403
 
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], lastoch;
 8080 int obufp, istty;
<>81 -int Cflag, Mflag, dMflag, Pflag, MPflag;
  81+int Cflag, Eflag, Mflag, dMflag, Pflag, MPflag;
8282 usch *Mfile, *MPfile, *Mxfile;
 8383 struct initar *initar;
 8484 int readmac;
 8585 int defining;
<> 86+int warnings;
8687 
 8788 /* include dirs */
 8889 struct incs {
 8990         struct incs *next;
 9091         usch *dir;
 9192         dev_t dev;
 9293         ino_t ino;
 9394 } *incdir[2];
 9495 
 9596 static struct symtab *filloc;
 9697 static struct symtab *linloc;
 9798 static struct symtab *pragloc;
 9899 int     trulvl;
 99100 int     flslvl;
 100101 int     elflvl;
 101102 int     elslvl;
 102103 usch *stringbuf = sbf;
 103104 
 104105 /*
 105106  * Macro replacement list syntax:
 106107  * - For object-type macros, replacement strings are stored as-is.
 107108  * - For function-type macros, macro args are substituted for the
 108109  *   character WARN followed by the argument number.
 109110  * - The value element points to the end of the string, to simplify
 110111  *   pushback onto the input queue.
 111112  *
 112113  * The first character (from the end) in the replacement list is
 113114  * the number of arguments:
 114115  *   VARG  - ends with ellipsis, next char is argcount without ellips.
 115116  *   OBJCT - object-type macro
 116117  *   0     - empty parenthesis, foo()
 117118  *   1->   - number of args.
 118119  *
 119120  * WARN is used:
 120121  *      - in stored replacement lists to tell that an argument comes
 121122  *      - When expanding replacement lists to tell that the list ended.
 122123  *
 123124  * To ensure that an already expanded identifier won't get expanded
 124125  * again a EBLOCK char + its number is stored directly before any
 125126  * expanded identifier.
 126127  */
 127128 
 128129 /* args for lookup() */
 129130 #define FIND    0
 130131 #define ENTER   1
 131132 
 132133 /*
 133134  * No-replacement array.  If a macro is found and exists in this array
 134135  * then no replacement shall occur.  This is a stack.
 135136  */
 136137 struct symtab *norep[RECMAX];   /* Symbol table index table */
 137138 int norepptr = 1;                       /* Top of index table */
 138139 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
 139140 int bidx;                       /* Top of bptr stack */
 140141 
 141142 static int readargs(struct symtab *sp, const usch **args);
 142143 static void exparg(int);
 143144 static void subarg(struct symtab *sp, const usch **args, int);
 144145 static void flbuf(void);
 145146 static void usage(void);
 146147 static usch *xstrdup(const usch *str);
 147148 static void addidir(char *idir, struct incs **ww);
 148149 static void vsheap(const char *, va_list);
 149150 
 150151 int
 151152 main(int argc, char **argv)
 152153 {
 153154         struct initar *it;
 154155         struct symtab *nl;
 155156         register int ch;
 156157         const usch *fn1, *fn2;
 157158 
 158159 #ifdef TIMING
 159160         struct timeval t1, t2;
 160161 
 161162         (void)gettimeofday(&t1, NULL);
 162163 #endif
 163164 
<>164 -        while ((ch = getopt(argc, argv, "CD:d:I:i:MPS:tU:Vvx:")) != -1) {
  165+        while ((ch = getopt(argc, argv, "CD:d:EI:i:MPS:tU:Vvx:")) != -1) {
165166                 switch (ch) {
 166167                 case 'C': /* Do not discard comments */
 167168                         Cflag++;
 168169                         break;
 169170 
<> 171+                case 'E': /* treat warnings as errors */
  172+                        Eflag++;
  173+                        break;
  174+
170175                 case 'D': /* define something */
 171176                 case 'i': /* include */
 172177                 case 'U': /* undef */
 173178                         /* XXX should not need malloc() here */
 174179                         if ((it = malloc(sizeof(struct initar))) == NULL)
 175180                                 error("couldn't apply -%c %s", ch, optarg);
 176181                         it->type = ch;
 177182                         it->str = optarg;
 178183                         it->next = initar;
 179184                         initar = it;
 180185                         break;
 181186 
 182187                 case 'd':
 183188                         while (*optarg) {
 184189                                 switch(*optarg) {
 185190                                 case 'M': /* display macro definitions */
 186191                                         dMflag = 1;
 187192                                         Mflag = 1;
 188193                                         break;
 189194 
 190195                                 default: /* ignore others */
 191196                                         break;
 192197                                 }
 193198                                 optarg++;
 194199                         }
 195200                         break;
 196201 
 197202                 case 'I':
 198203                 case 'S':
 199204                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
 200205                         break;
 201206 
 202207                 case 'M': /* Generate dependencies for make */
 203208                         Mflag++;
 204209                         break;
 205210 
 206211                 case 'P': /* Inhibit generation of line numbers */
 207212                         Pflag++;
 208213                         break;
 209214 
 210215                 case 't':
 211216                         tflag = 1;
 212217                         break;
 213218 
 214219 #ifdef PCC_DEBUG
 215220                 case 'V':
 216221                         dflag++;
 217222                         break;
 218223 #endif
 219224                 case 'v':
 220225                         xwrite(2, versstr, sizeof(versstr) - 1);
 221226                         break;
 222227 
 223228                 case 'x':
 224229                         if (strcmp(optarg, "MP") == 0) {
 225230                                 MPflag++;
 226231                         } else if (strncmp(optarg, "MT,", 3) == 0 ||
 227232                             strncmp(optarg, "MQ,", 3) == 0) {
 228233                                 usch *cp, *fn;
 229234                                 fn = stringbuf;
 230235                                 for (cp = (usch *)&optarg[3]; *cp; cp++) {
 231236                                         if (*cp == '$' && optarg[1] == 'Q')
 232237                                                 savch('$');
 233238                                         savch(*cp);
 234239                                 }
 235240                                 savstr((const usch *)"");
 236241                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
 237242                                 savch(0);
 238243                                 Mxfile = fn;
 239244                         } else
 240245                                 usage();
 241246                         break;
 242247 
 243248                 case '?':
 244249                 default:
 245250                         usage();
 246251                 }
 247252         }
 248253 
 249254         argc -= optind;
 250255         argv += optind;
 251256 
 252257         filloc = lookup((const usch *)"__FILE__", ENTER);
 253258         linloc = lookup((const usch *)"__LINE__", ENTER);
 254259         filloc->value = linloc->value = stringbuf;
 255260         savch(OBJCT);
 256261 
 257262         /* create a complete macro for pragma */
 258263         pragloc = lookup((const usch *)"_Pragma", ENTER);
 259264         savch(0);
 260265         savstr((const usch *)"_Pragma(");
 261266         savch(0);
 262267         savch(WARN);
 263268         savch(')');
 264269         pragloc->value = stringbuf;
 265270         savch(1);
 266271 
 267272         if (tflag == 0) {
 268273                 time_t t = time(NULL);
 269274                 usch *n = (usch *)ctime(&t);
 270275 
 271276                 /*
 272277                  * Manually move in the predefined macros.
 273278                  */
 274279                 nl = lookup((const usch *)"__TIME__", ENTER);
 275280                 savch(0); savch('"');  n[19] = 0; savstr(&n[11]); savch('"');
 276281                 savch(OBJCT);
 277282                 nl->value = stringbuf-1;
 278283 
 279284                 nl = lookup((const usch *)"__DATE__", ENTER);
 280285                 savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
 281286                 savstr(&n[20]); savch('"'); savch(OBJCT);
 282287                 nl->value = stringbuf-1;
 283288 
 284289                 nl = lookup((const usch *)"__STDC__", ENTER);
 285290                 savch(0); savch('1'); savch(OBJCT);
 286291                 nl->value = stringbuf-1;
 287292 
 288293                 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
 289294                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
 290295                 nl->value = stringbuf-1;
 291296         }
 292297 
 293298         if (Mflag && !dMflag) {
 294299                 usch *c;
 295300 
 296301                 if (argc < 1)
 297302                         error("-M and no infile");
 298303                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
 299304                         c = (usch *)argv[0];
 300305                 else
 301306                         c++;
 302307                 Mfile = stringbuf;
 303308                 savstr(c); savch(0);
 304309                 if (MPflag) {
 305310                         MPfile = stringbuf;
 306311                         savstr(c); savch(0);
 307312                 }
 308313                 if (Mxfile)
 309314                         Mfile = Mxfile;
 310315                 if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
 311316                         error("-M and no extension: ");
 312317                 c[1] = 'o';
 313318                 c[2] = 0;
 314319         }
 315320 
 316321         if (argc == 2) {
 317322                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
 318323                         error("Can't creat %s", argv[1]);
 319324         } else
 320325                 ofd = 1; /* stdout */
 321326         istty = isatty(ofd);
 322327 
 323328         if (argc && strcmp(argv[0], "-")) {
 324329                 fn1 = fn2 = (usch *)argv[0];
 325330         } else {
 326331                 fn1 = NULL;
 327332                 fn2 = (const usch *)"";
 328333         }
 329334         if (pushfile(fn1, fn2, 0, NULL))
 330335                 error("cannot open %s", argv[0]);
 331336 
 332337         flbuf();
 333338         close(ofd);
 334339 #ifdef TIMING
 335340         (void)gettimeofday(&t2, NULL);
 336341         t2.tv_sec -= t1.tv_sec;
 337342         t2.tv_usec -= t1.tv_usec;
 338343         if (t2.tv_usec < 0) {
 339344                 t2.tv_usec += 1000000;
 340345                 t2.tv_sec -= 1;
 341346         }
 342347         fprintf(stderr, "cpp total time: %ld s %ld us\n",
 343348              (long)t2.tv_sec, (long)t2.tv_usec);
 344349 #endif
<> 350+        if (Eflag && warnings > 0)
  351+                return 2;
  352+
345353         return 0;
 346354 }
 347355 
 348356 static void
 349357 addidir(char *idir, struct incs **ww)
 350358 {
 351359         struct incs *w;
 352360         struct stat st;
 353361 
 354362         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
 355363                 return; /* ignore */
 356364         if (*ww != NULL) {
 357365                 for (w = *ww; w->next; w = w->next) {
 358366 #ifdef os_win32
 359367                         if (strcmp(w->dir, idir) == 0)
 360368                                 return;
 361369 #else
 362370                         if (w->dev == st.st_dev && w->ino == st.st_ino)
 363371                                 return;
 364372 #endif
 365373                 }
 366374 #ifdef os_win32
 367375                 if (strcmp(w->dir, idir) == 0)
 368376                         return;
 369377 #else
 370378                 if (w->dev == st.st_dev && w->ino == st.st_ino)
 371379                         return;
 372380 #endif
 373381                 ww = &w->next;
 374382         }
 375383         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
 376384                 error("couldn't add path %s", idir);
 377385         w->dir = (usch *)idir;
 378386         w->dev = st.st_dev;
 379387         w->ino = st.st_ino;
 380388         *ww = w;
 381389 }
 382390 
 383391 void
 384392 line(void)
 385393 {
 386394         static usch *lbuf;
 387395         static int llen;
 388396         usch *p;
 389397         int c;
 390398 
 391399         if ((c = yylex()) != NUMBER)
 392400                 goto bad;
 393401         ifiles->lineno = (int)(yylval.node.nd_val - 1);
 394402         ifiles->escln = 0;
 395403 
 396404         if ((c = yylex()) == '\n')
 397405                 goto okret;
 398406 
 399407         if (c != STRING)
 400408                 goto bad;
 401409 
 402410         p = yytext;
 403411         if (*p++ == 'L')
 404412                 p++;
 405413         c = strlen((char *)p);
 406414         p[c - 1] = '\0';
 407415         if (llen < c) {
 408416                 /* XXX may lose heap space */
 409417                 lbuf = stringbuf;
 410418                 stringbuf += c;
 411419                 llen = c;
 412420                 if (stringbuf >= &sbf[SBSIZE]) {
 413421                         stringbuf = sbf; /* need space to write error message */
 414422                         error("#line filename exceeds buffer size");
 415423                 }
 416424         }
 417425         memcpy(lbuf, p, c);
 418426         ifiles->fname = lbuf;
 419427         if (yylex() != '\n')
 420428                 goto bad;
 421429 
 422430 okret:  prtline();
 423431         return;
 424432 
 425433 bad:    error("bad #line");
 426434 }
 427435 
 428436 /*
 429437  * Search for and include next file.
 430438  * Return 1 on success.
 431439  */
 432440 static int
 433441 fsrch(const usch *fn, int idx, struct incs *w)
 434442 {
 435443         int i;
 436444 
 437445         for (i = idx; i < 2; i++) {
 438446                 if (i > idx)
 439447                         w = incdir[i];
 440448                 for (; w; w = w->next) {
 441449                         usch *nm = stringbuf;
 442450 
 443451                         savstr(w->dir); savch('/');
 444452                         savstr(fn); savch(0);
 445453                         if (pushfile(nm, fn, i, w->next) == 0)
 446454                                 return 1;
 447455                         stringbuf = nm;
 448456                 }
 449457         }
 450458         return 0;
 451459 }
 452460 
 453461 static void
 454462 prem(void)
 455463 {
 456464         error("premature EOF");
 457465 }
 458466 
 459467 /*
 460468  * Include a file. Include order:
 461469  * - For <...> files, first search -I directories, then system directories.
 462470  * - For "..." files, first search "current" dir, then as <...> files.
 463471  */
 464472 void
 465473 include(void)
 466474 {
 467475         struct symtab *nl;
 468476         usch *osp;
 469477         usch *fn, *safefn;
 470478         int c;
 471479 
 472480         if (flslvl)
 473481                 return;
 474482         osp = stringbuf;
 475483 
 476484         while ((c = sloscan()) == WSPACE)
 477485                 ;
 478486         if (c == IDENT) {
 479487                 /* sloscan() will not expand idents */
 480488                 if ((nl = lookup(yytext, FIND)) == NULL)
 481489                         goto bad;
 482490                 if (kfind(nl))
 483491                         unpstr(stringbuf);
 484492                 else
 485493                         unpstr(nl->namep);
 486494                 stringbuf = osp;
 487495                 c = yylex();
 488496         }
 489497 
 490498         if (c == '<') {
 491499                 fn = stringbuf;
 492500                 while ((c = sloscan()) != '>') {
 493501                         if (c == 0)
 494502                                 prem();
 495503                         if (c == '\n')
 496504                                 goto bad;
 497505                         savstr(yytext);
 498506                 }
 499507                 savch('\0');
 500508                 while ((c = sloscan()) == WSPACE)
 501509                         ;
 502510                 if (c == 0)
 503511                         prem();
 504512                 if (c != '\n')
 505513                         goto bad;
 506514                 safefn = fn;
 507515         } else if (c == STRING) {
 508516                 usch *nm = stringbuf;
 509517 
 510518                 fn = yytext;
 511519                 if (*fn++ == 'L')
 512520                         fn++;
 513521                 fn[strlen((char *)fn) - 1] = 0;
 514522                 /* first try to open file relative to previous file */
 515523                 /* but only if it is not an absolute path */
 516524                 if (*fn != '/') {
 517525                         savstr(ifiles->orgfn);
 518526                         if ((stringbuf =
 519527                             (usch *)strrchr((char *)nm, '/')) == NULL)
 520528                                 stringbuf = nm;
 521529                         else
 522530                                 stringbuf++;
 523531                 }
 524532                 safefn = stringbuf;
 525533                 savstr(fn); savch(0);
 526534                 c = yylex();
 527535                 if (c == 0)
 528536                         prem();
 529537                 if (c != '\n')
 530538                         goto bad;
 531539                 if (pushfile(nm, safefn, 0, NULL) == 0)
 532540                         goto okret;
 533541                 /* XXX may lose stringbuf space */
 534542         } else
 535543                 goto bad;
 536544 
 537545         if (fsrch(safefn, 0, incdir[0]))
 538546                 goto okret;
 539547 
 540548         error("cannot find '%s'", safefn);
 541549         /* error() do not return */
 542550 
 543551 bad:    error("bad #include");
 544552         /* error() do not return */
 545553 okret:
 546554         prtline();
 547555 }
 548556 
 549557 void
 550558 include_next(void)
 551559 {
 552560         struct symtab *nl;
 553561         usch *osp;
 554562         usch *fn;
 555563         int c;
 556564 
 557565         if (flslvl)
 558566                 return;
 559567         osp = stringbuf;
 560568         while ((c = sloscan()) == WSPACE)
 561569                 ;
 562570         if (c == IDENT) {
 563571                 /* sloscan() will not expand idents */
 564572                 if ((nl = lookup(yytext, FIND)) == NULL)
 565573                         goto bad;
 566574                 if (kfind(nl))
 567575                         unpstr(stringbuf);
 568576                 else
 569577                         unpstr(nl->namep);
 570578                 stringbuf = osp;
 571579                 c = yylex();
 572580         }
 573581         if (c != STRING && c != '<')
 574582                 goto bad;
 575583 
 576584         fn = stringbuf;
 577585         if (c == STRING) {
 578586                 savstr(&yytext[1]);
 579587                 stringbuf[-1] = 0;
 580588         } else { /* < > */
 581589                 while ((c = sloscan()) != '>') {
 582590                         if (c == '\n')
 583591                                 goto bad;
 584592                         savstr(yytext);
 585593                 }
 586594                 savch('\0');
 587595         }
 588596         while ((c = sloscan()) == WSPACE)
 589597                 ;
 590598         if (c != '\n')
 591599                 goto bad;
 592600 
 593601         if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
 594602                 error("cannot find '%s'", fn);
 595603         prtline();
 596604         return;
 597605 
 598606 bad:    error("bad #include_next");
 599607         /* error() do not return */
 600608 }
 601609 
 602610 static int
 603611 definp(void)
 604612 {
 605613         int c;
 606614 
 607615         do
 608616                 c = sloscan();
 609617         while (c == WSPACE);
 610618         return c;
 611619 }
 612620 
 613621 void
 614622 getcmnt(void)
 615623 {
 616624         int c;
 617625 
 618626         savstr(yytext);
 619627         savch(cinput()); /* Lost * */
 620628         for (;;) {
 621629                 c = cinput();
 622630                 if (c == '*') {
 623631                         c = cinput();
 624632                         if (c == '/') {
 625633                                 savstr((const usch *)"*/");
 626634                                 return;
 627635                         }
 628636                         cunput(c);
 629637                         c = '*';
 630638                 }
 631639                 savch(c);
 632640         }
 633641 }
 634642 
 635643 /*
 636644  * Compare two replacement lists, taking in account comments etc.
 637645  */
 638646 static int
 639647 cmprepl(const usch *o, const usch *n)
 640648 {
 641649         for (; *o; o--, n--) {
 642650                 /* comment skip */
 643651                 if (*o == '/' && o[-1] == '*') {
 644652                         while (*o != '*' || o[-1] != '/')
 645653                                 o--;
 646654                         o -= 2;
 647655                 }
 648656                 if (*n == '/' && n[-1] == '*') {
 649657                         while (*n != '*' || n[-1] != '/')
 650658                                 n--;
 651659                         n -= 2;
 652660                 }
 653661                 while (*o == ' ' || *o == '\t')
 654662                         o--;
 655663                 while (*n == ' ' || *n == '\t')
 656664                         n--;
 657665                 if (*o != *n)
 658666                         return 1;
 659667         }
 660668         return 0;
 661669 }
 662670 
 663671 static int
 664672 isell(void)
 665673 {
 666674         int ch;
 667675 
 668676         if ((ch = cinput()) != '.') {
 669677                 cunput(ch);
 670678                 return 0;
 671679         }
 672680         if ((ch = cinput()) != '.') {
 673681                 cunput(ch);
 674682                 cunput('.');
 675683                 return 0;
 676684         }
 677685         return 1;
 678686 }
 679687 
 680688 void
 681689 define(void)
 682690 {
 683691         struct symtab *np;
 684692         usch *args[MAXARGS+1], *ubuf, *sbeg;
 685693         int c, i, redef;
 686694         int mkstr = 0, narg = -1;
 687695         int ellips = 0;
 688696 #ifdef GCC_COMPAT
 689697         usch *gccvari = NULL;
 690698         int wascon;
 691699 #endif
 692700 
 693701         if (flslvl)
 694702                 return;
 695703         if (sloscan() != WSPACE || sloscan() != IDENT)
 696704                 goto bad;
 697705 
 698706         np = lookup(yytext, ENTER);
 699707         redef = np->value != NULL;
 700708 
 701709         defining = readmac = 1;
 702710         sbeg = stringbuf;
 703711         if ((c = sloscan()) == '(') {
 704712                 narg = 0;
 705713                 /* function-like macros, deal with identifiers */
 706714                 c = definp();
 707715                 for (;;) {
 708716                         if (c == ')')
 709717                                 break;
 710718                         if (c == '.' && isell()) {
 711719                                 ellips = 1;
 712720                                 if (definp() != ')')
 713721                                         goto bad;
 714722                                 break;
 715723                         }
 716724                         if (c == IDENT) {
 717725                                 /* make sure there is no arg of same name */
 718726                                 for (i = 0; i < narg; i++)
 719727                                         if (!strcmp((char *) args[i], (char *)yytext))
 720728                                                 error("Duplicate macro "
 721729                                                   "parameter \"%s\"", yytext);
 722730                                 if (narg == MAXARGS)
 723731                                         error("Too many macro args");
 724732                                 args[narg++] = xstrdup(yytext);
 725733                                 if ((c = definp()) == ',') {
 726734                                         if ((c = definp()) == ')')
 727735                                                 goto bad;
 728736                                         continue;
 729737                                 }
 730738 #ifdef GCC_COMPAT
 731739                                 if (c == '.' && isell()) {
 732740                                         if (definp() != ')')
 733741                                                 goto bad;
 734742                                         gccvari = args[--narg];
 735743                                         break;
 736744                                 }
 737745 #endif
 738746                                 if (c == ')')
 739747                                         break;
 740748                         }
 741749                         goto bad;
 742750                 }
 743751                 c = sloscan();
 744752         } else if (c == '\n') {
 745753                 /* #define foo */
 746754                 ;
 747755         } else if (c == 0) {
 748756                 prem();
 749757         } else if (c != WSPACE)
 750758                 goto bad;
 751759 
 752760         while (c == WSPACE)
 753761                 c = sloscan();
 754762 
 755763         /* replacement list cannot start with ## operator */
 756764         if (c == '#') {
 757765                 if ((c = sloscan()) == '#')
 758766                         goto bad;
 759767                 savch('\0');
 760768 #ifdef GCC_COMPAT
 761769                 wascon = 0;
 762770 #endif
 763771                 goto in2;
 764772         }
 765773 
 766774         /* parse replacement-list, substituting arguments */
 767775         savch('\0');
 768776         while (c != '\n') {
 769777 #ifdef GCC_COMPAT
 770778                 wascon = 0;
 771779 loop:
 772780 #endif
 773781                 switch (c) {
 774782                 case WSPACE:
 775783                         /* remove spaces if it surrounds a ## directive */
 776784                         ubuf = stringbuf;
 777785                         savstr(yytext);
 778786                         c = sloscan();
 779787                         if (c == '#') {
 780788                                 if ((c = sloscan()) != '#')
 781789                                         goto in2;
 782790                                 stringbuf = ubuf;
 783791                                 savch(CONC);
 784792                                 if ((c = sloscan()) == WSPACE)
 785793                                         c = sloscan();
 786794 #ifdef GCC_COMPAT
 787795                                 if (c == '\n')
 788796                                         break;
 789797                                 wascon = 1;
 790798                                 goto loop;
 791799 #endif
 792800                         }
 793801                         continue;
 794802 
 795803                 case '#':
 796804                         c = sloscan();
 797805                         if (c == '#') {
 798806                                 /* concat op */
 799807                                 savch(CONC);
 800808                                 if ((c = sloscan()) == WSPACE)
 801809                                         c = sloscan();
 802810 #ifdef GCC_COMPAT
 803811                                 if (c == '\n')
 804812                                         break;
 805813                                 wascon = 1;
 806814                                 goto loop;
 807815 #else
 808816                                 continue;
 809817 #endif
 810818                         }
 811819 in2:                    if (narg < 0) {
 812820                                 /* no meaning in object-type macro */
 813821                                 savch('#');
 814822                                 continue;
 815823                         }
 816824                         /* remove spaces between # and arg */
 817825                         savch(SNUFF);
 818826                         if (c == WSPACE)
 819827                                 c = sloscan(); /* whitespace, ignore */
 820828                         mkstr = 1;
 821829                         if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
 822830                                 continue;
 823831 
 824832                         /* FALLTHROUGH */
 825833                 case IDENT:
 826834                         if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
 827835                                 if (ellips == 0)
 828836                                         error("unwanted %s", yytext);
 829837 #ifdef GCC_COMPAT
 830838                                 savch(wascon ? GCCARG : VARG);
 831839 #else
 832840                                 savch(VARG);
 833841 #endif
 834842 
 835843                                 savch(WARN);
 836844                                 if (mkstr)
 837845                                         savch(SNUFF), mkstr = 0;
 838846                                 break;
 839847                         }
 840848                         if (narg < 0)
 841849                                 goto id; /* just add it if object */
 842850                         /* check if its an argument */
 843851                         for (i = 0; i < narg; i++)
 844852                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
 845853                                         break;
 846854                         if (i == narg) {
 847855 #ifdef GCC_COMPAT
 848856                                 if (gccvari &&
 849857                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
 850858                                         savch(wascon ? GCCARG : VARG);
 851859                                         savch(WARN);
 852860                                         if (mkstr)
 853861                                                 savch(SNUFF), mkstr = 0;
 854862                                         break;
 855863                                 }
 856864 #endif
 857865                                 if (mkstr)
 858866                                         error("not argument");
 859867                                 goto id;
 860868                         }
 861869                         savch(i);
 862870                         savch(WARN);
 863871                         if (mkstr)
 864872                                 savch(SNUFF), mkstr = 0;
 865873                         break;
 866874 
 867875                 case CMNT: /* save comments */
 868876                         getcmnt();
 869877                         break;
 870878 
 871879                 case 0:
 872880                         prem();
 873881 
 874882                 default:
 875883 id:                     savstr(yytext);
 876884                         break;
 877885                 }
 878886                 c = sloscan();
 879887         }
 880888         defining = readmac = 0;
 881889         /* remove trailing whitespace */
 882890         while (stringbuf > sbeg) {
 883891                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
 884892                         stringbuf--;
 885893                 /* replacement list cannot end with ## operator */
 886894                 else if (stringbuf[-1] == CONC)
 887895                         goto bad;
 888896                 else
 889897                         break;
 890898         }
 891899 #ifdef GCC_COMPAT
 892900         if (gccvari) {
 893901                 savch(narg);
 894902                 savch(VARG);
 895903         } else
 896904 #endif
 897905         if (ellips) {
 898906                 savch(narg);
 899907                 savch(VARG);
 900908         } else
 901909                 savch(narg < 0 ? OBJCT : narg);
 902910         if (redef && ifiles->idx != SYSINC) {
 903911                 if (cmprepl(np->value, stringbuf-1)) {
 904912                         sbeg = stringbuf;
 905913                         np->value = stringbuf-1;
 906914                         warning("%s redefined (previously defined at \"%s\" line %d)",
 907915                             np->namep, np->file, np->line);
 908916                 }
 909917                 stringbuf = sbeg/* forget this space */
 910918         } else
 911919                 np->value = stringbuf-1;
 912920 
 913921 #ifdef PCC_DEBUG
 914922         if (dflag) {
 915923                 const usch *w = np->value;
 916924 
 917925                 printf("!define: ");
 918926                 if (*w == OBJCT)
 919927                         printf("[object]");
 920928                 else if (*w == VARG)
 921929                         printf("[VARG%d]", *--w);
 922930                 while (*--w) {
 923931                         switch (*w) {
 924932                         case WARN: printf("<%d>", *--w); break;
 925933                         case CONC: printf("<##>"); break;
 926934                         case SNUFF: printf("<\">"); break;
 927935                         default: putchar(*w); break;
 928936                         }
 929937                 }
 930938                 putchar('\n');
 931939         }
 932940 #endif
 933941         for (i = 0; i < narg; i++)
 934942                 free(args[i]);
 935943         return;
 936944 
 937945 bad:    error("bad #define");
 938946 }
 939947 
 940948 void
 941949 warning(const char *fmt, ...)
 942950 {
 943951         va_list ap;
 944952         usch *sb;
 945953 
 946954         flbuf();
 947955         savch(0);
 948956 
 949957         sb = stringbuf;
 950958         if (ifiles != NULL)
 951959                 sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
 952960 
 953961         va_start(ap, fmt);
 954962         vsheap(fmt, ap);
 955963         va_end(ap);
 956964         savch('\n');
 957965         xwrite(2, sb, stringbuf - sb);
 958966         stringbuf = sb;
<> 967+
  968+        warnings++;
<_959969 }
 960970 
 961971 void
 962972 error(const char *fmt, ...)
 963973 {
 964974         va_list ap;
 965975         usch *sb;
 966976 
 967977         flbuf();
 968978         savch(0);
 969979 
 970980         sb = stringbuf;
 971981         if (ifiles != NULL)
 972982                 sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
 973983 
 974984         va_start(ap, fmt);
 975985         vsheap(fmt, ap);
 976986         va_end(ap);
 977987         savch('\n');
 978988         xwrite(2, sb, stringbuf - sb);
 979989         stringbuf = sb;
 980990 
 981991         exit(1);
 982992 }
 983993 
 984994 static void
 985995 sss(void)
 986996 {
 987997         savch(EBLOCK);
 988998         savch(cinput());
 989999         savch(cinput());
 9901000 }
 9911001 
 9921002 static int
 9931003 addmac(struct symtab *sp)
 9941004 {
 9951005         int c, i;
 9961006 
 9971007         /* Check if it exists; then save some space */
 9981008         /* May be more difficult to debug cpp */
 9991009         for (i = 1; i < norepptr; i++)
 10001010                 if (norep[i] == sp)
 10011011                         return i;
 10021012         if (norepptr >= RECMAX)
 10031013                 error("too many macros");
 10041014         /* check norepptr */
 10051015         if ((norepptr & 255) == 0)
 10061016                 norepptr++;
 10071017         if (((norepptr >> 8) & 255) == 0)
 10081018                 norepptr += 256;
 10091019         c = norepptr;
 10101020         norep[norepptr++] = sp;
 10111021         return c;
 10121022 }
 10131023 
 10141024 static void
 10151025 doblk(void)
 10161026 {
 10171027         int c;
 10181028 
 10191029         do {
 10201030                 donex();
 10211031         } while ((c = sloscan()) == EBLOCK);
 10221032         if (c == IDENT)
 10231033                 return;
 10241034         error("EBLOCK sync error");
 10251035 }
 10261036 
 10271037 /* Block next nr in lex buffer to expand */
 10281038 int
 10291039 donex(void)
 10301040 {
 10311041         int n, i;
 10321042 
 10331043         if (bidx == RECMAX)
 10341044                 error("too deep macro recursion");
 10351045         n = cinput();
 10361046         n = MKB(n, cinput());
 10371047         for (i = 0; i < bidx; i++)
 10381048                 if (bptr[i] == n)
 10391049                         return n; /* already blocked */
 10401050         bptr[bidx++] = n;
 10411051         /* XXX - check for sp buffer overflow */
 10421052 #ifdef PCC_DEBUG
 10431053         if (dflag>1) {
 10441054                 printf("donex %d (%d) blocking:\n", bidx, n);
 10451055                 printf("donex %s(%d) blocking:", norep[n]->namep, n);
 10461056                 for (i = bidx-1; i >= 0; i--)
 10471057                         printf(" '%s'", norep[bptr[i]]->namep);
 10481058                 printf("\n");
 10491059         }
 10501060 #endif
 10511061         return n;
 10521062 }
 10531063 
 10541064 /*
 10551065  * store a character into the "define" buffer.
 10561066  */
 10571067 void
 10581068 savch(int c)
 10591069 {
 10601070         if (stringbuf >= &sbf[SBSIZE]) {
 10611071                 stringbuf = sbf; /* need space to write error message */
 10621072                 error("out of macro space!");
 10631073         }
 10641074         *stringbuf++ = (usch)c;
 10651075 }
 10661076 
 10671077 /*
 10681078  * convert _Pragma() to #pragma for output.
 10691079  * Syntax is already correct.
 10701080  */
 10711081 static void
 10721082 pragoper(void)
 10731083 {
 10741084         usch *s;
 10751085         int t;
 10761086 
 10771087         while ((t = sloscan()) != '(')
 10781088                 ;
 10791089 
 10801090         while ((t = sloscan()) == WSPACE)
 10811091                 ;
 10821092         if (t != STRING)
 10831093                 error("_Pragma() must have string argument");
 10841094         savstr((const usch *)"\n#pragma ");
 10851095         s = yytext;
 10861096         if (*s == 'L')
 10871097                 s++;
 10881098         for (; *s; s++) {
 10891099                 if (*s == EBLOCK) {
 10901100                         s+=2;
 10911101                         continue;
 10921102                 }
 10931103                 if (*s == '\"')
 10941104                         continue;
 10951105                 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
 10961106                         s++;
 10971107                 savch(*s);
 10981108         }
 10991109         sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
 11001110         while ((t = sloscan()) == WSPACE)
 11011111                 ;
 11021112         if (t != ')')
 11031113                 error("_Pragma() syntax error");
 11041114 }
 11051115 
 11061116 /*
 11071117  * Return true if it is OK to expand this symbol.
 11081118  */
 11091119 static int
 11101120 okexp(struct symtab *sp)
 11111121 {
 11121122         int i;
 11131123 
 11141124         if (sp == NULL)
 11151125                 return 0;
 11161126         for (i = 0; i < bidx; i++)
 11171127                 if (norep[bptr[i]] == sp)
 11181128                         return 0;
 11191129         return 1;
 11201130 }
 11211131 
 11221132 /*
 11231133  * Insert block(s) before each expanded name.
 11241134  * Input is in lex buffer, output on lex buffer.
 11251135  */
 11261136 static void
 11271137 insblock(int bnr)
 11281138 {
 11291139         usch *bp = stringbuf;
 11301140         int c, i;
 11311141  
 11321142         IMP("IB");
 11331143         readmac++;
 11341144         while ((c = sloscan()) != WARN) {
 11351145                 if (c == EBLOCK) {
 11361146                         sss();
 11371147                         continue;
 11381148                 }
 11391149                 if (c == CMNT) {
 11401150                         getcmnt();
 11411151                         continue;
 11421152                 }
 11431153                 if (c == IDENT) {
 11441154                         savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
 11451155                         for (i = 0; i < bidx; i++)
 11461156                                 savch(EBLOCK), savch(bptr[i] & 255),
 11471157                                     savch(bptr[i] >> 8);
 11481158                 }
 11491159                 savstr(yytext);
 11501160                 if (c == '\n')
 11511161                         (void)cinput();
 11521162         }
 11531163         savch(0);
 11541164         cunput(WARN);
 11551165         unpstr(bp);
 11561166         stringbuf = bp;
 11571167         readmac--;
 11581168         IMP("IBRET");
 11591169 }
 11601170 
 11611171 /* Delete next WARN on the input stream */
 11621172 static void
 11631173 delwarn(void)
 11641174 {
 11651175         usch *bp = stringbuf;
 11661176         int c;
 11671177  
 11681178         IMP("DELWARN");
 11691179         while ((c = sloscan()) != WARN) {
 11701180                 if (c == CMNT) {
 11711181                         getcmnt();
 11721182                 } else if (c == EBLOCK) {
 11731183                         sss();
 11741184                 } else if (c == '\n') {
 11751185                         putch(cinput());
 11761186                 } else
 11771187                         savstr(yytext);
 11781188         }
 11791189         if (stringbuf[-1] == '/')
 11801190                 savch(PHOLD); /* avoid creating comments */
 11811191         savch(0);
 11821192         unpstr(bp);
 11831193         stringbuf = bp;
 11841194         IMP("DELWRET");
 11851195 }
 11861196 
 11871197 /*
 11881198  * Handle defined macro keywords found on input stream.
 11891199  * When finished print out the full expanded line.
 11901200  * Everything on lex buffer except for the symtab.
 11911201  */
 11921202 int
 11931203 kfind(struct symtab *sp)
 11941204 {
 11951205         struct symtab *nl;
 11961206         const usch *argary[MAXARGS+1], *cbp;
 11971207         usch *sbp;
 11981208         int c, o, chkf;
 11991209 
 12001210         DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
 12011211         IMP("KFIND");
 12021212         if (*sp->value == OBJCT) {
 12031213                 if (sp == filloc) {
 12041214                         unpstr(sheap("\"%s\"", ifiles->fname));
 12051215                         return 1;
 12061216                 } else if (sp == linloc) {
 12071217                         unpstr(sheap("%d", ifiles->lineno));
 12081218                         return 1;
 12091219                 }
 12101220                 IMP("END1");
 12111221                 cunput(WARN);
 12121222                 for (cbp = sp->value-1; *cbp; cbp--)
 12131223                         cunput(*cbp);
 12141224                 insblock(addmac(sp));
 12151225                 IMP("ENDX");
 12161226                 exparg(1);
 12171227 
 12181228 upp:            sbp = stringbuf;
 12191229                 chkf = 1;
 12201230                 if (obufp != 0)
 12211231                         lastoch = outbuf[obufp-1];
 12221232                 if (iswsnl(lastoch))
 12231233                         chkf = 0;
 12241234                 if (Cflag)
 12251235                         readmac++;
 12261236                 while ((c = sloscan()) != WARN) {
 12271237                         switch (c) {
 12281238                         case CMNT:
 12291239                                 getcmnt();
 12301240                                 break;
 12311241 
 12321242                         case STRING:
 12331243                                 /* Remove embedded directives */
 12341244                                 for (cbp = yytext; *cbp; cbp++) {
 12351245                                         if (*cbp == EBLOCK)
 12361246                                                 cbp+=2;
 12371247                                         else if (*cbp != CONC)
 12381248                                                 savch(*cbp);
 12391249                                 }
 12401250                                 break;
 12411251 
 12421252                         case EBLOCK:
 12431253                                 doblk();
 12441254                                 /* FALLTHROUGH */
 12451255                         case IDENT:
 12461256                                 /*
 12471257                                  * Tricky: if this is the last identifier
 12481258                                  * in the expanded list, and it is defined
 12491259                                  * as a function-like macro, then push it
 12501260                                  * back on the input stream and let fastscan
 12511261                                  * handle it as a new macro.
 12521262                                  * BUT: if this macro is blocked then this
 12531263                                  * should not be done.
 12541264                                  */
 12551265                                 nl = lookup(yytext, FIND);
 12561266                                 o = okexp(nl);
 12571267                                 bidx = 0;
 12581268                                 /* Deal with pragmas here */
 12591269                                 if (nl == pragloc) {
 12601270                                         pragoper();
 12611271                                         break;
 12621272                                 }
 12631273                                 if (nl == NULL || !o || *nl->value == OBJCT) {
 12641274                                         /* Not fun-like macro */
 12651275                                         savstr(yytext);
 12661276                                         break;
 12671277                                 }
 12681278                                 c = cinput();
 12691279                                 if (c == WARN) {
 12701280                                         /* succeeded, push back */
 12711281                                         unpstr(yytext);
 12721282                                 } else {
 12731283                                         savstr(yytext);
 12741284                                 }
 12751285                                 cunput(c);
 12761286                                 break;
 12771287 
 12781288                         default:
 12791289                                 if (chkf && c < 127)
 12801290                                         putch(' ');
 12811291                                 savstr(yytext);
 12821292                                 break;
 12831293                         }
 12841294                         chkf = 0;
 12851295                 }
 12861296                 if (Cflag)
 12871297                         readmac--;
 12881298                 IMP("END2");
 12891299                 norepptr = 1;
 12901300                 savch(0);
 12911301                 stringbuf = sbp;
 12921302                 return 1;
 12931303         }
 12941304         /* Is a function-like macro */
 12951305 
 12961306         /* Search for '(' */
 12971307         sbp = stringbuf;
 12981308         while (iswsnl(c = cinput()))
 12991309                 savch(c);
 13001310         savch(0);
 13011311         stringbuf = sbp;
 13021312         if (c != '(') {
 13031313                 cunput(c);
 13041314                 unpstr(sbp);
 13051315                 return 0; /* Failed */
 13061316         }
 13071317 
 13081318         /* Found one, output \n to be in sync */
 13091319         for (; *sbp; sbp++) {
 13101320                 if (*sbp == '\n')
 13111321                         putch('\n'), ifiles->lineno++;
 13121322         }
 13131323 
 13141324         /* fetch arguments */
 13151325         if (Cflag)
 13161326                 readmac++;
 13171327         if (readargs(sp, argary))
 13181328                 error("readargs");
 13191329 
 13201330         c = addmac(sp);
 13211331         sbp = stringbuf;
 13221332         cunput(WARN);
 13231333 
 13241334         IMP("KEXP");
 13251335         subarg(sp, argary, 1);
 13261336         IMP("KNEX");
 13271337         insblock(c);
 13281338         IMP("KBLK");
 13291339 
 13301340         stringbuf = sbp;
 13311341 
 13321342         exparg(1);
 13331343         if (Cflag)
 13341344                 readmac--;
 13351345 
 13361346         IMP("END");
 13371347 
 13381348         goto upp;
 13391349 
 13401350 }
 13411351 
 13421352 /*
 13431353  * Replace and push-back on input stream the eventual replaced macro.
 13441354  * The check for whether it can expand or not should already have been done.
 13451355  * Blocks for this identifier will be added via insblock() after expansion.
 13461356  */
 13471357 int
 13481358 submac(struct symtab *sp, int lvl)
 13491359 {
 13501360         const usch *argary[MAXARGS+1];
 13511361         const usch *cp;
 13521362         usch *bp;
 13531363         int ch;
 13541364 
 13551365         DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
 13561366         if (*sp->value == OBJCT) {
 13571367                 if (sp == filloc) {
 13581368                         unpstr(sheap("\"%s\"", ifiles->fname));
 13591369                         return 1;
 13601370                 } else if (sp == linloc) {
 13611371                         unpstr(sheap("%d", ifiles->lineno));
 13621372                         return 1;
 13631373                 }
 13641374 
 13651375                 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
 13661376                 /* expand object-type macros */
 13671377                 ch = addmac(sp);
 13681378                 cunput(WARN);
 13691379 
 13701380                 for (cp = sp->value-1; *cp; cp--)
 13711381                         cunput(*cp);
 13721382                 insblock(ch);
 13731383                 delwarn();
 13741384                 return 1;
 13751385         }
 13761386 
 13771387         /*
 13781388          * Function-like macro; see if it is followed by a (
 13791389          * Be careful about the expand/noexpand balance.
 13801390          * Store read data on heap meanwhile.
 13811391          * For directive        #define foo() kaka
 13821392          * If input is          <NEX><NEX>foo<EXP>()<EXP> then
 13831393          * output should be     <NEX><NEX><EXP>kaka<EXP>.
 13841394          */
 13851395         bp = stringbuf;
 13861396         while (iswsnl(ch = cinput()))
 13871397                 savch(ch);
 13881398         savch(0);
 13891399         stringbuf = bp;
 13901400         if (ch != '(') {
 13911401                 cunput(ch);
 13921402                 unpstr(bp);
 13931403                 return 0; /* Failed */
 13941404         }
 13951405 
 13961406         /* no \n should be here */
 13971407 
 13981408         /*
 13991409          * A function-like macro has been found.  Read in the arguments,
 14001410          * expand them and push-back everything for another scan.
 14011411          */
 14021412         DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
 14031413         savch(0);
 14041414         if (readargs(sp, argary)) {
 14051415                 /* Bailed out in the middle of arg list */
 14061416                 unpstr(bp);
 14071417                 DDPRINT(("%d:noreadargs\n", lvl));
 14081418                 stringbuf = bp;
 14091419                 return 0;
 14101420         }
 14111421 
 14121422         /* when all args are read from input stream */
 14131423         ch = addmac(sp);
 14141424 
 14151425         DDPRINT(("%d:submac pre\n", lvl));
 14161426         cunput(WARN);
 14171427 
 14181428         subarg(sp, argary, lvl+1);
 14191429 
 14201430         DDPRINT(("%d:submac post\n", lvl));
 14211431         insblock(ch);
 14221432         delwarn();
 14231433 
 14241434         stringbuf = bp; /* Reset heap */
 14251435         DPRINT(("%d:Return submac\n", lvl));
 14261436         IMP("SM1");
 14271437         return 1;
 14281438 }
 14291439 
 14301440 static int
 14311441 isdir(void)
 14321442 {
 14331443         usch *bp = stringbuf;
 14341444         usch ch;
 14351445 
 14361446         while ((ch = cinput()) == ' ' || ch == '\t')
 14371447                 *stringbuf++ = ch;
 14381448         *stringbuf++ = ch;
 14391449         *stringbuf++ = 0;
 14401450         stringbuf = bp;
 14411451         if (ch == '#')
 14421452                 return 1;
 14431453         unpstr(bp);
 14441454         return 0;
 14451455 }
 14461456 
 14471457 /*
 14481458  * Deal with directives inside a macro.
 14491459  * Doing so is really ugly but gcc allows it, so...
 14501460  */
 14511461 static void
 14521462 chkdir(void)
 14531463 {
 14541464         usch ch;
 14551465 
 14561466         for (;;) {
 14571467                 if (isdir())
 14581468                         ppdir();
 14591469                 if (flslvl == 0)
 14601470                         return;
 14611471                 while ((ch = cinput()) != '\n')
 14621472                         ;
 14631473                 ifiles->lineno++;
 14641474                 putch('\n');
 14651475         }
 14661476 }
 14671477 
 14681478 /*
 14691479  * Read arguments and put in argument array.
 14701480  * If WARN is encountered return 1, otherwise 0.
 14711481  */
 14721482 int
 14731483 readargs(struct symtab *sp, const usch **args)
 14741484 {
 14751485         const usch *vp = sp->value;
 14761486         int c, i, plev, narg, ellips = 0;
 14771487         int warn;
 14781488 
 14791489         DPRINT(("readargs\n"));
 14801490 
 14811491         narg = *vp--;
 14821492         if (narg == VARG) {
 14831493                 narg = *vp--;
 14841494                 ellips = 1;
 14851495         }
 14861496 
 14871497         IMP("RDA1");
 14881498         /*
 14891499          * read arguments and store them on heap.
 14901500          */
 14911501         warn = 0;
 14921502         c = '(';
 14931503         for (i = 0; i < narg && c != ')'; i++) {
 14941504                 args[i] = stringbuf;
 14951505                 plev = 0;
 14961506                 while ((c = sloscan()) == WSPACE || c == '\n')
 14971507                         if (c == '\n') {
 14981508                                 ifiles->lineno++;
 14991509                                 putch(cinput());
 15001510                                 chkdir();
 15011511                         }
 15021512                 for (;;) {
 15031513                         while (c == EBLOCK) {
 15041514                                 sss();
 15051515                                 c = sloscan();
 15061516                         }
 15071517                         if (c == WARN) {
 15081518                                 warn++;
 15091519                                 goto oho;
 15101520                         }
 15111521                         if (plev == 0 && (c == ')' || c == ','))
 15121522                                 break;
 15131523                         if (c == '(')
 15141524                                 plev++;
 15151525                         if (c == ')')
 15161526                                 plev--;
 15171527                         savstr(yytext);
 15181528 oho:                    while ((c = sloscan()) == '\n') {
 15191529                                 ifiles->lineno++;
 15201530                                 putch(cinput());
 15211531                                 chkdir();
 15221532                                 savch(' ');
 15231533                         }
 15241534                         while (c == CMNT) {
 15251535                                 getcmnt();
 15261536                                 c = sloscan();
 15271537                         }
 15281538                         if (c == 0)
 15291539                                 error("eof in macro");
 15301540                 }
 15311541                 while (args[i] < stringbuf &&
 15321542                     iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
 15331543                         stringbuf--;
 15341544                 savch('\0');
 15351545 #ifdef PCC_DEBUG
 15361546                 if (dflag) {
 15371547                         printf("readargs: save arg %d '", i);
 15381548                         prline(args[i]);
 15391549                         printf("'\n");
 15401550                 }
 15411551 #endif
 15421552         }
 15431553 
 15441554         IMP("RDA2");
 15451555         /* Handle varargs readin */
 15461556         if (ellips)
 15471557                 args[i] = (const usch *)"";
 15481558         if (ellips && c != ')') {
 15491559                 args[i] = stringbuf;
 15501560                 plev = 0;
 15511561                 while ((c = sloscan()) == WSPACE || c == '\n')
 15521562                         if (c == '\n')
 15531563                                 cinput();
 15541564                 for (;;) {
 15551565                         if (plev == 0 && c == ')')
 15561566                                 break;
 15571567                         if (c == '(')
 15581568                                 plev++;
 15591569                         if (c == ')')
 15601570                                 plev--;
 15611571                         if (c == EBLOCK) {
 15621572                                 sss();
 15631573                         } else
 15641574                                 savstr(yytext);
 15651575                         while ((c = sloscan()) == '\n') {
 15661576                                 ifiles->lineno++;
 15671577                                 cinput();
 15681578                                 chkdir();
 15691579                                 savch(' ');
 15701580                         }
 15711581                 }
 15721582                 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
 15731583                         stringbuf--;
 15741584                 savch('\0');
 15751585                 
 15761586         }
 15771587         if (narg == 0 && ellips == 0)
 15781588                 while ((c = sloscan()) == WSPACE || c == '\n')
 15791589                         if (c == '\n')
 15801590                                 cinput();
 15811591 
 15821592         if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
 15831593                 error("wrong arg count");
 15841594         while (warn)
 15851595                 cunput(WARN), warn--;
 15861596         return 0;
 15871597 }
 15881598 
 15891599 /*
 15901600  * expand a function-like macro.
 15911601  * vp points to end of replacement-list
 15921602  * reads function arguments from sloscan()
 15931603  * result is pushed-back for more scanning.
 15941604  */
 15951605 void
 15961606 subarg(struct symtab *nl, const usch **args, int lvl)
 15971607 {
 15981608         int narg, instr, snuff;
 15991609         const usch *sp, *bp, *ap, *vp;
 16001610 
 16011611         DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
 16021612         vp = nl->value;
 16031613         narg = *vp--;
 16041614         if (narg == VARG)
 16051615                 narg = *vp--;
 16061616 
 16071617         sp = vp;
 16081618         instr = snuff = 0;
 16091619 #ifdef PCC_DEBUG
 16101620         if (dflag>1) {
 16111621                 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
 16121622                 prrep(vp);
 16131623                 printf("'\n");
 16141624         }
 16151625 #endif
 16161626 
 16171627         /*
 16181628          * push-back replacement-list onto lex buffer while replacing
 16191629          * arguments.  Arguments are macro-expanded if required.
 16201630          */
 16211631         while (*sp != 0) {
 16221632                 if (*sp == SNUFF)
 16231633                         cunput('\"'), snuff ^= 1;
 16241634                 else if (*sp == CONC)
 16251635                         ;
 16261636                 else if (*sp == WARN) {
 16271637 
 16281638                         if (sp[-1] == VARG) {
 16291639                                 bp = ap = args[narg];
 16301640                                 sp--;
 16311641 #ifdef GCC_COMPAT
 16321642                         } else if (sp[-1] == GCCARG) {
 16331643                                 ap = args[narg];
 16341644                                 if (ap[0] == 0)
 16351645                                         ap = (const usch *)"0";
 16361646                                 bp = ap;
 16371647                                 sp--;
 16381648 #endif
 16391649                         } else
 16401650                                 bp = ap = args[(int)*--sp];
 16411651 #ifdef PCC_DEBUG
 16421652                         if (dflag>1){
 16431653                                 printf("%d:subarg GOTwarn; arglist '", lvl);
 16441654                                 prline(bp);
 16451655                                 printf("'\n");
 16461656                         }
 16471657 #endif
 16481658                         if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
 16491659                                 /*
 16501660                                  * Expand an argument; 6.10.3.1:
 16511661                                  * "A parameter in the replacement list,
 16521662                                  *  is replaced by the corresponding argument
 16531663                                  *  after all macros contained therein have
 16541664                                  *  been expanded.".
 16551665                                  */
 16561666                                 cunput(WARN);
 16571667                                 unpstr(bp);
 16581668                                 exparg(lvl+1);
 16591669                                 delwarn();
 16601670                         } else {
 16611671                         while (*bp)
 16621672                                 bp++;
 16631673                         while (bp > ap) {
 16641674                                 bp--;
 16651675                                 if (snuff && !instr && iswsnl(*bp)) {
 16661676                                         while (iswsnl(*bp))
 16671677                                                 bp--;
 16681678                                         cunput(' ');
 16691679                                 }
 16701680 
 16711681                                 cunput(*bp);
 16721682                                 if ((*bp == '\'' || *bp == '"')
 16731683                                      && bp[-1] != '\\' && snuff) {
 16741684                                         instr ^= 1;
 16751685                                         if (instr == 0 && *bp == '"')
 16761686                                                 cunput('\\');
 16771687                                 }
 16781688                                 if (instr && (*bp == '\\' || *bp == '"'))
 16791689                                         cunput('\\');
 16801690                         }
 16811691                         }
 16821692                 } else
 16831693                         cunput(*sp);
 16841694                 sp--;
 16851695         }
 16861696         DPRINT(("%d:Return subarg\n", lvl));
 16871697         IMP("SUBARG");
 16881698 }
 16891699 
 16901700 /*
 16911701  * Do a (correct) expansion of a WARN-terminated buffer of tokens.
 16921702  * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
 16931703  * Expansion blocking is not altered here unless when tokens are
 16941704  * concatenated, in which case they are removed.
 16951705  */
 16961706 void
 16971707 exparg(int lvl)
 16981708 {
 16991709         struct symtab *nl;
 17001710         int c, i, gmult;
 17011711         usch *och;
 17021712         usch *osb = stringbuf;
 17031713         int anychange;
 17041714 
 17051715         DPRINT(("%d:exparg\n", lvl));
 17061716         IMP("EXPARG");
 17071717 
 17081718         readmac++;
 17091719 rescan:
 17101720         anychange = 0;
 17111721         while ((c = sloscan()) != WARN) {
 17121722                 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
 17131723                 IMP("EA0");
 17141724                 bidx = 0;
 17151725                 switch (c) {
 17161726 
 17171727                 case EBLOCK:
 17181728                         doblk();
 17191729                         /* FALLTHROUGH */
 17201730                 case IDENT:
 17211731                         /*
 17221732                          * Handle argument concatenation here.
 17231733                          * In case of concatenation, add all blockings.
 17241734                          */
 17251735                         DDPRINT(("%d:exparg ident %d\n", lvl, c));
 17261736                         och = stringbuf;
 17271737                         gmult = 0;
 17281738 
 17291739 sav:                    savstr(yytext);
 17301740 
 17311741                         if ((c = cinput()) == EBLOCK) {
 17321742                                 /* yep, are concatenating; add blocks */
 17331743                                 gmult = 1;
 17341744                                 do {
 17351745                                         donex();
 17361746                                 } while ((c = sloscan()) == EBLOCK);
 17371747                                 goto sav;
 17381748                         }
 17391749                         cunput(c);
 17401750 
 17411751                         DPRINT(("%d:exparg: str '%s'\n", lvl, och));
 17421752                         IMP("EA1");
 17431753                         /* see if ident is expandable */
 17441754                         if ((nl = lookup(och, FIND)) && okexp(nl)) {
 17451755                                 /* Save blocks */
 17461756                                 int donothing;
 17471757                                 unsigned short *svidx =
 17481758                                     malloc(sizeof(int)*(bidx+1));
 17491759                                 int svbidx = bidx;
 17501760 
 17511761                                 for (i = 0; i < bidx; i++)
 17521762                                         svidx[i] = bptr[i];
 17531763                                 if (submac(nl, lvl+1)) {
 17541764                                         /* Could expand, result on lexbuffer */
 17551765                                         stringbuf = och; /* clear saved name */
 17561766                                         anychange = 1;
 17571767                                 }
 17581768                                 donothing = 0;
 17591769                                 c = cinput();
 17601770                                 if (c == 'L') {
 17611771                                         int c2 = cinput();
 17621772                                         if (c2 == '\"' || c2 == '\'')
 17631773                                                 donothing = 1;
 17641774                                         cunput(c2);
 17651775                                 }
 17661776                                 cunput(c);
 17671777 
 17681778                                 if (donothing == 0)
 17691779                                     if ((spechr[c] & C_ID0) || c == EBLOCK) {
 17701780                                         for (i = 0; i < svbidx; i++) {
 17711781                                                 cunput(svidx[i] >> 8);
 17721782                                                 cunput(svidx[i] & 255);
 17731783                                                 cunput(EBLOCK);
 17741784                                         }
 17751785                                 }
 17761786                                 free(svidx);
 17771787                         } else if (bidx) {
 17781788                                 /* must restore blocks */
 17791789                                 if (gmult) {
 17801790                                         unpstr(och);
 17811791                                         if (sloscan() != IDENT)
 17821792                                                 error("exparg sync error");
 17831793                                 }
 17841794                                 stringbuf = och;
 17851795                                 for (i = 0; i < bidx; i++)
 17861796                                         savch(EBLOCK), savch(bptr[i] & 255),
 17871797                                             savch(bptr[i] >> 8);
 17881798                                 savstr(yytext);
 17891799                         }
 17901800                         bidx = 0;
 17911801                         IMP("EA2");
 17921802                         break;
 17931803 
 17941804                 case CMNT:
 17951805                         getcmnt();
 17961806                         break;
 17971807 
 17981808                 case '\n':
 17991809                         cinput();
 18001810                         savch(' ');
 18011811                         break;
 18021812 
 18031813                 default:
 18041814                         savstr(yytext);
 18051815                         break;
 18061816                 }
 18071817         }
 18081818         *stringbuf = 0;
 18091819         cunput(WARN);
 18101820         unpstr(osb);
 18111821         DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
 18121822         IMP("EXPRET");
 18131823         stringbuf = osb;
 18141824         if (anychange)
 18151825                 goto rescan;
 18161826         readmac--;
 18171827 }
 18181828 
 18191829 #ifdef PCC_DEBUG
 18201830 static void
 18211831 imp(const char *str)
 18221832 {
 18231833         printf("%s (%d) '", str, bidx);
 18241834         prline(ifiles->curptr);
 18251835         printf("'\n");
 18261836 }
 18271837 
 18281838 static void
 18291839 prrep(const usch *s)
 18301840 {
 18311841         while (*s) {
 18321842                 switch (*s) {
 18331843                 case WARN: printf("<ARG(%d)>", *--s); break;
 18341844                 case CONC: printf("<CONC>"); break;
 18351845                 case SNUFF: printf("<SNUFF>"); break;
 18361846                 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
 18371847                 default: printf("%c", *s); break;
 18381848                 }
 18391849                 s--;
 18401850         }
 18411851 }
 18421852 
 18431853 static void
 18441854 prline(const usch *s)
 18451855 {
 18461856         while (*s) {
 18471857                 switch (*s) {
 18481858                 case WARN: printf("<WARN>"); break;
 18491859                 case CONC: printf("<CONC>"); break;
 18501860                 case SNUFF: printf("<SNUFF>"); break;
 18511861                 case PHOLD: printf("<PHOLD>"); break;
 18521862                 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
 18531863                 case '\n': printf("<NL>"); break;
 18541864                 default: printf("%c", *s); break;
 18551865                 }
 18561866                 s++;
 18571867         }
 18581868 }
 18591869 #endif
 18601870 
 18611871 usch *
 18621872 savstr(const usch *str)
 18631873 {
 18641874         usch *rv = stringbuf;
 18651875 
 18661876         do {
 18671877                 if (stringbuf >= &sbf[SBSIZE])   {
 18681878                         stringbuf = sbf; /* need space to write error message */
 18691879                         error("out of macro space!");
 18701880                 }
 18711881         } while ((*stringbuf++ = *str++));
 18721882         stringbuf--;
 18731883         return rv;
 18741884 }
 18751885 
 18761886 void
 18771887 unpstr(const usch *c)
 18781888 {
 18791889         const usch *d = c;
 18801890 
 18811891 #if 0
 18821892         if (dflag>1) {
 18831893                 printf("Xunpstr: '");
 18841894                 prline(c);
 18851895                 printf("'\n");
 18861896         }
 18871897 #endif
 18881898         while (*d) {
 18891899                 if (*d == EBLOCK)
 18901900                         d += 2;
 18911901                 d++;
 18921902         }
 18931903         while (d > c) {
 18941904                 cunput(*--d);
 18951905         }
 18961906 }
 18971907 
 18981908 static void
 18991909 flbuf(void)
 19001910 {
 19011911         if (obufp == 0)
 19021912                 return;
 19031913         if (Mflag == 0)
 19041914                 xwrite(ofd, outbuf, obufp);
 19051915         lastoch = outbuf[obufp-1];
 19061916         obufp = 0;
 19071917 }
 19081918 
 19091919 void
 19101920 putch(int ch)
 19111921 {
 19121922         outbuf[obufp++] = (usch)ch;
 19131923         if (obufp == CPPBUF || (istty && ch == '\n'))
 19141924                 flbuf();
 19151925 }
 19161926 
 19171927 void
 19181928 putstr(const usch *s)
 19191929 {
 19201930         for (; *s; s++) {
 19211931                 if (*s == PHOLD)
 19221932                         continue;
 19231933                 outbuf[obufp++] = *s;
 19241934                 if (obufp == CPPBUF || (istty && *s == '\n'))
 19251935                         flbuf();
 19261936         }
 19271937 }
 19281938 
 19291939 /*
 19301940  * convert a number to an ascii string. Store it on the heap.
 19311941  */
 19321942 static void
 19331943 num2str(int num)
 19341944 {
 19351945         static usch buf[12];
 19361946         usch *b = buf;
 19371947         int m = 0;
 19381948         
 19391949         if (num < 0)
 19401950                 num = -num, m = 1;
 19411951         do {
 19421952                 *b++ = (usch)(num % 10 + '0');
 19431953                 num /= 10;
 19441954         } while (num);
 19451955         if (m)
 19461956                 *b++ = '-';
 19471957         while (b > buf)
 19481958                 savch(*--b);
 19491959 }
 19501960 
 19511961 /*
 19521962  * similar to sprintf, but only handles %c, %s and %d.
 19531963  * saves result on heap.
 19541964  */
 19551965 static void
 19561966 vsheap(const char *fmt, va_list ap)
 19571967 {
 19581968         for (; *fmt; fmt++) {
 19591969                 if (*fmt == '%') {
 19601970                         fmt++;
 19611971                         switch (*fmt) {
 19621972                         case 's':
 19631973                                 savstr(va_arg(ap, usch *));
 19641974                                 break;
 19651975                         case 'd':
 19661976                                 num2str(va_arg(ap, int));
 19671977                                 break;
 19681978                         case 'c':
 19691979                                 savch(va_arg(ap, int));
 19701980                                 break;
 19711981                         default:
 19721982                                 error("bad sheap");
 19731983                         }
 19741984                 } else
 19751985                         savch(*fmt);
 19761986         }
 19771987         *stringbuf = 0;
 19781988 }
 19791989 
 19801990 usch *
 19811991 sheap(const char *fmt, ...)
 19821992 {
 19831993         va_list ap;
 19841994         usch *op = stringbuf;
 19851995 
 19861996         va_start(ap, fmt);
 19871997         vsheap(fmt, ap);
 19881998         va_end(ap);
 19891999 
 19902000         return op;
 19912001 }
 19922002 
 19932003 static void
 19942004 usage(void)
 19952005 {
 19962006         error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
 19972007 }
 19982008 
 19992009 #ifdef notyet
 20002010 /*
 20012011  * Symbol table stuff.
 20022012  * The data structure used is a patricia tree implementation using only
 20032013  * bytes to store offsets. 
 20042014  * The information stored is (lower address to higher):
 20052015  *
 20062016  *      unsigned char bitno[2]; bit number in the string
 20072017  *      unsigned char left[3];  offset from base to left element
 20082018  *      unsigned char right[3]; offset from base to right element
 20092019  */
 20102020 #endif
 20112021 
 20122022 /*
 20132023  * This patricia implementation is more-or-less the same as
 20142024  * used in ccom for string matching.
 20152025  */
 20162026 struct tree {
 20172027         int bitno;
 20182028         struct tree *lr[2];
 20192029 };
 20202030 
 20212031 #define BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
 20222032 #define LEFT_IS_LEAF            0x80000000
 20232033 #define RIGHT_IS_LEAF           0x40000000
 20242034 #define IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
 20252035 #define IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
 20262036 #define P_BIT(key, bit)         (key[bit >> 3] >> (bit & 7)) & 1
 20272037 #define CHECKBITS               8
 20282038 
 20292039 static struct tree *sympole;
 20302040 static int numsyms;
 20312041 
 20322042 /*
 20332043  * Allocate a symtab struct and store the string.
 20342044  */
 20352045 static struct symtab *
 20362046 getsymtab(const usch *str)
 20372047 {
 20382048         struct symtab *sp = malloc(sizeof(struct symtab));
 20392049 
 20402050         if (sp == NULL)
 20412051                 error("getsymtab: couldn't allocate symtab");
 20422052         sp->namep = savstr(str);
 20432053         savch('\0');
 20442054         sp->value = NULL;
 20452055         sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
 20462056         sp->line = ifiles ? ifiles->lineno : 0;
 20472057         return sp;
 20482058 }
 20492059 
 20502060 /*
 20512061  * Do symbol lookup in a patricia tree.
 20522062  * Only do full string matching, no pointer optimisations.
 20532063  */
 20542064 struct symtab *
 20552065 lookup(const usch *key, int enterf)
 20562066 {
 20572067         struct symtab *sp;
 20582068         struct tree *w, *new, *last;
 20592069         int len, cix, bit, fbit, svbit, ix, bitno;
 20602070         const usch *k, *m;
 20612071 
 20622072         /* Count full string length */
 20632073         for (k = key, len = 0; *k; k++, len++)
 20642074                 ;
 20652075 
 20662076         switch (numsyms) {
 20672077         case 0: /* no symbols yet */
 20682078                 if (enterf != ENTER)
 20692079                         return NULL;
 20702080                 sympole = (struct tree *)getsymtab(key);
 20712081                 numsyms++;
 20722082                 return (struct symtab *)sympole;
 20732083 
 20742084         case 1:
 20752085                 w = sympole;
 20762086                 svbit = 0; /* XXX gcc */
 20772087                 break;
 20782088 
 20792089         default:
 20802090                 w = sympole;
 20812091                 bitno = len * CHECKBITS;
 20822092                 for (;;) {
 20832093                         bit = BITNO(w->bitno);
 20842094                         fbit = bit > bitno ? 0 : P_BIT(key, bit);
 20852095                         svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
 20862096                             IS_LEFT_LEAF(w->bitno);
 20872097                         w = w->lr[fbit];
 20882098                         if (svbit)
 20892099                                 break;
 20902100                 }
 20912101         }
 20922102 
 20932103         sp = (struct symtab *)w;
 20942104 
 20952105         m = sp->namep;
 20962106         k = key;
 20972107 
 20982108         /* Check for correct string and return */
 20992109         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
 21002110                 ;
 21012111         if (*m == 0 && *k == 0) {
 21022112                 if (enterf != ENTER && sp->value == NULL)
 21032113                         return NULL;
 21042114                 return sp;
 21052115         }
 21062116 
 21072117         if (enterf != ENTER)
 21082118                 return NULL; /* no string found and do not enter */
 21092119 
 21102120         ix = *m ^ *k;
 21112121         while ((ix & 1) == 0)
 21122122                 ix >>= 1, cix++;
 21132123 
 21142124         /* Create new node */
 21152125         if ((new = malloc(sizeof *new)) == NULL)
 21162126                 error("getree: couldn't allocate tree");
 21172127         bit = P_BIT(key, cix);
 21182128         new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21192129         new->lr[bit] = (struct tree *)getsymtab(key);
 21202130 
 21212131         if (numsyms++ == 1) {
 21222132                 new->lr[!bit] = sympole;
 21232133                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21242134                 sympole = new;
 21252135                 return (struct symtab *)new->lr[bit];
 21262136         }
 21272137 
 21282138         w = sympole;
 21292139         last = NULL;
 21302140         for (;;) {
 21312141                 fbit = w->bitno;
 21322142                 bitno = BITNO(w->bitno);
 21332143                 if (bitno == cix)
 21342144                         error("bitno == cix");
 21352145                 if (bitno > cix)
 21362146                         break;
 21372147                 svbit = P_BIT(key, bitno);
 21382148                 last = w;
 21392149                 w = w->lr[svbit];
 21402150                 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
 21412151                         break;
 21422152         }
 21432153 
 21442154         new->lr[!bit] = w;
 21452155         if (last == NULL) {
 21462156                 sympole = new;
 21472157         } else {
 21482158                 last->lr[svbit] = new;
 21492159                 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21502160         }
 21512161         if (bitno < cix)
 21522162                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21532163         return (struct symtab *)new->lr[bit];
 21542164 }
 21552165 
 21562166 static usch *
 21572167 xstrdup(const usch *str)
 21582168 {
 21592169         usch *rv;
 21602170 
 21612171         if ((rv = (usch *)strdup((const char *)str)) == NULL)
 21622172                 error("xstrdup: out of mem");
 21632173         return rv;
 21642174 }
 21652175 
 21662176 void
 21672177 xwrite(int fd, const void *buf, unsigned int len)
 21682178 {
 21692179         if (write(fd, buf, len) != (int)len) {
 21702180                 if (fd == 2)
 21712181                         exit(2);
 21722182                 error("write error");
 21732183         }
 21742184 }
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 10:55 +0100