Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20141218192129

Diff

Diff from 1.203 to:

Annotations

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

Annotated File View

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