Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20160516184350

Diff

Diff from 1.278 to:

Annotations

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

Annotated File View

ragge
1.278
1 /*      $Id: cpp.c,v 1.278 2016/05/16 18:43:50 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;
90 int warningsMxlen;
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.1
163
164 int
165 main(int argcchar **argv)
166 {
ragge
1.265
167         struct includ bic;
168         struct iobuf *fb = getobuf(BNORMAL);
ragge
1.26
169         register int ch;
ragge
1.103
170         const usch *fn1, *fn2;
ragge
1.265
171         char *a;
ragge
1.15
172
ragge
1.94
173 #ifdef TIMING
174         struct timeval t1t2;
175
176         (void)gettimeofday(&t1NULL);
177 #endif
178
ragge
1.269
179 #if LIBVMF
180         if (vminit(2))
181                 error("vminit");
182         if (vmopen(&ibspcNULL) < 0)
183                 error("vmopen ibspc");
184 #endif
185
plunky
1.188
186         while ((ch = getopt(argcargv"ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
ragge
1.1
187                 switch (ch) {
plunky
1.188
188                 case 'A'/* assembler input */
189                         Aflag++;
190                         break;
plunky
1.191
191
ragge
1.22
192                 case 'C'/* Do not discard comments */
193                         Cflag++;
194                         break;
195
plunky
1.187
196                 case 'E'/* treat warnings as errors */
197                         Eflag++;
198                         break;
199
plunky
1.142
200                 case 'D'/* define something */
ragge
1.265
201                         if ((a = strchr(optarg'=')) != NULL)
202                                 *a = ' ';
203                         bsheap(fb"#define %s%s"optarga ? "\n" : " 1\n");
204                         break;
205
ragge
1.53
206                 case 'i'/* include */
ragge
1.265
207                         bsheap(fb"#include \"%s\"\n"optarg);
208                         break;
209
ragge
1.53
210                 case 'U'/* undef */
ragge
1.265
211                         bsheap(fb"#undef %s\n"optarg);
ragge
1.7
212                         break;
213
plunky
1.142
214                 case 'd':
plunky
1.144
215                         while (*optarg) {
216                                 switch(*optarg) {
217                                 case 'M'/* display macro definitions */
218                                         dMflag = 1;
219                                         Mflag = 1;
220                                         break;
221
222                                 default/* ignore others */
223                                         break;
224                                 }
225                                 optarg++;
plunky
1.142
226                         }
227                         break;
228
229                 case 'I':
230                 case 'S':
231                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
232                         break;
233
ragge
1.51
234                 case 'M'/* Generate dependencies for make */
235                         Mflag++;
236                         break;
237
gmcgarry
1.85
238                 case 'P'/* Inhibit generation of line numbers */
239                         Pflag++;
240                         break;
241
plunky
1.142
242                 case 't':
243                         tflag = 1;
ragge
1.7
244                         break;
245
plunky
1.134
246 #ifdef PCC_DEBUG
ragge
1.64
247                 case 'V':
ragge
1.18
248                         dflag++;
ragge
1.1
249                         break;
250 #endif
ragge
1.64
251                 case 'v':
plunky
1.200
252                         fprintf(stderr"PCC preprocessor version "VERSSTR"\n");
ragge
1.64
253                         break;
ragge
1.1
254
ragge
1.151
255                 case 'x':
ragge
1.195
256                         if (strcmp(optarg"MMD") == 0) {
257                                 MMDflag++;
258                         } else if (strcmp(optarg"MP") == 0) {
ragge
1.151
259                                 MPflag++;
260                         } else if (strncmp(optarg"MT,"3) == 0 ||
261                             strncmp(optarg"MQ,"3) == 0) {
ragge
1.245
262                                 int l = strlen(optarg+3) + 2;
263                                 char *cp, *up;
264
265                                 if (optarg[1] == 'Q')
266                                         for (cp = optarg+3; *cpcp++)
267                                                 if (*cp == '$')
268                                                         l++;
269                                 Mxlen += l;
270                                 Mxfile = cp = realloc(MxfileMxlen);
271                                 for (up = Mxfile; *upup++)
272                                         ;
273                                 if (up != Mxfile)
274                                         *up++ = ' ';
275                                 for (cp = optarg+3; *cpcp++) {
276                                         *up++ = *cp;
277                                         if (optarg[1] == 'Q' && *cp == '$')
278                                                 *up++ = *cp;
ragge
1.151
279                                 }
ragge
1.245
280                                 *up = 0;
ragge
1.151
281                         } else
282                                 usage();
283                         break;
284
ragge
1.37
285                 case '?':
plunky
1.142
286                 default:
ragge
1.37
287                         usage();
ragge
1.1
288                 }
plunky
1.142
289         }
290
ragge
1.1
291         argc -= optind;
292         argv += optind;
293
ragge
1.103
294         filloc = lookup((const usch *)"__FILE__"ENTER);
295         linloc = lookup((const usch *)"__LINE__"ENTER);
296         pragloc = lookup((const usch *)"_Pragma"ENTER);
ragge
1.224
297         defloc = lookup((const usch *)"defined"ENTER);
ragge
1.252
298         ctrloc = lookup((const usch *)"__COUNTER__"ENTER);
ragge
1.274
299         filloc->value = linloc->value = pragloc->value =
300             ctrloc->value = (const usch *)"";
301         defloc->value = defloc->namep;
302         filloc->type = FILLOC;
303         linloc->type = LINLOC;
304         pragloc->type = PRAGLOC;
305         defloc->type = DEFLOC;
306         ctrloc->type = CTRLOC;
ragge
1.15
307
ragge
1.60
308         if (Mflag && !dMflag) {
ragge
1.247
309                 char *c;
ragge
1.51
310
311                 if (argc < 1)
312                         error("-M and no infile");
ragge
1.247
313                 if ((c = strrchr(argv[0], '/')) == NULL)
314                         c = argv[0];
ragge
1.51
315                 else
316                         c++;
ragge
1.247
317                 Mfile = (char *)xstrdup((usch *)c);
318                 if (MPflag)
319                         MPfile = (char *)xstrdup((usch *)c);
ragge
1.151
320                 if (Mxfile)
ragge
1.247
321                         Mfile = Mxfile;
322                 if ((c = strrchr(Mfile'.')) == NULL)
ragge
1.51
323                         error("-M and no extension: ");
324                 c[1] = 'o';
325                 c[2] = 0;
326         }
327
ragge
1.26
328         if (argc == 2) {
ragge
1.264
329                 close(1);
330                 if (open(argv[1], O_WRONLY|O_CREAT0600) < 0)
ragge
1.37
331                         error("Can't creat %s"argv[1]);
ragge
1.264
332         }
ragge
1.276
333         istty = isatty(1);
ragge
1.26
334
ragge
1.102
335         if (argc && strcmp(argv[0], "-")) {
336                 fn1 = fn2 = (usch *)argv[0];
337         } else {
338                 fn1 = NULL;
ragge
1.103
339                 fn2 = (const usch *)"";
ragge
1.102
340         }
ragge
1.265
341
342         /* initialization defines */
343         if (dMflag)
ragge
1.271
344                 write(1fb->buffb->cptr);
345         fb->buf[fb->cptr] = 0;
ragge
1.265
346         memset(&bic0sizeof(bic));
347         bic.fname = bic.orgfn = (const usch *)"<command line>";
348         bic.lineno = 1;
349         bic.infil = -1;
ragge
1.268
350         bic.ib = fb;
351         fb->bsz = fb->cptr;
ragge
1.271
352         fb->cptr = 0;
ragge
1.265
353         ifiles = &bic;
354         fastscan();
355         bufree(fb);
ragge
1.269
356         ifiles = NULL;
ragge
1.265
357         /* end initial defines */
358
ragge
1.102
359         if (pushfile(fn1fn20NULL))
ragge
1.26
360                 error("cannot open %s"argv[0]);
361
ragge
1.264
362         if (Mflag == 0)
ragge
1.271
363                 write(1pb.bufpb.cptr);
ragge
1.94
364 #ifdef TIMING
365         (void)gettimeofday(&t2NULL);
366         t2.tv_sec -= t1.tv_sec;
367         t2.tv_usec -= t1.tv_usec;
368         if (t2.tv_usec < 0) {
369                 t2.tv_usec += 1000000;
370                 t2.tv_sec -= 1;
371         }
372         fprintf(stderr"cpp total time: %ld s %ld us\n",
plunky
1.159
373              (long)t2.tv_sec, (long)t2.tv_usec);
ragge
1.94
374 #endif
plunky
1.187
375         if (Eflag && warnings > 0)
376                 return 2;
377
ragge
1.37
378         return 0;
ragge
1.26
379 }
380
ragge
1.215
381 /*
382  * Write a character to an out buffer.
383  */
ragge
1.253
384 void
ragge
1.215
385 putob(struct iobuf *obint ch)
386 {
387         if (ob->cptr == ob->bsz) {
ragge
1.271
388                 int sz = ob->bsz;
ragge
1.264
389                 switch (ob->type) {
390                 case BNORMAL:
ragge
1.269
391                         ob->buf = xrealloc(ob->bufsz + CPPBUF+1);
ragge
1.271
392                         /* ob->cptr = ob->buf + sz; */
393                         ob->bsz = sz + CPPBUF;
ragge
1.264
394                         break;
395                 case BMAC:
396                 case BINBUF:
397                         error("putob");
398                 case BUTBUF:
399                         if (Mflag == 0)
400                                 (void)write(1ob->bufsz);
ragge
1.271
401                         ob->cptr = 0;
ragge
1.264
402                         break;
403                 }
ragge
1.215
404         }
405 //      DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch));
ragge
1.271
406         ob->buf[ob->cptr++] = ch;
ragge
1.215
407 }
408
ragge
1.266
409 static struct iobuf *
410 giob(int typconst usch *bpint bsz)
411 {
412         struct iobuf *iob = xmalloc(sizeof(struct iobuf));
413
414         if (bp == NULL)
415                 bp = xmalloc(bsz);
ragge
1.271
416         iob->buf = (usch *)bp;
417         iob->cptr = 0;
418         iob->bsz = bsz;
ragge
1.266
419         iob->ro = 0;
420         iob->type = typ;
421         return iob;
422 }
423
424
ragge
1.261
425 int nbufused;
ragge
1.215
426 /*
427  * Write a character to an out buffer.
428  */
ragge
1.253
429 struct iobuf *
ragge
1.264
430 getobuf(int type)
ragge
1.215
431 {
ragge
1.264
432         struct iobuf *iob = 0;
ragge
1.215
433
ragge
1.264
434         switch (type) {
435         case BNORMAL:
436                 nbufused++;
ragge
1.269
437                 iob = giob(BNORMALNULLCPPBUF);
ragge
1.271
438                 iob->bsz = CPPBUF-1/* space for \0 */
ragge
1.264
439                 break;
440         case BINBUF:
ragge
1.269
441 #if LIBVMF
442                 iob = giob(BINBUF, (usch *)ifiles->vseg->s_cinfoCPPBUF);
443 #else
444                 iob = giob(BINBUFNULLCPPBUF);
445 #endif
ragge
1.265
446                 break;
447         default:
ragge
1.264
448                 error("getobuf");
449         }
ragge
1.215
450         return iob;
451 }
452
453 /*
ragge
1.216
454  * Create a read-only input buffer.
ragge
1.215
455  */
456 static struct iobuf *
457 mkrobuf(const usch *s)
458 {
ragge
1.266
459         struct iobuf *iob;
ragge
1.214
460
ragge
1.218
461         nbufused++;
ragge
1.266
462         iob = giob(BNORMALsstrlen((char *)s));
463         iob->ro = 1;
ragge
1.215
464         DPRINT(("mkrobuf %s\n"s));
465         return iob;
466 }
ragge
1.214
467
468 /*
ragge
1.262
469  * Copy a buffer to another buffer.
470  */
ragge
1.264
471 struct iobuf *
ragge
1.262
472 buftobuf(struct iobuf *instruct iobuf *iob)
473 {
ragge
1.271
474         int cp;
475
ragge
1.262
476         DPRINT(("strtobuf iob %p buf %p str %p\n"iobiob->bufin));
477         if (iob == NULL)
ragge
1.264
478                 iob = getobuf(BNORMAL);
ragge
1.271
479         for (cp = 0cp < in->cptrcp++)
480                 putob(iobin->buf[cp]);
ragge
1.262
481         return iob;
482 }
483
484 /*
ragge
1.215
485  * Copy a string to a buffer.
ragge
1.214
486  */
ragge
1.261
487 struct iobuf *
ragge
1.267
488 strtobuf(const usch *strstruct iobuf *iob)
ragge
1.215
489 {
490         if (iob == NULL)
ragge
1.264
491                 iob = getobuf(BNORMAL);
ragge
1.265
492         DPRINT(("strtobuf iob %p buf %p str %s\n"iobiob->bufstr));
ragge
1.215
493         do {
494                 putob(iob, *str);
495         } while (*str++);
496         iob->cptr--;
497         return iob;
498 }
499
ragge
1.256
500 static usch *macbase;
501 static int macposcmbase;
502
503 static void
504 macsav(int ch)
505 {
506         if (macbase == NULL)
507                 macbase = xmalloc(CPPBUF);
508         if (macpos == CPPBUF) {
509                 usch *tb;
510                 if (cmbase == 0)
511                         error("macro too large");
512                 tb = xmalloc(CPPBUF);
513                 memcpy(tbmacbase+cmbaseCPPBUF-cmbase);
514                 macpos -= cmbase;
515                 cmbase = 0;
516                 macbase = tb;
517         }
518         macbase[macpos++] = ch;
519 }
520
521 static void                     
ragge
1.257
522 macstr(const usch *s)
ragge
1.256
523 {
524         do {
525                 macsav(*s);
526         } while (*s++ != 0);
527         macpos--;
528 }
529
530 #define setcmbase()     cmbase = macpos
ragge
1.257
531 #define clrcmbase()     macpos = cmbase
ragge
1.256
532
ragge
1.253
533 void
ragge
1.215
534 bufree(struct iobuf *iob)
ragge
1.214
535 {
ragge
1.268
536         if (iob->type == BNORMAL)
537                 nbufused--;
ragge
1.215
538         if (iob->ro == 0)
539                 free(iob->buf);
540         free(iob);
ragge
1.214
541 }
542
ragge
1.108
543 static void
544 addidir(char *idirstruct incs **ww)
545 {
546         struct incs *w;
547         struct stat st;
548
plunky
1.163
549         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
ragge
1.108
550                 return/* ignore */
551         if (*ww != NULL) {
552                 for (w = *www->nextw = w->next) {
plunky
1.203
553 #ifdef _WIN32
gmcgarry
1.131
554                         if (strcmp(w->diridir) == 0)
555                                 return;
556 #else
ragge
1.108
557                         if (w->dev == st.st_dev && w->ino == st.st_ino)
558                                 return;
gmcgarry
1.131
559 #endif
ragge
1.108
560                 }
plunky
1.203
561 #ifdef _WIN32
gmcgarry
1.131
562                 if (strcmp(w->diridir) == 0)
563                         return;
564 #else
ragge
1.108
565                 if (w->dev == st.st_dev && w->ino == st.st_ino)
566                         return;
gmcgarry
1.131
567 #endif
ragge
1.108
568                 ww = &w->next;
569         }
570         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
571                 error("couldn't add path %s"idir);
572         w->dir = (usch *)idir;
573         w->dev = st.st_dev;
574         w->ino = st.st_ino;
575         *ww = w;
576 }
577
ragge
1.1
578 void
plunky
1.143
579 line(void)
ragge
1.9
580 {
ragge
1.254
581         struct iobuf *ob;
ragge
1.250
582         struct symtab *nl;
ragge
1.234
583         int cnln;
ragge
1.253
584         usch *cp, *dp;
ragge
1.250
585
586         c = skipws(0);
587         if (ISID0(c)) { /* expand macro */
ragge
1.253
588                 dp = readid(c);
ragge
1.254
589                 if ((nl = lookup(dpFIND)) == 0 || (ob = kfind(nl)) == 0)
ragge
1.250
590                         goto bad;
591         } else {
ragge
1.264
592                 ob = getobuf(BNORMAL);
ragge
1.250
593                 do {
ragge
1.254
594                         putob(obc);
ragge
1.250
595                 } while (ISDIGIT(c = cinput()));
596                 cunput(c);
ragge
1.254
597                 putob(ob0);
ragge
1.250
598         }
ragge
1.254
599         cp = ob->buf;
ragge
1.9
600
ragge
1.250
601         n = 0;
602         while (ISDIGIT(*cp))
603                 n = n * 10 + *cp++ - '0';
604         if (*cp != 0)
ragge
1.9
605                 goto bad;
ragge
1.254
606         bufree(ob);
ragge
1.216
607
ragge
1.209
608         /* Can only be decimal number here between 1-2147483647 */
ragge
1.216
609         if (n < 1 || n > 2147483647)
ragge
1.209
610                 goto bad;
611
ragge
1.234
612         ln = n;
plunky
1.185
613         ifiles->escln = 0;
ragge
1.230
614         if ((c = skipws(NULL)) != '\n') {
ragge
1.234
615                 if (c == 'L' || c == 'U' || c == 'u') {
616                         n = cc = cinput();
617                         if (n == 'u' && c == '8')
618                                 c = cinput();
619                         if (c == '\"')
620                                 warning("#line only allows character literals");
621                 }
ragge
1.216
622                 if (c != '\"')
623                         goto bad;
ragge
1.257
624
ragge
1.261
625                 ob = faststr(cNULL);
626                 if (strcmp((char *)ifiles->fname, (char *)ob->buf))
627                         ifiles->fname = xstrdup(ob->buf);
628                 bufree(ob);
ragge
1.97
629
ragge
1.216
630                 c = skipws(0);
ragge
1.37
631         }
ragge
1.216
632         if (c != '\n')
plunky
1.181
633                 goto bad;
634
ragge
1.234
635         ifiles->lineno = ln;
ragge
1.250
636         prtline(1);
ragge
1.251
637         ifiles->lineno--;
ragge
1.219
638         cunput('\n');
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