Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20140818184605

Diff

Diff from 1.195 to:

Annotations

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

Annotated File View

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