Quick Search:

Mode

Context

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

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.184
 
1.185
 
MAIN:plunky:20121107095159
 
cpp.c
_>11 /*      $Id$    */
 22 
 33 /*
 44  * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
 55  * All rights reserved.
 66  *
 77  * Redistribution and use in source and binary forms, with or without
 88  * modification, are permitted provided that the following conditions
 99  * are met:
 1010  * 1. Redistributions of source code must retain the above copyright
 1111  *    notice, this list of conditions and the following disclaimer.
 1212  * 2. Redistributions in binary form must reproduce the above copyright
 1313  *    notice, this list of conditions and the following disclaimer in the
 1414  *    documentation and/or other materials provided with the distribution.
 1515  *
 1616  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 1717  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 1818  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 1919  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 2020  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 2121  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 2222  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 2323  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 2424  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 2525  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 2626  */
 2727 
 2828 /*
 2929  * The C preprocessor.
 3030  * This code originates from the V6 preprocessor with some additions
 3131  * from V7 cpp, and at last ansi/c99 support.
 3232  */
 3333 
 3434 #include "config.h"
 3535 
 3636 #include <sys/stat.h>
 3737 
 3838 #include <fcntl.h>
 3939 #ifdef HAVE_UNISTD_H
 4040 #include <unistd.h>
 4141 #endif
 4242 #include <stdio.h>
 4343 #include <stdarg.h>
 4444 #include <stdlib.h>
 4545 #include <string.h>
 4646 #include <time.h>
 4747 
 4848 #include "compat.h"
 4949 #include "cpp.h"
 5050 #include "cpy.h"
 5151 
 5252 #ifndef S_ISDIR
 5353 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
 5454 #endif
 5555 
 5656 #define SBSIZE  1000000
 5757 
 5858 static const char versstr[] = "PCC preprocessor version " VERSSTR "\n";
 5959 
 6060 static usch     sbf[SBSIZE];
 6161 /* C command */
 6262 
 6363 int tflag;      /* traditional cpp syntax */
 6464 #ifdef PCC_DEBUG
 6565 int dflag;      /* debug printouts */
 6666 static void imp(const char *);
 6767 static void prline(const usch *s);
 6868 static void prrep(const usch *s);
 6969 #define DPRINT(x) if (dflag) printf x
 7070 #define DDPRINT(x) if (dflag > 1) printf x
 7171 #define IMP(x) if (dflag > 1) imp(x)
 7272 #else
 7373 #define DPRINT(x)
 7474 #define DDPRINT(x)
 7575 #define IMP(x)
 7676 #endif
 7777 
 7878 int ofd;
 7979 usch outbuf[CPPBUF];
 8080 int obufp, istty;
 8181 int Cflag, Mflag, dMflag, Pflag, MPflag;
 8282 usch *Mfile, *MPfile, *Mxfile;
 8383 struct initar *initar;
 8484 int readmac, lastoch;
 8585 int defining;
 8686 
 8787 /* include dirs */
 8888 struct incs {
 8989         struct incs *next;
 9090         usch *dir;
 9191         dev_t dev;
 9292         ino_t ino;
 9393 } *incdir[2];
 9494 
 9595 static struct symtab *filloc;
 9696 static struct symtab *linloc;
 9797 static struct symtab *pragloc;
 9898 int     trulvl;
 9999 int     flslvl;
 100100 int     elflvl;
 101101 int     elslvl;
 102102 usch *stringbuf = sbf;
 103103 
 104104 /*
 105105  * Macro replacement list syntax:
 106106  * - For object-type macros, replacement strings are stored as-is.
 107107  * - For function-type macros, macro args are substituted for the
 108108  *   character WARN followed by the argument number.
 109109  * - The value element points to the end of the string, to simplify
 110110  *   pushback onto the input queue.
 111111  *
 112112  * The first character (from the end) in the replacement list is
 113113  * the number of arguments:
 114114  *   VARG  - ends with ellipsis, next char is argcount without ellips.
 115115  *   OBJCT - object-type macro
 116116  *   0     - empty parenthesis, foo()
 117117  *   1->   - number of args.
 118118  *
 119119  * WARN is used:
 120120  *      - in stored replacement lists to tell that an argument comes
 121121  *      - When expanding replacement lists to tell that the list ended.
 122122  *
 123123  * To ensure that an already expanded identifier won't get expanded
 124124  * again a EBLOCK char + its number is stored directly before any
 125125  * expanded identifier.
 126126  */
 127127 
 128128 /* args for lookup() */
 129129 #define FIND    0
 130130 #define ENTER   1
 131131 
 132132 /*
 133133  * No-replacement array.  If a macro is found and exists in this array
 134134  * then no replacement shall occur.  This is a stack.
 135135  */
 136136 struct symtab *norep[RECMAX];   /* Symbol table index table */
 137137 int norepptr = 1;                       /* Top of index table */
 138138 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
 139139 int bidx;                       /* Top of bptr stack */
 140140 
 141141 static int readargs(struct symtab *sp, const usch **args);
 142142 static void exparg(int);
 143143 static void subarg(struct symtab *sp, const usch **args, int);
 144144 static void flbuf(void);
 145145 static void usage(void);
 146146 static usch *xstrdup(const usch *str);
 147147 static void addidir(char *idir, struct incs **ww);
 148148 static void vsheap(const char *, va_list);
 149149 
 150150 int
 151151 main(int argc, char **argv)
 152152 {
 153153         struct initar *it;
 154154         struct symtab *nl;
 155155         register int ch;
 156156         const usch *fn1, *fn2;
 157157 
 158158 #ifdef TIMING
 159159         struct timeval t1, t2;
 160160 
 161161         (void)gettimeofday(&t1, NULL);
 162162 #endif
 163163 
 164164         while ((ch = getopt(argc, argv, "CD:d:I:i:MPS:tU:Vvx:")) != -1) {
 165165                 switch (ch) {
 166166                 case 'C': /* Do not discard comments */
 167167                         Cflag++;
 168168                         break;
 169169 
 170170                 case 'D': /* define something */
 171171                 case 'i': /* include */
 172172                 case 'U': /* undef */
 173173                         /* XXX should not need malloc() here */
 174174                         if ((it = malloc(sizeof(struct initar))) == NULL)
 175175                                 error("couldn't apply -%c %s", ch, optarg);
 176176                         it->type = ch;
 177177                         it->str = optarg;
 178178                         it->next = initar;
 179179                         initar = it;
 180180                         break;
 181181 
 182182                 case 'd':
 183183                         while (*optarg) {
 184184                                 switch(*optarg) {
 185185                                 case 'M': /* display macro definitions */
 186186                                         dMflag = 1;
 187187                                         Mflag = 1;
 188188                                         break;
 189189 
 190190                                 default: /* ignore others */
 191191                                         break;
 192192                                 }
 193193                                 optarg++;
 194194                         }
 195195                         break;
 196196 
 197197                 case 'I':
 198198                 case 'S':
 199199                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
 200200                         break;
 201201 
 202202                 case 'M': /* Generate dependencies for make */
 203203                         Mflag++;
 204204                         break;
 205205 
 206206                 case 'P': /* Inhibit generation of line numbers */
 207207                         Pflag++;
 208208                         break;
 209209 
 210210                 case 't':
 211211                         tflag = 1;
 212212                         break;
 213213 
 214214 #ifdef PCC_DEBUG
 215215                 case 'V':
 216216                         dflag++;
 217217                         break;
 218218 #endif
 219219                 case 'v':
 220220                         xwrite(2, versstr, sizeof(versstr) - 1);
 221221                         break;
 222222 
 223223                 case 'x':
 224224                         if (strcmp(optarg, "MP") == 0) {
 225225                                 MPflag++;
 226226                         } else if (strncmp(optarg, "MT,", 3) == 0 ||
 227227                             strncmp(optarg, "MQ,", 3) == 0) {
 228228                                 usch *cp, *fn;
 229229                                 fn = stringbuf;
 230230                                 for (cp = (usch *)&optarg[3]; *cp; cp++) {
 231231                                         if (*cp == '$' && optarg[1] == 'Q')
 232232                                                 savch('$');
 233233                                         savch(*cp);
 234234                                 }
 235235                                 savstr((const usch *)"");
 236236                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
 237237                                 savch(0);
 238238                                 Mxfile = fn;
 239239                         } else
 240240                                 usage();
 241241                         break;
 242242 
 243243                 case '?':
 244244                 default:
 245245                         usage();
 246246                 }
 247247         }
 248248 
 249249         argc -= optind;
 250250         argv += optind;
 251251 
 252252         filloc = lookup((const usch *)"__FILE__", ENTER);
 253253         linloc = lookup((const usch *)"__LINE__", ENTER);
 254254         filloc->value = linloc->value = stringbuf;
 255255         savch(OBJCT);
 256256 
 257257         /* create a complete macro for pragma */
 258258         pragloc = lookup((const usch *)"_Pragma", ENTER);
 259259         savch(0);
 260260         savstr((const usch *)"_Pragma(");
 261261         savch(0);
 262262         savch(WARN);
 263263         savch(')');
 264264         pragloc->value = stringbuf;
 265265         savch(1);
 266266 
 267267         if (tflag == 0) {
 268268                 time_t t = time(NULL);
 269269                 usch *n = (usch *)ctime(&t);
 270270 
 271271                 /*
 272272                  * Manually move in the predefined macros.
 273273                  */
 274274                 nl = lookup((const usch *)"__TIME__", ENTER);
 275275                 savch(0); savch('"');  n[19] = 0; savstr(&n[11]); savch('"');
 276276                 savch(OBJCT);
 277277                 nl->value = stringbuf-1;
 278278 
 279279                 nl = lookup((const usch *)"__DATE__", ENTER);
 280280                 savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
 281281                 savstr(&n[20]); savch('"'); savch(OBJCT);
 282282                 nl->value = stringbuf-1;
 283283 
 284284                 nl = lookup((const usch *)"__STDC__", ENTER);
 285285                 savch(0); savch('1'); savch(OBJCT);
 286286                 nl->value = stringbuf-1;
 287287 
 288288                 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
 289289                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
 290290                 nl->value = stringbuf-1;
 291291         }
 292292 
 293293         if (Mflag && !dMflag) {
 294294                 usch *c;
 295295 
 296296                 if (argc < 1)
 297297                         error("-M and no infile");
 298298                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
 299299                         c = (usch *)argv[0];
 300300                 else
 301301                         c++;
 302302                 Mfile = stringbuf;
 303303                 savstr(c); savch(0);
 304304                 if (MPflag) {
 305305                         MPfile = stringbuf;
 306306                         savstr(c); savch(0);
 307307                 }
 308308                 if (Mxfile)
 309309                         Mfile = Mxfile;
 310310                 if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
 311311                         error("-M and no extension: ");
 312312                 c[1] = 'o';
 313313                 c[2] = 0;
 314314         }
 315315 
 316316         if (argc == 2) {
 317317                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
 318318                         error("Can't creat %s", argv[1]);
 319319         } else
 320320                 ofd = 1; /* stdout */
 321321         istty = isatty(ofd);
 322322 
 323323         if (argc && strcmp(argv[0], "-")) {
 324324                 fn1 = fn2 = (usch *)argv[0];
 325325         } else {
 326326                 fn1 = NULL;
 327327                 fn2 = (const usch *)"";
 328328         }
 329329         if (pushfile(fn1, fn2, 0, NULL))
 330330                 error("cannot open %s", argv[0]);
 331331 
 332332         flbuf();
 333333         close(ofd);
 334334 #ifdef TIMING
 335335         (void)gettimeofday(&t2, NULL);
 336336         t2.tv_sec -= t1.tv_sec;
 337337         t2.tv_usec -= t1.tv_usec;
 338338         if (t2.tv_usec < 0) {
 339339                 t2.tv_usec += 1000000;
 340340                 t2.tv_sec -= 1;
 341341         }
 342342         fprintf(stderr, "cpp total time: %ld s %ld us\n",
 343343              (long)t2.tv_sec, (long)t2.tv_usec);
 344344 #endif
 345345         return 0;
 346346 }
 347347 
 348348 static void
 349349 addidir(char *idir, struct incs **ww)
 350350 {
 351351         struct incs *w;
 352352         struct stat st;
 353353 
 354354         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
 355355                 return; /* ignore */
 356356         if (*ww != NULL) {
 357357                 for (w = *ww; w->next; w = w->next) {
 358358 #ifdef os_win32
 359359                         if (strcmp(w->dir, idir) == 0)
 360360                                 return;
 361361 #else
 362362                         if (w->dev == st.st_dev && w->ino == st.st_ino)
 363363                                 return;
 364364 #endif
 365365                 }
 366366 #ifdef os_win32
 367367                 if (strcmp(w->dir, idir) == 0)
 368368                         return;
 369369 #else
 370370                 if (w->dev == st.st_dev && w->ino == st.st_ino)
 371371                         return;
 372372 #endif
 373373                 ww = &w->next;
 374374         }
 375375         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
 376376                 error("couldn't add path %s", idir);
 377377         w->dir = (usch *)idir;
 378378         w->dev = st.st_dev;
 379379         w->ino = st.st_ino;
 380380         *ww = w;
 381381 }
 382382 
 383383 void
 384384 line(void)
 385385 {
 386386         static usch *lbuf;
 387387         static int llen;
 388388         usch *p;
 389389         int c;
 390390 
 391391         if ((c = yylex()) != NUMBER)
 392392                 goto bad;
 393393         ifiles->lineno = (int)(yylval.node.nd_val - 1);
<> 394+        ifiles->escln = 0;
<_394395 
 395396         if ((c = yylex()) == '\n')
 396397                 goto okret;
 397398 
 398399         if (c != STRING)
 399400                 goto bad;
 400401 
 401402         p = yytext;
 402403         if (*p++ == 'L')
 403404                 p++;
 404405         c = strlen((char *)p);
 405406         p[c - 1] = '\0';
 406407         if (llen < c) {
 407408                 /* XXX may lose heap space */
 408409                 lbuf = stringbuf;
 409410                 stringbuf += c;
 410411                 llen = c;
 411412                 if (stringbuf >= &sbf[SBSIZE]) {
 412413                         stringbuf = sbf; /* need space to write error message */
 413414                         error("#line filename exceeds buffer size");
 414415                 }
 415416         }
 416417         memcpy(lbuf, p, c);
 417418         ifiles->fname = lbuf;
 418419         if (yylex() != '\n')
 419420                 goto bad;
 420421 
 421422 okret:  prtline();
 422423         return;
 423424 
 424425 bad:    error("bad #line");
 425426 }
 426427 
 427428 /*
 428429  * Search for and include next file.
 429430  * Return 1 on success.
 430431  */
 431432 static int
 432433 fsrch(const usch *fn, int idx, struct incs *w)
 433434 {
 434435         int i;
 435436 
 436437         for (i = idx; i < 2; i++) {
 437438                 if (i > idx)
 438439                         w = incdir[i];
 439440                 for (; w; w = w->next) {
 440441                         usch *nm = stringbuf;
 441442 
 442443                         savstr(w->dir); savch('/');
 443444                         savstr(fn); savch(0);
 444445                         if (pushfile(nm, fn, i, w->next) == 0)
 445446                                 return 1;
 446447                         stringbuf = nm;
 447448                 }
 448449         }
 449450         return 0;
 450451 }
 451452 
 452453 static void
 453454 prem(void)
 454455 {
 455456         error("premature EOF");
 456457 }
 457458 
 458459 /*
 459460  * Include a file. Include order:
 460461  * - For <...> files, first search -I directories, then system directories.
 461462  * - For "..." files, first search "current" dir, then as <...> files.
 462463  */
 463464 void
 464465 include(void)
 465466 {
 466467         struct symtab *nl;
 467468         usch *osp;
 468469         usch *fn, *safefn;
 469470         int c;
 470471 
 471472         if (flslvl)
 472473                 return;
 473474         osp = stringbuf;
 474475 
 475476         while ((c = sloscan()) == WSPACE)
 476477                 ;
 477478         if (c == IDENT) {
 478479                 /* sloscan() will not expand idents */
 479480                 if ((nl = lookup(yytext, FIND)) == NULL)
 480481                         goto bad;
 481482                 if (kfind(nl))
 482483                         unpstr(stringbuf);
 483484                 else
 484485                         unpstr(nl->namep);
 485486                 stringbuf = osp;
 486487                 c = yylex();
 487488         }
 488489 
 489490         if (c == '<') {
 490491                 fn = stringbuf;
 491492                 while ((c = sloscan()) != '>') {
 492493                         if (c == 0)
 493494                                 prem();
 494495                         if (c == '\n')
 495496                                 goto bad;
 496497                         savstr(yytext);
 497498                 }
 498499                 savch('\0');
 499500                 while ((c = sloscan()) == WSPACE)
 500501                         ;
 501502                 if (c == 0)
 502503                         prem();
 503504                 if (c != '\n')
 504505                         goto bad;
 505506                 safefn = fn;
 506507         } else if (c == STRING) {
 507508                 usch *nm = stringbuf;
 508509 
 509510                 fn = yytext;
 510511                 if (*fn++ == 'L')
 511512                         fn++;
 512513                 fn[strlen((char *)fn) - 1] = 0;
 513514                 /* first try to open file relative to previous file */
 514515                 /* but only if it is not an absolute path */
 515516                 if (*fn != '/') {
 516517                         savstr(ifiles->orgfn);
 517518                         if ((stringbuf =
 518519                             (usch *)strrchr((char *)nm, '/')) == NULL)
 519520                                 stringbuf = nm;
 520521                         else
 521522                                 stringbuf++;
 522523                 }
 523524                 safefn = stringbuf;
 524525                 savstr(fn); savch(0);
 525526                 c = yylex();
 526527                 if (c == 0)
 527528                         prem();
 528529                 if (c != '\n')
 529530                         goto bad;
 530531                 if (pushfile(nm, safefn, 0, NULL) == 0)
 531532                         goto okret;
 532533                 /* XXX may lose stringbuf space */
 533534         } else
 534535                 goto bad;
 535536 
 536537         if (fsrch(safefn, 0, incdir[0]))
 537538                 goto okret;
 538539 
 539540         error("cannot find '%s'", safefn);
 540541         /* error() do not return */
 541542 
 542543 bad:    error("bad #include");
 543544         /* error() do not return */
 544545 okret:
 545546         prtline();
 546547 }
 547548 
 548549 void
 549550 include_next(void)
 550551 {
 551552         struct symtab *nl;
 552553         usch *osp;
 553554         usch *fn;
 554555         int c;
 555556 
 556557         if (flslvl)
 557558                 return;
 558559         osp = stringbuf;
 559560         while ((c = sloscan()) == WSPACE)
 560561                 ;
 561562         if (c == IDENT) {
 562563                 /* sloscan() will not expand idents */
 563564                 if ((nl = lookup(yytext, FIND)) == NULL)
 564565                         goto bad;
 565566                 if (kfind(nl))
 566567                         unpstr(stringbuf);
 567568                 else
 568569                         unpstr(nl->namep);
 569570                 stringbuf = osp;
 570571                 c = yylex();
 571572         }
 572573         if (c != STRING && c != '<')
 573574                 goto bad;
 574575 
 575576         fn = stringbuf;
 576577         if (c == STRING) {
 577578                 savstr(&yytext[1]);
 578579                 stringbuf[-1] = 0;
 579580         } else { /* < > */
 580581                 while ((c = sloscan()) != '>') {
 581582                         if (c == '\n')
 582583                                 goto bad;
 583584                         savstr(yytext);
 584585                 }
 585586                 savch('\0');
 586587         }
 587588         while ((c = sloscan()) == WSPACE)
 588589                 ;
 589590         if (c != '\n')
 590591                 goto bad;
 591592 
 592593         if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
 593594                 error("cannot find '%s'", fn);
 594595         prtline();
 595596         return;
 596597 
 597598 bad:    error("bad #include_next");
 598599         /* error() do not return */
 599600 }
 600601 
 601602 static int
 602603 definp(void)
 603604 {
 604605         int c;
 605606 
 606607         do
 607608                 c = sloscan();
 608609         while (c == WSPACE);
 609610         return c;
 610611 }
 611612 
 612613 void
 613614 getcmnt(void)
 614615 {
 615616         int c;
 616617 
 617618         savstr(yytext);
 618619         savch(cinput()); /* Lost * */
 619620         for (;;) {
 620621                 c = cinput();
 621622                 if (c == '*') {
 622623                         c = cinput();
 623624                         if (c == '/') {
 624625                                 savstr((const usch *)"*/");
 625626                                 return;
 626627                         }
 627628                         cunput(c);
 628629                         c = '*';
 629630                 }
 630631                 savch(c);
 631632         }
 632633 }
 633634 
 634635 /*
 635636  * Compare two replacement lists, taking in account comments etc.
 636637  */
 637638 static int
 638639 cmprepl(const usch *o, const usch *n)
 639640 {
 640641         for (; *o; o--, n--) {
 641642                 /* comment skip */
 642643                 if (*o == '/' && o[-1] == '*') {
 643644                         while (*o != '*' || o[-1] != '/')
 644645                                 o--;
 645646                         o -= 2;
 646647                 }
 647648                 if (*n == '/' && n[-1] == '*') {
 648649                         while (*n != '*' || n[-1] != '/')
 649650                                 n--;
 650651                         n -= 2;
 651652                 }
 652653                 while (*o == ' ' || *o == '\t')
 653654                         o--;
 654655                 while (*n == ' ' || *n == '\t')
 655656                         n--;
 656657                 if (*o != *n)
 657658                         return 1;
 658659         }
 659660         return 0;
 660661 }
 661662 
 662663 static int
 663664 isell(void)
 664665 {
 665666         int ch;
 666667 
 667668         if ((ch = cinput()) != '.') {
 668669                 cunput(ch);
 669670                 return 0;
 670671         }
 671672         if ((ch = cinput()) != '.') {
 672673                 cunput(ch);
 673674                 cunput('.');
 674675                 return 0;
 675676         }
 676677         return 1;
 677678 }
 678679 
 679680 void
 680681 define(void)
 681682 {
 682683         struct symtab *np;
 683684         usch *args[MAXARGS+1], *ubuf, *sbeg;
 684685         int c, i, redef;
 685686         int mkstr = 0, narg = -1;
 686687         int ellips = 0;
 687688 #ifdef GCC_COMPAT
 688689         usch *gccvari = NULL;
 689690         int wascon;
 690691 #endif
 691692 
 692693         if (flslvl)
 693694                 return;
 694695         if (sloscan() != WSPACE || sloscan() != IDENT)
 695696                 goto bad;
 696697 
 697698         np = lookup(yytext, ENTER);
 698699         redef = np->value != NULL;
 699700 
 700701         defining = readmac = 1;
 701702         sbeg = stringbuf;
 702703         if ((c = sloscan()) == '(') {
 703704                 narg = 0;
 704705                 /* function-like macros, deal with identifiers */
 705706                 c = definp();
 706707                 for (;;) {
 707708                         if (c == ')')
 708709                                 break;
 709710                         if (c == '.' && isell()) {
 710711                                 ellips = 1;
 711712                                 if (definp() != ')')
 712713                                         goto bad;
 713714                                 break;
 714715                         }
 715716                         if (c == IDENT) {
 716717                                 /* make sure there is no arg of same name */
 717718                                 for (i = 0; i < narg; i++)
 718719                                         if (!strcmp((char *) args[i], (char *)yytext))
 719720                                                 error("Duplicate macro "
 720721                                                   "parameter \"%s\"", yytext);
 721722                                 if (narg == MAXARGS)
 722723                                         error("Too many macro args");
 723724                                 args[narg++] = xstrdup(yytext);
 724725                                 if ((c = definp()) == ',') {
 725726                                         if ((c = definp()) == ')')
 726727                                                 goto bad;
 727728                                         continue;
 728729                                 }
 729730 #ifdef GCC_COMPAT
 730731                                 if (c == '.' && isell()) {
 731732                                         if (definp() != ')')
 732733                                                 goto bad;
 733734                                         gccvari = args[--narg];
 734735                                         break;
 735736                                 }
 736737 #endif
 737738                                 if (c == ')')
 738739                                         break;
 739740                         }
 740741                         goto bad;
 741742                 }
 742743                 c = sloscan();
 743744         } else if (c == '\n') {
 744745                 /* #define foo */
 745746                 ;
 746747         } else if (c == 0) {
 747748                 prem();
 748749         } else if (c != WSPACE)
 749750                 goto bad;
 750751 
 751752         while (c == WSPACE)
 752753                 c = sloscan();
 753754 
 754755         /* replacement list cannot start with ## operator */
 755756         if (c == '#') {
 756757                 if ((c = sloscan()) == '#')
 757758                         goto bad;
 758759                 savch('\0');
 759760 #ifdef GCC_COMPAT
 760761                 wascon = 0;
 761762 #endif
 762763                 goto in2;
 763764         }
 764765 
 765766         /* parse replacement-list, substituting arguments */
 766767         savch('\0');
 767768         while (c != '\n') {
 768769 #ifdef GCC_COMPAT
 769770                 wascon = 0;
 770771 loop:
 771772 #endif
 772773                 switch (c) {
 773774                 case WSPACE:
 774775                         /* remove spaces if it surrounds a ## directive */
 775776                         ubuf = stringbuf;
 776777                         savstr(yytext);
 777778                         c = sloscan();
 778779                         if (c == '#') {
 779780                                 if ((c = sloscan()) != '#')
 780781                                         goto in2;
 781782                                 stringbuf = ubuf;
 782783                                 savch(CONC);
 783784                                 if ((c = sloscan()) == WSPACE)
 784785                                         c = sloscan();
 785786 #ifdef GCC_COMPAT
 786787                                 if (c == '\n')
 787788                                         break;
 788789                                 wascon = 1;
 789790                                 goto loop;
 790791 #endif
 791792                         }
 792793                         continue;
 793794 
 794795                 case '#':
 795796                         c = sloscan();
 796797                         if (c == '#') {
 797798                                 /* concat op */
 798799                                 savch(CONC);
 799800                                 if ((c = sloscan()) == WSPACE)
 800801                                         c = sloscan();
 801802 #ifdef GCC_COMPAT
 802803                                 if (c == '\n')
 803804                                         break;
 804805                                 wascon = 1;
 805806                                 goto loop;
 806807 #else
 807808                                 continue;
 808809 #endif
 809810                         }
 810811 in2:                    if (narg < 0) {
 811812                                 /* no meaning in object-type macro */
 812813                                 savch('#');
 813814                                 continue;
 814815                         }
 815816                         /* remove spaces between # and arg */
 816817                         savch(SNUFF);
 817818                         if (c == WSPACE)
 818819                                 c = sloscan(); /* whitespace, ignore */
 819820                         mkstr = 1;
 820821                         if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
 821822                                 continue;
 822823 
 823824                         /* FALLTHROUGH */
 824825                 case IDENT:
 825826                         if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
 826827                                 if (ellips == 0)
 827828                                         error("unwanted %s", yytext);
 828829 #ifdef GCC_COMPAT
 829830                                 savch(wascon ? GCCARG : VARG);
 830831 #else
 831832                                 savch(VARG);
 832833 #endif
 833834 
 834835                                 savch(WARN);
 835836                                 if (mkstr)
 836837                                         savch(SNUFF), mkstr = 0;
 837838                                 break;
 838839                         }
 839840                         if (narg < 0)
 840841                                 goto id; /* just add it if object */
 841842                         /* check if its an argument */
 842843                         for (i = 0; i < narg; i++)
 843844                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
 844845                                         break;
 845846                         if (i == narg) {
 846847 #ifdef GCC_COMPAT
 847848                                 if (gccvari &&
 848849                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
 849850                                         savch(wascon ? GCCARG : VARG);
 850851                                         savch(WARN);
 851852                                         if (mkstr)
 852853                                                 savch(SNUFF), mkstr = 0;
 853854                                         break;
 854855                                 }
 855856 #endif
 856857                                 if (mkstr)
 857858                                         error("not argument");
 858859                                 goto id;
 859860                         }
 860861                         savch(i);
 861862                         savch(WARN);
 862863                         if (mkstr)
 863864                                 savch(SNUFF), mkstr = 0;
 864865                         break;
 865866 
 866867                 case CMNT: /* save comments */
 867868                         getcmnt();
 868869                         break;
 869870 
 870871                 case 0:
 871872                         prem();
 872873 
 873874                 default:
 874875 id:                     savstr(yytext);
 875876                         break;
 876877                 }
 877878                 c = sloscan();
 878879         }
 879880         defining = readmac = 0;
 880881         /* remove trailing whitespace */
 881882         while (stringbuf > sbeg) {
 882883                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
 883884                         stringbuf--;
 884885                 /* replacement list cannot end with ## operator */
 885886                 else if (stringbuf[-1] == CONC)
 886887                         goto bad;
 887888                 else
 888889                         break;
 889890         }
 890891 #ifdef GCC_COMPAT
 891892         if (gccvari) {
 892893                 savch(narg);
 893894                 savch(VARG);
 894895         } else
 895896 #endif
 896897         if (ellips) {
 897898                 savch(narg);
 898899                 savch(VARG);
 899900         } else
 900901                 savch(narg < 0 ? OBJCT : narg);
 901902         if (redef && ifiles->idx != SYSINC) {
 902903                 if (cmprepl(np->value, stringbuf-1)) {
 903904                         sbeg = stringbuf;
 904905                         np->value = stringbuf-1;
 905906                         warning("%s redefined (previously defined at \"%s\" line %d)",
 906907                             np->namep, np->file, np->line);
 907908                 }
 908909                 stringbuf = sbeg/* forget this space */
 909910         } else
 910911                 np->value = stringbuf-1;
 911912 
 912913 #ifdef PCC_DEBUG
 913914         if (dflag) {
 914915                 const usch *w = np->value;
 915916 
 916917                 printf("!define: ");
 917918                 if (*w == OBJCT)
 918919                         printf("[object]");
 919920                 else if (*w == VARG)
 920921                         printf("[VARG%d]", *--w);
 921922                 while (*--w) {
 922923                         switch (*w) {
 923924                         case WARN: printf("<%d>", *--w); break;
 924925                         case CONC: printf("<##>"); break;
 925926                         case SNUFF: printf("<\">"); break;
 926927                         default: putchar(*w); break;
 927928                         }
 928929                 }
 929930                 putchar('\n');
 930931         }
 931932 #endif
 932933         for (i = 0; i < narg; i++)
 933934                 free(args[i]);
 934935         return;
 935936 
 936937 bad:    error("bad #define");
 937938 }
 938939 
 939940 void
 940941 warning(const char *fmt, ...)
 941942 {
 942943         va_list ap;
 943944         usch *sb;
 944945 
 945946         flbuf();
 946947         savch(0);
 947948 
 948949         sb = stringbuf;
 949950         if (ifiles != NULL)
 950951                 sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
 951952 
 952953         va_start(ap, fmt);
 953954         vsheap(fmt, ap);
 954955         va_end(ap);
 955956         savch('\n');
 956957         xwrite(2, sb, stringbuf - sb);
 957958         stringbuf = sb;
 958959 }
 959960 
 960961 void
 961962 error(const char *fmt, ...)
 962963 {
 963964         va_list ap;
 964965         usch *sb;
 965966 
 966967         flbuf();
 967968         savch(0);
 968969 
 969970         sb = stringbuf;
 970971         if (ifiles != NULL)
 971972                 sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
 972973 
 973974         va_start(ap, fmt);
 974975         vsheap(fmt, ap);
 975976         va_end(ap);
 976977         savch('\n');
 977978         xwrite(2, sb, stringbuf - sb);
 978979         stringbuf = sb;
 979980 
 980981         exit(1);
 981982 }
 982983 
 983984 static void
 984985 sss(void)
 985986 {
 986987         savch(EBLOCK);
 987988         savch(cinput());
 988989         savch(cinput());
 989990 }
 990991 
 991992 static int
 992993 addmac(struct symtab *sp)
 993994 {
 994995         int c, i;
 995996 
 996997         /* Check if it exists; then save some space */
 997998         /* May be more difficult to debug cpp */
 998999         for (i = 1; i < norepptr; i++)
 9991000                 if (norep[i] == sp)
 10001001                         return i;
 10011002         if (norepptr >= RECMAX)
 10021003                 error("too many macros");
 10031004         /* check norepptr */
 10041005         if ((norepptr & 255) == 0)
 10051006                 norepptr++;
 10061007         if (((norepptr >> 8) & 255) == 0)
 10071008                 norepptr += 256;
 10081009         c = norepptr;
 10091010         norep[norepptr++] = sp;
 10101011         return c;
 10111012 }
 10121013 
 10131014 static void
 10141015 doblk(void)
 10151016 {
 10161017         int c;
 10171018 
 10181019         do {
 10191020                 donex();
 10201021         } while ((c = sloscan()) == EBLOCK);
 10211022         if (c == IDENT)
 10221023                 return;
 10231024         error("EBLOCK sync error");
 10241025 }
 10251026 
 10261027 /* Block next nr in lex buffer to expand */
 10271028 int
 10281029 donex(void)
 10291030 {
 10301031         int n, i;
 10311032 
 10321033         if (bidx == RECMAX)
 10331034                 error("too deep macro recursion");
 10341035         n = cinput();
 10351036         n = MKB(n, cinput());
 10361037         for (i = 0; i < bidx; i++)
 10371038                 if (bptr[i] == n)
 10381039                         return n; /* already blocked */
 10391040         bptr[bidx++] = n;
 10401041         /* XXX - check for sp buffer overflow */
 10411042 #ifdef PCC_DEBUG
 10421043         if (dflag>1) {
 10431044                 printf("donex %d (%d) blocking:\n", bidx, n);
 10441045                 printf("donex %s(%d) blocking:", norep[n]->namep, n);
 10451046                 for (i = bidx-1; i >= 0; i--)
 10461047                         printf(" '%s'", norep[bptr[i]]->namep);
 10471048                 printf("\n");
 10481049         }
 10491050 #endif
 10501051         return n;
 10511052 }
 10521053 
 10531054 /*
 10541055  * store a character into the "define" buffer.
 10551056  */
 10561057 void
 10571058 savch(int c)
 10581059 {
 10591060         if (stringbuf >= &sbf[SBSIZE]) {
 10601061                 stringbuf = sbf; /* need space to write error message */
 10611062                 error("out of macro space!");
 10621063         }
 10631064         *stringbuf++ = (usch)c;
 10641065 }
 10651066 
 10661067 /*
 10671068  * convert _Pragma() to #pragma for output.
 10681069  * Syntax is already correct.
 10691070  */
 10701071 static void
 10711072 pragoper(void)
 10721073 {
 10731074         usch *s;
 10741075         int t;
 10751076 
 10761077         while ((t = sloscan()) != '(')
 10771078                 ;
 10781079 
 10791080         while ((t = sloscan()) == WSPACE)
 10801081                 ;
 10811082         if (t != STRING)
 10821083                 error("_Pragma() must have string argument");
 10831084         savstr((const usch *)"\n#pragma ");
 10841085         s = yytext;
 10851086         if (*s == 'L')
 10861087                 s++;
 10871088         for (; *s; s++) {
 10881089                 if (*s == EBLOCK) {
 10891090                         s+=2;
 10901091                         continue;
 10911092                 }
 10921093                 if (*s == '\"')
 10931094                         continue;
 10941095                 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
 10951096                         s++;
 10961097                 savch(*s);
 10971098         }
 10981099         sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
 10991100         while ((t = sloscan()) == WSPACE)
 11001101                 ;
 11011102         if (t != ')')
 11021103                 error("_Pragma() syntax error");
 11031104 }
 11041105 
 11051106 /*
 11061107  * Return true if it is OK to expand this symbol.
 11071108  */
 11081109 static int
 11091110 okexp(struct symtab *sp)
 11101111 {
 11111112         int i;
 11121113 
 11131114         if (sp == NULL)
 11141115                 return 0;
 11151116         for (i = 0; i < bidx; i++)
 11161117                 if (norep[bptr[i]] == sp)
 11171118                         return 0;
 11181119         return 1;
 11191120 }
 11201121 
 11211122 /*
 11221123  * Insert block(s) before each expanded name.
 11231124  * Input is in lex buffer, output on lex buffer.
 11241125  */
 11251126 static void
 11261127 insblock(int bnr)
 11271128 {
 11281129         usch *bp = stringbuf;
 11291130         int c, i;
 11301131  
 11311132         IMP("IB");
 11321133         readmac++;
 11331134         while ((c = sloscan()) != WARN) {
 11341135                 if (c == EBLOCK) {
 11351136                         sss();
 11361137                         continue;
 11371138                 }
 11381139                 if (c == CMNT) {
 11391140                         getcmnt();
 11401141                         continue;
 11411142                 }
 11421143                 if (c == IDENT) {
 11431144                         savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
 11441145                         for (i = 0; i < bidx; i++)
 11451146                                 savch(EBLOCK), savch(bptr[i] & 255),
 11461147                                     savch(bptr[i] >> 8);
 11471148                 }
 11481149                 savstr(yytext);
 11491150                 if (c == '\n')
 11501151                         (void)cinput();
 11511152         }
 11521153         savch(0);
 11531154         cunput(WARN);
 11541155         unpstr(bp);
 11551156         stringbuf = bp;
 11561157         readmac--;
 11571158         IMP("IBRET");
 11581159 }
 11591160 
 11601161 /* Delete next WARN on the input stream */
 11611162 static void
 11621163 delwarn(void)
 11631164 {
 11641165         usch *bp = stringbuf;
 11651166         int c;
 11661167  
 11671168         IMP("DELWARN");
 11681169         while ((c = sloscan()) != WARN) {
 11691170                 if (c == CMNT) {
 11701171                         getcmnt();
 11711172                 } else if (c == EBLOCK) {
 11721173                         sss();
 11731174                 } else if (c == '\n') {
 11741175                         putch(cinput());
 11751176                 } else
 11761177                         savstr(yytext);
 11771178         }
 11781179         if (stringbuf[-1] == '/')
 11791180                 savch(PHOLD); /* avoid creating comments */
 11801181         savch(0);
 11811182         unpstr(bp);
 11821183         stringbuf = bp;
 11831184         IMP("DELWRET");
 11841185 }
 11851186 
 11861187 /*
 11871188  * Handle defined macro keywords found on input stream.
 11881189  * When finished print out the full expanded line.
 11891190  * Everything on lex buffer except for the symtab.
 11901191  */
 11911192 int
 11921193 kfind(struct symtab *sp)
 11931194 {
 11941195         struct symtab *nl;
 11951196         const usch *argary[MAXARGS+1], *cbp;
 11961197         usch *sbp;
 11971198         int c, o, chkf;
 11981199 
 11991200         DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
 12001201         IMP("KFIND");
 12011202         if (*sp->value == OBJCT) {
 12021203                 if (sp == filloc) {
 12031204                         unpstr(sheap("\"%s\"", ifiles->fname));
 12041205                         return 1;
 12051206                 } else if (sp == linloc) {
 12061207                         unpstr(sheap("%d", ifiles->lineno));
 12071208                         return 1;
 12081209                 }
 12091210                 IMP("END1");
 12101211                 cunput(WARN);
 12111212                 for (cbp = sp->value-1; *cbp; cbp--)
 12121213                         cunput(*cbp);
 12131214                 insblock(addmac(sp));
 12141215                 IMP("ENDX");
 12151216                 exparg(1);
 12161217 
 12171218 upp:            sbp = stringbuf;
 12181219                 chkf = 1;
 12191220                 if (obufp != 0)
 12201221                         lastoch = outbuf[obufp-1];
 12211222                 if (iswsnl(lastoch))
 12221223                         chkf = 0;
 12231224                 if (Cflag)
 12241225                         readmac++;
 12251226                 while ((c = sloscan()) != WARN) {
 12261227                         switch (c) {
 12271228                         case CMNT:
 12281229                                 getcmnt();
 12291230                                 break;
 12301231 
 12311232                         case STRING:
 12321233                                 /* Remove embedded directives */
 12331234                                 for (cbp = yytext; *cbp; cbp++) {
 12341235                                         if (*cbp == EBLOCK)
 12351236                                                 cbp+=2;
 12361237                                         else if (*cbp != CONC)
 12371238                                                 savch(*cbp);
 12381239                                 }
 12391240                                 break;
 12401241 
 12411242                         case EBLOCK:
 12421243                                 doblk();
 12431244                                 /* FALLTHROUGH */
 12441245                         case IDENT:
 12451246                                 /*
 12461247                                  * Tricky: if this is the last identifier
 12471248                                  * in the expanded list, and it is defined
 12481249                                  * as a function-like macro, then push it
 12491250                                  * back on the input stream and let fastscan
 12501251                                  * handle it as a new macro.
 12511252                                  * BUT: if this macro is blocked then this
 12521253                                  * should not be done.
 12531254                                  */
 12541255                                 nl = lookup(yytext, FIND);
 12551256                                 o = okexp(nl);
 12561257                                 bidx = 0;
 12571258                                 /* Deal with pragmas here */
 12581259                                 if (nl == pragloc) {
 12591260                                         pragoper();
 12601261                                         break;
 12611262                                 }
 12621263                                 if (nl == NULL || !o || *nl->value == OBJCT) {
 12631264                                         /* Not fun-like macro */
 12641265                                         savstr(yytext);
 12651266                                         break;
 12661267                                 }
 12671268                                 c = cinput();
 12681269                                 if (c == WARN) {
 12691270                                         /* succeeded, push back */
 12701271                                         unpstr(yytext);
 12711272                                 } else {
 12721273                                         savstr(yytext);
 12731274                                 }
 12741275                                 cunput(c);
 12751276                                 break;
 12761277 
 12771278                         default:
 12781279                                 if (chkf && c < 127)
 12791280                                         putch(' ');
 12801281                                 savstr(yytext);
 12811282                                 break;
 12821283                         }
 12831284                         chkf = 0;
 12841285                 }
 12851286                 if (Cflag)
 12861287                         readmac--;
 12871288                 IMP("END2");
 12881289                 norepptr = 1;
 12891290                 savch(0);
 12901291                 stringbuf = sbp;
 12911292                 return 1;
 12921293         }
 12931294         /* Is a function-like macro */
 12941295 
 12951296         /* Search for '(' */
 12961297         sbp = stringbuf;
 12971298         while (iswsnl(c = cinput()))
 12981299                 savch(c);
 12991300         savch(0);
 13001301         stringbuf = sbp;
 13011302         if (c != '(') {
 13021303                 cunput(c);
 13031304                 unpstr(sbp);
 13041305                 return 0; /* Failed */
 13051306         }
 13061307 
 13071308         /* Found one, output \n to be in sync */
 13081309         for (; *sbp; sbp++) {
 13091310                 if (*sbp == '\n')
 13101311                         putch('\n'), ifiles->lineno++;
 13111312         }
 13121313 
 13131314         /* fetch arguments */
 13141315         if (Cflag)
 13151316                 readmac++;
 13161317         if (readargs(sp, argary))
 13171318                 error("readargs");
 13181319 
 13191320         c = addmac(sp);
 13201321         sbp = stringbuf;
 13211322         cunput(WARN);
 13221323 
 13231324         IMP("KEXP");
 13241325         subarg(sp, argary, 1);
 13251326         IMP("KNEX");
 13261327         insblock(c);
 13271328         IMP("KBLK");
 13281329 
 13291330         stringbuf = sbp;
 13301331 
 13311332         exparg(1);
 13321333         if (Cflag)
 13331334                 readmac--;
 13341335 
 13351336         IMP("END");
 13361337 
 13371338         goto upp;
 13381339 
 13391340 }
 13401341 
 13411342 /*
 13421343  * Replace and push-back on input stream the eventual replaced macro.
 13431344  * The check for whether it can expand or not should already have been done.
 13441345  * Blocks for this identifier will be added via insblock() after expansion.
 13451346  */
 13461347 int
 13471348 submac(struct symtab *sp, int lvl)
 13481349 {
 13491350         const usch *argary[MAXARGS+1];
 13501351         const usch *cp;
 13511352         usch *bp;
 13521353         int ch;
 13531354 
 13541355         DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
 13551356         if (*sp->value == OBJCT) {
 13561357                 if (sp == filloc) {
 13571358                         unpstr(sheap("\"%s\"", ifiles->fname));
 13581359                         return 1;
 13591360                 } else if (sp == linloc) {
 13601361                         unpstr(sheap("%d", ifiles->lineno));
 13611362                         return 1;
 13621363                 }
 13631364 
 13641365                 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
 13651366                 /* expand object-type macros */
 13661367                 ch = addmac(sp);
 13671368                 cunput(WARN);
 13681369 
 13691370                 for (cp = sp->value-1; *cp; cp--)
 13701371                         cunput(*cp);
 13711372                 insblock(ch);
 13721373                 delwarn();
 13731374                 return 1;
 13741375         }
 13751376 
 13761377         /*
 13771378          * Function-like macro; see if it is followed by a (
 13781379          * Be careful about the expand/noexpand balance.
 13791380          * Store read data on heap meanwhile.
 13801381          * For directive        #define foo() kaka
 13811382          * If input is          <NEX><NEX>foo<EXP>()<EXP> then
 13821383          * output should be     <NEX><NEX><EXP>kaka<EXP>.
 13831384          */
 13841385         bp = stringbuf;
 13851386         while (iswsnl(ch = cinput()))
 13861387                 savch(ch);
 13871388         savch(0);
 13881389         stringbuf = bp;
 13891390         if (ch != '(') {
 13901391                 cunput(ch);
 13911392                 unpstr(bp);
 13921393                 return 0; /* Failed */
 13931394         }
 13941395 
 13951396         /* no \n should be here */
 13961397 
 13971398         /*
 13981399          * A function-like macro has been found.  Read in the arguments,
 13991400          * expand them and push-back everything for another scan.
 14001401          */
 14011402         DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
 14021403         savch(0);
 14031404         if (readargs(sp, argary)) {
 14041405                 /* Bailed out in the middle of arg list */
 14051406                 unpstr(bp);
 14061407                 DDPRINT(("%d:noreadargs\n", lvl));
 14071408                 stringbuf = bp;
 14081409                 return 0;
 14091410         }
 14101411 
 14111412         /* when all args are read from input stream */
 14121413         ch = addmac(sp);
 14131414 
 14141415         DDPRINT(("%d:submac pre\n", lvl));
 14151416         cunput(WARN);
 14161417 
 14171418         subarg(sp, argary, lvl+1);
 14181419 
 14191420         DDPRINT(("%d:submac post\n", lvl));
 14201421         insblock(ch);
 14211422         delwarn();
 14221423 
 14231424         stringbuf = bp; /* Reset heap */
 14241425         DPRINT(("%d:Return submac\n", lvl));
 14251426         IMP("SM1");
 14261427         return 1;
 14271428 }
 14281429 
 14291430 static int
 14301431 isdir(void)
 14311432 {
 14321433         usch *bp = stringbuf;
 14331434         usch ch;
 14341435 
 14351436         while ((ch = cinput()) == ' ' || ch == '\t')
 14361437                 *stringbuf++ = ch;
 14371438         *stringbuf++ = ch;
 14381439         *stringbuf++ = 0;
 14391440         stringbuf = bp;
 14401441         if (ch == '#')
 14411442                 return 1;
 14421443         unpstr(bp);
 14431444         return 0;
 14441445 }
 14451446 
 14461447 /*
 14471448  * Deal with directives inside a macro.
 14481449  * Doing so is really ugly but gcc allows it, so...
 14491450  */
 14501451 static void
 14511452 chkdir(void)
 14521453 {
 14531454         usch ch;
 14541455 
 14551456         for (;;) {
 14561457                 if (isdir())
 14571458                         ppdir();
 14581459                 if (flslvl == 0)
 14591460                         return;
 14601461                 while ((ch = cinput()) != '\n')
 14611462                         ;
 14621463                 ifiles->lineno++;
 14631464                 putch('\n');
 14641465         }
 14651466 }
 14661467 
 14671468 /*
 14681469  * Read arguments and put in argument array.
 14691470  * If WARN is encountered return 1, otherwise 0.
 14701471  */
 14711472 int
 14721473 readargs(struct symtab *sp, const usch **args)
 14731474 {
 14741475         const usch *vp = sp->value;
 14751476         int c, i, plev, narg, ellips = 0;
 14761477         int warn;
 14771478 
 14781479         DPRINT(("readargs\n"));
 14791480 
 14801481         narg = *vp--;
 14811482         if (narg == VARG) {
 14821483                 narg = *vp--;
 14831484                 ellips = 1;
 14841485         }
 14851486 
 14861487         IMP("RDA1");
 14871488         /*
 14881489          * read arguments and store them on heap.
 14891490          */
 14901491         warn = 0;
 14911492         c = '(';
 14921493         for (i = 0; i < narg && c != ')'; i++) {
 14931494                 args[i] = stringbuf;
 14941495                 plev = 0;
 14951496                 while ((c = sloscan()) == WSPACE || c == '\n')
 14961497                         if (c == '\n') {
 14971498                                 ifiles->lineno++;
 14981499                                 putch(cinput());
 14991500                                 chkdir();
 15001501                         }
 15011502                 for (;;) {
 15021503                         while (c == EBLOCK) {
 15031504                                 sss();
 15041505                                 c = sloscan();
 15051506                         }
 15061507                         if (c == WARN) {
 15071508                                 warn++;
 15081509                                 goto oho;
 15091510                         }
 15101511                         if (plev == 0 && (c == ')' || c == ','))
 15111512                                 break;
 15121513                         if (c == '(')
 15131514                                 plev++;
 15141515                         if (c == ')')
 15151516                                 plev--;
 15161517                         savstr(yytext);
 15171518 oho:                    while ((c = sloscan()) == '\n') {
 15181519                                 ifiles->lineno++;
 15191520                                 putch(cinput());
 15201521                                 chkdir();
 15211522                                 savch(' ');
 15221523                         }
 15231524                         while (c == CMNT) {
 15241525                                 getcmnt();
 15251526                                 c = sloscan();
 15261527                         }
 15271528                         if (c == 0)
 15281529                                 error("eof in macro");
 15291530                 }
 15301531                 while (args[i] < stringbuf &&
 15311532                     iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
 15321533                         stringbuf--;
 15331534                 savch('\0');
 15341535 #ifdef PCC_DEBUG
 15351536                 if (dflag) {
 15361537                         printf("readargs: save arg %d '", i);
 15371538                         prline(args[i]);
 15381539                         printf("'\n");
 15391540                 }
 15401541 #endif
 15411542         }
 15421543 
 15431544         IMP("RDA2");
 15441545         /* Handle varargs readin */
 15451546         if (ellips)
 15461547                 args[i] = (const usch *)"";
 15471548         if (ellips && c != ')') {
 15481549                 args[i] = stringbuf;
 15491550                 plev = 0;
 15501551                 while ((c = sloscan()) == WSPACE || c == '\n')
 15511552                         if (c == '\n')
 15521553                                 cinput();
 15531554                 for (;;) {
 15541555                         if (plev == 0 && c == ')')
 15551556                                 break;
 15561557                         if (c == '(')
 15571558                                 plev++;
 15581559                         if (c == ')')
 15591560                                 plev--;
 15601561                         if (c == EBLOCK) {
 15611562                                 sss();
 15621563                         } else
 15631564                                 savstr(yytext);
 15641565                         while ((c = sloscan()) == '\n') {
 15651566                                 ifiles->lineno++;
 15661567                                 cinput();
 15671568                                 chkdir();
 15681569                                 savch(' ');
 15691570                         }
 15701571                 }
 15711572                 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
 15721573                         stringbuf--;
 15731574                 savch('\0');
 15741575                 
 15751576         }
 15761577         if (narg == 0 && ellips == 0)
 15771578                 while ((c = sloscan()) == WSPACE || c == '\n')
 15781579                         if (c == '\n')
 15791580                                 cinput();
 15801581 
 15811582         if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
 15821583                 error("wrong arg count");
 15831584         while (warn)
 15841585                 cunput(WARN), warn--;
 15851586         return 0;
 15861587 }
 15871588 
 15881589 /*
 15891590  * expand a function-like macro.
 15901591  * vp points to end of replacement-list
 15911592  * reads function arguments from sloscan()
 15921593  * result is pushed-back for more scanning.
 15931594  */
 15941595 void
 15951596 subarg(struct symtab *nl, const usch **args, int lvl)
 15961597 {
 15971598         int narg, instr, snuff;
 15981599         const usch *sp, *bp, *ap, *vp;
 15991600 
 16001601         DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
 16011602         vp = nl->value;
 16021603         narg = *vp--;
 16031604         if (narg == VARG)
 16041605                 narg = *vp--;
 16051606 
 16061607         sp = vp;
 16071608         instr = snuff = 0;
 16081609 #ifdef PCC_DEBUG
 16091610         if (dflag>1) {
 16101611                 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
 16111612                 prrep(vp);
 16121613                 printf("'\n");
 16131614         }
 16141615 #endif
 16151616 
 16161617         /*
 16171618          * push-back replacement-list onto lex buffer while replacing
 16181619          * arguments.  Arguments are macro-expanded if required.
 16191620          */
 16201621         while (*sp != 0) {
 16211622                 if (*sp == SNUFF)
 16221623                         cunput('\"'), snuff ^= 1;
 16231624                 else if (*sp == CONC)
 16241625                         ;
 16251626                 else if (*sp == WARN) {
 16261627 
 16271628                         if (sp[-1] == VARG) {
 16281629                                 bp = ap = args[narg];
 16291630                                 sp--;
 16301631 #ifdef GCC_COMPAT
 16311632                         } else if (sp[-1] == GCCARG) {
 16321633                                 ap = args[narg];
 16331634                                 if (ap[0] == 0)
 16341635                                         ap = (const usch *)"0";
 16351636                                 bp = ap;
 16361637                                 sp--;
 16371638 #endif
 16381639                         } else
 16391640                                 bp = ap = args[(int)*--sp];
 16401641 #ifdef PCC_DEBUG
 16411642                         if (dflag>1){
 16421643                                 printf("%d:subarg GOTwarn; arglist '", lvl);
 16431644                                 prline(bp);
 16441645                                 printf("'\n");
 16451646                         }
 16461647 #endif
 16471648                         if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
 16481649                                 /*
 16491650                                  * Expand an argument; 6.10.3.1:
 16501651                                  * "A parameter in the replacement list,
 16511652                                  *  is replaced by the corresponding argument
 16521653                                  *  after all macros contained therein have
 16531654                                  *  been expanded.".
 16541655                                  */
 16551656                                 cunput(WARN);
 16561657                                 unpstr(bp);
 16571658                                 exparg(lvl+1);
 16581659                                 delwarn();
 16591660                         } else {
 16601661                         while (*bp)
 16611662                                 bp++;
 16621663                         while (bp > ap) {
 16631664                                 bp--;
 16641665                                 if (snuff && !instr && iswsnl(*bp)) {
 16651666                                         while (iswsnl(*bp))
 16661667                                                 bp--;
 16671668                                         cunput(' ');
 16681669                                 }
 16691670 
 16701671                                 cunput(*bp);
 16711672                                 if ((*bp == '\'' || *bp == '"')
 16721673                                      && bp[-1] != '\\' && snuff) {
 16731674                                         instr ^= 1;
 16741675                                         if (instr == 0 && *bp == '"')
 16751676                                                 cunput('\\');
 16761677                                 }
 16771678                                 if (instr && (*bp == '\\' || *bp == '"'))
 16781679                                         cunput('\\');
 16791680                         }
 16801681                         }
 16811682                 } else
 16821683                         cunput(*sp);
 16831684                 sp--;
 16841685         }
 16851686         DPRINT(("%d:Return subarg\n", lvl));
 16861687         IMP("SUBARG");
 16871688 }
 16881689 
 16891690 /*
 16901691  * Do a (correct) expansion of a WARN-terminated buffer of tokens.
 16911692  * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
 16921693  * Expansion blocking is not altered here unless when tokens are
 16931694  * concatenated, in which case they are removed.
 16941695  */
 16951696 void
 16961697 exparg(int lvl)
 16971698 {
 16981699         struct symtab *nl;
 16991700         int c, i, gmult;
 17001701         usch *och;
 17011702         usch *osb = stringbuf;
 17021703         int anychange;
 17031704 
 17041705         DPRINT(("%d:exparg\n", lvl));
 17051706         IMP("EXPARG");
 17061707 
 17071708         readmac++;
 17081709 rescan:
 17091710         anychange = 0;
 17101711         while ((c = sloscan()) != WARN) {
 17111712                 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
 17121713                 IMP("EA0");
 17131714                 bidx = 0;
 17141715                 switch (c) {
 17151716 
 17161717                 case EBLOCK:
 17171718                         doblk();
 17181719                         /* FALLTHROUGH */
 17191720                 case IDENT:
 17201721                         /*
 17211722                          * Handle argument concatenation here.
 17221723                          * In case of concatenation, add all blockings.
 17231724                          */
 17241725                         DDPRINT(("%d:exparg ident %d\n", lvl, c));
 17251726                         och = stringbuf;
 17261727                         gmult = 0;
 17271728 
 17281729 sav:                    savstr(yytext);
 17291730 
 17301731                         if ((c = cinput()) == EBLOCK) {
 17311732                                 /* yep, are concatenating; add blocks */
 17321733                                 gmult = 1;
 17331734                                 do {
 17341735                                         donex();
 17351736                                 } while ((c = sloscan()) == EBLOCK);
 17361737                                 goto sav;
 17371738                         }
 17381739                         cunput(c);
 17391740 
 17401741                         DPRINT(("%d:exparg: str '%s'\n", lvl, och));
 17411742                         IMP("EA1");
 17421743                         /* see if ident is expandable */
 17431744                         if ((nl = lookup(och, FIND)) && okexp(nl)) {
 17441745                                 /* Save blocks */
 17451746                                 int donothing;
 17461747                                 unsigned short *svidx =
 17471748                                     malloc(sizeof(int)*(bidx+1));
 17481749                                 int svbidx = bidx;
 17491750 
 17501751                                 for (i = 0; i < bidx; i++)
 17511752                                         svidx[i] = bptr[i];
 17521753                                 if (submac(nl, lvl+1)) {
 17531754                                         /* Could expand, result on lexbuffer */
 17541755                                         stringbuf = och; /* clear saved name */
 17551756                                         anychange = 1;
 17561757                                 }
 17571758                                 donothing = 0;
 17581759                                 c = cinput();
 17591760                                 if (c == 'L') {
 17601761                                         int c2 = cinput();
 17611762                                         if (c2 == '\"' || c2 == '\'')
 17621763                                                 donothing = 1;
 17631764                                         cunput(c2);
 17641765                                 }
 17651766                                 cunput(c);
 17661767 
 17671768                                 if (donothing == 0)
 17681769                                     if ((spechr[c] & C_ID0) || c == EBLOCK) {
 17691770                                         for (i = 0; i < svbidx; i++) {
 17701771                                                 cunput(svidx[i] >> 8);
 17711772                                                 cunput(svidx[i] & 255);
 17721773                                                 cunput(EBLOCK);
 17731774                                         }
 17741775                                 }
 17751776                                 free(svidx);
 17761777                         } else if (bidx) {
 17771778                                 /* must restore blocks */
 17781779                                 if (gmult) {
 17791780                                         unpstr(och);
 17801781                                         if (sloscan() != IDENT)
 17811782                                                 error("exparg sync error");
 17821783                                 }
 17831784                                 stringbuf = och;
 17841785                                 for (i = 0; i < bidx; i++)
 17851786                                         savch(EBLOCK), savch(bptr[i] & 255),
 17861787                                             savch(bptr[i] >> 8);
 17871788                                 savstr(yytext);
 17881789                         }
 17891790                         bidx = 0;
 17901791                         IMP("EA2");
 17911792                         break;
 17921793 
 17931794                 case CMNT:
 17941795                         getcmnt();
 17951796                         break;
 17961797 
 17971798                 case '\n':
 17981799                         cinput();
 17991800                         savch(' ');
 18001801                         break;
 18011802 
 18021803                 default:
 18031804                         savstr(yytext);
 18041805                         break;
 18051806                 }
 18061807         }
 18071808         *stringbuf = 0;
 18081809         cunput(WARN);
 18091810         unpstr(osb);
 18101811         DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
 18111812         IMP("EXPRET");
 18121813         stringbuf = osb;
 18131814         if (anychange)
 18141815                 goto rescan;
 18151816         readmac--;
 18161817 }
 18171818 
 18181819 #ifdef PCC_DEBUG
 18191820 static void
 18201821 imp(const char *str)
 18211822 {
 18221823         printf("%s (%d) '", str, bidx);
 18231824         prline(ifiles->curptr);
 18241825         printf("'\n");
 18251826 }
 18261827 
 18271828 static void
 18281829 prrep(const usch *s)
 18291830 {
 18301831         while (*s) {
 18311832                 switch (*s) {
 18321833                 case WARN: printf("<ARG(%d)>", *--s); break;
 18331834                 case CONC: printf("<CONC>"); break;
 18341835                 case SNUFF: printf("<SNUFF>"); break;
 18351836                 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
 18361837                 default: printf("%c", *s); break;
 18371838                 }
 18381839                 s--;
 18391840         }
 18401841 }
 18411842 
 18421843 static void
 18431844 prline(const usch *s)
 18441845 {
 18451846         while (*s) {
 18461847                 switch (*s) {
 18471848                 case WARN: printf("<WARN>"); break;
 18481849                 case CONC: printf("<CONC>"); break;
 18491850                 case SNUFF: printf("<SNUFF>"); break;
 18501851                 case PHOLD: printf("<PHOLD>"); break;
 18511852                 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
 18521853                 case '\n': printf("<NL>"); break;
 18531854                 default: printf("%c", *s); break;
 18541855                 }
 18551856                 s++;
 18561857         }
 18571858 }
 18581859 #endif
 18591860 
 18601861 usch *
 18611862 savstr(const usch *str)
 18621863 {
 18631864         usch *rv = stringbuf;
 18641865 
 18651866         do {
 18661867                 if (stringbuf >= &sbf[SBSIZE])   {
 18671868                         stringbuf = sbf; /* need space to write error message */
 18681869                         error("out of macro space!");
 18691870                 }
 18701871         } while ((*stringbuf++ = *str++));
 18711872         stringbuf--;
 18721873         return rv;
 18731874 }
 18741875 
 18751876 void
 18761877 unpstr(const usch *c)
 18771878 {
 18781879         const usch *d = c;
 18791880 
 18801881 #if 0
 18811882         if (dflag>1) {
 18821883                 printf("Xunpstr: '");
 18831884                 prline(c);
 18841885                 printf("'\n");
 18851886         }
 18861887 #endif
 18871888         while (*d) {
 18881889                 if (*d == EBLOCK)
 18891890                         d += 2;
 18901891                 d++;
 18911892         }
 18921893         while (d > c) {
 18931894                 cunput(*--d);
 18941895         }
 18951896 }
 18961897 
 18971898 static void
 18981899 flbuf(void)
 18991900 {
 19001901         if (obufp == 0)
 19011902                 return;
 19021903         if (Mflag == 0)
 19031904                 xwrite(ofd, outbuf, obufp);
 19041905         lastoch = outbuf[obufp-1];
 19051906         obufp = 0;
 19061907 }
 19071908 
 19081909 void
 19091910 putch(int ch)
 19101911 {
 19111912         outbuf[obufp++] = (usch)ch;
 19121913         if (obufp == CPPBUF || (istty && ch == '\n'))
 19131914                 flbuf();
 19141915 }
 19151916 
 19161917 void
 19171918 putstr(const usch *s)
 19181919 {
 19191920         for (; *s; s++) {
 19201921                 if (*s == PHOLD)
 19211922                         continue;
 19221923                 outbuf[obufp++] = *s;
 19231924                 if (obufp == CPPBUF || (istty && *s == '\n'))
 19241925                         flbuf();
 19251926         }
 19261927 }
 19271928 
 19281929 /*
 19291930  * convert a number to an ascii string. Store it on the heap.
 19301931  */
 19311932 static void
 19321933 num2str(int num)
 19331934 {
 19341935         static usch buf[12];
 19351936         usch *b = buf;
 19361937         int m = 0;
 19371938         
 19381939         if (num < 0)
 19391940                 num = -num, m = 1;
 19401941         do {
 19411942                 *b++ = (usch)(num % 10 + '0');
 19421943                 num /= 10;
 19431944         } while (num);
 19441945         if (m)
 19451946                 *b++ = '-';
 19461947         while (b > buf)
 19471948                 savch(*--b);
 19481949 }
 19491950 
 19501951 /*
 19511952  * similar to sprintf, but only handles %c, %s and %d.
 19521953  * saves result on heap.
 19531954  */
 19541955 static void
 19551956 vsheap(const char *fmt, va_list ap)
 19561957 {
 19571958         for (; *fmt; fmt++) {
 19581959                 if (*fmt == '%') {
 19591960                         fmt++;
 19601961                         switch (*fmt) {
 19611962                         case 's':
 19621963                                 savstr(va_arg(ap, usch *));
 19631964                                 break;
 19641965                         case 'd':
 19651966                                 num2str(va_arg(ap, int));
 19661967                                 break;
 19671968                         case 'c':
 19681969                                 savch(va_arg(ap, int));
 19691970                                 break;
 19701971                         default:
 19711972                                 error("bad sheap");
 19721973                         }
 19731974                 } else
 19741975                         savch(*fmt);
 19751976         }
 19761977         *stringbuf = 0;
 19771978 }
 19781979 
 19791980 usch *
 19801981 sheap(const char *fmt, ...)
 19811982 {
 19821983         va_list ap;
 19831984         usch *op = stringbuf;
 19841985 
 19851986         va_start(ap, fmt);
 19861987         vsheap(fmt, ap);
 19871988         va_end(ap);
 19881989 
 19891990         return op;
 19901991 }
 19911992 
 19921993 static void
 19931994 usage(void)
 19941995 {
 19951996         error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
 19961997 }
 19971998 
 19981999 #ifdef notyet
 19992000 /*
 20002001  * Symbol table stuff.
 20012002  * The data structure used is a patricia tree implementation using only
 20022003  * bytes to store offsets. 
 20032004  * The information stored is (lower address to higher):
 20042005  *
 20052006  *      unsigned char bitno[2]; bit number in the string
 20062007  *      unsigned char left[3];  offset from base to left element
 20072008  *      unsigned char right[3]; offset from base to right element
 20082009  */
 20092010 #endif
 20102011 
 20112012 /*
 20122013  * This patricia implementation is more-or-less the same as
 20132014  * used in ccom for string matching.
 20142015  */
 20152016 struct tree {
 20162017         int bitno;
 20172018         struct tree *lr[2];
 20182019 };
 20192020 
 20202021 #define BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
 20212022 #define LEFT_IS_LEAF            0x80000000
 20222023 #define RIGHT_IS_LEAF           0x40000000
 20232024 #define IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
 20242025 #define IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
 20252026 #define P_BIT(key, bit)         (key[bit >> 3] >> (bit & 7)) & 1
 20262027 #define CHECKBITS               8
 20272028 
 20282029 static struct tree *sympole;
 20292030 static int numsyms;
 20302031 
 20312032 /*
 20322033  * Allocate a symtab struct and store the string.
 20332034  */
 20342035 static struct symtab *
 20352036 getsymtab(const usch *str)
 20362037 {
 20372038         struct symtab *sp = malloc(sizeof(struct symtab));
 20382039 
 20392040         if (sp == NULL)
 20402041                 error("getsymtab: couldn't allocate symtab");
 20412042         sp->namep = savstr(str);
 20422043         savch('\0');
 20432044         sp->value = NULL;
 20442045         sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
 20452046         sp->line = ifiles ? ifiles->lineno : 0;
 20462047         return sp;
 20472048 }
 20482049 
 20492050 /*
 20502051  * Do symbol lookup in a patricia tree.
 20512052  * Only do full string matching, no pointer optimisations.
 20522053  */
 20532054 struct symtab *
 20542055 lookup(const usch *key, int enterf)
 20552056 {
 20562057         struct symtab *sp;
 20572058         struct tree *w, *new, *last;
 20582059         int len, cix, bit, fbit, svbit, ix, bitno;
 20592060         const usch *k, *m;
 20602061 
 20612062         /* Count full string length */
 20622063         for (k = key, len = 0; *k; k++, len++)
 20632064                 ;
 20642065 
 20652066         switch (numsyms) {
 20662067         case 0: /* no symbols yet */
 20672068                 if (enterf != ENTER)
 20682069                         return NULL;
 20692070                 sympole = (struct tree *)getsymtab(key);
 20702071                 numsyms++;
 20712072                 return (struct symtab *)sympole;
 20722073 
 20732074         case 1:
 20742075                 w = sympole;
 20752076                 svbit = 0; /* XXX gcc */
 20762077                 break;
 20772078 
 20782079         default:
 20792080                 w = sympole;
 20802081                 bitno = len * CHECKBITS;
 20812082                 for (;;) {
 20822083                         bit = BITNO(w->bitno);
 20832084                         fbit = bit > bitno ? 0 : P_BIT(key, bit);
 20842085                         svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
 20852086                             IS_LEFT_LEAF(w->bitno);
 20862087                         w = w->lr[fbit];
 20872088                         if (svbit)
 20882089                                 break;
 20892090                 }
 20902091         }
 20912092 
 20922093         sp = (struct symtab *)w;
 20932094 
 20942095         m = sp->namep;
 20952096         k = key;
 20962097 
 20972098         /* Check for correct string and return */
 20982099         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
 20992100                 ;
 21002101         if (*m == 0 && *k == 0) {
 21012102                 if (enterf != ENTER && sp->value == NULL)
 21022103                         return NULL;
 21032104                 return sp;
 21042105         }
 21052106 
 21062107         if (enterf != ENTER)
 21072108                 return NULL; /* no string found and do not enter */
 21082109 
 21092110         ix = *m ^ *k;
 21102111         while ((ix & 1) == 0)
 21112112                 ix >>= 1, cix++;
 21122113 
 21132114         /* Create new node */
 21142115         if ((new = malloc(sizeof *new)) == NULL)
 21152116                 error("getree: couldn't allocate tree");
 21162117         bit = P_BIT(key, cix);
 21172118         new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21182119         new->lr[bit] = (struct tree *)getsymtab(key);
 21192120 
 21202121         if (numsyms++ == 1) {
 21212122                 new->lr[!bit] = sympole;
 21222123                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21232124                 sympole = new;
 21242125                 return (struct symtab *)new->lr[bit];
 21252126         }
 21262127 
 21272128         w = sympole;
 21282129         last = NULL;
 21292130         for (;;) {
 21302131                 fbit = w->bitno;
 21312132                 bitno = BITNO(w->bitno);
 21322133                 if (bitno == cix)
 21332134                         error("bitno == cix");
 21342135                 if (bitno > cix)
 21352136                         break;
 21362137                 svbit = P_BIT(key, bitno);
 21372138                 last = w;
 21382139                 w = w->lr[svbit];
 21392140                 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
 21402141                         break;
 21412142         }
 21422143 
 21432144         new->lr[!bit] = w;
 21442145         if (last == NULL) {
 21452146                 sympole = new;
 21462147         } else {
 21472148                 last->lr[svbit] = new;
 21482149                 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
 21492150         }
 21502151         if (bitno < cix)
 21512152                 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
 21522153         return (struct symtab *)new->lr[bit];
 21532154 }
 21542155 
 21552156 static usch *
 21562157 xstrdup(const usch *str)
 21572158 {
 21582159         usch *rv;
 21592160 
 21602161         if ((rv = (usch *)strdup((const char *)str)) == NULL)
 21612162                 error("xstrdup: out of mem");
 21622163         return rv;
 21632164 }
 21642165 
 21652166 void
 21662167 xwrite(int fd, const void *buf, unsigned int len)
 21672168 {
 21682169         if (write(fd, buf, len) != (int)len) {
 21692170                 if (fd == 2)
 21702171                         exit(2);
 21712172                 error("write error");
 21722173         }
 21732174 }
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 14:28 +0100