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