Commit | Line | Data |
---|---|---|
476fcd16 SL |
1 | #ifndef lint |
2 | static char sccsid[] = "@(#)unifdef.c 4.4 (Berkeley) %G%"; | |
ba2c33c2 KM |
3 | #endif |
4 | ||
476fcd16 SL |
5 | /* |
6 | * unifdef - remove ifdef'ed lines | |
7 | */ | |
8 | ||
ba2c33c2 KM |
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 incomment 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; | |
535a99db SL |
57 | if ( ( *cp1 == 'D' |
58 | || *cp1 == 'U' | |
ba2c33c2 KM |
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; | |
535a99db | 68 | true[nsyms] = *cp1 == 'D' ? YES : NO; |
ba2c33c2 KM |
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, "\ | |
535a99db SL |
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); | |
ba2c33c2 KM |
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 (); | |
6404bb88 | 106 | perror(*curarg); |
ba2c33c2 KM |
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 | char * | |
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 | inside: | |
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 | } |