xref: /titanic_51/usr/src/cmd/sgs/unifdef/common/unifdef.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /* Copyright (c) 1982 Regents of the University of California */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 /*
35  *    unifdef - remove ifdef'ed lines
36  */
37 
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <locale.h>
41 #define BSS
42 FILE *input;
43 #ifndef YES
44 #define YES 1
45 #define NO  0
46 #endif
47 
48 char *progname BSS;
49 char *filename BSS;
50 char text BSS;          /* -t option in effect: this is a text file */
51 char lnblank BSS;       /* -l option in effect: blank deleted lines */
52 char complement BSS;    /* -c option in effect: complement the operation */
53 #define MAXSYMS 100
54 char true[MAXSYMS] BSS;
55 char ignore[MAXSYMS] BSS;
56 char *sym[MAXSYMS] BSS;
57 signed char insym[MAXSYMS] BSS;
58 #define KWSIZE 8
59 char buf[KWSIZE];
60 char nsyms BSS;
61 char incomment BSS;
62 #define QUOTE1 0
63 #define QUOTE2 1
64 char inquote[2] BSS;
65 int exitstat BSS;
66 char *skipcomment ();
67 char *skipquote ();
68 char *nextsym();
69 
70 #ifdef i386
71 #define gettext(s) s
72 #endif
73 
74 main (argc, argv)
75 int argc;
76 char **argv;
77 {
78     char **curarg;
79     register char *cp;
80     register char *cp1;
81     char ignorethis;
82 
83     (void) setlocale (LC_ALL, "");
84 
85 /* i386 doesn't handle this yet */
86 #ifndef i386
87 
88 #if !defined(TEXT_DOMAIN)
89 #define TEXT_DOMAIN "SYS_TEST"
90 #endif
91     (void) textdomain(TEXT_DOMAIN);
92 
93 #endif
94 
95     progname = argv[0][0] ? argv[0] : "unifdef";
96 
97     for (curarg = &argv[1]; --argc > 0; curarg++) {
98 	if (*(cp1 = cp = *curarg) != '-')
99 	    break;
100 	if (*++cp1 == 'i') {
101 	    ignorethis = YES;
102 	    cp1++;
103 	}
104 	else
105 	    ignorethis = NO;
106 	if (   (   *cp1 == 'D'
107 		|| *cp1 == 'U'
108 	       )
109 	    && cp1[1] != '\0'
110 	   ) {
111 	    if (nsyms >= MAXSYMS) {
112 		prname ();
113 		fprintf (stderr, gettext("too many symbols.\n"));
114 		exit (2);
115 	    }
116 	    ignore[nsyms] = ignorethis;
117 	    true[nsyms] = *cp1 == 'D' ? YES : NO;
118 	    sym[nsyms++] = &cp1[1];
119 	}
120 	else if (ignorethis)
121 	    goto unrec;
122 	else if (strcmp (&cp[1], "t") == 0)
123 	    text = YES;
124 	else if (strcmp (&cp[1], "l") == 0)
125 	    lnblank = YES;
126 	else if (strcmp (&cp[1], "c") == 0)
127 	    complement = YES;
128 	else {
129  unrec:
130 	    prname ();
131 	    fprintf (stderr, gettext("unrecognized option: %s\n"), cp);
132 	    goto usage;
133 	}
134     }
135     if (nsyms == 0) {
136  usage:
137 	fprintf (stderr, gettext("\
138 Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-idsym] [-iusym]]... [file]\n\
139     At least one arg from [-D -U -id -iu] is required\n"), progname);
140 	exit (2);
141     }
142 
143     if (argc > 1) {
144 	prname ();
145 	fprintf (stderr, gettext("can only do one file.\n"));
146     }
147     else if (argc == 1) {
148 	filename = *curarg;
149 	if ((input = fopen (filename, "r")) != NULL) {
150 	    pfile();
151 	    fclose (input);
152 	}
153 	else {
154 	    prname ();
155 	    perror(*curarg);
156 	}
157     }
158     else {
159 	filename = "[stdin]";
160 	input = stdin;
161 	pfile();
162     }
163 
164     fflush (stdout);
165     exit (exitstat);
166 	/* NOTREACHED */
167 }
168 
169 /* types of input lines: */
170 #define PLAIN       0   /* ordinary line */
171 #define TRUE        1   /* a true  #ifdef of a symbol known to us */
172 #define FALSE       2   /* a false #ifdef of a symbol known to us */
173 #define OTHER       3   /* an #ifdef of a symbol not known to us */
174 #define ELSE        4   /* #else */
175 #define ENDIF       5   /* #endif */
176 #define LEOF        6   /* end of file */
177 
178 /* should be int declaration, was char */
179 int reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
180 int linenum BSS;    /* current line number */
181 int stqcline BSS;   /* start of current coment or quote */
182 char *errs[] = {
183 #define NO_ERR      0
184 			"",
185 #define END_ERR     1
186 			"",
187 #define ELSE_ERR    2
188 			"Inappropriate else",
189 #define ENDIF_ERR   3
190 			"Inappropriate endif",
191 #define IEOF_ERR    4
192 			"Premature EOF in ifdef",
193 #define CEOF_ERR    5
194 			"Premature EOF in comment",
195 #define Q1EOF_ERR   6
196 			"Premature EOF in quoted character",
197 #define Q2EOF_ERR   7
198 			"Premature EOF in quoted string"
199 };
200 
201 pfile ()
202 {
203     reject = 0;
204     doif (-1, NO, reject, 0);
205     return;
206 }
207 
208 doif (thissym, inif, prevreject, depth)
209 register int thissym;   /* index of the symbol who was last ifdef'ed */
210 int inif;               /* YES or NO we are inside an ifdef */
211 int prevreject;         /* previous value of reject */
212 int depth;              /* depth of ifdef's */
213 {
214     register int lineval;
215     register int thisreject;
216     int doret;          /* tmp return value of doif */
217     int cursym;         /* index of the symbol returned by checkline */
218     int stline;         /* line number when called this time */
219 
220     stline = linenum;
221     for (;;) {
222 	switch (lineval = checkline (&cursym)) {
223 	case PLAIN:
224 	    flushline (YES);
225 	    break;
226 
227 	case TRUE:
228 	case FALSE:
229 	    thisreject = reject;
230 	    if (lineval == TRUE)
231 		insym[cursym] = 1;
232 	    else {
233 		if (reject < 2)
234 		    reject = ignore[cursym] ? 1 : 2;
235 		insym[cursym] = -1;
236 	    }
237 	    if (ignore[cursym])
238 		flushline (YES);
239 	    else {
240 		exitstat = 0;
241 		flushline (NO);
242 	    }
243 	    if ((doret = doif (cursym, YES, thisreject, depth + 1)) != NO_ERR)
244 		return error (doret, stline, depth);
245     	    break;
246 
247 	case OTHER:
248 	    flushline (YES);
249 	    if ((doret = doif (-1, YES, reject, depth + 1)) != NO_ERR)
250 		return error (doret, stline, depth);
251 	    break;
252 
253 	case ELSE:
254 	    if (inif != 1)
255 		return error (ELSE_ERR, linenum, depth);
256 	    inif = 2;
257 	    if (thissym >= 0) {
258 		if ((insym[thissym] = -insym[thissym]) < 0)
259 		    reject = ignore[thissym] ? 1 : 2;
260 		else
261 		    reject = prevreject;
262 		if (!ignore[thissym]) {
263 		    flushline (NO);
264 		    break;
265 		}
266 	    }
267 	    flushline (YES);
268 	    break;
269 
270 	case ENDIF:
271 	    if (inif == 0)
272 		return error (ENDIF_ERR, linenum, depth);
273 	    if (thissym >= 0) {
274 		insym[thissym] = 0;
275 		reject = prevreject;
276 		if (!ignore[thissym]) {
277 		    flushline (NO);
278 		    return NO_ERR;
279 		}
280 	    }
281 	    flushline (YES);
282 	    return NO_ERR;
283 
284 	case LEOF: {
285 	    int err;
286 	    err =   incomment
287 		  ? CEOF_ERR
288 		  : inquote[QUOTE1]
289 		  ? Q1EOF_ERR
290 		  : inquote[QUOTE2]
291 		  ? Q2EOF_ERR
292 		  : NO_ERR;
293 	    if (inif) {
294 		if (err != NO_ERR)
295 		    error (err, stqcline, depth);
296 		return error (IEOF_ERR, stline, depth);
297 	    }
298 	    else if (err != NO_ERR)
299 		return error (err, stqcline, depth);
300 	    else
301 		return NO_ERR;
302 	    }
303 	}
304     }
305 }
306 
307 #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
308 
309 #define MAXLINE 256
310 char tline[MAXLINE] BSS;
311 
312 checkline (cursym)
313 int *cursym;
314 {
315     register char *cp;
316     register char *symp;
317     register char chr;
318     char *scp;
319     int retval;
320     int symind;
321     char keyword[KWSIZE];
322 
323     linenum++;
324     if (getlin (tline, sizeof tline, input, NO) == EOF)
325         return LEOF;
326 
327     retval = PLAIN;
328     if (   *(cp = tline) != '#'
329 	|| incomment
330 	|| inquote[QUOTE1]
331 	|| inquote[QUOTE2]
332        )
333 	goto eol;
334 
335     cp = skipcomment (++cp);
336     symp = keyword;
337     while (!endsym (*cp)) {
338 	*symp = *cp++;
339 	if (++symp >= &keyword[KWSIZE])
340 	    goto eol;
341     }
342     *symp = '\0';
343 
344     if (strcmp (keyword, "ifdef") == 0) {
345 	retval = YES;
346 	goto ifdef;
347     }
348     else if (strcmp (keyword, "if") == 0) {
349 	cp = skipcomment(++cp);
350  	if (strcmp (nextsym(cp), "defined") == 0) {
351 		cp += strlen("defined") + 1;
352 		/* skip to identifier */
353 		while (endsym(*cp))
354 			++cp;
355 		retval = YES;
356 		goto ifdef;
357 	}
358 	else {
359 		retval = OTHER;
360 		goto eol;
361 	}
362     }
363     else if (strcmp (keyword, "ifndef") == 0) {
364 	retval = NO;
365  ifdef:
366 	scp = cp = skipcomment (cp);
367 	if (incomment) {
368 	    retval = PLAIN;
369 	    goto eol;
370 	}
371 	for (symind = 0; ; ) {
372 	    if (insym[symind] == 0) {
373 		for ( symp = sym[symind], cp = scp
374 		    ; *symp && *cp == *symp
375 		    ; cp++, symp++
376 		    )
377 		    {}
378 		chr = *cp;
379 		if (*symp == '\0' && endsym (chr)) {
380 		    *cursym = symind;
381 		    retval = (retval ^ true[symind]) ? FALSE : TRUE;
382 		    break;
383 		}
384 	    }
385 	    if (++symind >= nsyms) {
386 		retval = OTHER;
387 		break;
388 	    }
389 	}
390     }
391     else if (strcmp (keyword, "else") == 0)
392 	retval = ELSE;
393     else if (strcmp (keyword, "endif") == 0)
394 	retval = ENDIF;
395 
396  eol:
397     if (!text && !reject)
398 	for (; *cp; ) {
399 	    if (incomment)
400 		cp = skipcomment (cp);
401 	    else if (inquote[QUOTE1])
402 		cp = skipquote (cp, QUOTE1);
403 	    else if (inquote[QUOTE2])
404 		cp = skipquote (cp, QUOTE2);
405 	    else if (*cp == '/' && cp[1] == '*')
406 		cp = skipcomment (cp);
407 	    else if (*cp == '\'')
408 		cp = skipquote (cp, QUOTE1);
409 	    else if (*cp == '"')
410 		cp = skipquote (cp, QUOTE2);
411 	    else
412 		cp++;
413 	}
414     return retval;
415 }
416 
417 /*  Skip over comments and stop at the next character
418 *  position that is not whitespace.
419 */
420 char *
421 skipcomment (cp)
422 register char *cp;
423 {
424     if (incomment)
425 	goto inside;
426     for (;; cp++) {
427         while (*cp == ' ' || *cp == '\t')
428             cp++;
429 	if (text)
430             return cp;
431 	if (   cp[0] != '/'
432 	    || cp[1] != '*'
433 	   )
434             return cp;
435 	cp += 2;
436 	if (!incomment) {
437 	    incomment = YES;
438 	    stqcline = linenum;
439 	}
440  inside:
441 	for (;;) {
442 	    for (; *cp != '*'; cp++)
443 		if (*cp == '\0')
444 		    return cp;
445 	    if (*++cp == '/')
446 		break;
447 	}
448 	incomment = NO;
449     }
450 }
451 
452 /*  Skip over a quoted string or character and stop at the next charaacter
453 *  position that is not whitespace.
454 */
455 char *
456 skipquote (cp, type)
457 register char *cp;
458 register int type;
459 {
460     register char qchar;
461 
462     qchar = type == QUOTE1 ? '\'' : '"';
463 
464     if (inquote[type])
465 	goto inside;
466     for (;; cp++) {
467 	if (*cp != qchar)
468 	    return cp;
469 	cp++;
470 	if (!inquote[type]) {
471 	    inquote[type] = YES;
472 	    stqcline = linenum;
473 	}
474  inside:
475 	for (; ; cp++) {
476 	    if (*cp == qchar)
477 		break;
478 	    if (   *cp == '\0'
479 		|| *cp == '\\'
480 		&& *++cp == '\0'
481 	       )
482 		return cp;
483 	}
484 	inquote[type] = NO;
485     }
486 }
487 
488 /*
489 *   special getlin - treats form-feed as an end-of-line
490 *                    and expands tabs if asked for
491 *
492 */
493 getlin (line, maxline, inp, expandtabs)
494 register char *line;
495 int maxline;
496 FILE *inp;
497 int expandtabs;
498 {
499     int tmp;
500     register int num;
501     register int chr;
502 #ifdef FFSPECIAL
503     static char havechar = NO;  /* have leftover char from last time */
504     static char svchar BSS;
505 #endif
506 
507     num = 0;
508 #ifdef FFSPECIAL
509     if (havechar) {
510 	havechar = NO;
511 	chr = svchar;
512 	goto ent;
513     }
514 #endif
515     while (num + 8 < maxline) {   /* leave room for tab */
516         chr = getc (inp);
517 	if (isprint (chr)) {
518 #ifdef FFSPECIAL
519  ent:
520 #endif
521 	    *line++ = chr;
522 	    num++;
523 	}
524 	else
525 	    switch (chr) {
526 	    case EOF:
527 		return EOF;
528 
529 	    case '\t':
530 		if (expandtabs) {
531 		    num += tmp = 8 - (num & 7);
532 		    do
533 			*line++ = ' ';
534 		    while (--tmp);
535 		    break;
536 		}
537             default:
538                 *line++ = chr;
539                 num++;
540 		break;
541 
542 	    case '\n':
543                 *line = '\n';
544                 num++;
545                 goto end;
546 
547 #ifdef FFSPECIAL
548 	    case '\f':
549 		if (++num == 1)
550 		    *line = '\f';
551 		else {
552 		    *line = '\n';
553 		    havechar = YES;
554                     svchar = chr;
555                 }
556                 goto end;
557 #endif
558 	    }
559     }
560  end:
561     *++line = '\0';
562     return num;
563 }
564 
565 flushline (keep)
566 {
567     if ((keep && reject < 2) ^ complement)
568 	putlin (tline, stdout);
569     else if (lnblank)
570 	putlin ("\n", stdout);
571     return;
572 }
573 
574 /*
575 *  putlin - for tools
576 *
577 */
578 putlin (line, fio)
579 register char *line;
580 register FILE *fio;
581 {
582     register char chr;
583 
584     while (chr = *line++)
585 	putc (chr, fio);
586     return;
587 }
588 
589 prname ()
590 {
591     fprintf (stderr, "%s: ", progname);
592     return;
593 }
594 
595 
596 error (err, line, depth)
597 {
598     if (err == END_ERR)
599 	return err;
600 
601     prname ();
602 
603 #ifndef TESTING
604     fprintf (stderr, gettext("Error in %s line %d: %s.\n"),
605 	     filename, line, gettext(errs[err]));
606 #endif
607 
608 #ifdef TESTING
609     fprintf (stderr, gettext("Error in %s line %d: %s. "),
610 	     filename, line, errs[err]);
611     fprintf (stderr, gettext("ifdef depth: %d\n"), depth);
612 #endif
613 
614     exitstat = 1;
615     return depth > 1 ? IEOF_ERR : END_ERR;
616 }
617 
618 /* return the next token in the line buffer */
619 char *
620 nextsym(p)
621 char *p;
622 {
623 	register char *key;
624 	register int i = KWSIZE;
625 
626 	key = buf;
627 	while (!endsym(*p) && --i)
628 		*key++ = *p++;
629 	*key = '\0';
630 
631 	return (buf);
632 }
633