Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20141019174036

Diff

Diff from 1.197 to:

Annotations

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

Annotated File View

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