Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20150509150656

Diff

Diff from 1.214 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/cc/cpp/cpp.c

Annotated File View

ragge
1.214
1 /*      $Id: cpp.c,v 1.214 2015/05/09 15:06:56 ragge Exp $      */
ragge
1.1
2
3 /*
ragge
1.109
4  * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
ragge
1.1
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /*
29  * The C preprocessor.
30  * This code originates from the V6 preprocessor with some additions
31  * from V7 cpp, and at last ansi/c99 support.
32  */
pj
1.23
33
ragge
1.74
34 #include "config.h"
pj
1.23
35
ragge
1.108
36 #include <sys/stat.h>
ragge
1.1
37
38 #include <fcntl.h>
gmcgarry
1.81
39 #ifdef HAVE_UNISTD_H
ragge
1.1
40 #include <unistd.h>
gmcgarry
1.81
41 #endif
ragge
1.1
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
ragge
1.9
46 #include <time.h>
ragge
1.1
47
ragge
1.74
48 #include "compat.h"
ragge
1.1
49 #include "cpp.h"
50
gmcgarry
1.130
51 #ifndef S_ISDIR
52 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
53 #endif
54
ragge
1.126
55 #define SBSIZE  1000000
ragge
1.1
56
57 static usch     sbf[SBSIZE];
58 /* C command */
59
60 int tflag;      /* traditional cpp syntax */
plunky
1.134
61 #ifdef PCC_DEBUG
ragge
1.1
62 int dflag;      /* debug printouts */
plunky
1.135
63 static void imp(const char *);
64 static void prline(const usch *s);
65 static void prrep(const usch *s);
ragge
1.36
66 #define DPRINT(x) if (dflag) printf x
67 #define DDPRINT(x) if (dflag > 1) printf x
plunky
1.135
68 #define IMP(x) if (dflag > 1) imp(x)
ragge
1.36
69 #else
70 #define DPRINT(x)
71 #define DDPRINT(x)
plunky
1.135
72 #define IMP(x)
ragge
1.1
73 #endif
ragge
1.36
74
ragge
1.195
75 int AflagCflagEflagMflagdMflagPflagMPflagMMDflag;
ragge
1.151
76 usch *Mfile, *MPfile, *Mxfile;
ragge
1.53
77 struct initar *initar;
plunky
1.186
78 int readmac;
plunky
1.173
79 int defining;
plunky
1.187
80 int warnings;
ragge
1.197
81 FILE *of;
ragge
1.1
82
ragge
1.10
83 /* include dirs */
84 struct incs {
85         struct incs *next;
ragge
1.39
86         usch *dir;
ragge
1.108
87         dev_t dev;
88         ino_t ino;
ragge
1.20
89 } *incdir[2];
ragge
1.10
90
ragge
1.1
91 static struct symtab *filloc;
92 static struct symtab *linloc;
ragge
1.65
93 static struct symtab *pragloc;
ragge
1.10
94 int     trulvl;
95 int     flslvl;
96 int     elflvl;
97 int     elslvl;
98 usch *stringbuf = sbf;
ragge
1.1
99
100 /*
101  * Macro replacement list syntax:
102  * - For object-type macros, replacement strings are stored as-is.
103  * - For function-type macros, macro args are substituted for the
104  *   character WARN followed by the argument number.
ragge
1.214
105  * - The value element points to the beginning of the string.
plunky
1.191
106  *
ragge
1.213
107  * The first character in the replacement list is the number of arguments:
ragge
1.37
108  *   VARG  - ends with ellipsis, next char is argcount without ellips.
ragge
1.1
109  *   OBJCT - object-type macro
plunky
1.191
110  *   0     - empty parenthesis, foo()
ragge
1.1
111  *   1->   - number of args.
ragge
1.109
112  *
113  * WARN is used:
114  *      - in stored replacement lists to tell that an argument comes
115  *      - When expanding replacement lists to tell that the list ended.
ragge
1.116
116  *
117  * To ensure that an already expanded identifier won't get expanded
plunky
1.191
118  * again a EBLOCK char + its number is stored directly before any
ragge
1.116
119  * expanded identifier.
ragge
1.1
120  */
121
122 /* args for lookup() */
123 #define FIND    0
124 #define ENTER   1
125
plunky
1.166
126 /*
127  * No-replacement array.  If a macro is found and exists in this array
128  * then no replacement shall occur.  This is a stack.
129  */
130 struct symtab *norep[RECMAX];   /* Symbol table index table */
131 int norepptr = 1;                       /* Top of index table */
132 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
133 int bidx;                       /* Top of bptr stack */
134
ragge
1.112
135 static int readargs(struct symtab *spconst usch **args);
ragge
1.116
136 static void exparg(int);
ragge
1.112
137 static void subarg(struct symtab *spconst usch **argsint);
plunky
1.143
138 static void usage(void);
139 static usch *xstrdup(const usch *str);
ragge
1.108
140 static void addidir(char *idirstruct incs **ww);
plunky
1.178
141 static void vsheap(const char *, va_list);
ragge
1.1
142
143 int
144 main(int argcchar **argv)
145 {
ragge
1.53
146         struct initar *it;
ragge
1.26
147         struct symtab *nl;
148         register int ch;
ragge
1.103
149         const usch *fn1, *fn2;
ragge
1.15
150
ragge
1.94
151 #ifdef TIMING
152         struct timeval t1t2;
153
154         (void)gettimeofday(&t1NULL);
155 #endif
156
plunky
1.188
157         while ((ch = getopt(argcargv"ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
ragge
1.1
158                 switch (ch) {
plunky
1.188
159                 case 'A'/* assembler input */
160                         Aflag++;
161                         break;
plunky
1.191
162
ragge
1.22
163                 case 'C'/* Do not discard comments */
164                         Cflag++;
165                         break;
166
plunky
1.187
167                 case 'E'/* treat warnings as errors */
168                         Eflag++;
169                         break;
170
plunky
1.142
171                 case 'D'/* define something */
ragge
1.53
172                 case 'i'/* include */
173                 case 'U'/* undef */
ragge
1.58
174                         /* XXX should not need malloc() here */
175                         if ((it = malloc(sizeof(struct initar))) == NULL)
176                                 error("couldn't apply -%c %s"choptarg);
ragge
1.53
177                         it->type = ch;
178                         it->str = optarg;
179                         it->next = initar;
180                         initar = it;
ragge
1.7
181                         break;
182
plunky
1.142
183                 case 'd':
plunky
1.144
184                         while (*optarg) {
185                                 switch(*optarg) {
186                                 case 'M'/* display macro definitions */
187                                         dMflag = 1;
188                                         Mflag = 1;
189                                         break;
190
191                                 default/* ignore others */
192                                         break;
193                                 }
194                                 optarg++;
plunky
1.142
195                         }
196                         break;
197
198                 case 'I':
199                 case 'S':
200                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
201                         break;
202
ragge
1.51
203                 case 'M'/* Generate dependencies for make */
204                         Mflag++;
205                         break;
206
gmcgarry
1.85
207                 case 'P'/* Inhibit generation of line numbers */
208                         Pflag++;
209                         break;
210
plunky
1.142
211                 case 't':
212                         tflag = 1;
ragge
1.7
213                         break;
214
plunky
1.134
215 #ifdef PCC_DEBUG
ragge
1.64
216                 case 'V':
ragge
1.18
217                         dflag++;
ragge
1.1
218                         break;
219 #endif
ragge
1.64
220                 case 'v':
plunky
1.200
221                         fprintf(stderr"PCC preprocessor version "VERSSTR"\n");
ragge
1.64
222                         break;
ragge
1.1
223
ragge
1.151
224                 case 'x':
ragge
1.195
225                         if (strcmp(optarg"MMD") == 0) {
226                                 MMDflag++;
227                         } else if (strcmp(optarg"MP") == 0) {
ragge
1.151
228                                 MPflag++;
229                         } else if (strncmp(optarg"MT,"3) == 0 ||
230                             strncmp(optarg"MQ,"3) == 0) {
231                                 usch *cp, *fn;
232                                 fn = stringbuf;
233                                 for (cp = (usch *)&optarg[3]; *cpcp++) {
234                                         if (*cp == '$' && optarg[1] == 'Q')
235                                                 savch('$');
236                                         savch(*cp);
237                                 }
plunky
1.191
238                                 savstr((const usch *)"");
ragge
1.151
239                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
240                                 savch(0);
241                                 Mxfile = fn;
242                         } else
243                                 usage();
244                         break;
245
ragge
1.37
246                 case '?':
plunky
1.142
247                 default:
ragge
1.37
248                         usage();
ragge
1.1
249                 }
plunky
1.142
250         }
251
ragge
1.1
252         argc -= optind;
253         argv += optind;
254
ragge
1.103
255         filloc = lookup((const usch *)"__FILE__"ENTER);
256         linloc = lookup((const usch *)"__LINE__"ENTER);
ragge
1.114
257         filloc->value = linloc->value = stringbuf;
258         savch(OBJCT);
259
260         /* create a complete macro for pragma */
ragge
1.103
261         pragloc = lookup((const usch *)"_Pragma"ENTER);
ragge
1.213
262         pragloc->value = stringbuf;
ragge
1.214
263 #define PRAGLINE        "\001_Pragma(\001\0)"
264         memcpy(stringbufPRAGLINEsizeof(PRAGLINE));
265         stringbuf += sizeof(PRAGLINE);
ragge
1.15
266
ragge
1.12
267         if (tflag == 0) {
268                 time_t t = time(NULL);
ragge
1.39
269                 usch *n = (usch *)ctime(&t);
ragge
1.12
270
271                 /*
272                  * Manually move in the predefined macros.
273                  */
ragge
1.103
274                 nl = lookup((const usch *)"__TIME__"ENTER);
ragge
1.213
275                 nl->value = stringbuf;
ragge
1.12
276                 savch(OBJCT);
ragge
1.213
277                 savch('"'); n[19] = 0savstr(&n[11]); savch('"');savch(0); 
ragge
1.12
278
ragge
1.103
279                 nl = lookup((const usch *)"__DATE__"ENTER);
ragge
1.213
280                 nl->value = stringbuf;
281                 savch(OBJCT);
282                 savch('"'); n[24] = n[11] = 0savstr(&n[4]);
283                 savstr(&n[20]); savch('"'); savch(OBJCT);savch(0); 
ragge
1.12
284
ragge
1.103
285                 nl = lookup((const usch *)"__STDC__"ENTER);
ragge
1.213
286                 nl->value = stringbuf;
287                 savch(OBJCT); savch('1');savch(0);
ragge
1.73
288
ragge
1.103
289                 nl = lookup((const usch *)"__STDC_VERSION__"ENTER);
ragge
1.213
290                 nl->value = stringbuf;
291                 savch(OBJCT); savstr((const usch *)"199901L"); savch(0);
ragge
1.12
292         }
ragge
1.1
293
ragge
1.60
294         if (Mflag && !dMflag) {
ragge
1.51
295                 usch *c;
296
297                 if (argc < 1)
298                         error("-M and no infile");
299                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
300                         c = (usch *)argv[0];
301                 else
302                         c++;
303                 Mfile = stringbuf;
304                 savstr(c); savch(0);
ragge
1.151
305                 if (MPflag) {
306                         MPfile = stringbuf;
307                         savstr(c); savch(0);
308                 }
309                 if (Mxfile)
310                         Mfile = Mxfile;
ragge
1.51
311                 if ((c = (usch *)strrchr((char *)Mfile'.')) == NULL)
312                         error("-M and no extension: ");
313                 c[1] = 'o';
314                 c[2] = 0;
315         }
316
ragge
1.26
317         if (argc == 2) {
ragge
1.197
318                 if ((of = freopen(argv[1], "w"stdout)) == NULL)
ragge
1.37
319                         error("Can't creat %s"argv[1]);
ragge
1.26
320         } else
ragge
1.197
321                 of = stdout;
ragge
1.26
322
ragge
1.102
323         if (argc && strcmp(argv[0], "-")) {
324                 fn1 = fn2 = (usch *)argv[0];
325         } else {
326                 fn1 = NULL;
ragge
1.103
327                 fn2 = (const usch *)"";
ragge
1.102
328         }
329         if (pushfile(fn1fn20NULL))
ragge
1.26
330                 error("cannot open %s"argv[0]);
331
ragge
1.197
332         fclose(of);
ragge
1.94
333 #ifdef TIMING
334         (void)gettimeofday(&t2NULL);
335         t2.tv_sec -= t1.tv_sec;
336         t2.tv_usec -= t1.tv_usec;
337         if (t2.tv_usec < 0) {
338                 t2.tv_usec += 1000000;
339                 t2.tv_sec -= 1;
340         }
341         fprintf(stderr"cpp total time: %ld s %ld us\n",
plunky
1.159
342              (long)t2.tv_sec, (long)t2.tv_usec);
ragge
1.94
343 #endif
plunky
1.187
344         if (Eflag && warnings > 0)
345                 return 2;
346
ragge
1.37
347         return 0;
ragge
1.26
348 }
349
ragge
1.214
350 #define NOBUFS 2
351 static usch obs[NOBUFS][BUFSIZ];
352 struct obuf obufs[NOBUFS] = {
353         { obs[0], 0BUFSIZ },
354         { obs[1], 0BUFSIZ },
355 };
356 struct obuf *obufp;
357 usch *ibufp;
358
359
360 /*
361  * Sets which buffers to read from/write to.
362  * ibuf is a NULL-terminated string.  If NULL, use current input.
363  * obuf is the output buffer index. 0 sets current output, other indexes
364  * sets buffers.  The base output buffer address is returned.
365  */
366 static struct obuf *
367 inobuf(const usch *ibufint obuf)
368 {
369         ibufp = (usch *)ibuf;
370         if (obuf) {
371                 obufp = &obufs[obuf-1];
372                 obufp->curpos = 0;
373                 return obufp;
374         }
375         return NULL;
376 }
377
ragge
1.108
378 static void
379 addidir(char *idirstruct incs **ww)
380 {
381         struct incs *w;
382         struct stat st;
383
plunky
1.163
384         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
ragge
1.108
385                 return/* ignore */
386         if (*ww != NULL) {
387                 for (w = *www->nextw = w->next) {
plunky
1.203
388 #ifdef _WIN32
gmcgarry
1.131
389                         if (strcmp(w->diridir) == 0)
390                                 return;
391 #else
ragge
1.108
392                         if (w->dev == st.st_dev && w->ino == st.st_ino)
393                                 return;
gmcgarry
1.131
394 #endif
ragge
1.108
395                 }
plunky
1.203
396 #ifdef _WIN32
gmcgarry
1.131
397                 if (strcmp(w->diridir) == 0)
398                         return;
399 #else
ragge
1.108
400                 if (w->dev == st.st_dev && w->ino == st.st_ino)
401                         return;
gmcgarry
1.131
402 #endif
ragge
1.108
403                 ww = &w->next;
404         }
405         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
406                 error("couldn't add path %s"idir);
407         w->dir = (usch *)idir;
408         w->dev = st.st_dev;
409         w->ino = st.st_ino;
410         *ww = w;
411 }
412
ragge
1.1
413 void
plunky
1.143
414 line(void)
ragge
1.9
415 {
ragge
1.37
416         static usch *lbuf;
417         static int llen;
ragge
1.97
418         usch *p;
ragge
1.9
419         int c;
420
ragge
1.97
421         if ((c = yylex()) != NUMBER)
ragge
1.9
422                 goto bad;
ragge
1.209
423         p = yytext;
424         c = 0;
425         /* Can only be decimal number here between 1-2147483647 */
426         while (spechr[*p] & C_DIGIT)
427                 c = c * 10 + *p++ - '0';
428         if (*p != 0 || c < 1 || c > 2147483647)
429                 goto bad;
430
431         ifiles->lineno = c-1;
plunky
1.185
432         ifiles->escln = 0;
ragge
1.97
433         if ((c = yylex()) == '\n')
plunky
1.181
434                 goto okret;
ragge
1.97
435
436         if (c != STRING)
ragge
1.9
437                 goto bad;
ragge
1.97
438
plunky
1.160
439         p = yytext;
plunky
1.158
440         if (*p++ == 'L')
ragge
1.97
441                 p++;
442         c = strlen((char *)p);
plunky
1.158
443         p[c - 1] = '\0';
ragge
1.37
444         if (llen < c) {
plunky
1.136
445                 /* XXX may lose heap space */
ragge
1.37
446                 lbuf = stringbuf;
447                 stringbuf += c;
448                 llen = c;
plunky
1.201
449                 if (stringbuf >= &sbf[SBSIZE])
plunky
1.182
450                         error("#line filename exceeds buffer size");
ragge
1.37
451         }
plunky
1.158
452         memcpy(lbufpc);
ragge
1.37
453         ifiles->fname = lbuf;
plunky
1.181
454         if (yylex() != '\n')
455                 goto bad;
456
457 okret:  prtline();
458         return;
ragge
1.9
459
plunky
1.182
460 bad:    error("bad #line");
ragge
1.9
461 }
462
gmcgarry
1.189
463 #ifdef MACHOABI
464
465 /*
466  * Search for framework header file.
467  * Return 1 on success.
468  */
469
470 static int
471 fsrch_macos_framework(const usch *fnconst usch *dir)
472 {
473         usch *saved_stringbuf = stringbuf;
474         usch *s = (usch *)strchr((const char*)fn'/');
gmcgarry
1.194
475         usch *nm;
476         usch *p;
477         int len  = s - fn;
478
479         if (s == NULL)
480                 return 0;
481
482 //      fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir);
gmcgarry
1.189
483
gmcgarry
1.194
484         nm = savstr(dir);
485         savch(0);
486         p = savstr(fn);
487         stringbuf = p + len;
488         savch(0);
489 //      fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn);
490         p = (usch *)strstr((const char *)nm, (const char *)p);
491 //      fprintf(stderr, "p = %s\n", (const char *)p);
492         if (p != NULL) {
493                 stringbuf = p;
gmcgarry
1.189
494                 savch(0);
gmcgarry
1.194
495                 return fsrch_macos_framework(fnnm);
496         }
gmcgarry
1.189
497
gmcgarry
1.194
498         p = nm + strlen((char *)nm) - 1;
499         while (*p == '/')
500                 p--;
501         while (*p != '/')
502                 p--;
503         stringbuf = ++p;
504         savstr((const usch *)"Frameworks/");
505         stringbuf = savstr(fn) + len;
506         savstr((const usch*)".framework/Headers");
507         savstr(s);
508         savch(0);
gmcgarry
1.189
509
gmcgarry
1.194
510 //      fprintf(stderr, "nm: %s\n", nm);
gmcgarry
1.189
511
gmcgarry
1.194
512         if (pushfile(nmfnSYSINCNULL) == 0)
513                 return 1;
514 //      fprintf(stderr, "not found %s, continuing...\n", nm);
gmcgarry
1.189
515
516         stringbuf = saved_stringbuf;
517
518         return 0;
519 }
520
521 #endif
522
ragge
1.10
523 /*
ragge
1.102
524  * Search for and include next file.
525  * Return 1 on success.
526  */
527 static int
ragge
1.103
528 fsrch(const usch *fnint idxstruct incs *w)
ragge
1.102
529 {
530         int i;
531
532         for (i = idxi < 2i++) {
533                 if (i > idx)
534                         w = incdir[i];
535                 for (; ww = w->next) {
536                         usch *nm = stringbuf;
537
538                         savstr(w->dir); savch('/');
539                         savstr(fn); savch(0);
540                         if (pushfile(nmfniw->next) == 0)
541                                 return 1;
542                         stringbuf = nm;
543                 }
544         }
gmcgarry
1.189
545
546 #ifdef MACHOABI
547         /*
548          * On MacOS, we may have to do some clever stuff
549          * to resolve framework headers.
plunky
1.191
550          */
gmcgarry
1.194
551         {
552                 usch *dir = stringbuf;
553                 savstr(ifiles->orgfn);
554                 stringbuf = (usch *)strrchr((char *)dir'/');
555                 if (stringbuf != NULL) {
556                         stringbuf++;
557                         savch(0);
558                         if (fsrch_macos_framework(fndir) == 1)
559                                 return 1;
560                 }
561                 stringbuf = dir;
562
563                 if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1)
564                         return 1;
565
566                 if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1)
567                         return 1;
568         }
gmcgarry
1.189
569 #endif
570
ragge
1.102
571         return 0;
572 }
573
ragge
1.132
574 static void
575 prem(void)
576 {
577         error("premature EOF");
578 }
579
plunky
1.193
580 static usch *
581 incfn(int e)
582 {
583         usch *sb = stringbuf;
584         int c;
585
586         while ((c = cinput()) != e) {
587                 if (c == -1)
588                         prem();
589                 if (c == '\n') {
590                         stringbuf = sb;
591                         return NULL;
592                 }
593                 savch(c);
594         }
595         savch(0);
596
ragge
1.212
597         c = sloscan(NULLSLO_IGNOREWS);
plunky
1.193
598                 ;
599         if (c == 0)
600                 prem();
601         if (c != '\n') {
602                 stringbuf = sb;
603                 return NULL;
604         }
605
606         return sb;
607 }
608
ragge
1.102
609 /*
ragge
1.10
610  * Include a file. Include order:
ragge
1.20
611  * - For <...> files, first search -I directories, then system directories.
612  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
613  */
ragge
1.9
614 void
plunky
1.143
615 include(void)
ragge
1.3
616 {
ragge
1.101
617         struct symtab *nl;
plunky
1.193
618         usch *fn, *nm;
gmcgarry
1.133
619         int c;
ragge
1.3
620
ragge
1.37
621         if (flslvl)
622                 return;
ragge
1.97
623
plunky
1.193
624         while ((c = cinput()) == ' ' || c == '\t')
ragge
1.101
625                 ;
plunky
1.193
626
627         if (c != -1 && (spechr[c] & C_ID0)) {
628                 usch *sb;
629
630                 /* use sloscan() to read the identifier, then expand it */
631                 cunput(c);
ragge
1.212
632                 c = sloscan(NULL0);
plunky
1.160
633                 if ((nl = lookup(yytextFIND)) == NULL)
ragge
1.101
634                         goto bad;
plunky
1.193
635
636                 sb = stringbuf;
ragge
1.112
637                 if (kfind(nl))
638                         unpstr(stringbuf);
639                 else
640                         unpstr(nl->namep);
plunky
1.193
641                 stringbuf = sb;
642
643                 c = cinput();
ragge
1.101
644         }
ragge
1.3
645
ragge
1.97
646         if (c == '<') {
plunky
1.193
647                 if ((fn = incfn('>')) == NULL)
648                         goto bad;
649         } else if (c == '\"') {
650                 if ((fn = incfn('\"')) == NULL)
ragge
1.37
651                         goto bad;
plunky
1.193
652
ragge
1.20
653                 /* first try to open file relative to previous file */
ragge
1.53
654                 /* but only if it is not an absolute path */
plunky
1.193
655                 nm = stringbuf;
ragge
1.53
656                 if (*fn != '/') {
657                         savstr(ifiles->orgfn);
plunky
1.193
658                         stringbuf = (usch *)strrchr((char *)nm'/');
659                         if (stringbuf == NULL)
ragge
1.53
660                                 stringbuf = nm;
661                         else
662                                 stringbuf++;
663                 }
plunky
1.193
664                 savstr(fn);
665                 savch(0);
666
667                 if (pushfile(nmfn0NULL) == 0)
ragge
1.97
668                         goto okret;
plunky
1.193
669
plunky
1.136
670                 /* XXX may lose stringbuf space */
plunky
1.183
671         } else
672                 goto bad;
ragge
1.10
673
plunky
1.193
674         if (fsrch(fn0incdir[0]))
ragge
1.102
675                 goto okret;
ragge
1.10
676
plunky
1.193
677         error("cannot find '%s'"fn);
ragge
1.37
678         /* error() do not return */
ragge
1.3
679
plunky
1.182
680 bad:    error("bad #include");
ragge
1.37
681         /* error() do not return */
ragge
1.97
682 okret:
683         prtline();
ragge
1.37
684 }
685
ragge
1.102
686 void
plunky
1.143
687 include_next(void)
ragge
1.102
688 {
ragge
1.105
689         struct symtab *nl;
690         usch *fn;
691         int c;
692
ragge
1.107
693         if (flslvl)
694                 return;
plunky
1.193
695
696         while ((c = cinput()) == ' ' || c == '\t')
ragge
1.105
697                 ;
plunky
1.193
698
699         if (c != -1 && (spechr[c] & C_ID0)) {
700                 usch *sb;
701
ragge
1.210
702                 /* use sloscan(NULL) to read the identifier, then expand it */
plunky
1.193
703                 cunput(c);
ragge
1.212
704                 c = sloscan(NULL0);
plunky
1.160
705                 if ((nl = lookup(yytextFIND)) == NULL)
ragge
1.105
706                         goto bad;
plunky
1.193
707
708                 sb = stringbuf;
ragge
1.112
709                 if (kfind(nl))
710                         unpstr(stringbuf);
711                 else
712                         unpstr(nl->namep);
plunky
1.193
713                 stringbuf = sb;
714
715                 c = cinput();
ragge
1.105
716         }
717
plunky
1.193
718         if (c == '\"') {
719                 if ((fn = incfn('\"')) == NULL)
720                         goto bad;
721         } else if (c == '<') {
722                 if ((fn = incfn('>')) == NULL)
723                         goto bad;
724         } else
ragge
1.105
725                 goto bad;
726
727         if (fsrch(fnifiles->idxifiles->incs) == 0)
728                 error("cannot find '%s'"fn);
plunky
1.193
729
ragge
1.105
730         prtline();
731         return;
732
plunky
1.182
733 bad:    error("bad #include_next");
ragge
1.105
734         /* error() do not return */
ragge
1.102
735 }
736
ragge
1.37
737 static int
738 definp(void)
739 {
740         int c;
741
742         do
ragge
1.212
743                 c = sloscan(NULL0);
ragge
1.37
744         while (c == WSPACE);
745         return c;
ragge
1.3
746 }
747
ragge
1.79
748 /*
749  * Compare two replacement lists, taking in account comments etc.
750  */
751 static int
ragge
1.103
752 cmprepl(const usch *oconst usch *n)
ragge
1.79
753 {
ragge
1.213
754         for (; *oo++, n++) {
ragge
1.79
755                 /* comment skip */
ragge
1.213
756                 if (*o == '/' && o[1] == '*') {
757                         while (*o != '*' || o[1] != '/')
758                                 o++;
759                         o += 2;
760                 }
761                 if (*n == '/' && n[1] == '*') {
762                         while (*n != '*' || n[1] != '/')
763                                 n++;
764                         n += 2;
ragge
1.79
765                 }
766                 while (*o == ' ' || *o == '\t')
ragge
1.213
767                         o++;
ragge
1.79
768                 while (*n == ' ' || *n == '\t')
ragge
1.213
769                         n++;
ragge
1.79
770                 if (*o != *n)
771                         return 1;
772         }
773         return 0;
774 }
775
ragge
1.97
776 static int
777 isell(void)
778 {
779         int ch;
780
781         if ((ch = cinput()) != '.') {
782                 cunput(ch);
783                 return 0;
784         }
785         if ((ch = cinput()) != '.') {
786                 cunput(ch);
787                 cunput('.');
788                 return 0;
789         }
790         return 1;
791 }
792
ragge
1.3
793 void
plunky
1.143
794 define(void)
ragge
1.1
795 {
796         struct symtab *np;
ragge
1.112
797         usch *args[MAXARGS+1], *ubuf, *sbeg;
ragge
1.15
798         int ciredef;
ragge
1.1
799         int mkstr = 0narg = -1;
ragge
1.37
800         int ellips = 0;
ragge
1.128
801 #ifdef GCC_COMPAT
ragge
1.86
802         usch *gccvari = NULL;
ragge
1.91
803         int wascon;
ragge
1.86
804 #endif
ragge
1.1
805
ragge
1.37
806         if (flslvl)
807                 return;
ragge
1.212
808         if ((i = sloscan(NULLSLO_IGNOREWS)) != IDENT)
ragge
1.37
809                 goto bad;
ragge
1.36
810
plunky
1.160
811         np = lookup(yytextENTER);
ragge
1.15
812         redef = np->value != NULL;
ragge
1.1
813
ragge
1.138
814         defining = readmac = 1;
ragge
1.213
815         sbeg = stringbuf++;
ragge
1.212
816         if ((c = sloscan(NULL0)) == '(') {
ragge
1.1
817                 narg = 0;
818                 /* function-like macros, deal with identifiers */
ragge
1.213
819                 c = sloscan(NULLSLO_IGNOREWS); /* XXX -CC */
ragge
1.37
820                 for (;;) {
ragge
1.1
821                         if (c == ')')
822                                 break;
ragge
1.97
823                         if (c == '.' && isell()) {
ragge
1.37
824                                 ellips = 1;
ragge
1.212
825                                 if (sloscan(NULLSLO_IGNOREWS) != ')')
ragge
1.37
826                                         goto bad;
827                                 break;
828                         }
829                         if (c == IDENT) {
ragge
1.72
830                                 /* make sure there is no arg of same name */
831                                 for (i = 0i < nargi++)
ragge
1.116
832                                         if (!strcmp((char *) args[i], (char *)yytext))
ragge
1.72
833                                                 error("Duplicate macro "
834                                                   "parameter \"%s\""yytext);
ragge
1.112
835                                 if (narg == MAXARGS)
836                                         error("Too many macro args");
ragge
1.90
837                                 args[narg++] = xstrdup(yytext);
ragge
1.72
838                                 if ((c = definp()) == ',') {
ragge
1.212
839                                         if ((c = sloscan(NULL,
840                                             SLO_IGNOREWS)) == ')')
ragge
1.72
841                                                 goto bad;
ragge
1.37
842                                         continue;
ragge
1.72
843                                 }
ragge
1.128
844 #ifdef GCC_COMPAT
ragge
1.97
845                                 if (c == '.' && isell()) {
ragge
1.212
846                                         if (sloscan(NULLSLO_IGNOREWS) != ')')
ragge
1.86
847                                                 goto bad;
848                                         gccvari = args[--narg];
849                                         break;
850                                 }
851 #endif
ragge
1.37
852                                 if (c == ')')
853                                         break;
854                         }
855                         goto bad;
ragge
1.1
856                 }
ragge
1.212
857                 c = sloscan(savch0);
ragge
1.36
858         } else if (c == '\n') {
ragge
1.8
859                 /* #define foo */
ragge
1.36
860                 ;
ragge
1.132
861         } else if (c == 0) {
862                 prem();
ragge
1.1
863         } else if (c != WSPACE)
ragge
1.37
864                 goto bad;
ragge
1.1
865
ragge
1.31
866         while (c == WSPACE)
ragge
1.212
867                 c = sloscan(savch0);
ragge
1.1
868
ragge
1.213
869         if (ellips || gccvari)
870                 stringbuf++;
871
ragge
1.72
872         /* replacement list cannot start with ## operator */
ragge
1.97
873         if (c == '#') {
ragge
1.212
874                 if ((c = sloscan(savch0)) == '#')
ragge
1.97
875                         goto bad;
ragge
1.213
876 //              savch('\0');
ragge
1.128
877 #ifdef GCC_COMPAT
ragge
1.97
878                 wascon = 0;
879 #endif
880                 goto in2;
881         }
ragge
1.72
882
ragge
1.1
883         /* parse replacement-list, substituting arguments */
ragge
1.213
884 //      savch('\0');
ragge
1.36
885         while (c != '\n') {
ragge
1.128
886 #ifdef GCC_COMPAT
ragge
1.91
887                 wascon = 0;
888 loop:
889 #endif
ragge
1.1
890                 switch (c) {
891                 case WSPACE:
892                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
893                         ubuf = stringbuf;
plunky
1.160
894                         savstr(yytext);
ragge
1.212
895                         c = sloscan(savch0);
ragge
1.97
896                         if (c == '#') {
ragge
1.212
897                                 if ((c = sloscan(savch0)) != '#')
ragge
1.97
898                                         goto in2;
ragge
1.2
899                                 stringbuf = ubuf;
ragge
1.1
900                                 savch(CONC);
ragge
1.212
901                                 c = sloscan(savchSLO_IGNOREWS);
ragge
1.128