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