1: #ifndef lint
2: static char sccsid[] = "@(#)unifdef.c 4.4 (Berkeley) 8/11/83";
3: #endif
4:
5: /*
6: * unifdef - remove ifdef'ed lines
7: */
8:
9: #include <stdio.h>
10: #include <ctype.h>
11: #define BSS
12: FILE *input;
13: #ifndef YES
14: #define YES 1
15: #define NO 0
16: #endif
17:
18: char *progname BSS;
19: char *filename BSS;
20: char text BSS; /* -t option in effect: this is a text file */
21: char lnblank BSS; /* -l option in effect: blank deleted lines */
22: char complement BSS; /* -c option in effect: complement the operation */
23: #define MAXSYMS 100
24: char true[MAXSYMS] BSS;
25: char ignore[MAXSYMS] BSS;
26: char *sym[MAXSYMS] BSS;
27: char insym[MAXSYMS] BSS;
28: char nsyms BSS;
29: char BSS;
30: #define QUOTE1 0
31: #define QUOTE2 1
32: char inquote[2] BSS;
33: int exitstat BSS;
34: char *skipcomment ();
35: char *skipquote ();
36:
37: main (argc, argv)
38: int argc;
39: char **argv;
40: {
41: char **curarg;
42: register char *cp;
43: register char *cp1;
44: char ignorethis;
45:
46: progname = argv[0][0] ? argv[0] : "unifdef";
47:
48: for (curarg = &argv[1]; --argc > 0; curarg++) {
49: if (*(cp1 = cp = *curarg) != '-')
50: break;
51: if (*++cp1 == 'i') {
52: ignorethis = YES;
53: cp1++;
54: }
55: else
56: ignorethis = NO;
57: if ( ( *cp1 == 'D'
58: || *cp1 == 'U'
59: )
60: && cp1[1] != '\0'
61: ) {
62: if (nsyms >= MAXSYMS) {
63: prname ();
64: fprintf (stderr, "too many symbols.\n");
65: exit (2);
66: }
67: ignore[nsyms] = ignorethis;
68: true[nsyms] = *cp1 == 'D' ? YES : NO;
69: sym[nsyms++] = &cp1[1];
70: }
71: else if (ignorethis)
72: goto unrec;
73: else if (strcmp (&cp[1], "t") == 0)
74: text = YES;
75: else if (strcmp (&cp[1], "l") == 0)
76: lnblank = YES;
77: else if (strcmp (&cp[1], "c") == 0)
78: complement = YES;
79: else {
80: unrec:
81: prname ();
82: fprintf (stderr, "unrecognized option: %s\n", cp);
83: goto usage;
84: }
85: }
86: if (nsyms == 0) {
87: usage:
88: fprintf (stderr, "\
89: Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-idsym] [-iusym]]... [file]\n\
90: At least one arg from [-D -U -id -iu] is required\n", progname);
91: exit (2);
92: }
93:
94: if (argc > 1) {
95: prname ();
96: fprintf (stderr, "can only do one file.\n");
97: }
98: else if (argc == 1) {
99: filename = *curarg;
100: if ((input = fopen (filename, "r")) != NULL) {
101: pfile();
102: fclose (input);
103: }
104: else {
105: prname ();
106: perror(*curarg);
107: }
108: }
109: else {
110: filename = "[stdin]";
111: input = stdin;
112: pfile();
113: }
114:
115: fflush (stdout);
116: exit (exitstat);
117: }
118:
119: /* types of input lines: */
120: #define PLAIN 0 /* ordinary line */
121: #define TRUE 1 /* a true #ifdef of a symbol known to us */
122: #define FALSE 2 /* a false #ifdef of a symbol known to us */
123: #define OTHER 3 /* an #ifdef of a symbol not known to us */
124: #define ELSE 4 /* #else */
125: #define ENDIF 5 /* #endif */
126: #define LEOF 6 /* end of file */
127:
128: char reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */
129: int linenum BSS; /* current line number */
130: int stqcline BSS; /* start of current coment or quote */
131: char *errs[] = {
132: #define NO_ERR 0
133: "",
134: #define END_ERR 1
135: "",
136: #define ELSE_ERR 2
137: "Inappropriate else",
138: #define ENDIF_ERR 3
139: "Inappropriate endif",
140: #define IEOF_ERR 4
141: "Premature EOF in ifdef",
142: #define CEOF_ERR 5
143: "Premature EOF in comment",
144: #define Q1EOF_ERR 6
145: "Premature EOF in quoted character",
146: #define Q2EOF_ERR 7
147: "Premature EOF in quoted string"
148: };
149:
150: pfile ()
151: {
152: reject = 0;
153: doif (-1, NO, reject, 0);
154: return;
155: }
156:
157: doif (thissym, inif, prevreject, depth)
158: register int thissym; /* index of the symbol who was last ifdef'ed */
159: int inif; /* YES or NO we are inside an ifdef */
160: int prevreject; /* previous value of reject */
161: int depth; /* depth of ifdef's */
162: {
163: register int lineval;
164: register int thisreject;
165: int doret; /* tmp return valud]e of doif */
166: int cursym; /* index of the symbol returned by checkline */
167: int stline; /* line number when called this time */
168:
169: stline = linenum;
170: for (;;) {
171: switch (lineval = checkline (&cursym)) {
172: case PLAIN:
173: flushline (YES);
174: break;
175:
176: case TRUE:
177: case FALSE:
178: thisreject = reject;
179: if (lineval == TRUE)
180: insym[cursym] = 1;
181: else {
182: if (reject < 2)
183: reject = ignore[cursym] ? 1 : 2;
184: insym[cursym] = -1;
185: }
186: if (ignore[cursym])
187: flushline (YES);
188: else {
189: exitstat = 1;
190: flushline (NO);
191: }
192: if ((doret = doif (cursym, YES, thisreject, depth + 1)) != NO_ERR)
193: return error (doret, stline, depth);
194: break;
195:
196: case OTHER:
197: flushline (YES);
198: if ((doret = doif (-1, YES, reject, depth + 1)) != NO_ERR)
199: return error (doret, stline, depth);
200: break;
201:
202: case ELSE:
203: if (inif != 1)
204: return error (ELSE_ERR, linenum, depth);
205: inif = 2;
206: if (thissym >= 0) {
207: if ((insym[thissym] = -insym[thissym]) < 0)
208: reject = ignore[thissym] ? 1 : 2;
209: else
210: reject = prevreject;
211: if (!ignore[thissym]) {
212: flushline (NO);
213: break;
214: }
215: }
216: flushline (YES);
217: break;
218:
219: case ENDIF:
220: if (inif == 0)
221: return error (ENDIF_ERR, linenum, depth);
222: if (thissym >= 0) {
223: insym[thissym] = 0;
224: reject = prevreject;
225: if (!ignore[thissym]) {
226: flushline (NO);
227: return NO_ERR;
228: }
229: }
230: flushline (YES);
231: return NO_ERR;
232:
233: case LEOF: {
234: int err;
235: err = incomment
236: ? CEOF_ERR
237: : inquote[QUOTE1]
238: ? Q1EOF_ERR
239: : inquote[QUOTE2]
240: ? Q2EOF_ERR
241: : NO_ERR;
242: if (inif) {
243: if (err != NO_ERR)
244: error (err, stqcline, depth);
245: return error (IEOF_ERR, stline, depth);
246: }
247: else if (err != NO_ERR)
248: return error (err, stqcline, depth);
249: else
250: return NO_ERR;
251: }
252: }
253: }
254: }
255:
256: #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
257:
258: #define MAXLINE 256
259: char tline[MAXLINE] BSS;
260:
261: checkline (cursym)
262: int *cursym;
263: {
264: register char *cp;
265: register char *symp;
266: register char chr;
267: char *scp;
268: int retval;
269: int symind;
270: # define KWSIZE 8
271: char keyword[KWSIZE];
272:
273: linenum++;
274: if (getlin (tline, sizeof tline, input, NO) == EOF)
275: return LEOF;
276:
277: retval = PLAIN;
278: if ( *(cp = tline) != '#'
279: || incomment
280: || inquote[QUOTE1]
281: || inquote[QUOTE2]
282: )
283: goto eol;
284:
285: cp = skipcomment (++cp);
286: symp = keyword;
287: while (!endsym (*cp)) {
288: *symp = *cp++;
289: if (++symp >= &keyword[KWSIZE])
290: goto eol;
291: }
292: *symp = '\0';
293:
294: if (strcmp (keyword, "ifdef") == 0) {
295: retval = YES;
296: goto ifdef;
297: }
298: else if (strcmp (keyword, "ifndef") == 0) {
299: retval = NO;
300: ifdef:
301: scp = cp = skipcomment (++cp);
302: if (incomment) {
303: retval = PLAIN;
304: goto eol;
305: }
306: for (symind = 0; ; ) {
307: if (insym[symind] == 0) {
308: for ( symp = sym[symind], cp = scp
309: ; *symp && *cp == *symp
310: ; cp++, symp++
311: )
312: {}
313: chr = *cp;
314: if (*symp == '\0' && endsym (chr)) {
315: *cursym = symind;
316: retval = (retval ^ true[symind]) ? FALSE : TRUE;
317: break;
318: }
319: }
320: if (++symind >= nsyms) {
321: retval = OTHER;
322: break;
323: }
324: }
325: }
326: else if (strcmp (keyword, "if") == 0)
327: retval = OTHER;
328: else if (strcmp (keyword, "else") == 0)
329: retval = ELSE;
330: else if (strcmp (keyword, "endif") == 0)
331: retval = ENDIF;
332:
333: eol:
334: if (!text && !reject)
335: for (; *cp; ) {
336: if (incomment)
337: cp = skipcomment (cp);
338: else if (inquote[QUOTE1])
339: cp = skipquote (cp, QUOTE1);
340: else if (inquote[QUOTE2])
341: cp = skipquote (cp, QUOTE2);
342: else if (*cp == '/' && cp[1] == '*')
343: cp = skipcomment (cp);
344: else if (*cp == '\'')
345: cp = skipquote (cp, QUOTE1);
346: else if (*cp == '"')
347: cp = skipquote (cp, QUOTE2);
348: else
349: cp++;
350: }
351: return retval;
352: }
353:
354: /* Skip over comments and stop at the next charaacter
355: /* position that is not whitespace.
356: /**/
357: *
358: skipcomment (cp)
359: register char *cp;
360: {
361: if (incomment)
362: goto inside;
363: for (;; cp++) {
364: while (*cp == ' ' || *cp == '\t')
365: cp++;
366: if (text)
367: return cp;
368: if ( cp[0] != '/'
369: || cp[1] != '*'
370: )
371: return cp;
372: cp += 2;
373: if (!incomment) {
374: incomment = YES;
375: stqcline = linenum;
376: }
377: :
378: for (;;) {
379: for (; *cp != '*'; cp++)
380: if (*cp == '\0')
381: return cp;
382: if (*++cp == '/')
383: break;
384: }
385: incomment = NO;
386: }
387: }
388:
389: /* Skip over a quoted string or character and stop at the next charaacter
390: /* position that is not whitespace.
391: /**/
392: char *
393: skipquote (cp, type)
394: register char *cp;
395: register int type;
396: {
397: register char qchar;
398:
399: qchar = type == QUOTE1 ? '\'' : '"';
400:
401: if (inquote[type])
402: goto inside;
403: for (;; cp++) {
404: if (*cp != qchar)
405: return cp;
406: cp++;
407: if (!inquote[type]) {
408: inquote[type] = YES;
409: stqcline = linenum;
410: }
411: inside:
412: for (; ; cp++) {
413: if (*cp == qchar)
414: break;
415: if ( *cp == '\0'
416: || *cp == '\\'
417: && *++cp == '\0'
418: )
419: return cp;
420: }
421: inquote[type] = NO;
422: }
423: }
424:
425: /*
426: /* special getlin - treats form-feed as an end-of-line
427: /* and expands tabs if asked for
428: /*
429: /**/
430: getlin (line, maxline, inp, expandtabs)
431: register char *line;
432: int maxline;
433: FILE *inp;
434: int expandtabs;
435: {
436: int tmp;
437: register int num;
438: register int chr;
439: #ifdef FFSPECIAL
440: static char havechar = NO; /* have leftover char from last time */
441: static char svchar BSS;
442: #endif
443:
444: num = 0;
445: #ifdef FFSPECIAL
446: if (havechar) {
447: havechar = NO;
448: chr = svchar;
449: goto ent;
450: }
451: #endif
452: while (num + 8 < maxline) { /* leave room for tab */
453: chr = getc (inp);
454: if (isprint (chr)) {
455: #ifdef FFSPECIAL
456: ent:
457: #endif
458: *line++ = chr;
459: num++;
460: }
461: else
462: switch (chr) {
463: case EOF:
464: return EOF;
465:
466: case '\t':
467: if (expandtabs) {
468: num += tmp = 8 - (num & 7);
469: do
470: *line++ = ' ';
471: while (--tmp);
472: break;
473: }
474: default:
475: *line++ = chr;
476: num++;
477: break;
478:
479: case '\n':
480: *line = '\n';
481: num++;
482: goto end;
483:
484: #ifdef FFSPECIAL
485: case '\f':
486: if (++num == 1)
487: *line = '\f';
488: else {
489: *line = '\n';
490: havechar = YES;
491: svchar = chr;
492: }
493: goto end;
494: #endif
495: }
496: }
497: end:
498: *++line = '\0';
499: return num;
500: }
501:
502: flushline (keep)
503: {
504: if ((keep && reject < 2) ^ complement)
505: putlin (tline, stdout);
506: else if (lnblank)
507: putlin ("\n", stdout);
508: return;
509: }
510:
511: /*
512: /* putlin - for tools
513: /*
514: /**/
515: putlin (line, fio)
516: register char *line;
517: register FILE *fio;
518: {
519: register char chr;
520:
521: while (chr = *line++)
522: putc (chr, fio);
523: return;
524: }
525:
526: prname ()
527: {
528: fprintf (stderr, "%s: ", progname);
529: return;
530: }
531:
532:
533: error (err, line, depth)
534: {
535: if (err == END_ERR)
536: return err;
537:
538: prname ();
539:
540: #ifndef TESTING
541: fprintf (stderr, "Error in %s line %d: %s.\n",
542: filename, line, errs[err]);
543: #endif
544:
545: #ifdef TESTING
546: fprintf (stderr, "Error in %s line %d: %s. ",
547: filename, line, errs[err]);
548: fprintf (stderr, "ifdef depth: %d\n", depth);
549: #endif
550:
551: exitstat = 2;
552: return depth > 1 ? IEOF_ERR : END_ERR;
553: }