|
|
1.1 root 1: /* C Compatible Compiler Preprocessor (CCCP)
2: Copyright (C) 1986, Free Software Foundation, Inc.
3: Written by Paul Rubin, June 1986
4:
5: NO WARRANTY
6:
7: BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
8: NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
9: WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
10: RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
11: WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
12: BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
13: FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
14: AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
15: DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
16: CORRECTION.
17:
18: IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
19: STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
20: WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
21: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
22: OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
23: USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
24: DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
25: A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
26: PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
27: DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
28:
29: GENERAL PUBLIC LICENSE TO COPY
30:
31: 1. You may copy and distribute verbatim copies of this source file
32: as you receive it, in any medium, provided that you conspicuously
33: and appropriately publish on each copy a valid copyright notice
34: "Copyright (C) 1986 Free Software Foundation"; and include
35: following the copyright notice a verbatim copy of the above disclaimer
36: of warranty and of this License.
37:
38: 2. You may modify your copy or copies of this source file or
39: any portion of it, and copy and distribute such modifications under
40: the terms of Paragraph 1 above, provided that you also do the following:
41:
42: a) cause the modified files to carry prominent notices stating
43: that you changed the files and the date of any change; and
44:
45: b) cause the whole of any work that you distribute or publish,
46: that in whole or in part contains or is a derivative of this
47: program or any part thereof, to be licensed at no charge to all
48: third parties on terms identical to those contained in this
49: License Agreement (except that you may choose to grant more extensive
50: warranty protection to some or all third parties, at your option).
51:
52: c) You may charge a distribution fee for the physical act of
53: transferring a copy, and you may at your option offer warranty
54: protection in exchange for a fee.
55:
56: Mere aggregation of another unrelated program with this program (or its
57: derivative) on a volume of a storage or distribution medium does not bring
58: the other program under the scope of these terms.
59:
60: 3. You may copy and distribute this program (or a portion or derivative
61: of it, under Paragraph 2) in object code or executable form under the terms
62: of Paragraphs 1 and 2 above provided that you also do one of the following:
63:
64: a) accompany it with the complete corresponding machine-readable
65: source code, which must be distributed under the terms of
66: Paragraphs 1 and 2 above; or,
67:
68: b) accompany it with a written offer, valid for at least three
69: years, to give any third party free (except for a nominal
70: shipping charge) a complete machine-readable copy of the
71: corresponding source code, to be distributed under the terms of
72: Paragraphs 1 and 2 above; or,
73:
74: c) accompany it with the information you received as to where the
75: corresponding source code may be obtained. (This alternative is
76: allowed only for noncommercial distribution and only if you
77: received the program in object code or executable form alone.)
78:
79: For an executable file, complete source code means all the source code for
80: all modules it contains; but, as a special exception, it need not include
81: source code for modules which are standard libraries that accompany the
82: operating system on which the executable file runs.
83:
84: 4. You may not copy, sublicense, distribute or transfer this program
85: except as expressly provided under this License Agreement. Any attempt
86: otherwise to copy, sublicense, distribute or transfer this program is void and
87: your rights to use the program under this License agreement shall be
88: automatically terminated. However, parties who have received computer
89: software programs from you with this License Agreement will not have
90: their licenses terminated so long as such parties remain in full compliance.
91:
92: In other words, you are welcome to use, share and improve this program.
93: You are forbidden to forbid anyone else to use, share and improve
94: what you give them. Help stamp out software-hoarding! */
95:
96: typedef unsigned char U_CHAR;
97:
98: #ifdef EMACS
99: #define NO_SHORTNAMES
100: #include "../src/config.h"
101: #ifdef static
102: #undef static
103: #endif
104: #ifdef open
105: #undef open
106: #undef close
107: #undef read
108: #undef write
109: #endif /* open */
110: #endif /* EMACS */
111:
112: #include <sys/types.h>
113: #include <sys/stat.h>
114: #include <sys/file.h>
115: #include <ctype.h>
116: #include <stdio.h>
117: #ifndef USG
118: #include <sys/time.h> /* for __DATE__ and __TIME__ */
119: #else
120: #define index strchr
121: #define rindex strrchr
122: #include <time.h>
123: #include <fcntl.h>
124: #endif /* USG */
125:
126: void bcopy (), bzero ();
127: int bcmp ();
128:
129: char *xmalloc (), *xrealloc (), *xcalloc ();
130: void fatal (), pfatal_with_name (), perror_with_name ();
131:
132: char *progname;
133:
134: #define FATAL_EXIT_CODE 33 /* gnu cc command understands this */
135:
136: struct directory_stack
137: {
138: struct directory_stack *next;
139: char *fname;
140: };
141:
142: /* #include "file" starts with the first entry in the stack */
143: /* #include <file> starts with the second. */
144: /* -I directories are added after the first */
145: struct directory_stack default_includes[2] =
146: {
147: { &default_includes[1], "." },
148: { 0, "/usr/include" }
149: };
150: struct directory_stack *include = &default_includes[0];
151:
152: int max_include_len = 14; /* strlen (default_include) + 2
153: (for / and null) */
154:
155: char STDIN_FILE[] = ""; /* Empty, like real cpp */
156: int put_out_comments = 0; /* JF non-zero means leave comments in the
157: output file. Used by lint */
158:
159: /* table to tell if char can be part of a C identifier. */
160: U_CHAR is_idchar[256];
161: /* table to tell if char can be first char of a c identifier. */
162: U_CHAR is_idstart[256];
163: /* table to tell if c is horizontal space. isspace() thinks that
164: newline is space; this is not a good idea for this program. */
165: U_CHAR is_hor_space[256];
166:
167: /* I/O buffer structure. Ought to be used for the output file too.
168: These are also used when there is no file present, for example,
169: when rescanning a definition. Then, the fname field is null. */
170: #define INPUT_STACK_MAX 100
171: struct file_buf {
172: struct infile *next; /* for making stacks of file ptrs */
173: char *fname;
174: int lineno;
175: int length;
176: U_CHAR *buf;
177: U_CHAR *bufp;
178: } instack[INPUT_STACK_MAX];
179: int indepth = 0;
180:
181: typedef struct file_buf FILE_BUF;
182:
183: /* The output buffer. Its LENGTH field is the amount of room allocated
184: for the buffer, not the number of chars actually present. To get
185: that, subtract outbuf.buf from outbuf.bufp. */
186:
187: #define OUTBUF_SIZE 10 /* initial size of output buffer */
188: FILE_BUF outbuf;
189:
190: /* Structure allocated for every #define. For a simple replacement
191: such as
192: #define foo bar ,
193: nargs = -1, the `pattern' list is null, and the expansion is just
194: the replacement text. Nargs = 0 means a real macro with no args,
195: e.g.,
196: #define getchar() getc(stdin) .
197: When there are args, the expansion is the replacement text with the
198: args squashed out, and the reflist is a list describing how to
199: build the output from the input: e.g., "3 chars, then the 1st arg,
200: then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
201: The chars here come from the expansion. Thus, for any definition
202: d , strlen(d->expansion) should equal the sum of all the
203: d->pattern->nchars. Note that the list can be arbitrarily long---
204: its length depends on the number of times the arguements appear in
205: the replacement text, not how many args there are. Example:
206: #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
207: pattern list
208: { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
209: where (x, y) means (nchars, argno). */
210:
211: typedef struct definition DEFINITION;
212: struct definition {
213: int nargs;
214: int length; /* length of expansion string */
215: U_CHAR *expansion;
216: struct reflist {
217: struct reflist *next;
218: int nchars;
219: int argno;
220: } *pattern;
221: };
222:
223: /* different kinds of things that can appear in the value field
224: of a hash node. Actually, this may be useless now. */
225: union hashval {
226: int ival;
227: char *cpval;
228: DEFINITION *defn;
229: };
230:
231:
232: /* The structure of a node in the hash table. The hash table
233: has entries for all tokens defined by #define commands (type T_MACRO),
234: plus some special tokens like __LINE__ (these each have their own
235: type, and the appropriate code is run when that type of node is seen.
236: It does not contain control words like "#define", which are recognized
237: by a separate piece of code. */
238: typedef struct hashnode HASHNODE;
239: struct hashnode {
240: HASHNODE *next; /* double links for easy deletion */
241: HASHNODE *prev;
242: HASHNODE **bucket_hdr; /* also, a back pointer to this node's hash
243: chain is kept, in case the node is the head
244: of the chain and gets deleted. */
245: int type; /* type of special token */
246: int length; /* length of token, for quick comparison */
247: U_CHAR *name; /* the actual name */
248: union hashval value; /* pointer to expansion, or whatever */
249: };
250:
251:
252: HASHNODE *install();
253: /* different flavors of hash nodes --- also used in keyword table */
254: #define T_DEFINE 1 /* the "#define" keyword */
255: #define T_INCLUDE 2 /* the "#include" keyword */
256: #define T_IFDEF 3 /* the "#ifdef" keyword */
257: #define T_IF 4 /* the "#if" keyword */
258: #define T_EXPAND 5 /* argument to be expanded (now unused) */
259: #define T_MACRO 6 /* macro defined by "#define" */
260: #define T_ELSE 7 /* "#else" */
261: #define T_PRAGMA 8 /* "#pragma" */
262: #define T_ELIF 9 /* "#else" */
263: #define T_UNDEF 10 /* "#undef" */
264: #define T_LINE 11 /* "#line" */
265: #define T_ERROR 12 /* "#error" */
266: #define T_IFNDEF 13 /* "#ifndef"; forgot this earlier */
267: #define T_ENDIF 14 /* "#endif" */
268: #define T_SPECLINE 15 /* special symbol "__LINE__" */
269: #define T_DATE 16 /* "__DATE__" */
270: #define T_FILE 17 /* "__FILE__" */
271: #define T_TIME 18 /* "__TIME__" */
272:
273: #define T_SPEC_DEFINED 19 /* special macro for use in #if statements */
274:
275:
276:
277: /* some more different types will be needed --- no longer bloody likely */
278:
279:
280: int do_define(), do_line(), do_include(), do_undef(), do_error(),
281: do_pragma(), do_if(), do_xifdef(), do_else(),
282: do_elif(), do_endif();
283:
284:
285: /* table of control words, along with code to execute when the keyword
286: is seen. For now, it is searched linearly, so put the most frequently
287: found keywords at the beginning of the list. */
288:
289: struct keyword_table {
290: int length;
291: int (*func)();
292: char *name;
293: int type;
294: } keyword_table[] = {
295: { 6, do_define, "define", T_DEFINE},
296: { 4, do_line, "line", T_LINE},
297: { 7, do_include, "include", T_INCLUDE},
298: { 5, do_undef, "undef", T_UNDEF},
299: { 5, do_error, "error", T_ERROR},
300: { 2, do_if, "if", T_IF},
301: { 5, do_xifdef, "ifdef", T_IFDEF},
302: { 6, do_xifdef, "ifndef", T_IFNDEF},
303: { 4, do_else, "else", T_ELSE},
304: { 4, do_elif, "elif", T_ELIF},
305: { 5, do_endif, "endif", T_ENDIF},
306: { 6, do_pragma, "pragma", T_PRAGMA},
307: { -1, 0, "", -1},
308: };
309:
310: /* Some definitions for the hash table. The hash function MUST be
311: computed as shown in hashf() below. That is because the rescan
312: loop computes the hash value `on the fly' for most tokens,
313: in order to avoid the overhead of a lot of procedure calls to
314: the hashf() function. Hashf() only exists for the sake of
315: politeness, for use when speed isn't so important. */
316:
317: #define HASHSIZE 1009
318: HASHNODE *hashtab[HASHSIZE];
319: #define HASHSTEP(old, c) ((old << 1) + c)
320: #define MAKE_POS(v) (v & ~0x80000000) /* make number positive */
321:
322: #define SKIP_WHITE_SPACE(p) { while (is_hor_space[*p]) p++; }
323:
324:
325:
326: main (argc, argv)
327: int argc;
328: char **argv;
329: {
330: struct stat sbuf;
331: char *in_fname, *out_fname;
332: int out_fd = 1; /* default to stdout */
333: int f, i;
334: FILE_BUF *fp;
335:
336: progname = argv[0];
337: in_fname = NULL;
338: out_fname = NULL;
339: initialize_random_junk ();
340:
341: fp = &instack[indepth++];
342:
343: /* if (argc < 2) JF no args means work as filter
344: return FATAL_EXIT_CODE; */
345:
346: for (i = 1; i < argc; i++) {
347: if (argv[i][0] != '-') {
348: if (out_fname != NULL)
349: fatal ("Usage: %s [switches] input output\n", argv[0]);
350: else if (in_fname != NULL) {
351: out_fname = argv[i];
352: if ((out_fd = creat (out_fname, 0666)) < 0)
353: pfatal_with_name (out_fname);
354: } else
355: in_fname = argv[i];
356: } else {
357: switch (argv[i][1]) {
358: U_CHAR *p;
359: struct directory_stack *dirtmp;
360: case 'D':
361: if ((p = (U_CHAR *) index(argv[i]+2, '=')) != NULL)
362: *p = ' ';
363: make_definition (argv[i] + 2);
364: break;
365: case 'U': /* JF #undef something */
366: make_undef(argv[i] + 2);
367: break;
368: case 'C': /* JF do later -C means leave comments alone! */
369: put_out_comments++;
370: break;
371: case 'E': /* -E comes from cc -E; ignore it. */
372: break;
373: case 'M': /* Makefile dependencies or something like
374: that. Not implimented yet */
375: break;
376: case 'I': /* JF handle directory path right */
377: dirtmp = (struct directory_stack *)
378: xmalloc (sizeof (struct directory_stack));
379: dirtmp->next = include->next;
380: include->next = dirtmp;
381: dirtmp->fname = argv[i]+2;
382: include = dirtmp;
383: if (strlen (argv[i]) > max_include_len)
384: max_include_len = strlen (argv[i]);
385: break;
386:
387: case '\0': /* JF handle '-' as file name meaning stdin or stdout */
388: if (in_fname == NULL) {
389: in_fname = STDIN_FILE;
390: break;
391: } else if (out_fname == NULL) {
392: out_fname = "stdout";
393: break;
394: } /* else fall through into error */
395:
396: default:
397: fatal ("Illegal option %s\n", argv[i]);
398: }
399: }
400: }
401:
402: /* JF check for stdin */
403: if (in_fname == STDIN_FILE || in_fname == NULL)
404: f = 0;
405: else if ((f = open (in_fname, O_RDONLY)) < 0)
406: goto perror;
407:
408: fstat (f, &sbuf);
409: fp->fname = in_fname;
410: fp->lineno = 1;
411: /* JF all this is mine about reading pipes and ttys */
412: if ((sbuf.st_mode & S_IFMT) != S_IFREG) {
413: int size;
414: int bsize;
415: int cnt;
416: U_CHAR *bufp;
417:
418: bsize = 2000;
419: size = 0;
420: fp->buf = (U_CHAR *) xmalloc (bsize + 1);
421: bufp = fp->buf;
422: for (;;) {
423: cnt = read (f, bufp, bsize - size);
424: if (cnt < 0) goto perror; /* error! */
425: if (cnt == 0) break; /* End of file */
426: size += cnt;
427: bufp += cnt;
428: if (bsize-size == 0) { /* Buffer is full! */
429: bsize *= 2;
430: fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 1);
431: bufp = fp->buf + size; /* May have moved */
432: }
433: }
434: fp->buf[size] = '\0';
435: fp->length = size;
436: } else {
437: fp->length = sbuf.st_size;
438: fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1);
439:
440: if (read (f, fp->buf, sbuf.st_size) != sbuf.st_size)
441: goto perror;
442:
443: fp->buf[sbuf.st_size] = '\0';
444: }
445:
446: /* initialize output buffer */
447: outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);
448: outbuf.bufp = outbuf.buf;
449: outbuf.length = OUTBUF_SIZE;
450:
451: output_line_command (fp, &outbuf);
452: rescan (fp, &outbuf);
453:
454: /* do something different than this later */
455: fflush (stdout);
456: write (out_fd, outbuf.buf, outbuf.bufp - outbuf.buf);
457: exit (0);
458:
459: perror:
460: pfatal_with_name (argv[1]);
461: }
462:
463: /*
464: * The main loop of the program. Try to examine and move past most
465: * ordinary input chars as fast as possible. Call appropriate routines
466: * when something special (such as a macro expansion) has to happen.
467:
468: IP is the source of input to scan.
469: OP is the place to put input. */
470:
471: rescan (ip, op)
472: FILE_BUF *ip, *op;
473: {
474: register int c;
475: register int ident_length = 0, hash = 0;
476: register U_CHAR *limit;
477: U_CHAR *check_expand ();
478: struct keyword_table *handle_directive ();
479: int excess_newlines = 0;
480: int escaped = 0;
481:
482: U_CHAR *bp;
483:
484: check_expand(op, ip->length);
485:
486: ip->bufp = ip->buf;
487: limit = ip->buf + ip->length;
488: while (1) {
489: if (ip->bufp < limit) {
490: c = *ip->bufp++;
491: *op->bufp++ = c;
492: } else {
493: c = -1;
494: }
495:
496: --escaped;
497: /* Now ESCAPED is 0 if and only if this character is escaped. */
498:
499: switch (c) {
500: case '\\':
501: if (escaped == 0)
502: goto randomchar;
503: if (*ip->bufp != '\n')
504: {
505: escaped = 1;
506: goto randomchar;
507: }
508: /* always merge lines ending with backslash-newline */
509: ++ip->bufp;
510: ++ip->lineno;
511: ++excess_newlines;
512: --op->bufp; /* remove backslash from obuf */
513: continue; /* back to top of while loop */
514:
515: case '#':
516: /* # keyword: a # must be first nonblank char on the line */
517: for (bp = ip->bufp - 1; bp >= ip->buf; bp--)
518: if (*bp == '\n')
519: break;
520: bp++; /* skip nl or move back into buffer */
521: SKIP_WHITE_SPACE (bp);
522: if (*bp != '#')
523: goto randomchar;
524: ident_length = hash = 0;
525: --op->bufp; /* don't copy the '#' */
526:
527: if (handle_directive (ip, op, &excess_newlines) == NULL) {
528: ++op->bufp; /* copy the '#' after all */
529: goto randomchar;
530: }
531: break;
532:
533: case '\"': /* skip quoted string */
534: case '\'':
535: /* a single quoted string is treated like a double -- some
536: programs (e.g., troff) are perverse this way */
537:
538: if (escaped == 0)
539: goto randomchar; /* false alarm-- it's escaped. */
540:
541: /* skip ahead to a matching quote. */
542:
543: bp = ip->bufp;
544: while (bp < limit) {
545: *op->bufp++ = *bp;
546: switch (*bp++) {
547: case '\n':
548: ++ip->lineno;
549: break;
550: case '\\':
551: if (bp >= limit)
552: break;
553: if (*bp == '\n')
554: {
555: /* backslash newline is replaced by nothing at all,
556: but remember that the source line count is out of synch. */
557: --op->bufp;
558: ++bp;
559: ++excess_newlines;
560: ++ip->lineno;
561: }
562: else
563: *op->bufp++ = *bp++;
564: break;
565: case '\"':
566: case '\'':
567: if (bp[-1] == c)
568: goto while2end;
569: break;
570: }
571: }
572: while2end:
573: ip->bufp = bp;
574: break;
575:
576: case '/': /* possible comment */
577: if (*ip->bufp != '*')
578: goto randomchar;
579: if (put_out_comments) {
580: bp = ip->bufp;
581: *op->bufp++ = *bp++;
582: } else {
583: bp = ip->bufp + 1;
584: --op->bufp; /* don't leave initial slash in buffer */
585: }
586:
587: for (;;) {
588: while (bp < limit) {
589: if (put_out_comments)
590: *op->bufp++ = *bp;
591: switch (*bp++) {
592: case '*':
593: goto whileend;
594: case '\n':
595: /* copy the newline into the output buffer, in order to
596: avoid the pain of a #line every time a multiline comment
597: is seen. This means keywords with embedded comments
598: that contain newlines (blucch!) will lose. By making
599: sure that excess_newlines is not just a flag, but really
600: an accurate count, it might be possible to get around this. */
601: if (!put_out_comments)
602: *op->bufp++ = '\n';
603: ++ip->lineno;
604: }
605: }
606: whileend:
607: if (bp >= limit) {
608: error ("unterminated comment");
609: break; /* causes eof condition */
610: }
611: if (*bp == '/')
612: break;
613: }
614: if (put_out_comments)
615: *op->bufp++ = '/';
616: ip->bufp = bp + 1;
617: break;
618:
619: case '0': case '1': case '2': case '3': case '4':
620: case '5': case '6': case '7': case '8': case '9':
621: /* if digit is not part of identifier, it is random */
622: if (ident_length == 0)
623: goto randomchar;
624: /* fall through */
625:
626: case '_':
627: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
628: case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
629: case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
630: case 's': case 't': case 'u': case 'v': case 'w': case 'x':
631: case 'y': case 'z':
632: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
633: case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
634: case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
635: case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
636: case 'Y': case 'Z':
637: ident_length++;
638: /* compute step of hash function, to avoid a proc call on every token */
639: hash = HASHSTEP(hash, c);
640: break;
641:
642: default:
643: randomchar:
644: if (ident_length > 0) {
645: register HASHNODE *hp;
646: for (hp = hashtab[MAKE_POS(hash) % HASHSIZE]; hp != NULL;
647: hp = hp->next) {
648: U_CHAR *save_ibufp; /* kludge, see below */
649:
650: if (hp->length == ident_length) {
651: register int i = ident_length;
652: register U_CHAR *p = hp->name;
653: register U_CHAR *q = op->bufp - i;
654:
655: if (c != (U_CHAR) -1)
656: q--;
657:
658: do { /* all this to avoid a strncmp() */
659: if (*p++ != *q++)
660: goto hashcollision;
661: } while (--i);
662:
663: save_ibufp = ip->bufp;
664: /* back up over identifier, then expand token */
665: op->bufp -= ident_length;
666: if (c != (U_CHAR) -1) op->bufp--;
667: macroexpand (hp, ip, op, &excess_newlines);
668:
669: check_expand(op, ip->length - (ip->bufp - ip->buf));
670:
671: /* If we just processed an identifier at end of input,
672: return right away. */
673: if (c == (U_CHAR) -1)
674: return;
675:
676: /* if the expansion routine has not moved the input
677: pointer, put back the char that ended the token.
678: This is a kludge because there might be a different
679: reason to put it back or not put it back. */
680: if (ip->bufp == save_ibufp)
681: *op->bufp++ = c;
682:
683: break; /* out of for loop */
684: }
685: hashcollision:
686: ;
687: } /* end for loop */
688: ident_length = hash = 0; /* stop collecting identifier */
689: }
690:
691: /* If we just processed an identifier at end of input,
692: return right away. */
693: if (c == -1)
694: return;
695:
696: /* count the newline, if it was one. The reason this is
697: done down here instead of as a case in the switch is
698: that some expansions might want to look at the line
699: number, and if they happen right before the newline,
700: we don't want them to get the wrong one. So the newline
701: must be counted AFTER any expansions happen. */
702: if (c == '\n') {
703: ++ip->lineno;
704: if (excess_newlines > 0) {
705: output_line_command (ip, op);
706: check_expand(op, ip->length - (ip->bufp - ip->buf));
707:
708: excess_newlines = 0;
709: }
710: }
711: break; /* from switch */
712: }
713: }
714: }
715:
716: /*
717: * Process a # directive. Expects ip->bufp to point to the '#', as in
718: * "#define foo bar". Bumps *excess_newlines counter as necessary if
719: * the command is several lines long (and also updates ip->lineno).
720: * The main reason for this is that the comments could contain
721: * newlines, which would be confusing. Passes to the command handler
722: * (do_define, do_include, etc.): the addresses of the 1st and
723: * last chars of the command (starting immediately after the #
724: * keyword), plus op and the keyword table pointer. If the line
725: * contains comments the command is copied into a temporary buffer
726: * (sans comments) and the temporary buffer is passed to the command
727: * handler instead.
728: */
729:
730: struct keyword_table *
731: handle_directive (ip, op, excess_newlines)
732: FILE_BUF *ip, *op;
733: int *excess_newlines;
734: {
735: register U_CHAR *bp, *cp;
736: register struct keyword_table *kt;
737: register int ident_length;
738:
739: /* Nonzero means we must copy the entire command
740: to get rid of comments or backslash-newlines. */
741: int copy_command = 0;
742:
743: bp = ip->bufp;
744: SKIP_WHITE_SPACE(bp);
745: cp = bp;
746: while (is_idchar[*cp])
747: cp++;
748: ident_length = cp - bp;
749:
750: /*
751: * Decode the keyword and call the appropriate expansion
752: * routine, after moving the input pointer up to the next line.
753: * If the keyword is not a legitimate control word, return NULL.
754: * Otherwise, return ptr to the keyword structure matched.
755: */
756: for (kt = keyword_table; kt->length > 0; kt++) {
757: if (kt->length == ident_length && !strncmp(kt->name, bp, ident_length)) {
758: register U_CHAR *buf;
759: register U_CHAR *limit = ip->buf + ip->length;
760: U_CHAR *skip_to_end_of_comment();
761:
762: buf = bp = bp + ident_length;
763: while (bp < limit) {
764: if (*bp == '\'' || *bp == '\"') { /* JF handle quotes right */
765: U_CHAR quotec;
766:
767: for (quotec = *bp++; bp < limit && *bp != quotec; bp++) {
768: if (*bp == '\\') bp++;
769: if (*bp == '\n') {
770: if (bp[-1] == '\\')
771: copy_command++;
772: else {
773: /* --bp; */
774: break; /* JF ugly, but might work */
775: }
776: }
777: }
778: continue;
779: }
780: if (*bp == '/' && bp[1] == '*') {
781: copy_command++;
782: ip->bufp = bp + 2;
783: skip_to_end_of_comment (ip, NULL);
784: bp = ip->bufp;
785: continue;
786: }
787:
788: if (*bp++ == '\n') {
789: if (*(bp-2) == '\\')
790: copy_command++;
791: else {
792: --bp; /* point to the newline */
793: break;
794: }
795: }
796: }
797: if (copy_command) {
798: /* need to copy entire command into temp buffer before dispatching */
799:
800: cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus
801: some slop */
802: bp = buf;
803: buf = cp;
804:
805: while (bp < limit) {
806: if (*bp == '\'' || *bp == '\"') { /* JF handle quotes right */
807: U_CHAR quotec;
808:
809: *cp++ = *bp;
810: for (quotec = *bp++; bp < limit && *bp != quotec; *cp++ = *bp++) {
811: if (*bp == '\\')
812: *cp++ = *bp++;
813: if (*bp == '\n') {
814: if (bp[-1] == '\\') {
815: ++ip->lineno;
816: ++*excess_newlines;
817: } else break; /* JF ugly, but might work */
818: }
819: }
820: continue;
821: }
822: if (*bp == '/' && bp[1] == '*') {
823: int newlines_found = 0;
824: ip->bufp = bp + 2;
825: skip_to_end_of_comment (ip, &newlines_found);
826: *excess_newlines += newlines_found;
827: ip->lineno += newlines_found;
828: bp = ip->bufp;
829: continue;
830: }
831:
832: if (*bp == '\n') {
833: if (bp[-1] == '\\') {
834: ++ip->lineno;
835: ++*excess_newlines;
836: } else
837: break;
838: }
839: *cp++ = *bp++;
840: }
841: }
842: else
843: cp = bp;
844:
845: ip->bufp = bp; /* skip to the end of the command */
846:
847: /* call the appropriate command handler. Buf now points to
848: either the appropriate place in the input buffer, or to
849: the temp buffer if it was necessary to make one. Cp
850: points to the first char after the contents of the (possibly
851: copied) command, in either case. */
852: (*kt->func) (buf, cp, op, kt);
853: check_expand (op, ip->length - (ip->bufp - ip->buf));
854:
855: break;
856: }
857: }
858: if (kt->length <= 0)
859: kt = NULL;
860:
861: return kt;
862: }
863:
864: static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
865: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
866: };
867:
868: /*
869: * expand things like __FILE__. Place the expansion into the output
870: * buffer *without* rescanning.
871: */
872: expand_special_symbol (hp, ip, op)
873: HASHNODE *hp;
874: FILE_BUF *ip, *op;
875: {
876: char *buf;
877: int i, len;
878: FILE_BUF *last_ip = NULL;
879: static struct tm *timebuf = NULL;
880: struct tm *localtime();
881:
882: int paren = 0; /* for special `defined' keyword */
883: HASHNODE *lookup();
884:
885: for (i = indepth - 1; i >= 0; i--)
886: if (instack[i].fname != NULL) {
887: last_ip = &instack[i];
888: break;
889: }
890: if (last_ip == NULL) {
891: error("CCCP error: not in any file?!");
892: return; /* the show must go on */
893: }
894:
895: switch (hp->type) {
896: case T_FILE:
897: buf = (char *) alloca (3 + strlen(last_ip->fname));
898: sprintf (buf, "\"%s\"", last_ip->fname);
899: break;
900: case T_SPECLINE:
901: buf = (char *) alloca (10);
902: sprintf (buf, "%d", last_ip->lineno);
903: break;
904: case T_DATE:
905: case T_TIME:
906: if (timebuf == NULL) {
907: i = time(0);
908: timebuf = localtime(&i);
909: }
910: buf = (char *) alloca (20);
911: if (hp->type == T_DATE)
912: sprintf(buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon - 1],
913: timebuf->tm_mday, timebuf->tm_year + 1900);
914: else
915: sprintf(buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
916: timebuf->tm_sec);
917: break;
918: case T_SPEC_DEFINED:
919: buf = " 0 "; /* assume symbol is not defined */
920: if (is_hor_space[*(ip->bufp-1)]) {
921: SKIP_WHITE_SPACE(ip->bufp);
922: if (*ip->bufp == '(') {
923: paren++;
924: ip->bufp++; /* skip over the paren */
925: }
926: } else if (*(ip->bufp-1) == '(')
927: paren++;
928:
929: if (!is_idstart[*ip->bufp])
930: goto oops;
931: if (lookup(ip->bufp))
932: buf = " 1 ";
933: while (is_idchar[*ip->bufp])
934: ++ip->bufp;
935: SKIP_WHITE_SPACE (ip->bufp);
936: if (paren) {
937: if (*ip->bufp != ')')
938: goto oops;
939: ++ip->bufp;
940: }
941: break;
942:
943: oops:
944:
945: error ("`defined' must be followed by IDENT or (IDENT)");
946: break;
947:
948: default:
949: error("CCCP error: illegal special hash type"); /* time for gdb */
950: abort ();
951: }
952: len = strlen(buf);
953: check_expand(op, len);
954: bcopy (buf, op->bufp, len);
955: op->bufp += len;
956:
957: return;
958: }
959:
960:
961: /* routines to handle #directives */
962:
963: /*
964: * process include file by reading it in and calling rescan.
965: * expects to see "fname" or <fname> on the input.
966: * add error checking and -I option later.
967: */
968:
969: do_include (buf, limit, op, keyword)
970: U_CHAR *buf, *limit;
971: FILE_BUF *op;
972: struct keyword_table *keyword;
973: {
974: char *fname; /* dynamically allocated fname buffer */
975: U_CHAR *fbeg, *fend; /* beginning and end of fname */
976: U_CHAR term; /* terminator for fname */
977: int err = 0; /* some error has happened */
978: struct stat sbuf; /* to stat the include file */
979: FILE_BUF *fp; /* for input stack frame */
980: struct directory_stack *stackp;
981: int flen;
982:
983: int save_indepth = indepth;
984: /* in case of errors */
985:
986: int f; /* file number */
987: char *other_dir; /* JF */
988:
989: f= -1; /* JF we iz PARANOID! */
990: fbeg = buf;
991: SKIP_WHITE_SPACE(fbeg);
992:
993: switch (*fbeg++) {
994: case '\"':
995: term = '\"';
996: stackp = include;
997: break;
998: case '<':
999: term = '>';
1000: stackp = include->next;
1001: break;
1002: default:
1003: error ("#include expects \"fname\" or <fname>");
1004: fbeg--; /* so person can see whole fname */
1005: err++;
1006: term = '\n';
1007: break;
1008: }
1009: for (fend = fbeg; *fend != term; fend++)
1010: {
1011: if (fend >= limit)
1012: {
1013: error ("illegal or unterminated include file name");
1014: goto nope;
1015: }
1016: }
1017:
1018: flen = fend - fbeg;
1019: if (err)
1020: goto nope;
1021:
1022: other_dir = NULL;
1023: if (stackp == include)
1024: {
1025: fp = &instack[indepth];
1026: while(--fp >= &instack[0])
1027: {
1028: int n;
1029: char *ep,*nam;
1030: extern char *rindex ();
1031:
1032: if ((nam = fp->fname) != NULL)
1033: {
1034: if ((ep = rindex (nam, '/')) != NULL)
1035: {
1036: n = ep - nam;
1037: other_dir = (char *) alloca (n + 1);
1038: strncpy (other_dir, nam, n);
1039: other_dir[n] = '\0';
1040: }
1041: break;
1042: }
1043: }
1044: }
1045: /* JF search directory path */
1046: fname = (char *) alloca (max_include_len + flen);
1047: for (; stackp; stackp = stackp->next)
1048: {
1049: if (other_dir)
1050: {
1051: strcpy (fname, other_dir);
1052: other_dir = 0;
1053: }
1054: else
1055: strcpy (fname, stackp->fname);
1056: strcat (fname, "/");
1057: strncat (fname, fbeg, flen);
1058: if ((f = open (fname, O_RDONLY)) >= 0)
1059: break;
1060: }
1061: if (f < 0)
1062: {
1063: err++;
1064: goto nope;
1065: }
1066:
1067: if (fstat(f, &sbuf) < 0)
1068: {
1069: perror_with_name (fname);
1070: goto nope; /* impossible? */
1071: }
1072:
1073: fp = &instack[indepth++];
1074: fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1);
1075: fp->fname = fname;
1076: fp->length = sbuf.st_size;
1077: fp->lineno = 1;
1078:
1079: if (read(f, fp->buf, sbuf.st_size) != sbuf.st_size)
1080: goto nope;
1081:
1082: fp->buf[sbuf.st_size] = '\0';
1083:
1084: output_line_command (fp, op);
1085: rescan(fp, op);
1086:
1087: nope:
1088:
1089: if (f > 0)
1090: close (f);
1091: indepth = save_indepth;
1092: output_line_command (&instack[indepth-1], op);
1093: if (err) {
1094: strncpy (fname, fbeg, flen);
1095: fname[flen] = '\0';
1096: perror_with_name (fname);
1097: }
1098: return err;
1099: }
1100:
1101: /* the arglist structure is built by do_define to tell
1102: collect_definition where the argument names begin. That
1103: is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
1104: would contain pointers to the strings x, y, and z.
1105: Collect_definition would then build a DEFINITION node,
1106: with reflist nodes pointing to the places x, y, and z had
1107: appeared. So the arglist is just convenience data passed
1108: between these two routines. It is not kept around after
1109: the current #define has been processed and entered into the
1110: hash table. */
1111:
1112: struct arglist {
1113: struct arglist *next;
1114: U_CHAR *name;
1115: int length;
1116: int argno;
1117: };
1118:
1119: /* Process a #define command.
1120: BUF points to the contents of the #define command, as a continguous string.
1121: LIMIT points to the first character past the end of the definition.
1122: KEYWORD is the keyword-table entry for #define. */
1123:
1124: do_define (buf, limit, op, keyword)
1125: U_CHAR *buf, *limit;
1126: FILE_BUF *op;
1127: struct keyword_table *keyword;
1128: {
1129: U_CHAR *bp; /* temp ptr into input buffer */
1130: U_CHAR *symname; /* remember where symbol name starts */
1131: int sym_length; /* and how long it is */
1132: U_CHAR *def; /* beginning of expansion */
1133:
1134: DEFINITION *defn, *collect_expansion();
1135:
1136: bp = buf;
1137:
1138: while (is_hor_space[*bp])
1139: bp++;
1140: if (!is_idstart[*bp]) {
1141: error("illegal macro name: must start with an alphabetic or '_'");
1142: goto nope;
1143: }
1144: symname = bp; /* remember where it starts */
1145: while (is_idchar[*bp] && bp < limit)
1146: bp++;
1147: sym_length = bp - symname;
1148:
1149: /* lossage will occur if identifiers or control keywords are broken
1150: across lines using backslash. This is not the right place to take
1151: care of that. */
1152:
1153: if (is_hor_space[*bp] || *bp == '\n' || bp >= limit) {
1154: /* simple expansion or empty definition; gobble it */
1155: if (is_hor_space[*bp])
1156: def = ++bp; /* skip exactly one blank/tab char */
1157: else
1158: def = bp; /* empty definition */
1159:
1160: defn = (DEFINITION *) xmalloc (sizeof (DEFINITION) + limit - def);
1161: defn->nargs = -1;
1162: defn->pattern = NULL;
1163: defn->expansion = ((U_CHAR *) defn) + sizeof (DEFINITION);
1164: defn->length = limit - def;
1165: if (defn->length > 0)
1166: bcopy (def, defn->expansion, defn->length);
1167: }
1168: else if (*bp == '(') {
1169: struct arglist *arg_ptrs = NULL;
1170: int argno = 0;
1171:
1172: bp++; /* skip '(' */
1173: SKIP_WHITE_SPACE(bp);
1174:
1175: while (*bp != ')') {
1176: struct arglist *temp;
1177:
1178: temp = (struct arglist *) alloca (sizeof (struct arglist));
1179: temp->name = bp;
1180: temp->next = arg_ptrs;
1181: temp->argno = ++argno;
1182: arg_ptrs = temp;
1183: while (is_idchar[*bp])
1184: bp++;
1185: temp->length = bp - temp->name;
1186: SKIP_WHITE_SPACE (bp); /* there should not be spaces here,
1187: but let it slide if there are. */
1188: if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
1189: error ("illegal parameter to macro");
1190: goto nope;
1191: }
1192: if (*bp == ',') {
1193: bp++;
1194: SKIP_WHITE_SPACE(bp);
1195: }
1196: if (bp >= limit) {
1197: error ("unterminated format parameter list in #define");
1198: goto nope;
1199: }
1200: }
1201:
1202: ++bp; /* skip paren */
1203: /* Skip exactly one space or tab if any. */
1204: if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
1205:
1206: /* now everything from bp before limit is the definition. */
1207: defn = collect_expansion(bp, limit - bp, arg_ptrs);
1208: } else {
1209: error("#define symbol name not followed by SPC, TAB, or '('");
1210: goto nope;
1211: }
1212:
1213: {
1214: HASHNODE *hp, *lookup();
1215: DEFINITION *old_def;
1216: if ((hp = lookup(symname)) != NULL) {
1217: old_def = hp->value.defn;
1218: if (compare_defs(defn, old_def)) {
1219: U_CHAR *msg; /* what pain... */
1220: msg = (U_CHAR *) alloca (sym_length + 20);
1221: bcopy (symname, msg, sym_length);
1222: strcpy (msg + sym_length, " redefined");
1223: error (msg);
1224: /* flush the most recent old definition */
1225: delete (hp);
1226: }
1227: }
1228: }
1229:
1230: install (symname, T_MACRO, defn);
1231: return 0;
1232:
1233: nope:
1234:
1235: return 1;
1236: }
1237:
1238: /*
1239: * return zero if two DEFINITIONs are isomorphic
1240: */
1241: static
1242: compare_defs(d1, d2)
1243: DEFINITION *d1, *d2;
1244: {
1245: struct reflist *a1, *a2;
1246:
1247: if (d1->nargs != d2->nargs || d1->length != d2->length)
1248: return 1;
1249: if (strncmp(d1->expansion, d2->expansion, d1->length) != 0)
1250: return 1;
1251: for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
1252: a1 = a1->next, a2 = a2->next)
1253: if (a1->nchars != a2->nchars || a1->argno != a2->argno)
1254: return 1;
1255: return 0;
1256: }
1257:
1258: /* Read a macro definition for a macro with parameters.
1259: Build the DEFINITION structure.
1260: Reads SIZE characters of text starting at BUF.
1261: ARGLIST specifies the formal parameters to look for
1262: in the text of the definition. */
1263:
1264: static DEFINITION *
1265: collect_expansion(buf, size, arglist)
1266: U_CHAR *buf;
1267: int size;
1268: struct arglist *arglist;
1269: {
1270: DEFINITION *defn;
1271: U_CHAR *p, *lastp, *exp_p;
1272: int id_len;
1273: struct arglist *arg;
1274: struct reflist *endpat = NULL;
1275:
1276: /* scan thru the macro definition, ignoring comments and quoted
1277: strings, picking up on the macro calls. It does a linear search
1278: thru the arg list on every potential symbol. Profiling might say
1279: that something smarter should happen. */
1280:
1281:
1282: if (size < 0)
1283: abort ();
1284:
1285: defn = (DEFINITION *) xcalloc (1, sizeof (DEFINITION));
1286:
1287: /* watch out! the arg count here depends on the order in which
1288: arglist was built. you might have to count the args if
1289: you change something. */
1290: if (arglist != NULL)
1291: defn->nargs = arglist->argno;
1292: else
1293: defn->nargs = 0;
1294: exp_p = defn->expansion = (U_CHAR *) xmalloc (size + 1);
1295:
1296: /* write comment and quote handling
1297: and speed this loop up later; this is a stripped version */
1298:
1299: /* On the other hand, is it really worth doing that here?
1300: comments will get taken care of on rescan. The sun /lib/cpp doc
1301: says that arg substitution happens even inside quoted strings,
1302: which would mean DON'T do anything with them here. Check the
1303: standard on this. */
1304:
1305: lastp = p = buf;
1306: while (p < buf+size) {
1307: int skipped_arg = 0;
1308:
1309: if (is_idstart[*p] && (p==buf || !is_idchar[*(p-1)])) {
1310:
1311: for (id_len = 0; is_idchar[p[id_len]]; id_len++)
1312: ;
1313: for (arg = arglist; arg != NULL; arg = arg->next) {
1314: struct reflist *tpat;
1315:
1316: if (arg->length == id_len && strncmp(arg->name, p, id_len) == 0) {
1317: /* make a pat node for this arg and append it to the end of
1318: the pat list */
1319: tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
1320: tpat->next = NULL;
1321: if (endpat == NULL)
1322: defn->pattern = tpat;
1323: else
1324: endpat->next = tpat;
1325: endpat = tpat;
1326:
1327: tpat->argno = arg->argno;
1328: tpat->nchars = p - lastp;
1329: p += id_len;
1330: lastp = p; /* place to start copying from next time */
1331: skipped_arg++;
1332: break;
1333: }
1334: }
1335: }
1336:
1337: if (skipped_arg == 0)
1338: *exp_p++ = *p++;
1339: }
1340:
1341: *exp_p++ = '\0';
1342:
1343: defn->length = exp_p - defn->expansion - 1;
1344:
1345: /* give back excess storage */
1346: defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);
1347:
1348: return defn;
1349: }
1350:
1351: #ifdef DEBUG
1352: /*
1353: * debugging routine ---- return a ptr to a string containing
1354: * first n chars of s. Returns a ptr to a static object
1355: * since I happen to know it will fit.
1356: */
1357: static U_CHAR *
1358: prefix (s, n)
1359: U_CHAR *s;
1360: int n;
1361: {
1362: static U_CHAR buf[1000];
1363: bcopy (s, buf, n);
1364: buf[n] = '\0'; /* this should not be necessary! */
1365: return buf;
1366: }
1367: #endif
1368:
1369: /*
1370: * interpret #line command. Remembers previously seen fnames
1371: * in its very own hash table.
1372: */
1373: #define FNAME_HASHSIZE 37
1374:
1375: do_line(buf, limit, op, keyword)
1376: U_CHAR *buf, *limit;
1377: FILE_BUF *op;
1378: struct keyword_table *keyword;
1379: {
1380: register U_CHAR *bp;
1381: FILE_BUF *ip = &instack[indepth - 1];
1382:
1383: bp = buf;
1384: ip->lineno = atoi(bp);
1385: /* this time, skip to the end of the line WITHOUT
1386: bumping lineno. If line counting is consolidated,
1387: this will have to be hacked, perhaps horribly. */
1388:
1389: /* skip over blanks, optional sign, digits, blanks. */
1390: SKIP_WHITE_SPACE (bp);
1391: if (*bp == '-' || *bp == '+')
1392: bp++;
1393: while (isdigit(*bp))
1394: bp++;
1395: SKIP_WHITE_SPACE (bp);
1396:
1397: if (*bp != '\n') { /* if eol, then don't hack fname */
1398: static HASHNODE *fname_table[FNAME_HASHSIZE];
1399: HASHNODE *hp, **hash_bucket;
1400: U_CHAR *fname;
1401: int fname_length;
1402:
1403: if (*bp != '"') {
1404: error ("#line directive must be #line NNN [\"fname\"]");
1405: goto done;
1406: }
1407: fname = ++bp;
1408:
1409: while (*bp != '"' && bp < limit)
1410: bp++;
1411: if (*bp != '"') {
1412: error ("Unterminated fname in #line command");
1413: goto done;
1414: }
1415: fname_length = bp - fname;
1416: hash_bucket =
1417: &fname_table[hashf(fname, fname_length, FNAME_HASHSIZE)];
1418: for (hp = *hash_bucket; hp != NULL; hp = hp->next)
1419: if (hp->length == fname_length &&
1420: strncmp(hp->value.cpval, fname, fname_length) == 0) {
1421: ip->fname = hp->value.cpval;
1422: goto done;
1423: }
1424: /* didn't find it, cons up a new one */
1425: hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1);
1426: hp->next = *hash_bucket;
1427: *hash_bucket = hp;
1428:
1429: hp->length = fname_length;
1430: ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
1431: bcopy (fname, hp->value.cpval, fname_length);
1432: }
1433:
1434: done:
1435:
1436: output_line_command (ip, op);
1437: check_expand (op, ip->length - (ip->bufp - ip->buf));
1438: }
1439:
1440: /*
1441: * remove all definitions of symbol from symbol table.
1442: * according to un*x /lib/cpp, it is not an error to undef
1443: * something that has no definitions, so it isn't one here either.
1444: */
1445: do_undef(buf, limit, op, keyword)
1446: U_CHAR *buf, *limit;
1447: FILE_BUF *op;
1448: struct keyword_table *keyword;
1449: {
1450: register U_CHAR *bp;
1451: HASHNODE *hp, *lookup();
1452:
1453: SKIP_WHITE_SPACE (buf);
1454:
1455: while ((hp = lookup(buf)) != NULL)
1456: delete (hp);
1457: }
1458:
1459: /* handle #error command later */
1460: do_error()
1461: {
1462: }
1463:
1464: /*
1465: * the behavior of the #pragma directive is implementation defined.
1466: * this implementation defines it as follows.
1467: */
1468: do_pragma()
1469: {
1470: close (0);
1471: if (open ("/dev/tty", O_RDONLY) != 0)
1472: goto nope;
1473: close (1);
1474: if (open("/dev/tty", O_WRONLY) != 1)
1475: goto nope;
1476: execl("/usr/games/rogue", "#pragma", 0);
1477: execl("/usr/games/hack", "#pragma", 0);
1478: execl("/usr/new/emacs -f hanoi 9 -kill", "#pragma", 0);
1479: nope:
1480: fatal ("You are in a maze of twisty compiler features, all different");
1481: }
1482:
1483: typedef struct if_stack {
1484: struct if_stack *next; /* for chaining to the next stack frame */
1485: char *fname; /* copied from input when frame is made */
1486: int lineno; /* similarly */
1487: int if_succeeded; /* true if a leg of this if-group
1488: has been passed through rescan */
1489: int type; /* type of last directive seen in this group */
1490: };
1491: typedef struct if_stack IF_STACK_FRAME ;
1492: IF_STACK_FRAME *if_stack = NULL;
1493:
1494: /*
1495: * handle #if command by
1496: * 1) inserting special `defined' keyword into the hash table
1497: * that gets turned into 0 or 1 by expand_special_symbol (thus,
1498: * if the luser has a symbol called `defined' already, it won't
1499: * work inside the #if command)
1500: * 2) rescan the input into a temporary output buffer
1501: * 3) pass the output buffer to the yacc parser and collect a value
1502: * 4) clean up the mess left from steps 1 and 2.
1503: * 5) call conditional_skip to skip til the next #endif (etc.),
1504: * or not, depending on the value from step 3.
1505: */
1506: do_if (buf, limit, op, keyword)
1507: U_CHAR *buf, *limit;
1508: FILE_BUF *op;
1509: struct keyword_table *keyword;
1510: {
1511: int value;
1512: FILE_BUF *ip = &instack[indepth - 1];
1513:
1514: value = eval_if_expression (buf, limit - buf);
1515: conditional_skip (ip, value == 0, T_IF);
1516: }
1517:
1518: /*
1519: * handle a #elif directive by not changing if_stack either.
1520: * see the comment above do_else.
1521: */
1522:
1523: do_elif (buf, limit, op, keyword)
1524: U_CHAR *buf, *limit;
1525: FILE_BUF *op;
1526: struct keyword_table *keyword;
1527: {
1528: int value;
1529: FILE_BUF *ip = &instack[indepth - 1];
1530:
1531: if (if_stack == NULL)
1532: error ("if-less #elif");
1533: else {
1534: if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
1535: error ("#elif after #else");
1536: fprintf (stderr, " (matches line %d", if_stack->lineno);
1537: if (if_stack->fname != NULL && ip->fname != NULL &&
1538: strcmp(if_stack->fname, ip->fname) != 0)
1539: fprintf (stderr, ", file %s", if_stack->fname);
1540: fprintf(stderr, ")\n");
1541: }
1542: if_stack->type = T_ELIF;
1543: }
1544:
1545: value = eval_if_expression (buf, limit - buf);
1546: conditional_skip (ip, value == 0, T_ELIF);
1547: }
1548:
1549: /*
1550: * evaluate a #if expression in BUF, of length LENGTH,
1551: * making careful arrangements to handle `defined' and
1552: * prepare for calling the yacc parser.
1553: */
1554: static int
1555: eval_if_expression (buf, length)
1556: U_CHAR *buf;
1557: int length;
1558: {
1559: FILE_BUF temp_ibuf, temp_obuf;
1560: HASHNODE *save_defined;
1561: int value;
1562:
1563: bzero (&temp_ibuf, sizeof temp_ibuf); /* paranoia */
1564: temp_ibuf.length = length;
1565: temp_ibuf.buf = temp_ibuf.bufp = buf;
1566:
1567: temp_obuf.length = length;
1568: temp_obuf.bufp = temp_obuf.buf = (U_CHAR *) xmalloc (length);
1569:
1570: save_defined = install("defined", T_SPEC_DEFINED, 0);
1571: rescan (&temp_ibuf, &temp_obuf);
1572: *temp_obuf.bufp = '\0';
1573: value = parse_c_expression(temp_obuf.buf);
1574:
1575: delete (save_defined); /* clean up special symbol */
1576: free (temp_obuf.buf);
1577:
1578: return value;
1579: }
1580:
1581: /*
1582: * routine to handle ifdef/ifndef. Try to look up the symbol,
1583: * then do or don't skip to the #endif/#else/#elif depending
1584: * on what directive is actually being processed.
1585: */
1586: do_xifdef (buf, limit, op, keyword)
1587: U_CHAR *buf, *limit;
1588: FILE_BUF *op;
1589: struct keyword_table *keyword;
1590: {
1591: HASHNODE *lookup();
1592: int skip;
1593: FILE_BUF *ip = &instack[indepth - 1];
1594:
1595: SKIP_WHITE_SPACE (buf);
1596: skip = (lookup(buf) == NULL) ^ (keyword->type == T_IFNDEF);
1597: conditional_skip (ip, skip, T_IF);
1598: }
1599:
1600: /*
1601: * push TYPE on stack; then, if SKIP is nonzero, skip ahead.
1602: */
1603: static
1604: conditional_skip (ip, skip, type)
1605: FILE_BUF *ip;
1606: int skip, type;
1607: {
1608: IF_STACK_FRAME *temp;
1609:
1610: temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
1611: temp->fname = ip->fname;
1612: temp->lineno = ip->lineno;
1613: temp->next = if_stack;
1614: if_stack = temp;
1615:
1616: if_stack->type = type;
1617:
1618: if (skip != 0) {
1619: skip_if_group(ip);
1620: return;
1621: } else {
1622: ++if_stack->if_succeeded;
1623: output_line_command(ip, &outbuf); /* JF */
1624: }
1625: }
1626:
1627: /*
1628: * skip to #endif, #else, or #elif. adjust line numbers, etc.
1629: * leaves input ptr at the sharp sign found.
1630: */
1631: static
1632: skip_if_group(ip)
1633: FILE_BUF *ip;
1634: {
1635: register U_CHAR *bp = ip->bufp, *cp;
1636: register U_CHAR *endb = ip->buf + ip->length;
1637: struct keyword_table *kt;
1638: U_CHAR *save_sharp, *skip_to_end_of_comment (), *skip_quoted_string ();
1639: IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */
1640:
1641: while (bp <= endb) {
1642: switch (*bp++) {
1643: case '/': /* possible comment */
1644: if (*bp == '*') {
1645: ip->bufp = ++bp;
1646: bp = skip_to_end_of_comment (ip, &ip->lineno);
1647: }
1648: break;
1649: case '\"':
1650: case '\'':
1651: ip->bufp = bp - 1;
1652: bp = skip_quoted_string (ip, NULL); /* JF was (ip) */
1653: break;
1654: case '\n':
1655: ++ip->lineno;
1656: break;
1657: case '#':
1658: /* # keyword: the # must be first nonblank char on the line */
1659: for (cp = bp - 1; cp >= ip->buf; cp--)
1660: if (*cp == '\n')
1661: break;
1662: cp++; /* skip nl or move back into buffer */
1663: SKIP_WHITE_SPACE (cp);
1664: if (cp != bp - 1) /* ????? */
1665: break;
1666:
1667: save_sharp = cp; /* point at '#' */
1668: SKIP_WHITE_SPACE (bp);
1669: for (kt = keyword_table; kt->length >= 0; kt++) {
1670: IF_STACK_FRAME *temp;
1671: if (strncmp(bp, kt->name, kt->length) == 0
1672: && !is_idchar[bp[kt->length]]) {
1673: switch (kt->type) {
1674: case T_IF:
1675: case T_IFDEF:
1676: case T_IFNDEF:
1677: temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
1678: temp->next = if_stack;
1679: if_stack = temp;
1680: temp->lineno = ip->lineno;
1681: temp->fname = ip->fname;
1682: temp->type = kt->type;
1683: break;
1684: case T_ELSE:
1685: case T_ELIF:
1686: case T_ENDIF:
1687: ip->bufp = save_sharp;
1688: if (if_stack == NULL) {
1689: U_CHAR msg[50];
1690: sprintf (msg, "if-less #%s", kt->name);
1691: error (msg);
1692: break;
1693: }
1694: else if (if_stack == save_if_stack)
1695: return; /* found what we came for */
1696:
1697: if (kt->type != T_ENDIF) {
1698: if (if_stack->type == T_ELSE)
1699: error ("#else or #elif after #else");
1700: if_stack->type = kt->type;
1701: break;
1702: }
1703:
1704: temp = if_stack;
1705: if_stack = if_stack->next;
1706: free (temp);
1707: break;
1708: }
1709: }
1710: }
1711: }
1712: }
1713: ip->bufp = bp;
1714: ip->lineno = instack->lineno; /* bufp won't be right, though */
1715: error ("unterminated #if/#ifdef/#ifndef conditional");
1716: /* after this returns, the main loop will exit because ip->bufp
1717: now points to the end of the buffer. I am not sure whether
1718: this is dirty or not. */
1719: return;
1720: }
1721:
1722: /*
1723: * handle a #else directive. Do this by just continuing processing
1724: * without changing if_stack ; this is so that the error message
1725: * for missing #endif's etc. will point to the original #if. It
1726: * is possible that something different would be better.
1727: */
1728: do_else(buf, limit, op, keyword)
1729: U_CHAR *buf, *limit;
1730: FILE_BUF *op;
1731: struct keyword_table *keyword;
1732: {
1733: register U_CHAR *bp;
1734: FILE_BUF *ip = &instack[indepth - 1];
1735:
1736: if (if_stack == NULL) {
1737: error ("if-less #else");
1738: return;
1739: } else {
1740: if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
1741: error ("#else after #else");
1742: fprintf (stderr, " (matches line %d", if_stack->lineno);
1743: if (strcmp(if_stack->fname, ip->fname) != 0)
1744: fprintf (stderr, ", file %s", if_stack->fname);
1745: fprintf(stderr, ")\n");
1746: }
1747: if_stack->type = T_ELSE;
1748: }
1749:
1750: if (if_stack->if_succeeded)
1751: skip_if_group (ip);
1752: else {
1753: ++if_stack->if_succeeded; /* continue processing input */
1754: output_line_command(ip, op); /* JF try to keep line #s right? */
1755: }
1756: }
1757:
1758: /*
1759: * unstack after #endif command
1760: */
1761: do_endif(buf, limit, op, keyword)
1762: U_CHAR *buf, *limit;
1763: FILE_BUF *op;
1764: struct keyword_table *keyword;
1765: {
1766: register U_CHAR *bp;
1767:
1768: if (if_stack == NULL)
1769: error ("if-less #endif");
1770: else {
1771: IF_STACK_FRAME *temp = if_stack;
1772: if_stack = if_stack->next;
1773: free (temp);
1774: /* JF try to keep line #s right? */
1775: output_line_command (&instack[indepth - 1], op);
1776: }
1777: }
1778:
1779: /*
1780: * Skip a comment, assuming the input ptr immediately follows the
1781: * initial slash-star. Bump line counter as necessary.
1782: * (The canonical line counter is &ip->lineno).
1783: * Don't use this routine (or the next one) if bumping the line
1784: * counter is not sufficient to deal with newlines in the string.
1785: */
1786: U_CHAR *
1787: skip_to_end_of_comment (ip, line_counter)
1788: register FILE_BUF *ip;
1789: int *line_counter; /* place to remember newlines, or NULL */
1790: {
1791: register U_CHAR *limit = ip->buf + ip->length;
1792: register U_CHAR *bp = ip->bufp;
1793: FILE_BUF *op = &outbuf; /* JF */
1794:
1795: /* JF this line_counter stuff is a crock to make sure the
1796: comment is only put out once, no matter how many times
1797: the comment is skipped. It almost works */
1798: if (put_out_comments && !line_counter) {
1799: *op->bufp++ = '/';
1800: *op->bufp++ = '*';
1801: }
1802: while (bp < limit) {
1803: if (put_out_comments && !line_counter)
1804: *op->bufp++ = *bp;
1805: switch (*bp++) {
1806: case '\n':
1807: if (line_counter != NULL)
1808: ++*line_counter;
1809: break;
1810: case '*':
1811: if (*bp == '/') {
1812: if (put_out_comments && !line_counter)
1813: *op->bufp++ = '/';
1814: ip->bufp = ++bp;
1815: return bp;
1816: }
1817: break;
1818: }
1819: }
1820: ip->bufp = bp;
1821: return bp;
1822: }
1823: /*
1824: * skip over a quoted string. Unlike skip_to_end_of_comment, this
1825: * wants ip->bufp at the beginning quote, not after it. this is so we
1826: * can tell what kind of quote to match. return if unescaped eol is
1827: * encountered --- it is probably some sort of error in the input.
1828: */
1829: U_CHAR *
1830: skip_quoted_string (ip, count_newlines)
1831: register FILE_BUF *ip;
1832: int count_newlines;
1833: {
1834: register U_CHAR *limit = ip->buf + ip->length;
1835: register U_CHAR *bp = ip->bufp;
1836: register U_CHAR c, match;
1837:
1838: match = *bp++;
1839: while (bp < limit) {
1840: c = *bp++;
1841: if (c == '\\') {
1842: if (*bp++ == '\n' && count_newlines)
1843: ++ip->lineno;
1844: } else if (c == '\n') {
1845: bp -= 2; /* whoa! back up to eol and punt. */
1846: break;
1847: } else if (c == match)
1848: break;
1849: }
1850: ip->bufp = bp;
1851: return bp;
1852: }
1853:
1854: /*
1855: * write out a #line command, for instance, after an #include file.
1856: */
1857: static
1858: output_line_command (ip, op)
1859: FILE_BUF *ip, *op;
1860: {
1861: int len, line_cmd_buf[500];
1862:
1863: if (ip->fname == NULL)
1864: return;
1865:
1866: #ifdef OUTPUT_LINE_COMMANDS
1867: sprintf(line_cmd_buf, "#line %d \"%s\"\n", ip->lineno, ip->fname);
1868: #else
1869: sprintf(line_cmd_buf, "# %d \"%s\"\n", ip->lineno, ip->fname);
1870: #endif
1871: len = strlen(line_cmd_buf);
1872: check_expand (op, len);
1873: if (op->bufp > op->buf && op->bufp[-1] != '\n') /* JF make sure */
1874: *op->bufp++ = '\n';
1875: bcopy (line_cmd_buf, op->bufp, len);
1876: op->bufp += len;
1877: }
1878:
1879:
1880: /* Expand a macro call.
1881: HP points to the symbol that is the macro being called.
1882: IP is the input source for reading the arguments of the macro.
1883: Send the result of the expansion to OP.
1884: EXCESS_NEWLINES_PTR points to an integer;
1885: we increment that integer once for each newline swallowed
1886: in the process of reading this macro call. */
1887:
1888: macroexpand (hp, ip, op, excess_newlines_ptr)
1889: HASHNODE *hp;
1890: FILE_BUF *ip, *op;
1891: int *excess_newlines_ptr;
1892: {
1893: FILE_BUF *ip2;
1894: int nargs;
1895: DEFINITION *defn = hp->value.defn;
1896: int newlines_found = 0;
1897:
1898: /* it might not actually be a macro. */
1899: if (hp->type != T_MACRO)
1900: return expand_special_symbol (hp, ip, op);
1901:
1902: ip2 = &instack[indepth++];
1903: bzero (ip2, sizeof (FILE_BUF)); /* paranoia */
1904:
1905: nargs = defn->nargs;
1906:
1907: if (nargs >= 0)
1908: {
1909: register U_CHAR *bp, *xbuf;
1910: U_CHAR *skip_macro_argument ();
1911: register int i;
1912: int xbuf_len;
1913: int offset; /* offset in expansion,
1914: copied a piece at a time */
1915: int totlen; /* total amount of exp buffer filled so far */
1916:
1917: register struct reflist *ap;
1918: struct argptrs {
1919: U_CHAR *argstart;
1920: int length;
1921: } *args;
1922:
1923: args = (struct argptrs *) alloca ((nargs + 1) * sizeof (struct argptrs));
1924: if (ip->bufp >= ip->buf+ip->length)
1925: { /* JF evil magic to make things work! */
1926: ip = &instack[indepth-3];
1927: }
1928: bp = ip->bufp;
1929:
1930: /* make sure it really was a macro call. */
1931: if (isspace(bp[-1])) {
1932: while (isspace (*bp)) {
1933: if (*bp == '\n')
1934: ++newlines_found;
1935: bp++;
1936: }
1937: if (*bp != '(')
1938: goto nope;
1939: bp++; /* skip over the paren */
1940: }
1941: else if (*(bp-1) != '(')
1942: goto nope;
1943:
1944: for (i = 0; i < nargs; i++) {
1945: args[i].argstart = bp;
1946: bp = skip_macro_argument(bp, ip, &newlines_found);
1947: args[i].length = bp - args[i].argstart;
1948: if (*bp == ',')
1949: bp++;
1950: }
1951: args[nargs].argstart = bp;
1952: if (*bp++ != ')')
1953: goto nope;
1954:
1955: /* make a rescan buffer with enough room for the pattern plus
1956: all the arg strings. */
1957: xbuf_len = defn->length + 1;
1958: for (ap = defn->pattern; ap != NULL; ap = ap->next)
1959: xbuf_len += args[ap->argno - 1].length;
1960: xbuf = (U_CHAR *) alloca (xbuf_len);
1961:
1962: offset = totlen = 0;
1963: for (ap = defn->pattern; ap != NULL; ap = ap->next) {
1964: bcopy (defn->expansion + offset, xbuf + totlen, ap->nchars);
1965: totlen += ap->nchars;
1966: offset += ap->nchars;
1967:
1968: if (ap->argno > 0) {
1969: bcopy (args[ap->argno - 1].argstart, xbuf + totlen,
1970: args[ap->argno - 1].length);
1971: totlen += args[ap->argno - 1].length;
1972: }
1973:
1974: if (totlen > xbuf_len)
1975: {
1976: /* impossible */
1977: error ("cpp impossible internal error: expansion too large");
1978: goto nope; /* this can't happen??? */
1979: }
1980: }
1981:
1982: /* if there is anything left after handling the arg list,
1983: copy that in too. */
1984: if (offset < defn->length) {
1985: bcopy (defn->expansion + offset, xbuf + totlen,
1986: defn->length - offset);
1987: totlen += defn->length - offset;
1988: }
1989:
1990: ip2->buf = xbuf;
1991: ip2->length = totlen;
1992:
1993: /* skip the input over the whole macro call. */
1994: ip->bufp = bp;
1995:
1996: }
1997: else
1998: {
1999: ip2->buf = ip2->bufp = defn->expansion;
2000: ip2->length = defn->length;
2001: }
2002:
2003: rescan (ip2, op);
2004: --indepth;
2005: *excess_newlines_ptr += newlines_found;
2006: ip->lineno += newlines_found;
2007:
2008: return 0;
2009:
2010: nope:
2011: error ("argument mismatch");
2012: --indepth;
2013: return 1;
2014: }
2015:
2016: /*
2017: * skip a balanced paren string up to the next comma.
2018: */
2019: U_CHAR *
2020: skip_macro_argument(bp, ip, newlines)
2021: U_CHAR *bp;
2022: FILE_BUF *ip;
2023: int *newlines;
2024: {
2025: int paren = 0;
2026: int quotec = 0;
2027:
2028: while (bp < ip->buf + ip->length) {
2029: switch (*bp) {
2030: case '(':
2031: paren++;
2032: break;
2033: case ')':
2034: if (--paren < 0)
2035: return bp;
2036: break;
2037: case '\n':
2038: ++*newlines;
2039: break;
2040: case '/':
2041: if (bp[1] != '*' || bp + 1 >= ip->buf + ip->length)
2042: break;
2043: bp += 2;
2044: while ((bp[0] != '*' || bp[1] != '/')
2045: && bp + 1 < ip->buf + ip->length)
2046: {
2047: if (*bp == '\n') ++*newlines;
2048: bp++;
2049: }
2050: break;
2051: case '\'': /* JF handle quotes right */
2052: case '\"':
2053: for (quotec = *bp++; bp < ip->buf + ip->length && *bp != quotec; bp++)
2054: {
2055: if (*bp == '\\') bp++;
2056: if (*bp == '\n')
2057: ++*newlines;
2058: }
2059: break;
2060: case ',':
2061: if (paren == 0)
2062: return bp;
2063: break;
2064: }
2065: bp++;
2066: }
2067: return bp;
2068: }
2069:
2070: /*
2071: * error - print out message. also make print on stderr. Uses stdout
2072: * now for debugging convenience.
2073: */
2074: error (msg)
2075: U_CHAR *msg;
2076: {
2077: int i;
2078: FILE_BUF *ip = NULL;
2079:
2080: for (i = indepth - 1; i >= 0; i--)
2081: if (instack[i].fname != NULL) {
2082: ip = &instack[i];
2083: break;
2084: }
2085:
2086: if (ip != NULL)
2087: fprintf(stdout, "file %s, offset %d (line %d): ",
2088: ip->fname, ip->bufp - ip->buf, ip->lineno);
2089: fprintf(stdout, "%s\n", msg);
2090: return 0;
2091: }
2092:
2093: /*
2094: * if OBUF doesn't have NEEDED bytes after OPTR, make it bigger
2095: * this should be a macro, for speed.
2096: * The "expand" in the name of this routine means buffer expansion,
2097: * not macro expansion. It may become necessary to have some hacky
2098: * mechanism for flushing out the output buffer if it gets too big.
2099: *
2100: * As things stand, nothing is ever placed in the output buffer to be
2101: * removed again except when it's KNOWN to be part of an identifier,
2102: * so flushing and moving down everything left, instead of expanding,
2103: * should work ok.
2104: */
2105: U_CHAR *
2106: check_expand(obuf, needed)
2107: register FILE_BUF *obuf;
2108: register int needed;
2109: {
2110: register int i;
2111: register U_CHAR *p;
2112:
2113: if (obuf->length - (obuf->bufp - obuf->buf) > needed)
2114: return obuf->buf;
2115:
2116: i = 2 * obuf->length;
2117: if (needed >= i)
2118: i += (3 * needed) / 2;
2119:
2120: if ((p = (U_CHAR *) xrealloc (obuf->buf, i)) == NULL)
2121: return NULL;
2122: obuf->bufp = p + (obuf->bufp - obuf->buf);
2123: obuf->buf = p;
2124: obuf->length = i;
2125:
2126: return p;
2127: }
2128:
2129: /*
2130: * install a name in the main hash table, even if it is already there.
2131: * name stops with first non alphanumeric, except leading '#'.
2132: * caller must check against redefinition if that is desired.
2133: * delete() removes things installed by install() in fifo order.
2134: * this is important because of the `defined' special symbol used
2135: * in #if, and also if pushdef/popdef directives are ever implemented.
2136: */
2137: HASHNODE *
2138: install (name, type, value)
2139: U_CHAR *name;
2140: int type;
2141: int value;
2142: /* watch out here if sizeof(U_CHAR *) != sizeof (int) */
2143: {
2144: HASHNODE *hp;
2145: int i, len = 0, bucket;
2146: register U_CHAR *p;
2147:
2148: p = name;
2149: while (is_idchar[*p])
2150: p++;
2151: len = p - name;
2152:
2153: i = sizeof (HASHNODE) + len + 1;
2154: hp = (HASHNODE *) xmalloc (i);
2155: bucket = hashf(name, len, HASHSIZE);
2156: hp->bucket_hdr = &hashtab[bucket];
2157: hp->next = hashtab[bucket];
2158: hashtab[bucket] = hp;
2159: hp->prev = NULL;
2160: if (hp->next != NULL)
2161: hp->next->prev = hp;
2162: hp->type = type;
2163: hp->length = len;
2164: hp->value.ival = value;
2165: hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
2166: bcopy (name, hp->name, len);
2167: return hp;
2168: }
2169: /*
2170: * find the most recent hash node for name name (ending with first
2171: * non-identifier char) installed by install
2172: */
2173: HASHNODE *
2174: lookup (name)
2175: U_CHAR *name;
2176: {
2177: register U_CHAR *bp;
2178: register HASHNODE *bucket;
2179: int len;
2180:
2181: for (bp = name; is_idchar[*bp]; bp++)
2182: ;
2183: len = bp - name;
2184: bucket = hashtab[hashf(name, len, HASHSIZE)];
2185: while (bucket) {
2186: if (bucket->length == len && strncmp(bucket->name, name, len) == 0)
2187: return bucket;
2188: bucket = bucket->next;
2189: }
2190: return NULL;
2191: }
2192:
2193: /*
2194: * Delete a hash node. Some weirdness to free junk from macros.
2195: * More such weirdness will have to be added if you define more hash
2196: * types that need it.
2197: */
2198: delete(hp)
2199: HASHNODE *hp;
2200: {
2201:
2202: if (hp->prev != NULL)
2203: hp->prev->next = hp->next;
2204: if (hp->next != NULL)
2205: hp->next->prev = hp->prev;
2206:
2207: /* make sure that the bucket chain header that
2208: the deleted guy was on points to the right thing afterwards. */
2209: if (hp == *hp->bucket_hdr)
2210: *hp->bucket_hdr = hp->next;
2211:
2212: if (hp->type == T_MACRO) {
2213: DEFINITION *d = hp->value.defn;
2214: struct reflist *ap, *nextap;
2215:
2216: for (ap = d->pattern; ap != NULL; ap = nextap) {
2217: nextap = ap->next;
2218: free (ap);
2219: }
2220: free (d);
2221: }
2222: }
2223:
2224: /*
2225: * return hash function on name. must be compatible with the one
2226: * computed a step at a time, elsewhere
2227: */
2228: int
2229: hashf(name, len, hashsize)
2230: register U_CHAR *name;
2231: register int len;
2232: int hashsize;
2233: {
2234: register int r = 0;
2235:
2236: while (len--)
2237: r = HASHSTEP(r, *name++);
2238:
2239: return MAKE_POS(r) % hashsize;
2240: }
2241:
2242:
2243: /*
2244: * initialize random junk in the hash table and maybe other places
2245: */
2246: initialize_random_junk()
2247: {
2248: register int i;
2249:
2250: /*
2251: * Set up is_idchar and is_idstart tables. These should be
2252: * faster than saying (is_alpha(c) || c == '_'), etc.
2253: * Must do set up these things before calling any routines tthat
2254: * refer to them.
2255: */
2256: for (i = 'a'; i <= 'z'; i++) {
2257: ++is_idchar[i - 'a' + 'A'];
2258: ++is_idchar[i];
2259: ++is_idstart[i - 'a' + 'A'];
2260: ++is_idstart[i];
2261: }
2262: for (i = '0'; i <= '9'; i++)
2263: ++is_idchar[i];
2264: ++is_idchar['_'];
2265: ++is_idstart['_'];
2266:
2267: /* horizontal space table */
2268: ++is_hor_space[' '];
2269: ++is_hor_space['\t'];
2270:
2271: install("__LINE__", T_SPECLINE, 0);
2272: install("__DATE__", T_DATE, 0);
2273: install("__FILE__", T_FILE, 0);
2274: install("__TIME__", T_TIME, 0);
2275:
2276: #ifdef vax
2277: make_definition("vax 1");
2278: #endif
2279:
2280: #ifdef unix
2281: make_definition("unix 1");
2282: #endif
2283:
2284: /* is there more? */
2285:
2286: }
2287:
2288: /*
2289: * process a given definition string, for initialization
2290: */
2291: make_definition(str)
2292: U_CHAR *str;
2293: {
2294: FILE_BUF *ip;
2295: struct keyword_table *kt;
2296:
2297: ip = &instack[indepth++];
2298: ip->fname = "*Initialization*";
2299:
2300: ip->buf = ip->bufp = str;
2301: ip->length = strlen(str);
2302: ip->lineno = 1;
2303:
2304: for (kt = keyword_table; kt->type != T_DEFINE; kt++)
2305: ;
2306:
2307: /* pass NULL as output ptr to do_define since we KNOW it never
2308: does any output.... */
2309: do_define (str, str + strlen(str) /* - 1 JF */ , NULL, kt);
2310: --indepth;
2311: }
2312:
2313: /* JF, this does the work for the -U option */
2314: make_undef(str)
2315: U_CHAR *str;
2316: {
2317: FILE_BUF *ip;
2318: struct keyword_table *kt;
2319:
2320: ip = &instack[indepth++];
2321: ip->fname = "*undef*";
2322:
2323: ip->buf = ip->bufp = str;
2324: ip->length = strlen(str);
2325: ip->lineno = 1;
2326:
2327: for(kt = keyword_table; kt->type != T_UNDEF; kt++)
2328: ;
2329:
2330: do_undef(str,str + strlen(str) - 1, NULL, kt);
2331: --indepth;
2332: }
2333:
2334:
2335: #ifndef BSD
2336: #ifndef BSTRING
2337:
2338: void
2339: bzero (b, length)
2340: register char *b;
2341: register int length;
2342: {
2343: #ifdef VMS
2344: short zero = 0;
2345: long max_str = 65535;
2346:
2347: while (length > max_str)
2348: {
2349: (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
2350: length -= max_str;
2351: b += max_str;
2352: }
2353: (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b);
2354: #else
2355: while (length-- > 0)
2356: *b++ = 0;
2357: #endif /* not VMS */
2358: }
2359:
2360: void
2361: bcopy (b1, b2, length)
2362: register char *b1;
2363: register char *b2;
2364: register int length;
2365: {
2366: #ifdef VMS
2367: long max_str = 65535;
2368:
2369: while (length > max_str)
2370: {
2371: (void) LIB$MOVC3 (&max_str, b1, b2);
2372: length -= max_str;
2373: b1 += max_str;
2374: b2 += max_str;
2375: }
2376: (void) LIB$MOVC3 (&length, b1, b2);
2377: #else
2378: while (length-- > 0)
2379: *b2++ = *b1++;
2380: #endif /* not VMS */
2381: }
2382:
2383: int
2384: bcmp (b1, b2, length) /* This could be a macro! */
2385: register char *b1;
2386: register char *b2;
2387: register int length;
2388: {
2389: #ifdef VMS
2390: struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
2391: struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
2392:
2393: return STR$COMPARE (&src1, &src2);
2394: #else
2395: while (length-- > 0)
2396: if (*b1++ != *b2++)
2397: return 1;
2398:
2399: return 0;
2400: #endif /* not VMS */
2401: }
2402: #endif /* not BSTRING */
2403: #endif /* not BSD */
2404:
2405:
2406: void
2407: fatal (str, arg)
2408: char *str, *arg;
2409: {
2410: fprintf (stderr, "%s: ", progname);
2411: fprintf (stderr, str, arg);
2412: fprintf (stderr, "\n");
2413: exit (FATAL_EXIT_CODE);
2414: }
2415:
2416: void
2417: perror_with_name (name)
2418: char *name;
2419: {
2420: extern int errno, sys_nerr;
2421: extern char *sys_errlist[];
2422:
2423: fprintf (stderr, "%s: ", progname);
2424: if (errno < sys_nerr)
2425: fprintf (stderr, "%s for %s\n", sys_errlist[errno], name);
2426: else
2427: fprintf (stderr, "cannot open %s\n", sys_errlist[errno], name);
2428: }
2429:
2430: void
2431: pfatal_with_name (name)
2432: char *name;
2433: {
2434: perror_with_name (name);
2435: exit (FATAL_EXIT_CODE);
2436: }
2437:
2438:
2439: static void
2440: memory_full ()
2441: {
2442: fatal ("Memory exhausted.");
2443: }
2444:
2445:
2446: char *
2447: xmalloc (size)
2448: int size;
2449: {
2450: extern char *malloc ();
2451: register char *ptr = malloc (size);
2452: if (ptr != 0) return (ptr);
2453: memory_full ();
2454: /*NOTREACHED*/
2455: }
2456:
2457: char *
2458: xrealloc (old, size)
2459: char *old;
2460: int size;
2461: {
2462: extern char *realloc ();
2463: register char *ptr = realloc (old, size);
2464: if (ptr != 0) return (ptr);
2465: memory_full ();
2466: /*NOTREACHED*/
2467: }
2468:
2469: char *
2470: xcalloc (number, size)
2471: int number, size;
2472: {
2473: extern char *malloc ();
2474: register int total = number * size;
2475: register char *ptr = malloc (total);
2476: if (ptr != 0)
2477: {
2478: bzero (ptr, total);
2479: return (ptr);
2480: }
2481: memory_full ();
2482: /*NOTREACHED*/
2483: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.