Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20101125211249

Diff

Diff from 1.108 to:

Annotations

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

Annotated File View

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