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