grammar
[unix-history] / usr / src / usr.bin / unifdef / unifdef.c
CommitLineData
476fcd16
SL
1#ifndef lint
2static 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
12FILE *input;
13#ifndef YES
14#define YES 1
15#define NO 0
16#endif
17
18char *progname BSS;
19char *filename BSS;
20char text BSS; /* -t option in effect: this is a text file */
21char lnblank BSS; /* -l option in effect: blank deleted lines */
22char complement BSS; /* -c option in effect: complement the operation */
23#define MAXSYMS 100
24char true[MAXSYMS] BSS;
25char ignore[MAXSYMS] BSS;
26char *sym[MAXSYMS] BSS;
27char insym[MAXSYMS] BSS;
28char nsyms BSS;
29char incomment BSS;
30#define QUOTE1 0
31#define QUOTE2 1
32char inquote[2] BSS;
33int exitstat BSS;
34char *skipcomment ();
35char *skipquote ();
36
37main (argc, argv)
38int argc;
39char **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
89Usage: %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
128char reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */
129int linenum BSS; /* current line number */
130int stqcline BSS; /* start of current coment or quote */
131char *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
150pfile ()
151{
152 reject = 0;
153 doif (-1, NO, reject, 0);
154 return;
155}
156
157doif (thissym, inif, prevreject, depth)
158register int thissym; /* index of the symbol who was last ifdef'ed */
159int inif; /* YES or NO we are inside an ifdef */
160int prevreject; /* previous value of reject */
161int 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
259char tline[MAXLINE] BSS;
260
261checkline (cursym)
262int *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/**/
357char *
358skipcomment (cp)
359register 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/**/
392char *
393skipquote (cp, type)
394register char *cp;
395register 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/**/
430getlin (line, maxline, inp, expandtabs)
431register char *line;
432int maxline;
433FILE *inp;
434int 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
502flushline (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/**/
515putlin (line, fio)
516register char *line;
517register FILE *fio;
518{
519 register char chr;
520
521 while (chr = *line++)
522 putc (chr, fio);
523 return;
524}
525
526prname ()
527{
528 fprintf (stderr, "%s: ", progname);
529 return;
530}
531
532
533error (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}