Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090801155306

Diff

Diff from 1.97 to:

Annotations

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

Annotated File View

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