date and time created 83/02/11 15:44:29 by rrh
[unix-history] / usr / src / usr.bin / unifdef / unifdef.c
CommitLineData
ba2c33c2
KM
1/* Copyright (c) 1982 Regents of the University of California */
2
3static char sccsid[] = "@(#)unifdef.c 4.1 (Berkeley) %G%";
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
14FILE *input;
15#ifndef YES
16#define YES 1
17#define NO 0
18#endif
19
20char *progname BSS;
21char *filename BSS;
22char text BSS; /* -t option in effect: this is a text file */
23char lnblank BSS; /* -l option in effect: blank deleted lines */
24char complement BSS; /* -c option in effect: complement the operation */
25#define MAXSYMS 100
26char true[MAXSYMS] BSS;
27char ignore[MAXSYMS] BSS;
28char *sym[MAXSYMS] BSS;
29char insym[MAXSYMS] BSS;
30char nsyms BSS;
31char incomment BSS;
32#define QUOTE1 0
33#define QUOTE2 1
34char inquote[2] BSS;
35int exitstat BSS;
36char *skipcomment ();
37char *skipquote ();
38
39main (argc, argv)
40int argc;
41char **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, "\
91Usage: %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 ();
108 fprintf (stderr, "can't open %s\n", *curarg);
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
130char reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */
131int linenum BSS; /* current line number */
132int stqcline BSS; /* start of current coment or quote */
133char *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
152pfile ()
153{
154 reject = 0;
155 doif (-1, NO, reject, 0);
156 return;
157}
158
159doif (thissym, inif, prevreject, depth)
160register int thissym; /* index of the symbol who was last ifdef'ed */
161int inif; /* YES or NO we are inside an ifdef */
162int prevreject; /* previous value of reject */
163int 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
261char tline[MAXLINE] BSS;
262
263checkline (cursym)
264int *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/**/
359char *
360skipcomment (cp)
361register 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/**/
394char *
395skipquote (cp, type)
396register char *cp;
397register 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/**/
432getlin (line, maxline, inp, expandtabs)
433register char *line;
434int maxline;
435FILE *inp;
436int 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
504flushline (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/**/
517putlin (line, fio)
518register char *line;
519register FILE *fio;
520{
521 register char chr;
522
523 while (chr = *line++)
524 putc (chr, fio);
525 return;
526}
527
528prname ()
529{
530 fprintf (stderr, "%s: ", progname);
531 return;
532}
533
534
535error (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}