|
|
1.1 root 1: /*
2: * Copyright (c) 1985 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Dave Yost.
7: *
8: * Redistribution and use in source and binary forms are permitted
9: * provided that: (1) source distributions retain this entire copyright
10: * notice and comment, and (2) distributions including binaries display
11: * the following acknowledgement: ``This product includes software
12: * developed by the University of California, Berkeley and its contributors''
13: * in the documentation or other materials provided with the distribution
14: * and in all advertising materials mentioning features or use of this
15: * software. Neither the name of the University nor the names of its
16: * contributors may be used to endorse or promote products derived
17: * from this software without specific prior written permission.
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21: */
22:
23: #ifndef lint
24: char copyright[] =
25: "@(#) Copyright (c) 1985 The Regents of the University of California.\n\
26: All rights reserved.\n";
27: #endif /* not lint */
28:
29: #ifndef lint
30: static char sccsid[] = "@(#)unifdef.c 4.7 (Berkeley) 6/1/90";
31: #endif /* not lint */
32:
33: /*
34: * unifdef - remove ifdef'ed lines
35: *
36: * Warning: will not work correctly if input contains null characters.
37: *
38: * Wishlist:
39: * provide an option which will append the name of the
40: * appropriate symbol after #else's and #endif's
41: * provide an option which will check symbols after
42: * #else's and #endif's to see that they match their
43: * corresponding #ifdef or #ifndef
44: */
45:
46: #include <stdio.h>
47: #include <ctype.h>
48:
49: #define BSS
50: FILE *input;
51: #ifndef YES
52: #define YES 1
53: #define NO 0
54: #endif/*YES */
55: typedef int Bool;
56:
57: char *progname BSS;
58: char *filename BSS;
59: char text BSS; /* -t option in effect: this is a text file */
60: char lnblank BSS; /* -l option in effect: blank deleted lines */
61: char complement BSS; /* -c option in effect: complement the operation */
62:
63: #define MAXSYMS 100
64: char *symname[MAXSYMS] BSS; /* symbol name */
65: char true[MAXSYMS] BSS; /* -Dsym */
66: char ignore[MAXSYMS] BSS; /* -iDsym or -iUsym */
67: char insym[MAXSYMS] BSS; /* state: false, inactive, true */
68: #define SYM_INACTIVE 0 /* symbol is currently inactive */
69: #define SYM_FALSE 1 /* symbol is currently false */
70: #define SYM_TRUE 2 /* symbol is currently true */
71:
72: char nsyms BSS;
73: char incomment BSS; /* inside C comment */
74:
75: #define QUOTE_NONE 0
76: #define QUOTE_SINGLE 1
77: #define QUOTE_DOUBLE 2
78: char inquote BSS; /* inside single or double quotes */
79:
80: int exitstat BSS;
81: char *skipcomment ();
82: char *skipquote ();
83:
84: main (argc, argv)
85: int argc;
86: char **argv;
87: {
88: char **curarg;
89: register char *cp;
90: register char *cp1;
91: char ignorethis;
92:
93: progname = argv[0][0] ? argv[0] : "unifdef";
94:
95: for (curarg = &argv[1]; --argc > 0; curarg++) {
96: if (*(cp1 = cp = *curarg) != '-')
97: break;
98: if (*++cp1 == 'i') {
99: ignorethis = YES;
100: cp1++;
101: } else
102: ignorethis = NO;
103: if ( ( *cp1 == 'D'
104: || *cp1 == 'U'
105: )
106: && cp1[1] != '\0'
107: ) {
108: register int symind;
109:
110: if ((symind = findsym (&cp1[1])) < 0) {
111: if (nsyms >= MAXSYMS) {
112: prname ();
113: fprintf (stderr, "too many symbols.\n");
114: exit (2);
115: }
116: symind = nsyms++;
117: symname[symind] = &cp1[1];
118: insym[symind] = SYM_INACTIVE;
119: }
120: ignore[symind] = ignorethis;
121: true[symind] = *cp1 == 'D' ? YES : NO;
122: } else if (ignorethis)
123: goto unrec;
124: else if (strcmp (&cp[1], "t") == 0)
125: text = YES;
126: else if (strcmp (&cp[1], "l") == 0)
127: lnblank = YES;
128: else if (strcmp (&cp[1], "c") == 0)
129: complement = YES;
130: else {
131: unrec:
132: prname ();
133: fprintf (stderr, "unrecognized option: %s\n", cp);
134: goto usage;
135: }
136: }
137: if (nsyms == 0) {
138: usage:
139: fprintf (stderr, "\
140: Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]]... [file]\n\
141: At least one arg from [-D -U -iD -iU] is required\n", progname);
142: exit (2);
143: }
144:
145: if (argc > 1) {
146: prname ();
147: fprintf (stderr, "can only do one file.\n");
148: } else if (argc == 1) {
149: filename = *curarg;
150: if ((input = fopen (filename, "r")) != NULL) {
151: pfile();
152: (void) fclose (input);
153: } else {
154: prname ();
155: fprintf (stderr, "can't open ");
156: perror(*curarg);
157: }
158: } else {
159: filename = "[stdin]";
160: input = stdin;
161: pfile();
162: }
163:
164: (void) fflush (stdout);
165: exit (exitstat);
166: }
167:
168: /* types of input lines: */
169: typedef int Linetype;
170: #define LT_PLAIN 0 /* ordinary line */
171: #define LT_TRUE 1 /* a true #ifdef of a symbol known to us */
172: #define LT_FALSE 2 /* a false #ifdef of a symbol known to us */
173: #define LT_OTHER 3 /* an #ifdef of a symbol not known to us */
174: #define LT_IF 4 /* an #ifdef of a symbol not known to us */
175: #define LT_ELSE 5 /* #else */
176: #define LT_ENDIF 6 /* #endif */
177: #define LT_LEOF 7 /* end of file */
178: extern Linetype checkline ();
179:
180: typedef int Reject_level;
181: Reject_level reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */
182: #define REJ_NO 0
183: #define REJ_IGNORE 1
184: #define REJ_YES 2
185:
186: int linenum BSS; /* current line number */
187: int stqcline BSS; /* start of current coment or quote */
188: char *errs[] = {
189: #define NO_ERR 0
190: "",
191: #define END_ERR 1
192: "",
193: #define ELSE_ERR 2
194: "Inappropriate else",
195: #define ENDIF_ERR 3
196: "Inappropriate endif",
197: #define IEOF_ERR 4
198: "Premature EOF in ifdef",
199: #define CEOF_ERR 5
200: "Premature EOF in comment",
201: #define Q1EOF_ERR 6
202: "Premature EOF in quoted character",
203: #define Q2EOF_ERR 7
204: "Premature EOF in quoted string"
205: };
206:
207: /* States for inif arg to doif */
208: #define IN_NONE 0
209: #define IN_IF 1
210: #define IN_ELSE 2
211:
212: pfile ()
213: {
214: reject = REJ_NO;
215: (void) doif (-1, IN_NONE, reject, 0);
216: return;
217: }
218:
219: int
220: doif (thissym, inif, prevreject, depth)
221: register int thissym; /* index of the symbol who was last ifdef'ed */
222: int inif; /* YES or NO we are inside an ifdef */
223: Reject_level prevreject;/* previous value of reject */
224: int depth; /* depth of ifdef's */
225: {
226: register Linetype lineval;
227: register Reject_level thisreject;
228: int doret; /* tmp return value of doif */
229: int cursym; /* index of the symbol returned by checkline */
230: int stline; /* line number when called this time */
231:
232: stline = linenum;
233: for (;;) {
234: switch (lineval = checkline (&cursym)) {
235: case LT_PLAIN:
236: flushline (YES);
237: break;
238:
239: case LT_TRUE:
240: case LT_FALSE:
241: thisreject = reject;
242: if (lineval == LT_TRUE)
243: insym[cursym] = SYM_TRUE;
244: else {
245: if (reject != REJ_YES)
246: reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
247: insym[cursym] = SYM_FALSE;
248: }
249: if (ignore[cursym])
250: flushline (YES);
251: else {
252: exitstat = 1;
253: flushline (NO);
254: }
255: if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
256: return error (doret, stline, depth);
257: break;
258:
259: case LT_IF:
260: case LT_OTHER:
261: flushline (YES);
262: if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
263: return error (doret, stline, depth);
264: break;
265:
266: case LT_ELSE:
267: if (inif != IN_IF)
268: return error (ELSE_ERR, linenum, depth);
269: inif = IN_ELSE;
270: if (thissym >= 0) {
271: if (insym[thissym] == SYM_TRUE) {
272: reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
273: insym[thissym] = SYM_FALSE;
274: } else { /* (insym[thissym] == SYM_FALSE) */
275: reject = prevreject;
276: insym[thissym] = SYM_TRUE;
277: }
278: if (!ignore[thissym]) {
279: flushline (NO);
280: break;
281: }
282: }
283: flushline (YES);
284: break;
285:
286: case LT_ENDIF:
287: if (inif == IN_NONE)
288: return error (ENDIF_ERR, linenum, depth);
289: if (thissym >= 0) {
290: insym[thissym] = SYM_INACTIVE;
291: reject = prevreject;
292: if (!ignore[thissym]) {
293: flushline (NO);
294: return NO_ERR;
295: }
296: }
297: flushline (YES);
298: return NO_ERR;
299:
300: case LT_LEOF: {
301: int err;
302: err = incomment
303: ? CEOF_ERR
304: : inquote == QUOTE_SINGLE
305: ? Q1EOF_ERR
306: : inquote == QUOTE_DOUBLE
307: ? Q2EOF_ERR
308: : NO_ERR;
309: if (inif != IN_NONE) {
310: if (err != NO_ERR)
311: (void) error (err, stqcline, depth);
312: return error (IEOF_ERR, stline, depth);
313: } else if (err != NO_ERR)
314: return error (err, stqcline, depth);
315: else
316: return NO_ERR;
317: }
318: }
319: }
320: }
321:
322: #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
323:
324: #define MAXLINE 256
325: char tline[MAXLINE] BSS;
326:
327: Linetype
328: checkline (cursym)
329: int *cursym; /* if LT_TRUE or LT_FALSE returned, set this to sym index */
330: {
331: register char *cp;
332: register char *symp;
333: char *scp;
334: Linetype retval;
335: # define KWSIZE 8
336: char keyword[KWSIZE];
337:
338: linenum++;
339: if (getlin (tline, sizeof tline, input, NO) == EOF)
340: return LT_LEOF;
341:
342: retval = LT_PLAIN;
343: if ( *(cp = tline) != '#'
344: || incomment
345: || inquote == QUOTE_SINGLE
346: || inquote == QUOTE_DOUBLE
347: )
348: goto eol;
349:
350: cp = skipcomment (++cp);
351: symp = keyword;
352: while (!endsym (*cp)) {
353: *symp = *cp++;
354: if (++symp >= &keyword[KWSIZE])
355: goto eol;
356: }
357: *symp = '\0';
358:
359: if (strcmp (keyword, "ifdef") == 0) {
360: retval = YES;
361: goto ifdef;
362: } else if (strcmp (keyword, "ifndef") == 0) {
363: retval = NO;
364: ifdef:
365: scp = cp = skipcomment (++cp);
366: if (incomment) {
367: retval = LT_PLAIN;
368: goto eol;
369: }
370: {
371: int symind;
372:
373: if ((symind = findsym (scp)) >= 0)
374: retval = (retval ^ true[*cursym = symind])
375: ? LT_FALSE : LT_TRUE;
376: else
377: retval = LT_OTHER;
378: }
379: } else if (strcmp (keyword, "if") == 0)
380: retval = LT_IF;
381: else if (strcmp (keyword, "else") == 0)
382: retval = LT_ELSE;
383: else if (strcmp (keyword, "endif") == 0)
384: retval = LT_ENDIF;
385:
386: eol:
387: if (!text && reject != REJ_IGNORE)
388: for (; *cp; ) {
389: if (incomment)
390: cp = skipcomment (cp);
391: else if (inquote == QUOTE_SINGLE)
392: cp = skipquote (cp, QUOTE_SINGLE);
393: else if (inquote == QUOTE_DOUBLE)
394: cp = skipquote (cp, QUOTE_DOUBLE);
395: else if (*cp == '/' && cp[1] == '*')
396: cp = skipcomment (cp);
397: else if (*cp == '\'')
398: cp = skipquote (cp, QUOTE_SINGLE);
399: else if (*cp == '"')
400: cp = skipquote (cp, QUOTE_DOUBLE);
401: else
402: cp++;
403: }
404: return retval;
405: }
406:
407: /*
408: * Skip over comments and stop at the next charaacter
409: * position that is not whitespace.
410: */
411: char *
412: skipcomment (cp)
413: register char *cp;
414: {
415: if (incomment)
416: goto inside;
417: for (;; cp++) {
418: while (*cp == ' ' || *cp == '\t')
419: cp++;
420: if (text)
421: return cp;
422: if ( cp[0] != '/'
423: || cp[1] != '*'
424: )
425: return cp;
426: cp += 2;
427: if (!incomment) {
428: incomment = YES;
429: stqcline = linenum;
430: }
431: inside:
432: for (;;) {
433: for (; *cp != '*'; cp++)
434: if (*cp == '\0')
435: return cp;
436: if (*++cp == '/') {
437: incomment = NO;
438: break;
439: }
440: }
441: }
442: }
443:
444: /*
445: * Skip over a quoted string or character and stop at the next charaacter
446: * position that is not whitespace.
447: */
448: char *
449: skipquote (cp, type)
450: register char *cp;
451: register int type;
452: {
453: register char qchar;
454:
455: qchar = type == QUOTE_SINGLE ? '\'' : '"';
456:
457: if (inquote == type)
458: goto inside;
459: for (;; cp++) {
460: if (*cp != qchar)
461: return cp;
462: cp++;
463: inquote = type;
464: stqcline = linenum;
465: inside:
466: for (; ; cp++) {
467: if (*cp == qchar)
468: break;
469: if ( *cp == '\0'
470: || *cp == '\\' && *++cp == '\0'
471: )
472: return cp;
473: }
474: inquote = QUOTE_NONE;
475: }
476: }
477:
478: /*
479: * findsym - look for the symbol in the symbol table.
480: * if found, return symbol table index,
481: * else return -1.
482: */
483: int
484: findsym (str)
485: char *str;
486: {
487: register char *cp;
488: register char *symp;
489: register int symind;
490: register char chr;
491:
492: for (symind = 0; symind < nsyms; ++symind) {
493: if (insym[symind] == SYM_INACTIVE) {
494: for ( symp = symname[symind], cp = str
495: ; *symp && *cp == *symp
496: ; cp++, symp++
497: )
498: continue;
499: chr = *cp;
500: if (*symp == '\0' && endsym (chr))
501: return symind;
502: }
503: }
504: return -1;
505: }
506:
507: /*
508: * getlin - expands tabs if asked for
509: * and (if compiled in) treats form-feed as an end-of-line
510: */
511: int
512: getlin (line, maxline, inp, expandtabs)
513: register char *line;
514: int maxline;
515: FILE *inp;
516: int expandtabs;
517: {
518: int tmp;
519: register int num;
520: register int chr;
521: #ifdef FFSPECIAL
522: static char havechar = NO; /* have leftover char from last time */
523: static char svchar BSS;
524: #endif/*FFSPECIAL */
525:
526: num = 0;
527: #ifdef FFSPECIAL
528: if (havechar) {
529: havechar = NO;
530: chr = svchar;
531: goto ent;
532: }
533: #endif/*FFSPECIAL */
534: while (num + 8 < maxline) { /* leave room for tab */
535: chr = getc (inp);
536: if (isprint (chr)) {
537: #ifdef FFSPECIAL
538: ent:
539: #endif/*FFSPECIAL */
540: *line++ = chr;
541: num++;
542: } else
543: switch (chr) {
544: case EOF:
545: return EOF;
546:
547: case '\t':
548: if (expandtabs) {
549: num += tmp = 8 - (num & 7);
550: do
551: *line++ = ' ';
552: while (--tmp);
553: break;
554: }
555: default:
556: *line++ = chr;
557: num++;
558: break;
559:
560: case '\n':
561: *line = '\n';
562: num++;
563: goto end;
564:
565: #ifdef FFSPECIAL
566: case '\f':
567: if (++num == 1)
568: *line = '\f';
569: else {
570: *line = '\n';
571: havechar = YES;
572: svchar = chr;
573: }
574: goto end;
575: #endif/*FFSPECIAL */
576: }
577: }
578: end:
579: *++line = '\0';
580: return num;
581: }
582:
583: flushline (keep)
584: Bool keep;
585: {
586: if ((keep && reject != REJ_YES) ^ complement) {
587: register char *line = tline;
588: register FILE *out = stdout;
589: register char chr;
590:
591: while (chr = *line++)
592: putc (chr, out);
593: } else if (lnblank)
594: putc ('\n', stdout);
595: return;
596: }
597:
598: prname ()
599: {
600: fprintf (stderr, "%s: ", progname);
601: return;
602: }
603:
604: int
605: error (err, line, depth)
606: int err; /* type of error & index into error string array */
607: int line; /* line number */
608: int depth; /* how many ifdefs we are inside */
609: {
610: if (err == END_ERR)
611: return err;
612:
613: prname ();
614:
615: #ifndef TESTING
616: fprintf (stderr, "Error in %s line %d: %s.\n", filename, line, errs[err]);
617: #else/* TESTING */
618: fprintf (stderr, "Error in %s line %d: %s. ", filename, line, errs[err]);
619: fprintf (stderr, "ifdef depth: %d\n", depth);
620: #endif/*TESTING */
621:
622: exitstat = 2;
623: return depth > 1 ? IEOF_ERR : END_ERR;
624: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.