Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20160810173323

Diff

Diff from 1.281 to:

Annotations

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

Annotated File View

ragge
1.281
1 /*      $Id: cpp.c,v 1.281 2016/08/10 17:33:23 ragge Exp $      */
ragge
1.1
2
3 /*
ragge
1.109
4  * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
ragge
1.1
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /*
29  * The C preprocessor.
30  * This code originates from the V6 preprocessor with some additions
31  * from V7 cpp, and at last ansi/c99 support.
ragge
1.215
32  *
ragge
1.254
33  *      - kfind() expands the input buffer onto an output buffer.
ragge
1.215
34  *      - exparg() expand one buffer into another.
35  *              Recurses into submac() for fun-like macros.
36  *      - submac() replaces the given macro.
37  *              Recurses into subarg() for fun-like macros.
38  *      - subarg() expands fun-like macros.
39  *              Create strings, concats args, recurses into exparg.
ragge
1.1
40  */
pj
1.23
41
ragge
1.74
42 #include "config.h"
pj
1.23
43
ragge
1.108
44 #include <sys/stat.h>
ragge
1.1
45
46 #include <fcntl.h>
gmcgarry
1.81
47 #ifdef HAVE_UNISTD_H
ragge
1.1
48 #include <unistd.h>
gmcgarry
1.81
49 #endif
ragge
1.1
50 #include <stdio.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <string.h>
ragge
1.9
54 #include <time.h>
ragge
1.1
55
ragge
1.74
56 #include "compat.h"
ragge
1.1
57 #include "cpp.h"
58
gmcgarry
1.130
59 #ifndef S_ISDIR
60 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
61 #endif
62
ragge
1.254
63 /*
64  * Buffers used:
ragge
1.264
65  *      - expansion buffers (BNORMAL)
ragge
1.254
66  *      - string buffers (used to store macros)
67  */
68
ragge
1.252
69 static int      counter;
ragge
1.1
70 /* C command */
71
72 int tflag;      /* traditional cpp syntax */
plunky
1.134
73 #ifdef PCC_DEBUG
ragge
1.1
74 int dflag;      /* debug printouts */
plunky
1.135
75 static void prline(const usch *s);
76 static void prrep(const usch *s);
ragge
1.36
77 #define DPRINT(x) if (dflag) printf x
78 #define DDPRINT(x) if (dflag > 1) printf x
plunky
1.135
79 #define IMP(x) if (dflag > 1) imp(x)
ragge
1.36
80 #else
81 #define DPRINT(x)
82 #define DDPRINT(x)
plunky
1.135
83 #define IMP(x)
ragge
1.1
84 #endif
ragge
1.36
85
ragge
1.276
86 static int istty;
ragge
1.195
87 int AflagCflagEflagMflagdMflagPflagMPflagMMDflag;
ragge
1.247
88 char *Mfile, *MPfile;
ragge
1.245
89 char *Mxfile;
ragge
1.279
90 int warningsMxlenskpows;
ragge
1.264
91 static usch utbuf[CPPBUF];
ragge
1.271
92 struct iobuf pb = { utbuf0CPPBUF01BUTBUF };
ragge
1.269
93 #if LIBVMF
94 struct vspace ibspc;
95 #endif
ragge
1.1
96
ragge
1.10
97 /* include dirs */
98 struct incs {
99         struct incs *next;
ragge
1.39
100         usch *dir;
ragge
1.108
101         dev_t dev;
102         ino_t ino;
ragge
1.20
103 } *incdir[2];
ragge
1.10
104
ragge
1.1
105 static struct symtab *filloc;
106 static struct symtab *linloc;
ragge
1.65
107 static struct symtab *pragloc;
ragge
1.224
108 static struct symtab *defloc;
ragge
1.252
109 static struct symtab *ctrloc;
ragge
1.10
110 int     trulvl;
111 int     flslvl;
112 int     elflvl;
113 int     elslvl;
ragge
1.1
114
115 /*
116  * Macro replacement list syntax:
117  * - For object-type macros, replacement strings are stored as-is.
118  * - For function-type macros, macro args are substituted for the
119  *   character WARN followed by the argument number.
ragge
1.214
120  * - The value element points to the beginning of the string.
plunky
1.191
121  *
ragge
1.213
122  * The first character in the replacement list is the number of arguments:
ragge
1.37
123  *   VARG  - ends with ellipsis, next char is argcount without ellips.
ragge
1.1
124  *   OBJCT - object-type macro
plunky
1.191
125  *   0     - empty parenthesis, foo()
ragge
1.1
126  *   1->   - number of args.
ragge
1.109
127  *
128  * WARN is used:
129  *      - in stored replacement lists to tell that an argument comes
130  *      - When expanding replacement lists to tell that the list ended.
ragge
1.116
131  *
132  * To ensure that an already expanded identifier won't get expanded
plunky
1.191
133  * again a EBLOCK char + its number is stored directly before any
ragge
1.116
134  * expanded identifier.
ragge
1.1
135  */
136
137 /* args for lookup() */
138 #define FIND    0
139 #define ENTER   1
140
plunky
1.166
141 /*
142  * No-replacement array.  If a macro is found and exists in this array
ragge
1.216
143  * then no replacement shall occur.
plunky
1.166
144  */
ragge
1.215
145 struct blocker {
146         struct blocker *next;
147         struct symtab *sp;
148 };
149 struct blocker *blkidx[RECMAX];
150 int blkidp;
151
ragge
1.271
152 static struct iobuf *readargs2(struct iobuf *, struct symtab *spconst usch **args);
ragge
1.259
153 static struct iobuf *readargs1(struct symtab *spconst usch **args);
ragge
1.215
154 static struct iobuf *exparg(intstruct iobuf *, struct iobuf *, struct blocker *);
155 static struct iobuf *subarg(struct symtab *spconst usch **argsintstruct blocker *);
plunky
1.143
156 static void usage(void);
157 static usch *xstrdup(const usch *str);
ragge
1.108
158 static void addidir(char *idirstruct incs **ww);
ragge
1.255
159 static void vsheap(struct iobuf *, const char *, va_list);
ragge
1.215
160 static int skipws(struct iobuf *ib);
161 static int getyp(usch *s);
ragge
1.277
162 static void macsav(int ch);
ragge
1.281
163 static void fstrstr(struct iobuf *ibstruct iobuf *ob);
ragge
1.1
164
165 int
166 main(int argcchar **argv)
167 {
ragge
1.265
168         struct includ bic;
169         struct iobuf *fb = getobuf(BNORMAL);
ragge
1.26
170         register int ch;
ragge
1.103
171         const usch *fn1, *fn2;
ragge
1.265
172         char *a;
ragge
1.15
173
ragge
1.94
174 #ifdef TIMING
175         struct timeval t1t2;
176
177         (void)gettimeofday(&t1NULL);
178 #endif
179
ragge
1.269
180 #if LIBVMF
181         if (vminit(2))
182                 error("vminit");
183         if (vmopen(&ibspcNULL) < 0)
184                 error("vmopen ibspc");
185 #endif
186
plunky
1.188
187         while ((ch = getopt(argcargv"ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
ragge
1.1
188                 switch (ch) {
plunky
1.188
189                 case 'A'/* assembler input */
190                         Aflag++;
191                         break;
plunky
1.191
192
ragge
1.22
193                 case 'C'/* Do not discard comments */
194                         Cflag++;
195                         break;
196
plunky
1.187
197                 case 'E'/* treat warnings as errors */
198                         Eflag++;
199                         break;
200
plunky
1.142
201                 case 'D'/* define something */
ragge
1.265
202                         if ((a = strchr(optarg'=')) != NULL)
203                                 *a = ' ';
204                         bsheap(fb"#define %s%s"optarga ? "\n" : " 1\n");
205                         break;
206
ragge
1.53
207                 case 'i'/* include */
ragge
1.265
208                         bsheap(fb"#include \"%s\"\n"optarg);
209                         break;
210
ragge
1.53
211                 case 'U'/* undef */
ragge
1.265
212                         bsheap(fb"#undef %s\n"optarg);
ragge
1.7
213                         break;
214
plunky
1.142
215                 case 'd':
plunky
1.144
216                         while (*optarg) {
217                                 switch(*optarg) {
218                                 case 'M'/* display macro definitions */
219                                         dMflag = 1;
220                                         Mflag = 1;
221                                         break;
222
223                                 default/* ignore others */
224                                         break;
225                                 }
226                                 optarg++;
plunky
1.142
227                         }
228                         break;
229
230                 case 'I':
231                 case 'S':
232                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
233                         break;
234
ragge
1.51
235                 case 'M'/* Generate dependencies for make */
236                         Mflag++;
237                         break;
238
gmcgarry
1.85
239                 case 'P'/* Inhibit generation of line numbers */
240                         Pflag++;
241                         break;
242
plunky
1.142
243                 case 't':
244                         tflag = 1;
ragge
1.7
245                         break;
246
plunky
1.134
247 #ifdef PCC_DEBUG
ragge
1.64
248                 case 'V':
ragge
1.18
249                         dflag++;
ragge
1.1
250                         break;
251 #endif
ragge
1.64
252                 case 'v':
plunky
1.200
253                         fprintf(stderr"PCC preprocessor version "VERSSTR"\n");
ragge
1.64
254                         break;
ragge
1.1
255
ragge
1.151
256                 case 'x':
ragge
1.195
257                         if (strcmp(optarg"MMD") == 0) {
258                                 MMDflag++;
259                         } else if (strcmp(optarg"MP") == 0) {
ragge
1.151
260                                 MPflag++;
261                         } else if (strncmp(optarg"MT,"3) == 0 ||
262                             strncmp(optarg"MQ,"3) == 0) {
ragge
1.245
263                                 int l = strlen(optarg+3) + 2;
264                                 char *cp, *up;
265
266                                 if (optarg[1] == 'Q')
267                                         for (cp = optarg+3; *cpcp++)
268                                                 if (*cp == '$')
269                                                         l++;
270                                 Mxlen += l;
271                                 Mxfile = cp = realloc(MxfileMxlen);
272                                 for (up = Mxfile; *upup++)
273                                         ;
274                                 if (up != Mxfile)
275                                         *up++ = ' ';
276                                 for (cp = optarg+3; *cpcp++) {
277                                         *up++ = *cp;
278                                         if (optarg[1] == 'Q' && *cp == '$')
279                                                 *up++ = *cp;
ragge
1.151
280                                 }
ragge
1.245
281                                 *up = 0;
ragge
1.151
282                         } else
283                                 usage();
284                         break;
285
ragge
1.37
286                 case '?':
plunky
1.142
287                 default:
ragge
1.37
288                         usage();
ragge
1.1
289                 }
plunky
1.142
290         }
291
ragge
1.1
292         argc -= optind;
293         argv += optind;
294
ragge
1.103
295         filloc = lookup((const usch *)"__FILE__"ENTER);
296         linloc = lookup((const usch *)"__LINE__"ENTER);
297         pragloc = lookup((const usch *)"_Pragma"ENTER);
ragge
1.224
298         defloc = lookup((const usch *)"defined"ENTER);
ragge
1.252
299         ctrloc = lookup((const usch *)"__COUNTER__"ENTER);
ragge
1.274
300         filloc->value = linloc->value = pragloc->value =
301             ctrloc->value = (const usch *)"";
302         defloc->value = defloc->namep;
303         filloc->type = FILLOC;
304         linloc->type = LINLOC;
305         pragloc->type = PRAGLOC;
306         defloc->type = DEFLOC;
307         ctrloc->type = CTRLOC;
ragge
1.15
308
ragge
1.60
309         if (Mflag && !dMflag) {
ragge
1.247
310                 char *c;
ragge
1.51
311
312                 if (argc < 1)
313                         error("-M and no infile");
ragge
1.247
314                 if ((c = strrchr(argv[0], '/')) == NULL)
315                         c = argv[0];
ragge
1.51
316                 else
317                         c++;
ragge
1.247
318                 Mfile = (char *)xstrdup((usch *)c);
319                 if (MPflag)
320                         MPfile = (char *)xstrdup((usch *)c);
ragge
1.151
321                 if (Mxfile)
ragge
1.247
322                         Mfile = Mxfile;
323                 if ((c = strrchr(Mfile'.')) == NULL)
ragge
1.51
324                         error("-M and no extension: ");
325                 c[1] = 'o';
326                 c[2] = 0;
327         }
328
ragge
1.26
329         if (argc == 2) {
ragge
1.264
330                 close(1);
331                 if (open(argv[1], O_WRONLY|O_CREAT0600) < 0)
ragge
1.37
332                         error("Can't creat %s"argv[1]);
ragge
1.264
333         }
ragge
1.276
334         istty = isatty(1);
ragge
1.26
335
ragge
1.102
336         if (argc && strcmp(argv[0], "-")) {
337                 fn1 = fn2 = (usch *)argv[0];
338         } else {
339                 fn1 = NULL;
ragge
1.103
340                 fn2 = (const usch *)"";
ragge
1.102
341         }
ragge
1.265
342
343         /* initialization defines */
344         if (dMflag)
ragge
1.271
345                 write(1fb->buffb->cptr);
346         fb->buf[fb->cptr] = 0;
ragge
1.265
347         memset(&bic0sizeof(bic));
348         bic.fname = bic.orgfn = (const usch *)"<command line>";
349         bic.lineno = 1;
350         bic.infil = -1;
ragge
1.268
351         bic.ib = fb;
352         fb->bsz = fb->cptr;
ragge
1.271
353         fb->cptr = 0;
ragge
1.265
354         ifiles = &bic;
355         fastscan();
356         bufree(fb);
ragge
1.269
357         ifiles = NULL;
ragge
1.265
358         /* end initial defines */
359
ragge
1.102
360         if (pushfile(fn1fn20NULL))
ragge
1.26
361                 error("cannot open %s"argv[0]);
362
ragge
1.279
363         if (Mflag == 0) {
364                 if (skpows)
365                         pb.buf[pb.cptr++] = '\n';
ragge
1.271
366                 write(1pb.bufpb.cptr);
ragge
1.279
367         }
ragge
1.94
368 #ifdef TIMING
369         (void)gettimeofday(&t2NULL);
370         t2.tv_sec -= t1.tv_sec;
371         t2.tv_usec -= t1.tv_usec;
372         if (t2.tv_usec < 0) {
373                 t2.tv_usec += 1000000;
374                 t2.tv_sec -= 1;
375         }
376         fprintf(stderr"cpp total time: %ld s %ld us\n",
plunky
1.159
377              (long)t2.tv_sec, (long)t2.tv_usec);
ragge
1.94
378 #endif
plunky
1.187
379         if (Eflag && warnings > 0)
380                 return 2;
381
ragge
1.37
382         return 0;
ragge
1.26
383 }
384
ragge
1.215
385 /*
386  * Write a character to an out buffer.
387  */
ragge
1.253
388 void
ragge
1.215
389 putob(struct iobuf *obint ch)
390 {
391         if (ob->cptr == ob->bsz) {
ragge
1.271
392                 int sz = ob->bsz;
ragge
1.264
393                 switch (ob->type) {
394                 case BNORMAL:
ragge
1.269
395                         ob->buf = xrealloc(ob->bufsz + CPPBUF+1);
ragge
1.271
396                         /* ob->cptr = ob->buf + sz; */
397                         ob->bsz = sz + CPPBUF;
ragge
1.264
398                         break;
399                 case BMAC:
400                 case BINBUF:
401                         error("putob");
402                 case BUTBUF:
403                         if (Mflag == 0)
404                                 (void)write(1ob->bufsz);
ragge
1.271
405                         ob->cptr = 0;
ragge
1.264
406                         break;
407                 }
ragge
1.215
408         }
409 //      DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch));
ragge
1.271
410         ob->buf[ob->cptr++] = ch;
ragge
1.215
411 }
412
ragge
1.266
413 static struct iobuf *
414 giob(int typconst usch *bpint bsz)
415 {
416         struct iobuf *iob = xmalloc(sizeof(struct iobuf));
417
418         if (bp == NULL)
419                 bp = xmalloc(bsz);
ragge
1.271
420         iob->buf = (usch *)bp;
421         iob->cptr = 0;
422         iob->bsz = bsz;
ragge
1.266
423         iob->ro = 0;
424         iob->type = typ;
425         return iob;
426 }
427
428
ragge
1.261
429 int nbufused;
ragge
1.215
430 /*
431  * Write a character to an out buffer.
432  */
ragge
1.253
433 struct iobuf *
ragge
1.264
434 getobuf(int type)
ragge
1.215
435 {
ragge
1.264
436         struct iobuf *iob = 0;
ragge
1.215
437
ragge
1.264
438         switch (type) {
439         case BNORMAL:
440                 nbufused++;
ragge
1.269
441                 iob = giob(BNORMALNULLCPPBUF);
ragge
1.271
442                 iob->bsz = CPPBUF-1/* space for \0 */
ragge
1.264
443                 break;
444         case BINBUF:
ragge
1.269
445 #if LIBVMF
446                 iob = giob(BINBUF, (usch *)ifiles->vseg->s_cinfoCPPBUF);
447 #else
448                 iob = giob(BINBUFNULLCPPBUF);
449 #endif
ragge
1.265
450                 break;
451         default:
ragge
1.264
452                 error("getobuf");
453         }
ragge
1.215
454         return iob;
455 }
456
457 /*
ragge
1.216
458  * Create a read-only input buffer.
ragge
1.215
459  */
460 static struct iobuf *
461 mkrobuf(const usch *s)
462 {
ragge
1.266
463         struct iobuf *iob;
ragge
1.214
464
ragge
1.218
465         nbufused++;
ragge
1.266
466         iob = giob(BNORMALsstrlen((char *)s));
467         iob->ro = 1;
ragge
1.215
468         DPRINT(("mkrobuf %s\n"s));
469         return iob;
470 }
ragge
1.214
471
472 /*
ragge
1.262
473  * Copy a buffer to another buffer.
474  */
ragge
1.264
475 struct iobuf *
ragge
1.262
476 buftobuf(struct iobuf *instruct iobuf *iob)
477 {
ragge
1.271
478         int cp;
479
ragge
1.262
480         DPRINT(("strtobuf iob %p buf %p str %p\n"iobiob->bufin));
481         if (iob == NULL)
ragge
1.264
482                 iob = getobuf(BNORMAL);
ragge
1.271
483         for (cp = 0cp < in->cptrcp++)
484                 putob(iobin->buf[cp]);
ragge
1.262
485         return iob;
486 }
487
488 /*
ragge
1.215
489  * Copy a string to a buffer.
ragge
1.214
490  */
ragge
1.261
491 struct iobuf *
ragge
1.267
492 strtobuf(const usch *strstruct iobuf *iob)
ragge
1.215
493 {
494         if (iob == NULL)
ragge
1.264
495                 iob = getobuf(BNORMAL);
ragge
1.265
496         DPRINT(("strtobuf iob %p buf %p str %s\n"iobiob->bufstr));
ragge
1.215
497         do {
498                 putob(iob, *str);
499         } while (*str++);
500         iob->cptr--;
501         return iob;
502 }
503
ragge
1.256
504 static usch *macbase;
505 static int macposcmbase;
506
507 static void
508 macsav(int ch)
509 {
510         if (macbase == NULL)
511                 macbase = xmalloc(CPPBUF);
512         if (macpos == CPPBUF) {
513                 usch *tb;
514                 if (cmbase == 0)
515                         error("macro too large");
516                 tb = xmalloc(CPPBUF);
517                 memcpy(tbmacbase+cmbaseCPPBUF-cmbase);
518                 macpos -= cmbase;
519                 cmbase = 0;
520                 macbase = tb;
521         }
522         macbase[macpos++] = ch;
523 }
524
525 static void                     
ragge
1.257
526 macstr(const usch *s)
ragge
1.256
527 {
528         do {
529                 macsav(*s);
530         } while (*s++ != 0);
531         macpos--;
532 }
533
534 #define setcmbase()     cmbase = macpos
ragge
1.257
535 #define clrcmbase()     macpos = cmbase
ragge
1.256
536
ragge
1.253
537 void
ragge
1.215
538 bufree(struct iobuf *iob)
ragge
1.214
539 {
ragge
1.268
540         if (iob->type == BNORMAL)
541                 nbufused--;
ragge
1.215
542         if (iob->ro == 0)
543                 free(iob->buf);
544         free(iob);
ragge
1.214
545 }
546
ragge
1.108
547 static void
548 addidir(char *idirstruct incs **ww)
549 {
550         struct incs *w;
551         struct stat st;
552
plunky
1.163
553         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
ragge
1.108
554                 return/* ignore */
555         if (*ww != NULL) {
556                 for (w = *www->nextw = w->next) {
plunky
1.203
557 #ifdef _WIN32
gmcgarry
1.131
558                         if (strcmp(w->diridir) == 0)
559                                 return;
560 #else
ragge
1.108
561                         if (w->dev == st.st_dev && w->ino == st.st_ino)
562                                 return;
gmcgarry
1.131
563 #endif
ragge
1.108
564                 }
plunky
1.203
565 #ifdef _WIN32
gmcgarry
1.131
566                 if (strcmp(w->diridir) == 0)
567                         return;
568 #else
ragge
1.108
569                 if (w->dev == st.st_dev && w->ino == st.st_ino)
570                         return;
gmcgarry
1.131
571 #endif
ragge
1.108
572                 ww = &w->next;
573         }
574         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
575                 error("couldn't add path %s"idir);
576         w->dir = (usch *)idir;
577         w->dev = st.st_dev;
578         w->ino = st.st_ino;
579         *ww = w;
580 }
581
ragge
1.1
582 void
plunky
1.143
583 line(void)
ragge
1.9
584 {
ragge
1.281
585         struct iobuf *ib, *ob;
586         int nln;
587
588
589         ob = savln();
590         ob->cptr = 0;
591         ib = getobuf(BNORMAL);
592         exparg(1obibNULL);
ragge
1.250
593
ragge
1.281
594         ib->cptr = 0;
595         while (ISWSNL(ib->buf[ib->cptr]))
596                 ib->cptr++;
ragge
1.9
597
ragge
1.250
598         n = 0;
ragge
1.281
599         while (ISDIGIT(ib->buf[ib->cptr]))
600                 n = n * 10 + ib->buf[ib->cptr++] - '0';
ragge
1.216
601
ragge
1.209
602         /* Can only be decimal number here between 1-2147483647 */
ragge
1.216
603         if (n < 1 || n > 2147483647)
ragge
1.209
604                 goto bad;
605
ragge
1.281
606         while (ISWSNL(ib->buf[ib->cptr]))
607                 ib->cptr++;
608
ragge
1.234
609         ln = n;
plunky
1.185
610         ifiles->escln = 0;
ragge
1.257
611
ragge
1.281
612         if (ib->buf[ib->cptr] == 0)
613                 goto out;
614
615         if (getyp(ib->buf+ib->cptr) != STRING)
616                 goto bad;
617         if (ib->buf[ib->cptr] != '\"')
618                 warning("#line only allows character literals");
619
620         ob->cptr = 0;
621         fstrstr(ibob);
622         ob->buf[ob->cptr] = 0;
623
624         if (strcmp((char *)ifiles->fname, (char *)ob->buf))
625                 ifiles->fname = xstrdup(ob->buf);
626         bufree(ob);
627
628         while (ISWSNL(ib->buf[ib->cptr]))
629                 ib->cptr++;
ragge
1.97
630
ragge
1.281
631         if (ib->buf[ib->cptr] != 0)
plunky
1.181
632                 goto bad;
633
ragge
1.281
634         bufree(ib);
635
636 out:    ifiles->lineno = ln;
ragge
1.250
637         prtline(1);
ragge
1.251
638         ifiles->lineno--;
plunky
1.181
639         return;
ragge
1.9
640
plunky
1.182
641 bad:    error("bad #line");
ragge
1.9
642 }
643
gmcgarry
1.189
644 #ifdef MACHOABI
645
646 /*
ragge
1.261
647  * Example:
648  * Library/Frameworks/VideoToolbox.framework/Headers/VTSession.h
649  *
gmcgarry
1.189
650  * Search for framework header file.
651  * Return 1 on success.
652  */
653
654 static int
655 fsrch_macos_framework(const usch *fnconst usch *dir)
656 {
ragge
1.261
657         struct iobuf *ob;
gmcgarry
1.189
658         usch *s = (usch *)strchr((const char*)fn'/');
ragge
1.270
659         usch *p, *q, *nm;
gmcgarry
1.194
660         int len  = s - fn;
661
662         if (s == NULL)
663                 return 0;
664
ragge
1.261
665         nm = xstrdup(dir);
666         p = xstrdup(fn);
667         *(p + len) = 0;
668
669         q = (usch *)strstr((const char *)nm, (const char *)p);
670         if (q != NULL) {
671                 *q = 0;
gmcgarry
1.194
672                 return fsrch_macos_framework(fnnm);
673         }
ragge
1.261
674         free(p);
gmcgarry
1.189
675
gmcgarry
1.194
676         p = nm + strlen((char *)nm) - 1;
677         while (*p == '/')
678                 p--;
679         while (*p != '/')
680                 p--;
ragge
1.261
681         ++p;
682         
683         ob = bsheap(NULL"%s/Frameworks/%s.framework/Headers%s"nmfns);
684         free(nm);
685         nm = xstrdup(ob->buf);
686         bufree(ob);
gmcgarry
1.194
687         if (pushfile(nmfnSYSINCNULL) == 0)
688                 return 1;
gmcgarry
1.189
689
690         return 0;
691 }
692
693 #endif
694
ragge
1.10
695 /*
ragge
1.102
696  * Search for and include next file.
697  * Return 1 on success.
698  */
699 static int
ragge
1.103
700 fsrch(const usch *fnint idxstruct incs *w)
ragge
1.102
701 {
702         int i;
703
ragge
1.257
704         setcmbase();
ragge
1.102
705         for (i = idxi < 2i++) {
706                 if (i > idx)
707                         w = incdir[i];
708                 for (; ww = w->next) {
ragge
1.257
709                         macstr(w->dir); macsav('/');
710                         macstr(fn); macsav(0);
711                         if (pushfile(macbase+cmbasefniw->next) == 0)
ragge
1.102
712                                 return 1;
ragge
1.257
713                         clrcmbase();
ragge
1.102
714                 }
715         }
gmcgarry
1.189
716
717 #ifdef MACHOABI
718         /*
719          * On MacOS, we may have to do some clever stuff
720          * to resolve framework headers.
plunky
1.191
721          */
gmcgarry
1.194
722         {
ragge
1.261
723                 /*
724                  * Dig out org filename path and try to find.
725                  */
726                 usch *p, *dir = xstrdup(ifiles->orgfn);
727                 if ((p = (usch *)strrchr((char *)dir'/')) != NULL) {
728                         p[1] = 0;
gmcgarry
1.194
729                         if (fsrch_macos_framework(fndir) == 1)
730                                 return 1;
731                 }
ragge
1.261
732                 free(dir);
gmcgarry
1.194
733
ragge
1.261
734                 if (fsrch_macos_framework(fn,
735                     (const usch *)"/Library/Frameworks/") == 1)
gmcgarry
1.194
736                         return 1;
737
ragge
1.261
738                 if (fsrch_macos_framework(fn,
739                     (const usch *)"/System/Library/Frameworks/") == 1)
gmcgarry
1.194
740                         return 1;
741         }
gmcgarry
1.189
742 #endif
743
ragge
1.102
744         return 0;
745 }
746
ragge
1.132
747 static void
748 prem(void)
749 {
750         error("premature EOF");
751 }
752
ragge
1.221
753 static struct iobuf *
754 incfn(void)
plunky
1.193
755 {
ragge
1.221
756         struct iobuf *ob;
757         struct symtab *nl;
ragge
1.254
758         usch *dp;
plunky
1.193
759         int c;
760
ragge
1.221
761         if (spechr[c = skipws(NULL)] & C_ID0) {
ragge
1.253
762                 dp = readid(c);
763                 if ((nl = lookup(dpFIND)) == NULL)
ragge
1.221
764                         return NULL;
765
ragge
1.254
766                 if ((ob = kfind(nl)) == 0)
ragge
1.221
767                         return NULL;
768         } else {
ragge
1.264
769                 ob = getobuf(BNORMAL);
ragge
1.221
770                 putob(obc);
771                 while ((c = cinput()) && c != '\n')
772                         putob(obc);
773                 if (c != '\n')
774                         return NULL;
775                 cunput(c);
plunky
1.193
776         }
ragge
1.221
777
778         /* now we have an (expanded?) filename in obuf */
ragge
1.271
779         while (0 < ob->cptr && ISWS(ob->buf[ob->cptr-1]))
ragge
1.221
780                 ob->cptr--;
781
782         if (ob->buf[0] != '\"' && ob->buf[0] != '<')
783                 return NULL;
ragge
1.271
784         if (ob->buf[ob->cptr-1] != '\"' && ob->buf[ob->cptr-1] != '>')
ragge
1.221
785                 return NULL;
ragge
1.271
786         ob->buf[ob->cptr-1] = 0;
ragge
1.221
787         return ob;
plunky
1.193
788 }
789
ragge
1.102
790 /*
ragge
1.10
791  * Include a file. Include order:
ragge
1.20
792  * - For <...> files, first search -I directories, then system directories.
793  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
794  */
ragge
1.9
795 void
plunky
1.143
796 include(void)
ragge
1.3
797 {
ragge
1.221
798         struct iobuf *ob;
ragge
1.242
799         usch *fn, *nm = NULL;
ragge
1.3
800
ragge
1.37
801         if (flslvl)
802                 return;
ragge
1.97
803
ragge
1.221
804         if ((ob = incfn()) == NULL/* get include file name in obuf */
805                 error("bad #include");
plunky
1.193
806
ragge
1.221
807         fn = xstrdup(ob->buf) + 1;      /* Save on string heap? */
808         bufree(ob);
ragge
1.238
809         /* test absolute path first */
810         if (fn[0] == '/' && pushfile(fnfn0NULL) == 0)
811                 goto okret;
ragge
1.221
812         if (fn[-1] == '\"') {
813                 /* nope, failed, try to create a path for it */
814                 if ((nm = (usch *)strrchr((char *)ifiles->orgfn'/'))) {
815                         ob = strtobuf((usch *)ifiles->orgfnNULL);
ragge
1.271
816                         ob->cptr = (nm - ifiles->orgfn) + 1;
ragge
1.221
817                         strtobuf(fnob);
818                         nm = xstrdup(ob->buf);
819                         bufree(ob);
ragge
1.264
820                 } else
ragge
1.242
821                         nm = xstrdup(fn);
822                 if (pushfile(nmnm0NULL) == 0) {
823                         free(fn-1);
824                         goto okret;
ragge
1.53
825                 }
ragge
1.221
826         }
plunky
1.193
827         if (fsrch(fn0incdir[0]))
ragge
1.102
828                 goto okret;
ragge
1.10
829
plunky
1.193
830         error("cannot find '%s'"fn);
ragge
1.37
831         /* error() do not return */
ragge
1.3
832
ragge
1.97
833 okret:
ragge
1.242
834         if (nm)
835                 free(nm);
ragge
1.219
836         prtline(1);
ragge
1.37
837 }
838
ragge
1.102
839 void
plunky
1.143
840 include_next(void)
ragge
1.102
841 {
ragge
1.221
842         struct iobuf *ob;
843         usch *nm;
ragge
1.105
844
ragge
1.107
845         if (flslvl)
846                 return;
plunky
1.193
847
ragge
1.221
848         if ((ob = incfn()) == NULL/* get include file name in obuf */
849                 error("bad #include_next");
plunky
1.193
850
ragge
1.221
851         nm = xstrdup(ob->buf+1);
852         bufree(ob);
plunky
1.193
853
ragge
1.221
854         if (fsrch(nmifiles->idxifiles->incs) == 0)
855                 error("cannot find '%s'"nm);
ragge
1.219
856         prtline(1);
ragge
1.102
857 }
858
ragge
1.79
859 /*
860  * Compare two replacement lists, taking in account comments etc.
861  */
862 static int
ragge
1.103
863 cmprepl(const usch *oconst usch *n)
ragge
1.79
864 {
ragge
1.213
865         for (; *oo++, n++) {
ragge
1.79
866                 /* comment skip */
ragge
1.213
867                 if (*o == '/' && o[1] == '*') {
868                         while (*o != '*' || o[1] != '/')
869                                 o++;
870                         o += 2;
871                 }
872                 if (*n == '/' && n[1] == '*') {
873                         while (*n != '*' || n[1] != '/')
874                                 n++;
875                         n += 2;
ragge
1.79
876                 }
877                 while (*o == ' ' || *o == '\t')
ragge
1.213
878                         o++;
ragge
1.79
879                 while (*n == ' ' || *n == '\t')
ragge
1.213
880                         n++;
ragge
1.79
881                 if (*o != *n)
882                         return 1;
883         }
884         return 0;
885 }
886
ragge
1.97
887 static int
888 isell(void)
889 {
ragge