]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/unifdef/unifdef.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / usr.bin / unifdef / unifdef.c
1 /*
2  * Copyright (c) 1985, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Dave Yost.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #ifndef lint
38 static const char copyright[] =
39 "@(#) Copyright (c) 1985, 1993\n\
40         The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)unifdef.c   8.1 (Berkeley) 6/6/93";
46 #endif
47 static const char rcsid[] =
48   "$FreeBSD$";
49 #endif /* not lint */
50
51 /*
52  * unifdef - remove ifdef'ed lines
53  *
54  *  Warning: will not work correctly if input contains null characters.
55  *
56  *  Wishlist:
57  *      provide an option which will append the name of the
58  *        appropriate symbol after #else's and #endif's
59  *      provide an option which will check symbols after
60  *        #else's and #endif's to see that they match their
61  *        corresponding #ifdef or #ifndef
62  */
63
64 #include <ctype.h>
65 #include <err.h>
66 #include <stdio.h>
67
68 typedef int Reject_level;
69
70 #define BSS
71 FILE *input;
72 #ifndef YES
73 #define YES 1
74 #define NO  0
75 #endif/*YES */
76 typedef int Bool;
77
78 char *filename BSS;
79 char text BSS;          /* -t option in effect: this is a text file */
80 char lnblank BSS;       /* -l option in effect: blank deleted lines */
81 char complement BSS;    /* -c option in effect: complement the operation */
82
83 #define MAXSYMS 100
84 char *symname[MAXSYMS] BSS; /* symbol name */
85 char true[MAXSYMS] BSS;     /* -Dsym */
86 char ignore[MAXSYMS] BSS;   /* -iDsym or -iUsym */
87 char insym[MAXSYMS] BSS;    /* state: false, inactive, true */
88 #define SYM_INACTIVE 0      /* symbol is currently inactive */
89 #define SYM_FALSE    1      /* symbol is currently false */
90 #define SYM_TRUE     2      /* symbol is currently true  */
91
92 char nsyms BSS;
93 char incomment BSS;         /* inside C comment */
94
95 #define QUOTE_NONE   0
96 #define QUOTE_SINGLE 1
97 #define QUOTE_DOUBLE 2
98 char inquote BSS;           /* inside single or double quotes */
99
100 int exitstat BSS;
101 char *skipcomment ();
102 char *skipquote ();
103 static void usage __P((void));
104 void flushline __P((Bool));
105 int getlin __P((char *, int, FILE *, int));
106 int error __P((int, int, int));
107 void pfile __P((void));
108 int doif __P((int, int, Reject_level, int));
109 int findsym __P((char *));
110
111 int
112 main (argc, argv)
113 int argc;
114 char **argv;
115 {
116     char **curarg;
117     register char *cp;
118     register char *cp1;
119     char ignorethis;
120
121     for (curarg = &argv[1]; --argc > 0; curarg++) {
122         if (*(cp1 = cp = *curarg) != '-')
123             break;
124         if (*++cp1 == 'i') {
125             ignorethis = YES;
126             cp1++;
127         } else
128             ignorethis = NO;
129         if (   (   *cp1 == 'D'
130                 || *cp1 == 'U'
131                )
132             && cp1[1] != '\0'
133            ) {
134             register int symind;
135
136             if ((symind = findsym (&cp1[1])) < 0) {
137                 if (nsyms >= MAXSYMS)
138                     errx(2, "too many symbols");
139                 symind = nsyms++;
140                 symname[symind] = &cp1[1];
141                 insym[symind] = SYM_INACTIVE;
142             }
143             ignore[symind] = ignorethis;
144             true[symind] = *cp1 == 'D' ? YES : NO;
145         } else if (ignorethis)
146             goto unrec;
147         else if (strcmp (&cp[1], "t") == 0)
148             text = YES;
149         else if (strcmp (&cp[1], "l") == 0)
150             lnblank = YES;
151         else if (strcmp (&cp[1], "c") == 0)
152             complement = YES;
153         else {
154  unrec:
155             warnx("unrecognized option: %s", cp);
156             usage();
157         }
158     }
159     if (nsyms == 0)
160                 usage();
161
162     if (argc > 1) {
163         warnx("can only do one file");
164     } else if (argc == 1) {
165         filename = *curarg;
166         if ((input = fopen (filename, "r")) != NULL) {
167             pfile();
168             (void) fclose (input);
169         } else {
170             warn("can't open %s", *curarg);
171         }
172     } else {
173         filename = "[stdin]";
174         input = stdin;
175         pfile();
176     }
177
178     (void) fflush (stdout);
179     exit (exitstat);
180 }
181
182 static void
183 usage()
184 {
185         fprintf (stderr, "usage: %s",
186 "unifdef [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]] ... [file]\n");
187         exit (2);
188 }
189
190 /* types of input lines: */
191 typedef int Linetype;
192 #define LT_PLAIN       0   /* ordinary line */
193 #define LT_TRUE        1   /* a true  #ifdef of a symbol known to us */
194 #define LT_FALSE       2   /* a false #ifdef of a symbol known to us */
195 #define LT_OTHER       3   /* an #ifdef of a symbol not known to us */
196 #define LT_IF          4   /* an #ifdef of a symbol not known to us */
197 #define LT_ELSE        5   /* #else */
198 #define LT_ENDIF       6   /* #endif */
199 #define LT_LEOF        7   /* end of file */
200 extern Linetype checkline ();
201
202 Reject_level reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
203 #define REJ_NO          0
204 #define REJ_IGNORE      1
205 #define REJ_YES         2
206
207 int linenum BSS;    /* current line number */
208 int stqcline BSS;   /* start of current coment or quote */
209 char *errs[] = {
210 #define NO_ERR      0
211                         "",
212 #define END_ERR     1
213                         "",
214 #define ELSE_ERR    2
215                         "Inappropriate else",
216 #define ENDIF_ERR   3
217                         "Inappropriate endif",
218 #define IEOF_ERR    4
219                         "Premature EOF in ifdef",
220 #define CEOF_ERR    5
221                         "Premature EOF in comment",
222 #define Q1EOF_ERR   6
223                         "Premature EOF in quoted character",
224 #define Q2EOF_ERR   7
225                         "Premature EOF in quoted string"
226 };
227
228 /* States for inif arg to doif */
229 #define IN_NONE 0
230 #define IN_IF   1
231 #define IN_ELSE 2
232
233 void
234 pfile ()
235 {
236     reject = REJ_NO;
237     (void) doif (-1, IN_NONE, reject, 0);
238 }
239
240 int
241 doif (thissym, inif, prevreject, depth)
242 register int thissym;   /* index of the symbol who was last ifdef'ed */
243 int inif;               /* YES or NO we are inside an ifdef */
244 Reject_level prevreject;/* previous value of reject */
245 int depth;              /* depth of ifdef's */
246 {
247     register Linetype lineval;
248     register Reject_level thisreject;
249     int doret;          /* tmp return value of doif */
250     int cursym;         /* index of the symbol returned by checkline */
251     int stline;         /* line number when called this time */
252
253     stline = linenum;
254     for (;;) {
255         switch (lineval = checkline (&cursym)) {
256         case LT_PLAIN:
257             flushline (YES);
258             break;
259
260         case LT_TRUE:
261         case LT_FALSE:
262             thisreject = reject;
263             if (lineval == LT_TRUE)
264                 insym[cursym] = SYM_TRUE;
265             else {
266                 if (reject != REJ_YES)
267                     reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
268                 insym[cursym] = SYM_FALSE;
269             }
270             if (ignore[cursym])
271                 flushline (YES);
272             else {
273                 exitstat = 1;
274                 flushline (NO);
275             }
276             if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
277                 return error (doret, stline, depth);
278             break;
279
280         case LT_IF:
281         case LT_OTHER:
282             flushline (YES);
283             if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
284                 return error (doret, stline, depth);
285             break;
286
287         case LT_ELSE:
288             if (inif != IN_IF)
289                 return error (ELSE_ERR, linenum, depth);
290             inif = IN_ELSE;
291             if (thissym >= 0) {
292                 if (insym[thissym] == SYM_TRUE) {
293                     reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
294                     insym[thissym] = SYM_FALSE;
295                 } else { /* (insym[thissym] == SYM_FALSE) */
296                     reject = prevreject;
297                     insym[thissym] = SYM_TRUE;
298                 }
299                 if (!ignore[thissym]) {
300                     flushline (NO);
301                     break;
302                 }
303             }
304             flushline (YES);
305             break;
306
307         case LT_ENDIF:
308             if (inif == IN_NONE)
309                 return error (ENDIF_ERR, linenum, depth);
310             if (thissym >= 0) {
311                 insym[thissym] = SYM_INACTIVE;
312                 reject = prevreject;
313                 if (!ignore[thissym]) {
314                     flushline (NO);
315                     return NO_ERR;
316                 }
317             }
318             flushline (YES);
319             return NO_ERR;
320
321         case LT_LEOF: {
322             int err;
323             err =   incomment
324                   ? CEOF_ERR
325                   : inquote == QUOTE_SINGLE
326                   ? Q1EOF_ERR
327                   : inquote == QUOTE_DOUBLE
328                   ? Q2EOF_ERR
329                   : NO_ERR;
330             if (inif != IN_NONE) {
331                 if (err != NO_ERR)
332                     (void) error (err, stqcline, depth);
333                 return error (IEOF_ERR, stline, depth);
334             } else if (err != NO_ERR)
335                 return error (err, stqcline, depth);
336             else
337                 return NO_ERR;
338             }
339         }
340     }
341 }
342
343 #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
344
345 #define MAXLINE 256
346 char tline[MAXLINE] BSS;
347
348 Linetype
349 checkline (cursym)
350 int *cursym;    /* if LT_TRUE or LT_FALSE returned, set this to sym index */
351 {
352     register char *cp;
353     register char *symp;
354     char *scp;
355     Linetype retval;
356 #   define KWSIZE 8
357     char keyword[KWSIZE];
358
359     linenum++;
360     if (getlin (tline, sizeof tline, input, NO) == EOF)
361         return LT_LEOF;
362
363     retval = LT_PLAIN;
364     if (   *(cp = tline) != '#'
365         || incomment
366         || inquote == QUOTE_SINGLE
367         || inquote == QUOTE_DOUBLE
368        )
369         goto eol;
370
371     cp = skipcomment (++cp);
372     symp = keyword;
373     while (!endsym (*cp)) {
374         *symp = *cp++;
375         if (++symp >= &keyword[KWSIZE])
376             goto eol;
377     }
378     *symp = '\0';
379
380     if (strcmp (keyword, "ifdef") == 0) {
381         retval = YES;
382         goto ifdef;
383     } else if (strcmp (keyword, "ifndef") == 0) {
384         retval = NO;
385  ifdef:
386         scp = cp = skipcomment (++cp);
387         if (incomment) {
388             retval = LT_PLAIN;
389             goto eol;
390         }
391         {
392             int symind;
393
394             if ((symind = findsym (scp)) >= 0)
395                 retval = (retval ^ true[*cursym = symind])
396                          ? LT_FALSE : LT_TRUE;
397             else
398                 retval = LT_OTHER;
399         }
400     } else if (strcmp (keyword, "if") == 0)
401         retval = LT_IF;
402     else if (strcmp (keyword, "else") == 0)
403         retval = LT_ELSE;
404     else if (strcmp (keyword, "endif") == 0)
405         retval = LT_ENDIF;
406
407  eol:
408     if (!text && reject != REJ_IGNORE)
409         for (; *cp; ) {
410             if (incomment)
411                 cp = skipcomment (cp);
412             else if (inquote == QUOTE_SINGLE)
413                 cp = skipquote (cp, QUOTE_SINGLE);
414             else if (inquote == QUOTE_DOUBLE)
415                 cp = skipquote (cp, QUOTE_DOUBLE);
416             else if (*cp == '/' && cp[1] == '*')
417                 cp = skipcomment (cp);
418             else if (*cp == '\'')
419                 cp = skipquote (cp, QUOTE_SINGLE);
420             else if (*cp == '"')
421                 cp = skipquote (cp, QUOTE_DOUBLE);
422             else
423                 cp++;
424         }
425     return retval;
426 }
427
428 /*
429  *  Skip over comments and stop at the next charaacter
430  *  position that is not whitespace.
431  */
432 char *
433 skipcomment (cp)
434 register char *cp;
435 {
436     if (incomment)
437         goto inside;
438     for (;; cp++) {
439         while (*cp == ' ' || *cp == '\t')
440             cp++;
441         if (text)
442             return cp;
443         if (   cp[0] != '/'
444             || cp[1] != '*'
445            )
446             return cp;
447         cp += 2;
448         if (!incomment) {
449             incomment = YES;
450             stqcline = linenum;
451         }
452  inside:
453         for (;;) {
454             for (; *cp != '*'; cp++)
455                 if (*cp == '\0')
456                     return cp;
457             if (*++cp == '/') {
458                 incomment = NO;
459                 break;
460             }
461         }
462     }
463 }
464
465 /*
466  *  Skip over a quoted string or character and stop at the next charaacter
467  *  position that is not whitespace.
468  */
469 char *
470 skipquote (cp, type)
471 register char *cp;
472 register int type;
473 {
474     register char qchar;
475
476     qchar = type == QUOTE_SINGLE ? '\'' : '"';
477
478     if (inquote == type)
479         goto inside;
480     for (;; cp++) {
481         if (*cp != qchar)
482             return cp;
483         cp++;
484         inquote = type;
485         stqcline = linenum;
486  inside:
487         for (; ; cp++) {
488             if (*cp == qchar)
489                 break;
490             if (   *cp == '\0'
491                 || (*cp == '\\' && *++cp == '\0')
492                )
493                 return cp;
494         }
495         inquote = QUOTE_NONE;
496     }
497 }
498
499 /*
500  *  findsym - look for the symbol in the symbol table.
501  *            if found, return symbol table index,
502  *            else return -1.
503  */
504 int
505 findsym (str)
506 char *str;
507 {
508     register char *cp;
509     register char *symp;
510     register int symind;
511     register char chr;
512
513     for (symind = 0; symind < nsyms; ++symind) {
514         if (insym[symind] == SYM_INACTIVE) {
515             for ( symp = symname[symind], cp = str
516                 ; *symp && *cp == *symp
517                 ; cp++, symp++
518                 )
519                 continue;
520             chr = *cp;
521             if (*symp == '\0' && endsym (chr))
522                 return symind;
523         }
524     }
525     return -1;
526 }
527
528 /*
529  *   getlin - expands tabs if asked for
530  *            and (if compiled in) treats form-feed as an end-of-line
531  */
532 int
533 getlin (line, maxline, inp, expandtabs)
534 register char *line;
535 int maxline;
536 FILE *inp;
537 int expandtabs;
538 {
539     int tmp;
540     register int num;
541     register int chr;
542 #ifdef  FFSPECIAL
543     static char havechar = NO;  /* have leftover char from last time */
544     static char svchar BSS;
545 #endif/*FFSPECIAL */
546
547     num = 0;
548 #ifdef  FFSPECIAL
549     if (havechar) {
550         havechar = NO;
551         chr = svchar;
552         goto ent;
553     }
554 #endif/*FFSPECIAL */
555     while (num + 8 < maxline) {   /* leave room for tab */
556         chr = getc (inp);
557         if (isprint (chr)) {
558 #ifdef  FFSPECIAL
559  ent:
560 #endif/*FFSPECIAL */
561             *line++ = chr;
562             num++;
563         } else
564             switch (chr) {
565             case EOF:
566                 return EOF;
567
568             case '\t':
569                 if (expandtabs) {
570                     num += tmp = 8 - (num & 7);
571                     do
572                         *line++ = ' ';
573                     while (--tmp);
574                     break;
575                 }
576             default:
577                 *line++ = chr;
578                 num++;
579                 break;
580
581             case '\n':
582                 *line = '\n';
583                 num++;
584                 goto end;
585
586 #ifdef  FFSPECIAL
587             case '\f':
588                 if (++num == 1)
589                     *line = '\f';
590                 else {
591                     *line = '\n';
592                     havechar = YES;
593                     svchar = chr;
594                 }
595                 goto end;
596 #endif/*FFSPECIAL */
597             }
598     }
599  end:
600     *++line = '\0';
601     return num;
602 }
603
604 void
605 flushline (keep)
606 Bool keep;
607 {
608     if ((keep && reject != REJ_YES) ^ complement) {
609         register char *line = tline;
610         register FILE *out = stdout;
611         register char chr;
612
613         while ((chr = *line++))
614             putc (chr, out);
615     } else if (lnblank)
616         putc ('\n', stdout);
617 }
618
619 int
620 error (err, line, depth)
621 int err;        /* type of error & index into error string array */
622 int line;       /* line number */
623 int depth;      /* how many ifdefs we are inside */
624 {
625     if (err == END_ERR)
626         return err;
627
628 #ifndef TESTING
629     warnx("error in %s line %d: %s", filename, line, errs[err]);
630 #else/* TESTING */
631     warnx("error in %s line %d: %s. ifdef depth: %d",
632                         filename, line, errs[err], depth);
633 #endif/*TESTING */
634
635     exitstat = 2;
636     return depth > 1 ? IEOF_ERR : END_ERR;
637 }