Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20140604064349

Diff

Diff from 1.194 to:

Annotations

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

Annotated File View

gmcgarry
1.194
1 /*      $Id: cpp.c,v 1.194 2014/06/04 06:43:49 gmcgarry 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;
plunky
1.188
81 int AflagCflagEflagMflagdMflagPflagMPflag;
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':
233                         if (strcmp(optarg"MP") == 0) {
234                                 MPflag++;
235                         } else if (strncmp(optarg"MT,"3) == 0 ||
236                             strncmp(optarg"MQ,"3) == 0) {
237                                 usch *cp, *fn;
238                                 fn = stringbuf;
239                                 for (cp = (usch *)&optarg[3]; *cpcp++) {
240                                         if (*cp == '$' && optarg[1] == 'Q')
241                                                 savch('$');
242                                         savch(*cp);
243                                 }
plunky
1.191
244                                 savstr((const usch *)"");
ragge
1.151
245                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
246                                 savch(0);
247                                 Mxfile = fn;
248                         } else
249                                 usage();
250                         break;
251
ragge
1.37
252                 case '?':
plunky
1.142
253                 default:
ragge
1.37
254                         usage();
ragge
1.1
255                 }
plunky
1.142
256         }
257
ragge
1.1
258         argc -= optind;
259         argv += optind;
260
ragge
1.103
261         filloc = lookup((const usch *)"__FILE__"ENTER);
262         linloc = lookup((const usch *)"__LINE__"ENTER);
ragge
1.114
263         filloc->value = linloc->value = stringbuf;
264         savch(OBJCT);
265
266         /* create a complete macro for pragma */
ragge
1.103
267         pragloc = lookup((const usch *)"_Pragma"ENTER);
ragge
1.114
268         savch(0);
ragge
1.115
269         savstr((const usch *)"_Pragma(");
ragge
1.114
270         savch(0);
271         savch(WARN);
272         savch(')');
273         pragloc->value = stringbuf;
274         savch(1);
ragge
1.15
275
ragge
1.12
276         if (tflag == 0) {
277                 time_t t = time(NULL);
ragge
1.39
278                 usch *n = (usch *)ctime(&t);
ragge
1.12
279
280                 /*
281                  * Manually move in the predefined macros.
282                  */
ragge
1.103
283                 nl = lookup((const usch *)"__TIME__"ENTER);
ragge
1.13
284                 savch(0); savch('"');  n[19] = 0savstr(&n[11]); savch('"');
ragge
1.12
285                 savch(OBJCT);
286                 nl->value = stringbuf-1;
287
ragge
1.103
288                 nl = lookup((const usch *)"__DATE__"ENTER);
ragge
1.13
289                 savch(0); savch('"'); n[24] = n[11] = 0savstr(&n[4]);
290                 savstr(&n[20]); savch('"'); savch(OBJCT);
ragge
1.12
291                 nl->value = stringbuf-1;
292
ragge
1.103
293                 nl = lookup((const usch *)"__STDC__"ENTER);
ragge
1.13
294                 savch(0); savch('1'); savch(OBJCT);
ragge
1.12
295                 nl->value = stringbuf-1;
ragge
1.73
296
ragge
1.103
297                 nl = lookup((const usch *)"__STDC_VERSION__"ENTER);
298                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
ragge
1.73
299                 nl->value = stringbuf-1;
ragge
1.12
300         }
ragge
1.1
301
ragge
1.60
302         if (Mflag && !dMflag) {
ragge
1.51
303                 usch *c;
304
305                 if (argc < 1)
306                         error("-M and no infile");
307                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
308                         c = (usch *)argv[0];
309                 else
310                         c++;
311                 Mfile = stringbuf;
312                 savstr(c); savch(0);
ragge
1.151
313                 if (MPflag) {
314                         MPfile = stringbuf;
315                         savstr(c); savch(0);
316                 }
317                 if (Mxfile)
318                         Mfile = Mxfile;
ragge
1.51
319                 if ((c = (usch *)strrchr((char *)Mfile'.')) == NULL)
320                         error("-M and no extension: ");
321                 c[1] = 'o';
322                 c[2] = 0;
323         }
324
ragge
1.26
325         if (argc == 2) {
plunky
1.180
326                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC0666)) < 0)
ragge
1.37
327                         error("Can't creat %s"argv[1]);
ragge
1.26
328         } else
ragge
1.37
329                 ofd = 1/* stdout */
330         istty = isatty(ofd);
ragge
1.26
331
ragge
1.102
332         if (argc && strcmp(argv[0], "-")) {
333                 fn1 = fn2 = (usch *)argv[0];
334         } else {
335                 fn1 = NULL;
ragge
1.103
336                 fn2 = (const usch *)"";
ragge
1.102
337         }
338         if (pushfile(fn1fn20NULL))
ragge
1.26
339                 error("cannot open %s"argv[0]);
340
ragge
1.37
341         flbuf();
342         close(ofd);
ragge
1.94
343 #ifdef TIMING
344         (void)gettimeofday(&t2NULL);
345         t2.tv_sec -= t1.tv_sec;
346         t2.tv_usec -= t1.tv_usec;
347         if (t2.tv_usec < 0) {
348                 t2.tv_usec += 1000000;
349                 t2.tv_sec -= 1;
350         }
351         fprintf(stderr"cpp total time: %ld s %ld us\n",
plunky
1.159
352              (long)t2.tv_sec, (long)t2.tv_usec);
ragge
1.94
353 #endif
plunky
1.187
354         if (Eflag && warnings > 0)
355                 return 2;
356
ragge
1.37
357         return 0;
ragge
1.26
358 }
359
ragge
1.108
360 static void
361 addidir(char *idirstruct incs **ww)
362 {
363         struct incs *w;
364         struct stat st;
365
plunky
1.163
366         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
ragge
1.108
367                 return/* ignore */
368         if (*ww != NULL) {
369                 for (w = *www->nextw = w->next) {
plunky
1.145
370 #ifdef os_win32
gmcgarry
1.131
371                         if (strcmp(w->diridir) == 0)
372                                 return;
373 #else
ragge
1.108
374                         if (w->dev == st.st_dev && w->ino == st.st_ino)
375                                 return;
gmcgarry
1.131
376 #endif
ragge
1.108
377                 }
plunky
1.145
378 #ifdef os_win32
gmcgarry
1.131
379                 if (strcmp(w->diridir) == 0)
380                         return;
381 #else
ragge
1.108
382                 if (w->dev == st.st_dev && w->ino == st.st_ino)
383                         return;
gmcgarry
1.131
384 #endif
ragge
1.108
385                 ww = &w->next;
386         }
387         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
388                 error("couldn't add path %s"idir);
389         w->dir = (usch *)idir;
390         w->dev = st.st_dev;
391         w->ino = st.st_ino;
392         *ww = w;
393 }
394
ragge
1.1
395 void
plunky
1.143
396 line(void)
ragge
1.9
397 {
ragge
1.37
398         static usch *lbuf;
399         static int llen;
ragge
1.97
400         usch *p;
ragge
1.9
401         int c;
402
ragge
1.97
403         if ((c = yylex()) != NUMBER)
ragge
1.9
404                 goto bad;
gmcgarry
1.100
405         ifiles->lineno = (int)(yylval.node.nd_val - 1);
plunky
1.185
406         ifiles->escln = 0;
ragge
1.9
407
ragge
1.97
408         if ((c = yylex()) == '\n')
plunky
1.181
409                 goto okret;
ragge
1.97
410
411         if (c != STRING)
ragge
1.9
412                 goto bad;
ragge
1.97
413
plunky
1.160
414         p = yytext;
plunky
1.158
415         if (*p++ == 'L')
ragge
1.97
416                 p++;
417         c = strlen((char *)p);
plunky
1.158
418         p[c - 1] = '\0';
ragge
1.37
419         if (llen < c) {
plunky
1.136
420                 /* XXX may lose heap space */
ragge
1.37
421                 lbuf = stringbuf;
422                 stringbuf += c;
423                 llen = c;
plunky
1.158
424                 if (stringbuf >= &sbf[SBSIZE]) {
425                         stringbuf = sbf/* need space to write error message */
plunky
1.182
426                         error("#line filename exceeds buffer size");
plunky
1.158
427                 }
ragge
1.37
428         }
plunky
1.158
429         memcpy(lbufpc);
ragge
1.37
430         ifiles->fname = lbuf;
plunky
1.181
431         if (yylex() != '\n')
432                 goto bad;
433
434 okret:  prtline();
435         return;
ragge
1.9
436
plunky
1.182
437 bad:    error("bad #line");
ragge
1.9
438 }
439
gmcgarry
1.189
440 #ifdef MACHOABI
441
442 /*
443  * Search for framework header file.
444  * Return 1 on success.
445  */
446
447 static int
448 fsrch_macos_framework(const usch *fnconst usch *dir)
449 {
450         usch *saved_stringbuf = stringbuf;
451         usch *s = (usch *)strchr((const char*)fn'/');
gmcgarry
1.194
452         usch *nm;
453         usch *p;
454         int len  = s - fn;
455
456         if (s == NULL)
457                 return 0;
458
459 //      fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir);
gmcgarry
1.189
460
gmcgarry
1.194
461         nm = savstr(dir);
462         savch(0);
463         p = savstr(fn);
464         stringbuf = p + len;
465         savch(0);
466 //      fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn);
467         p = (usch *)strstr((const char *)nm, (const char *)p);
468 //      fprintf(stderr, "p = %s\n", (const char *)p);
469         if (p != NULL) {
470                 stringbuf = p;
gmcgarry
1.189
471                 savch(0);
gmcgarry
1.194
472                 return fsrch_macos_framework(fnnm);
473         }
gmcgarry
1.189
474
gmcgarry
1.194
475         p = nm + strlen((char *)nm) - 1;
476         while (*p == '/')
477                 p--;
478         while (*p != '/')
479                 p--;
480         stringbuf = ++p;
481         savstr((const usch *)"Frameworks/");
482         stringbuf = savstr(fn) + len;
483         savstr((const usch*)".framework/Headers");
484         savstr(s);
485         savch(0);
gmcgarry
1.189
486
gmcgarry
1.194
487 //      fprintf(stderr, "nm: %s\n", nm);
gmcgarry
1.189
488
gmcgarry
1.194
489         if (pushfile(nmfnSYSINCNULL) == 0)
490                 return 1;
491 //      fprintf(stderr, "not found %s, continuing...\n", nm);
gmcgarry
1.189
492
493         stringbuf = saved_stringbuf;
494
495         return 0;
496 }
497
498 #endif
499
ragge
1.10
500 /*
ragge
1.102
501  * Search for and include next file.
502  * Return 1 on success.
503  */
504 static int
ragge
1.103
505 fsrch(const usch *fnint idxstruct incs *w)
ragge
1.102
506 {
507         int i;
508
509         for (i = idxi < 2i++) {
510                 if (i > idx)
511                         w = incdir[i];
512                 for (; ww = w->next) {
513                         usch *nm = stringbuf;
514
515                         savstr(w->dir); savch('/');
516                         savstr(fn); savch(0);
517                         if (pushfile(nmfniw->next) == 0)
518                                 return 1;
519                         stringbuf = nm;
520                 }
521         }
gmcgarry
1.189
522
523 #ifdef MACHOABI
524         /*
525          * On MacOS, we may have to do some clever stuff
526          * to resolve framework headers.
plunky
1.191
527          */
gmcgarry
1.194
528         {
529                 usch *dir = stringbuf;
530                 savstr(ifiles->orgfn);
531                 stringbuf = (usch *)strrchr((char *)dir'/');
532                 if (stringbuf != NULL) {
533                         stringbuf++;
534                         savch(0);
535                         if (fsrch_macos_framework(fndir) == 1)
536                                 return 1;
537                 }
538                 stringbuf = dir;
539
540                 if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1)
541                         return 1;
542
543                 if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1)
544                         return 1;
545         }
gmcgarry
1.189
546 #endif
547
ragge
1.102
548         return 0;
549 }
550
ragge
1.132
551 static void
552 prem(void)
553 {
554         error("premature EOF");
555 }
556
plunky
1.193
557 static usch *
558 incfn(int e)
559 {
560         usch *sb = stringbuf;
561         int c;
562
563         while ((c = cinput()) != e) {
564                 if (c == -1)
565                         prem();
566                 if (c == '\n') {
567                         stringbuf = sb;
568                         return NULL;
569                 }
570                 savch(c);
571         }
572         savch(0);
573
574         while ((c = sloscan()) == WSPACE)
575                 ;
576         if (c == 0)
577                 prem();
578         if (c != '\n') {
579                 stringbuf = sb;
580                 return NULL;
581         }
582
583         return sb;
584 }
585
ragge
1.102
586 /*
ragge
1.10
587  * Include a file. Include order:
ragge
1.20
588  * - For <...> files, first search -I directories, then system directories.
589  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
590  */
ragge
1.9
591 void
plunky
1.143
592 include(void)
ragge
1.3
593 {
ragge
1.101
594         struct symtab *nl;
plunky
1.193
595         usch *fn, *nm;
gmcgarry
1.133
596         int c;
ragge
1.3
597
ragge
1.37
598         if (flslvl)
599                 return;
ragge
1.97
600
plunky
1.193
601         while ((c = cinput()) == ' ' || c == '\t')
ragge
1.101
602                 ;
plunky
1.193
603
604         if (c != -1 && (spechr[c] & C_ID0)) {
605                 usch *sb;
606
607                 /* use sloscan() to read the identifier, then expand it */
608                 cunput(c);
609                 c = sloscan();
plunky
1.160
610                 if ((nl = lookup(yytextFIND)) == NULL)
ragge
1.101
611                         goto bad;
plunky
1.193
612
613                 sb = stringbuf;
ragge
1.112
614                 if (kfind(nl))
615                         unpstr(stringbuf);
616                 else
617                         unpstr(nl->namep);
plunky
1.193
618                 stringbuf = sb;
619
620                 c = cinput();
ragge
1.101
621         }
ragge
1.3
622
ragge
1.97
623         if (c == '<') {
plunky
1.193
624                 if ((fn = incfn('>')) == NULL)
625                         goto bad;
626         } else if (c == '\"') {
627                 if ((fn = incfn('\"')) == NULL)
ragge
1.37
628                         goto bad;
plunky
1.193
629
ragge
1.20
630                 /* first try to open file relative to previous file */
ragge
1.53
631                 /* but only if it is not an absolute path */
plunky
1.193
632                 nm = stringbuf;
ragge
1.53
633                 if (*fn != '/') {
634                         savstr(ifiles->orgfn);
plunky
1.193
635                         stringbuf = (usch *)strrchr((char *)nm'/');
636                         if (stringbuf == NULL)
ragge
1.53
637                                 stringbuf = nm;
638                         else
639                                 stringbuf++;
640                 }
plunky
1.193
641                 savstr(fn);
642                 savch(0);
643
644                 if (pushfile(nmfn0NULL) == 0)
ragge
1.97
645                         goto okret;
plunky
1.193
646
plunky
1.136
647                 /* XXX may lose stringbuf space */
plunky
1.183
648         } else
649                 goto bad;
ragge
1.10
650
plunky
1.193
651         if (fsrch(fn0incdir[0]))
ragge
1.102
652                 goto okret;
ragge
1.10
653
plunky
1.193
654         error("cannot find '%s'"fn);
ragge
1.37
655         /* error() do not return */
ragge
1.3
656
plunky
1.182
657 bad:    error("bad #include");
ragge
1.37
658         /* error() do not return */
ragge
1.97
659 okret:
660         prtline();
ragge
1.37
661 }
662
ragge
1.102
663 void
plunky
1.143
664 include_next(void)
ragge
1.102
665 {
ragge
1.105
666         struct symtab *nl;
667         usch *fn;
668         int c;
669
ragge
1.107
670         if (flslvl)
671                 return;
plunky
1.193
672
673         while ((c = cinput()) == ' ' || c == '\t')
ragge
1.105
674                 ;
plunky
1.193
675
676         if (c != -1 && (spechr[c] & C_ID0)) {
677                 usch *sb;
678
679                 /* use sloscan() to read the identifier, then expand it */
680                 cunput(c);
681                 c = sloscan();
plunky
1.160
682                 if ((nl = lookup(yytextFIND)) == NULL)
ragge
1.105
683                         goto bad;
plunky
1.193
684
685                 sb = stringbuf;
ragge
1.112
686                 if (kfind(nl))
687                         unpstr(stringbuf);
688                 else
689                         unpstr(nl->namep);
plunky
1.193
690                 stringbuf = sb;
691
692                 c = cinput();
ragge
1.105
693         }
694
plunky
1.193
695         if (c == '\"') {
696                 if ((fn = incfn('\"')) == NULL)
697                         goto bad;
698         } else if (c == '<') {
699                 if ((fn = incfn('>')) == NULL)
700                         goto bad;
701         } else
ragge
1.105
702                 goto bad;
703
704         if (fsrch(fnifiles->idxifiles->incs) == 0)
705                 error("cannot find '%s'"fn);
plunky
1.193
706
ragge
1.105
707         prtline();
708         return;
709
plunky
1.182
710 bad:    error("bad #include_next");
ragge
1.105
711         /* error() do not return */
ragge
1.102
712 }
713
ragge
1.37
714 static int
715 definp(void)
716 {
717         int c;
718
719         do
ragge
1.97
720                 c = sloscan();
ragge
1.37
721         while (c == WSPACE);
722         return c;
ragge
1.3
723 }
724
ragge
1.80
725 void
ragge
1.79
726 getcmnt(void)
727 {
728         int c;
729
plunky
1.160
730         savstr(yytext);
ragge
1.104
731         savch(cinput()); /* Lost * */
ragge
1.79
732         for (;;) {
733                 c = cinput();
734                 if (c == '*') {
735                         c = cinput();
736                         if (c == '/') {
ragge
1.103
737                                 savstr((const usch *)"*/");
ragge
1.79
738                                 return;
739                         }
740                         cunput(c);
741                         c = '*';
742                 }
743                 savch(c);
744         }
745 }
746
747 /*
748  * Compare two replacement lists, taking in account comments etc.
749  */
750 static int
ragge
1.103
751 cmprepl(const usch *oconst usch *n)
ragge
1.79
752 {
753         for (; *oo--, n--) {
754                 /* comment skip */
755                 if (*o == '/' && o[-1] == '*') {
756                         while (*o != '*' || o[-1] != '/')
757                                 o--;
758                         o -= 2;
759                 }
760                 if (*n == '/' && n[-1] == '*') {
761                         while (*n != '*' || n[-1] != '/')
762                                 n--;
763                         n -= 2;
764                 }
765                 while (*o == ' ' || *o == '\t')
766                         o--;
767                 while (*n == ' ' || *n == '\t')
768                         n--;
769                 if (*o != *n)
770                         return 1;
771         }
772         return 0;
773 }
774
ragge
1.97
775 static int
776 isell(void)
777 {
778         int ch;
779
780         if ((ch = cinput()) != '.') {
781                 cunput(ch);
782                 return 0;
783         }
784         if ((ch = cinput()) != '.') {
785                 cunput(ch);
786                 cunput('.');
787                 return 0;
788         }
789         return 1;
790 }
791
ragge
1.3
792 void
plunky
1.143
793 define(void)
ragge
1.1
794 {
795         struct symtab *np;
ragge
1.112
796         usch *args[MAXARGS+1], *ubuf, *sbeg;
ragge
1.15
797         int ciredef;
ragge
1.1
798         int mkstr = 0narg = -1;
ragge
1.37
799         int ellips = 0;
ragge
1.128
800 #ifdef GCC_COMPAT
ragge
1.86
801         usch *gccvari = NULL;
ragge
1.91
802         int wascon;
ragge
1.86
803 #endif
ragge
1.1
804
ragge
1.37
805         if (flslvl)
806                 return;
ragge
1.97
807         if (sloscan() != WSPACE || sloscan() != IDENT)
ragge
1.37
808                 goto bad;
ragge
1.36
809
plunky
1.160
810         np = lookup(yytextENTER);
ragge
1.15
811         redef = np->value != NULL;
ragge
1.1
812
ragge
1.138
813         defining = readmac = 1;
ragge
1.15
814         sbeg = stringbuf;
ragge
1.97
815         if ((c = sloscan()) == '(') {
ragge
1.1
816                 narg = 0;
817                 /* function-like macros, deal with identifiers */
ragge
1.72
818                 c = definp();
ragge
1.37
819                 for (;;) {
ragge
1.1
820                         if (c == ')')
821                                 break;
ragge
1.97
822                         if (c == '.' && isell()) {
ragge
1.37
823                                 ellips = 1;
824                                 if (definp() != ')')
825                                         goto bad;
826                                 break;
827                         }
828                         if (c == IDENT) {
ragge
1.72
829                                 /* make sure there is no arg of same name */
830                                 for (i = 0i < nargi++)
ragge
1.116
831                                         if (!strcmp((char *) args[i], (char *)yytext))
ragge
1.72
832                                                 error("Duplicate macro "
833                                                   "parameter \"%s\""yytext);
ragge
1.112
834                                 if (narg == MAXARGS)
835                                         error("Too many macro args");
ragge
1.90
836                                 args[narg++] = xstrdup(yytext);
ragge
1.72
837                                 if ((c = definp()) == ',') {
838                                         if ((c = definp()) == ')')
839                                                 goto bad;
ragge
1.37
840                                         continue;
ragge
1.72
841                                 }
ragge
1.128
842 #ifdef GCC_COMPAT
ragge
1.97
843                                 if (c == '.' && isell()) {
ragge
1.86
844                                         if (definp() != ')')
845                                                 goto bad;
846                                         gccvari = args[--narg];
847                                         break;
848                                 }
849 #endif
ragge
1.37
850                                 if (c == ')')
851                                         break;
852                         }
853                         goto bad;
ragge
1.1
854                 }
ragge
1.97
855                 c = sloscan();
ragge
1.36
856         } else if (c == '\n') {
ragge
1.8
857                 /* #define foo */
ragge
1.36
858                 ;
ragge
1.132
859         } else if (c == 0) {
860                 prem();
ragge
1.1
861         } else if (c != WSPACE)
ragge
1.37
862                 goto bad;
ragge
1.1
863
ragge
1.31
864         while (c == WSPACE)
ragge
1.97
865                 c = sloscan();
ragge
1.1
866
ragge
1.72
867         /* replacement list cannot start with ## operator */
ragge
1.97
868         if (c == '#') {
869                 if ((c = sloscan()) == '#')
870                         goto bad;
871                 savch('\0');
ragge
1.128
872 #ifdef GCC_COMPAT
ragge
1.97
873                 wascon = 0;
874 #endif
875                 goto in2;
876         }
ragge
1.72
877
ragge
1.1
878         /* parse replacement-list, substituting arguments */
879         savch('\0');
ragge
1.36
880         while (c != '\n') {
ragge
1.128
881 #ifdef GCC_COMPAT
ragge
1.91
882                 wascon = 0;
883 loop:
884 #endif
ragge
1.1
885                 switch (c) {
886                 case WSPACE:
887                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
888                         ubuf = stringbuf;
plunky
1.160
889                         savstr(yytext);
ragge
1.97
890                         c = sloscan();
891                         if (c == '#') {
892                                 if ((c = sloscan()) != '#')
893                                         goto in2;
ragge
1.2
894                                 stringbuf = ubuf;
ragge
1.1
895                                 savch(CONC);
ragge
1.97
896                                 if ((c = sloscan()) == WSPACE)
897                                         c = sloscan();
ragge
1.128
898 #ifdef GCC_COMPAT
ragge
1.91
899                                 if (c == '\n')
900                                         break;
901                                 wascon = 1;
902                                 goto loop;
903 #endif
ragge
1.1
904                         }
905                         continue;
906
ragge
1.97
907                 case '#':
908                         c = sloscan();
909                         if (c == '#') {
910                                 /* concat op */
911                                 savch(CONC);
912                                 if ((c = sloscan()) == WSPACE)
913                                         c = sloscan();
ragge
1.128
914