[net.sources] Rand's unifdef sources

oz@yetti.UUCP (Ozan Yigit) (07/23/86)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	unifdef.1
#	unifdef.c
# This archive created: Wed Jul 23 15:32:52 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'unifdef.1'" '(2591 characters)'
if test -f 'unifdef.1'
then
	echo shar: over-writing existing file "'unifdef.1'"
fi
sed 's/^X//' << \SHAR_EOF > 'unifdef.1'
X.TH UNIFDEF 1 Rand
X.SH NAME
Xunifdef \- remove ifdef'ed lines
X.SH SYNOPSIS
X.B unifdef
X[
X.B \-t
X.B \-l
X.B \-c
X.BI \-d sym
X.BI \-u sym
X.BI \-id sym
X.BI \-iu sym
X] ...  [ file ]
X.SH DESCRIPTION
X.I Unifdef
Xis useful for removing ifdef'ed lines from a file while otherwise leaving the
Xfile alone.
X.I Unifdef
Xis like a stripped-down C preprocessor:
Xit is smart enough to deal with the nested ifdefs, comments,
Xsingle and double
Xquotes of C syntax so that it can do its job, but it doesn't do any including
Xor interpretation of macros.
XNeither does it strip out comments, though it recognizes and ignores them.
X.PP
XYou specify which symbols you want defined
X(\fB\-d\fIsym\fR)
Xor undefined
X(\fB\-u\fIsym\fR)
Xand the lines inside those ifdefs will be copied to the output or removed as
Xappropriate.
XThe ifdef, ifndef, else, and endif lines associated with
X.I sym
Xwill also be removed.
XIfdefs involving symbols you don't specify
Xand ``#if'' control lines
Xare untouched and copied out
Xalong with their associated
Xifdef, else, and endif lines.
XIf an ifdef X occurs nested inside another ifdef X, then the
Xinside ifdef is treated as if it were an unrecognized symbol.
XIf the same symbol appears in more than one argument, only the first
Xoccurrence is significant.
X.PP
XThe
X.B \-l
Xoption causes
X.I unifdef
Xto replace removed lines with blank lines
Xinstead of deleting them.
X.PP
XIf you use ifdefs to delimit non-C lines, such as comments
Xor code which is under construction,
Xthen you must tell
X.I unifdef
Xwhich symbols are used for that purpose so that it won't try to parse
Xfor quotes and comments
Xin those ifdef'ed lines.
XYou specify that you want the lines inside certain ifdefs to be ignored
Xbut copied out with
X.BI \-id sym
Xand
X.BI \-iu sym
Xsimilar to
X.BI \-d sym
Xand
X.BI \-u sym
Xabove.
X.PP
XIf you want to use
X.I unifdef
Xfor plain text (not C code), use the
X.B \-t
Xoption.
XThis makes
X.I unifdef
Xrefrain from attempting to recognize comments and single and double quotes.
X.PP
X.I Unifdef
Xcopies its output to
X.I stdout
Xand will take its input from
X.I stdin
Xif no
X.I file
Xargument is given.
XIf the
X.B \-c
Xargument is specified, then the operation of
X.I unifdef
Xis complemented,
Xi.e. the lines that would have been removed or blanked
Xare retained and vice versa.
X.PP
X.I Unifdef
Xworks nicely with the
X.BI \-i sym
Xoption recently added to
X.I diff
Xat Rand.
X.SH "SEE ALSO"
Xdiff(1)
X.SH DIAGNOSTICS
XPremature EOF, inappropriate else or endif.
X.PP
XExit status is 0 if output is exact copy of input, 1 if not, 2 if trouble.
X.SH AUTHOR
XDave Yost, The Rand Corporation
X.SH BUGS
XShould try to deal with ``#if'' lines.
SHAR_EOF
if test 2591 -ne "`wc -c 'unifdef.1'`"
then
	echo shar: error transmitting "'unifdef.1'" '(should have been 2591 characters)'
fi
echo shar: extracting "'unifdef.c'" '(12319 characters)'
if test -f 'unifdef.c'
then
	echo shar: over-writing existing file "'unifdef.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'unifdef.c'
X#ifdef COMMENT
X
X    unifdef - remove ifdef'ed lines
X
X    Wishlist:
X	provide an option which will append the name of the
X	  appropriate symbol after #else's and #endif's
X	provide an option which will check symbols after
X	  #else's and #endif's to see that they match their
X	  corresponding #ifdef or #ifndef
X
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X#include <c_env.h>
X
X#define BSS
XFILE *input;
X#ifndef YES
X#define YES 1
X#define NO  0
X#endif
Xtypedef int Bool;
X
Xchar *progname BSS;
Xchar *filename BSS;
Xchar text BSS;          /* -t option in effect: this is a text file */
Xchar lnblank BSS;       /* -l option in effect: blank deleted lines */
Xchar complement BSS;    /* -c option in effect: complement the operation */
X
X#define MAXSYMS 100
Xchar *sym[MAXSYMS] BSS;     /* symbol name */
Xchar true[MAXSYMS] BSS;     /* -dsym */
Xchar ignore[MAXSYMS] BSS;   /* -idsym or -iusym */
Xchar insym[MAXSYMS] BSS;    /* state: false, inactive, true */
X#define SYM_INACTIVE 0      /* symbol is currently inactive */
X#define SYM_FALSE    1      /* symbol is currently false */
X#define SYM_TRUE     2      /* symbol is currently true  */
X
Xchar nsyms BSS;
Xchar incomment BSS;         /* inside C comment */
X
X#define QUOTE_NONE   0
X#define QUOTE_SINGLE 1
X#define QUOTE_DOUBLE 2
Xchar inquote BSS;           /* inside single or double quotes */
X
Xint exitstat BSS;
Xchar *skipcomment ();
Xchar *skipquote ();
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X    char **curarg;
X    register char *cp;
X    register char *cp1;
X    char ignorethis;
X
X    progname = argv[0][0] ? argv[0] : "unifdef";
X
X    for (curarg = &argv[1]; --argc > 0; curarg++) {
X	if (*(cp1 = cp = *curarg) != '-')
X	    break;
X	if (*++cp1 == 'i') {
X	    ignorethis = YES;
X	    cp1++;
X	}
X	else
X	    ignorethis = NO;
X	if (   (   *cp1 == 'd'
X		|| *cp1 == 'u'
X	       )
X	    && cp1[1] != '\0'
X	   ) {
X	    if (nsyms >= MAXSYMS) {
X		prname ();
X		fprintf (stderr, "too many symbols.\n");
X		exit (2);
X	    }
X	    insym[nsyms] = SYM_INACTIVE;
X	    ignore[nsyms] = ignorethis;
X	    true[nsyms] = *cp1 == 'd' ? YES : NO;
X	    sym[nsyms++] = &cp1[1];
X	}
X	else if (ignorethis)
X	    goto unrec;
X	else if (strcmp (&cp[1], "t") == 0)
X	    text = YES;
X	else if (strcmp (&cp[1], "l") == 0)
X	    lnblank = YES;
X	else if (strcmp (&cp[1], "c") == 0)
X	    complement = YES;
X	else {
X unrec:
X	    prname ();
X	    fprintf (stderr, "unrecognized option: %s\n", cp);
X	    goto usage;
X	}
X    }
X    if (nsyms == 0) {
X usage:
X	fprintf (stderr, "\
XUsage: %s [-l] [-t] [-c] [[-dsym] [-usym] [-idsym] [-iusym]]... [file]\n\
X    At least one arg from [-d -u -id -iu] is required\n", progname);
X	exit (2);
X    }
X
X    if (argc > 1) {
X	prname ();
X	fprintf (stderr, "can only do one file.\n");
X    }
X    else if (argc == 1) {
X	filename = *curarg;
X	if ((input = fopen (filename, "r")) != NULL) {
X	    pfile();
X	    (void) fclose (input);
X	}
X	else {
X	    prname ();
X	    fprintf (stderr, "can't open %s\n", *curarg);
X	}
X    }
X    else {
X	filename = "[stdin]";
X	input = stdin;
X	pfile();
X    }
X
X    (void) fflush (stdout);
X    exit (exitstat);
X}
X
X/* types of input lines: */
Xtypedef int Linetype;
X#define LT_PLAIN       0   /* ordinary line */
X#define LT_TRUE        1   /* a true  #ifdef of a symbol known to us */
X#define LT_FALSE       2   /* a false #ifdef of a symbol known to us */
X#define LT_OTHER       3   /* an #ifdef of a symbol not known to us */
X#define LT_IF          4   /* an #ifdef of a symbol not known to us */
X#define LT_ELSE        5   /* #else */
X#define LT_ENDIF       6   /* #endif */
X#define LT_LEOF        7   /* end of file */
Xextern Linetype checkline ();
X
Xtypedef int Reject_level;
XReject_level reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
X#define REJ_NO          0
X#define REJ_IGNORE      1
X#define REJ_YES         2
X
Xint linenum BSS;    /* current line number */
Xint stqcline BSS;   /* start of current coment or quote */
Xchar *errs[] = {
X#define NO_ERR      0
X			"",
X#define END_ERR     1
X			"",
X#define ELSE_ERR    2
X			"Inappropriate else",
X#define ENDIF_ERR   3
X			"Inappropriate endif",
X#define IEOF_ERR    4
X			"Premature EOF in ifdef",
X#define CEOF_ERR    5
X			"Premature EOF in comment",
X#define Q1EOF_ERR   6
X			"Premature EOF in quoted character",
X#define Q2EOF_ERR   7
X			"Premature EOF in quoted string"
X};
X
X/* States for inif arg to doif */
X#define IN_NONE 0
X#define IN_IF   1
X#define IN_ELSE 2
X
Xpfile ()
X{
X    reject = REJ_NO;
X    (void) doif (-1, IN_NONE, reject, 0);
X    return;
X}
X
Xdoif (thissym, inif, prevreject, depth)
Xregister int thissym;   /* index of the symbol who was last ifdef'ed */
Xint inif;               /* YES or NO we are inside an ifdef */
XReject_level prevreject;/* previous value of reject */
Xint depth;              /* depth of ifdef's */
X{
X    register Linetype lineval;
X    register Reject_level thisreject;
X    int doret;          /* tmp return value of doif */
X    int cursym;         /* index of the symbol returned by checkline */
X    int stline;         /* line number when called this time */
X
X    stline = linenum;
X    for (;;) {
X	switch (lineval = checkline (&cursym)) {
X	case LT_PLAIN:
X	    flushline (YES);
X	    break;
X
X	case LT_TRUE:
X	case LT_FALSE:
X	    thisreject = reject;
X	    if (lineval == LT_TRUE)
X		insym[cursym] = SYM_TRUE;
X	    else {
X		if (reject != REJ_YES)
X		    reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
X		insym[cursym] = SYM_FALSE;
X	    }
X	    if (ignore[cursym])
X		flushline (YES);
X	    else {
X		exitstat = 1;
X		flushline (NO);
X	    }
X	    if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
X		return error (doret, stline, depth);
X    	    break;
X
X	case LT_IF:
X	case LT_OTHER:
X	    flushline (YES);
X	    if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
X		return error (doret, stline, depth);
X	    break;
X
X	case LT_ELSE:
X	    if (inif != IN_IF)
X		return error (ELSE_ERR, linenum, depth);
X	    inif = IN_ELSE;
X	    if (thissym >= 0) {
X		if (insym[thissym] == SYM_TRUE) {
X		    reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
X		    insym[thissym] = SYM_FALSE;
X		}
X		else { /* (insym[thissym] == SYM_FALSE) */
X		    reject = prevreject;
X		    insym[thissym] = SYM_TRUE;
X		}
X		if (!ignore[thissym]) {
X		    flushline (NO);
X		    break;
X		}
X	    }
X	    flushline (YES);
X	    break;
X
X	case LT_ENDIF:
X	    if (inif == IN_NONE)
X		return error (ENDIF_ERR, linenum, depth);
X	    if (thissym >= 0) {
X		insym[thissym] = SYM_INACTIVE;
X		reject = prevreject;
X		if (!ignore[thissym]) {
X		    flushline (NO);
X		    return NO_ERR;
X		}
X	    }
X	    flushline (YES);
X	    return NO_ERR;
X
X	case LT_LEOF: {
X	    int err;
X	    err =   incomment
X		  ? CEOF_ERR
X		  : inquote == QUOTE_SINGLE
X		  ? Q1EOF_ERR
X		  : inquote == QUOTE_DOUBLE
X		  ? Q2EOF_ERR
X		  : NO_ERR;
X	    if (inif != IN_NONE) {
X		if (err != NO_ERR)
X		    (void) error (err, stqcline, depth);
X		return error (IEOF_ERR, stline, depth);
X	    }
X	    else if (err != NO_ERR)
X		return error (err, stqcline, depth);
X	    else
X		return NO_ERR;
X	    }
X	}
X    }
X}
X
X#define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
X
X#define MAXLINE 256
Xchar tline[MAXLINE] BSS;
X
XLinetype
Xcheckline (cursym)
Xint *cursym;
X{
X    register char *cp;
X    register char *symp;
X    register char chr;
X    char *scp;
X    Linetype retval;
X    int symind;
X#   define KWSIZE 8
X    char keyword[KWSIZE];
X
X    linenum++;
X    if (getlin (tline, sizeof tline, input, NO) == EOF)
X	return LT_LEOF;
X
X    retval = LT_PLAIN;
X    if (   *(cp = tline) != '#'
X	|| incomment
X	|| inquote == QUOTE_SINGLE
X	|| inquote == QUOTE_DOUBLE
X       )
X	goto eol;
X
X    cp = skipcomment (++cp);
X    symp = keyword;
X    while (!endsym (*cp)) {
X	*symp = *cp++;
X	if (++symp >= &keyword[KWSIZE])
X	    goto eol;
X    }
X    *symp = '\0';
X
X    if (strcmp (keyword, "ifdef") == 0) {
X	retval = YES;
X	goto ifdef;
X    }
X    else if (strcmp (keyword, "ifndef") == 0) {
X	retval = NO;
X ifdef:
X	scp = cp = skipcomment (++cp);
X	if (incomment) {
X	    retval = LT_PLAIN;
X	    goto eol;
X	}
X	for (symind = 0; ; ) {
X	    if (insym[symind] == SYM_INACTIVE) {
X		for ( symp = sym[symind], cp = scp
X		    ; *symp && *cp == *symp
X		    ; cp++, symp++
X		    )
X		    continue;
X		chr = *cp;
X		if (*symp == '\0' && endsym (chr)) {
X		    *cursym = symind;
X		    retval = (retval ^ true[symind]) ? LT_FALSE : LT_TRUE;
X		    break;
X		}
X	    }
X	    if (++symind >= nsyms) {
X		retval = LT_OTHER;
X		break;
X	    }
X	}
X    }
X    else if (strcmp (keyword, "if") == 0)
X	retval = LT_IF;
X    else if (strcmp (keyword, "else") == 0)
X	retval = LT_ELSE;
X    else if (strcmp (keyword, "endif") == 0)
X	retval = LT_ENDIF;
X
X eol:
X    if (!text && reject == REJ_NO)
X	for (; *cp; ) {
X	    if (incomment)
X		cp = skipcomment (cp);
X	    else if (inquote == QUOTE_SINGLE)
X		cp = skipquote (cp, QUOTE_SINGLE);
X	    else if (inquote == QUOTE_DOUBLE)
X		cp = skipquote (cp, QUOTE_DOUBLE);
X	    else if (*cp == '/' && cp[1] == '*')
X		cp = skipcomment (cp);
X	    else if (*cp == '\'')
X		cp = skipquote (cp, QUOTE_SINGLE);
X	    else if (*cp == '"')
X		cp = skipquote (cp, QUOTE_DOUBLE);
X	    else
X		cp++;
X	}
X    return retval;
X}
X
X/*  Skip over comments and stop at the next charaacter
X/*  position that is not whitespace.
X/**/
Xchar *
Xskipcomment (cp)
Xregister char *cp;
X{
X    if (incomment)
X	goto inside;
X    for (;; cp++) {
X        while (*cp == ' ' || *cp == '\t')
X            cp++;
X	if (text)
X            return cp;
X	if (   cp[0] != '/'
X	    || cp[1] != '*'
X	   )
X            return cp;
X	cp += 2;
X	if (!incomment) {
X	    incomment = YES;
X	    stqcline = linenum;
X	}
X inside:
X	for (;;) {
X	    for (; *cp != '*'; cp++)
X		if (*cp == '\0')
X		    return cp;
X	    if (*++cp == '/')
X		break;
X	}
X	incomment = NO;
X    }
X}
X
X/*  Skip over a quoted string or character and stop at the next charaacter
X/*  position that is not whitespace.
X/**/
Xchar *
Xskipquote (cp, type)
Xregister char *cp;
Xregister int type;
X{
X    register char qchar;
X
X    qchar = type == QUOTE_SINGLE ? '\'' : '"';
X
X    if (inquote == type)
X	goto inside;
X    for (;; cp++) {
X	if (*cp != qchar)
X	    return cp;
X	cp++;
X	inquote = type;
X	stqcline = linenum;
X inside:
X	for (; ; cp++) {
X	    if (*cp == qchar)
X		break;
X	    if (   *cp == '\0'
X		|| *cp == '\\'
X		&& *++cp == '\0'
X	       )
X		return cp;
X	}
X	inquote = QUOTE_NONE;
X    }
X}
X
X/*
X/*   special getlin - treats form-feed as an end-of-line
X/*                    and expands tabs if asked for
X/*
X/**/
Xgetlin (line, maxline, inp, expandtabs)
Xregister char *line;
Xint maxline;
XFILE *inp;
Xint expandtabs;
X{
X    int tmp;
X    register int num;
X    register int chr;
X#ifdef FFSPECIAL
X    static char havechar = NO;  /* have leftover char from last time */
X    static char svchar BSS;
X#endif
X
X    num = 0;
X#ifdef FFSPECIAL
X    if (havechar) {
X	havechar = NO;
X	chr = svchar;
X	goto ent;
X    }
X#endif
X    while (num + 8 < maxline) {   /* leave room for tab */
X        chr = getc (inp);
X	if (isprint (chr)) {
X#ifdef FFSPECIAL
X ent:
X#endif
X	    *line++ = chr;
X	    num++;
X	}
X	else
X	    switch (chr) {
X	    case EOF:
X		return EOF;
X
X	    case '\t':
X		if (expandtabs) {
X		    num += tmp = 8 - (num & 7);
X		    do
X			*line++ = ' ';
X		    while (--tmp);
X		    break;
X		} 
X            default:
X                *line++ = chr;
X                num++;
X		break;
X
X	    case '\n':
X                *line = '\n';
X                num++;
X                goto end;
X    
X#ifdef FFSPECIAL
X	    case '\f':
X		if (++num == 1)
X		    *line = '\f';
X		else {
X		    *line = '\n';
X		    havechar = YES;
X                    svchar = chr;
X                }
X                goto end;
X#endif
X	    }
X    }
X end:
X    *++line = '\0';
X    return num;
X}
X
Xflushline (keep)
XBool keep;
X{
X    if ((keep && reject != REJ_YES) ^ complement)
X	putlin (tline, stdout);
X    else if (lnblank)
X	putlin ("\n", stdout);
X    return;
X}
X
X/*
X/*  putlin - for tools
X/*
X/**/
Xputlin (line, fio)
Xregister char *line;
Xregister FILE *fio;
X{
X    register char chr;
X
X    while (chr = *line++)
X	putc (chr, fio);
X    return;
X}
X
Xprname ()
X{
X    fprintf (stderr, "%s: ", progname);
X    return;
X}
X
Xint
Xerror (err, line, depth)
X{
X    if (err == END_ERR)
X	return err;
X
X    prname ();
X
X#ifndef TESTING
X    fprintf (stderr, "Error in %s line %d: %s.\n",
X	     filename, line, errs[err]);
X#endif
X
X#ifdef TESTING
X    fprintf (stderr, "Error in %s line %d: %s. ",
X	     filename, line, errs[err]);
X    fprintf (stderr, "ifdef depth: %d\n", depth);
X#endif
X
X    exitstat = 2;
X    return depth > 1 ? IEOF_ERR : END_ERR;
X}
SHAR_EOF
if test 12319 -ne "`wc -c 'unifdef.c'`"
then
	echo shar: error transmitting "'unifdef.c'" '(should have been 12319 characters)'
fi
#	End of shell archive
exit 0
-- 
The best way to have a 		Usenet: [decvax|ihnp4]!utzoo!yetti!oz
good idea is to have a 		Bitnet: oz@[yusol|yuyetti].BITNET
lot of ideas.			Phonet: [416] 736-5053 x 3976

bill@kontron.UUCP (Bill Cox) (07/29/86)

> #!/bin/sh
> # This is a shell archive, meaning:
> # 1. Remove everything above the #!/bin/sh line.
> # 2. Save the resulting text in a file.
> # 3. Execute the file with /bin/sh (not csh) to create the files:
> #	unifdef.1
> #	unifdef.c
> # This archive created: Wed Jul 23 15:32:52 1986
> export PATH; PATH=/bin:$PATH
> echo shar: extracting "'unifdef.1'" '(2591 characters)'
> if test -f 'unifdef.1'
> then
> 	echo shar: over-writing existing file "'unifdef.1'"
> fi
> sed 's/^X//' << \SHAR_EOF > 'unifdef.1'
> X.TH UNIFDEF 1 Rand
> X.SH NAME
> Xunifdef \- remove ifdef'ed lines
> X.SH SYNOPSIS
> X.B unifdef
> X[
> X.B \-t
> X.B \-l
> X.B \-c
> X.BI \-d sym
> X.BI \-u sym
> X.BI \-id sym
> X.BI \-iu sym
> X] ...  [ file ]
> X.SH DESCRIPTION
> X.I Unifdef
> Xis useful for removing ifdef'ed lines from a file while otherwise leaving the
> Xfile alone.
> X.I Unifdef
> Xis like a stripped-down C preprocessor:
> Xit is smart enough to deal with the nested ifdefs, comments,
> Xsingle and double
> Xquotes of C syntax so that it can do its job, but it doesn't do any including
> Xor interpretation of macros.
> XNeither does it strip out comments, though it recognizes and ignores them.
> X.PP
> XYou specify which symbols you want defined
> X(\fB\-d\fIsym\fR)
> Xor undefined
> X(\fB\-u\fIsym\fR)
> Xand the lines inside those ifdefs will be copied to the output or removed as
> Xappropriate.
> XThe ifdef, ifndef, else, and endif lines associated with
> X.I sym
> Xwill also be removed.
> XIfdefs involving symbols you don't specify
> Xand ``#if'' control lines
> Xare untouched and copied out
> Xalong with their associated
> Xifdef, else, and endif lines.
> XIf an ifdef X occurs nested inside another ifdef X, then the
> Xinside ifdef is treated as if it were an unrecognized symbol.
> XIf the same symbol appears in more than one argument, only the first
> Xoccurrence is significant.
> X.PP
> XThe
> X.B \-l
> Xoption causes
> X.I unifdef
> Xto replace removed lines with blank lines
> Xinstead of deleting them.
> X.PP
> XIf you use ifdefs to delimit non-C lines, such as comments
> Xor code which is under construction,
> Xthen you must tell
> X.I unifdef
> Xwhich symbols are used for that purpose so that it won't try to parse
> Xfor quotes and comments
> Xin those ifdef'ed lines.
> XYou specify that you want the lines inside certain ifdefs to be ignored
> Xbut copied out with
> X.BI \-id sym
> Xand
> X.BI \-iu sym
> Xsimilar to
> X.BI \-d sym
> Xand
> X.BI \-u sym
> Xabove.
> X.PP
> XIf you want to use
> X.I unifdef
> Xfor plain text (not C code), use the
> X.B \-t
> Xoption.
> XThis makes
> X.I unifdef
> Xrefrain from attempting to recognize comments and single and double quotes.
> X.PP
> X.I Unifdef
> Xcopies its output to
> X.I stdout
> Xand will take its input from
> X.I stdin
> Xif no
> X.I file
> Xargument is given.
> XIf the
> X.B \-c
> Xargument is specified, then the operation of
> X.I unifdef
> Xis complemented,
> Xi.e. the lines that would have been removed or blanked
> Xare retained and vice versa.
> X.PP
> X.I Unifdef
> Xworks nicely with the
> X.BI \-i sym
> Xoption recently added to
> X.I diff
> Xat Rand.
> X.SH "SEE ALSO"
> Xdiff(1)
> X.SH DIAGNOSTICS
> XPremature EOF, inappropriate else or endif.
> X.PP
> XExit status is 0 if output is exact copy of input, 1 if not, 2 if trouble.
> X.SH AUTHOR
> XDave Yost, The Rand Corporation
> X.SH BUGS
> XShould try to deal with ``#if'' lines.
> SHAR_EOF
> if test 2591 -ne "`wc -c 'unifdef.1'`"
> then
> 	echo shar: error transmitting "'unifdef.1'" '(should have been 2591 characters)'
> fi
> echo shar: extracting "'unifdef.c'" '(12319 characters)'
> if test -f 'unifdef.c'
> then
> 	echo shar: over-writing existing file "'unifdef.c'"
> fi
> sed 's/^X//' << \SHAR_EOF > 'unifdef.c'
> X#ifdef COMMENT
> X
> X    unifdef - remove ifdef'ed lines
> X
> X    Wishlist:
> X	provide an option which will append the name of the
> X	  appropriate symbol after #else's and #endif's
> X	provide an option which will check symbols after
> X	  #else's and #endif's to see that they match their
> X	  corresponding #ifdef or #ifndef
> X
> X#endif
> X
> X#include <stdio.h>
> X#include <ctype.h>
> X#include <c_env.h>
> X
> X#define BSS
> XFILE *input;
> X#ifndef YES
> X#define YES 1
> X#define NO  0
> X#endif
> Xtypedef int Bool;
> X
> Xchar *progname BSS;
> Xchar *filename BSS;
> Xchar text BSS;          /* -t option in effect: this is a text file */
> Xchar lnblank BSS;       /* -l option in effect: blank deleted lines */
> Xchar complement BSS;    /* -c option in effect: complement the operation */
> X
> X#define MAXSYMS 100
> Xchar *sym[MAXSYMS] BSS;     /* symbol name */
> Xchar true[MAXSYMS] BSS;     /* -dsym */
> Xchar ignore[MAXSYMS] BSS;   /* -idsym or -iusym */
> Xchar insym[MAXSYMS] BSS;    /* state: false, inactive, true */
> X#define SYM_INACTIVE 0      /* symbol is currently inactive */
> X#define SYM_FALSE    1      /* symbol is currently false */
> X#define SYM_TRUE     2      /* symbol is currently true  */
> X
> Xchar nsyms BSS;
> Xchar incomment BSS;         /* inside C comment */
> X
> X#define QUOTE_NONE   0
> X#define QUOTE_SINGLE 1
> X#define QUOTE_DOUBLE 2
> Xchar inquote BSS;           /* inside single or double quotes */
> X
> Xint exitstat BSS;
> Xchar *skipcomment ();
> Xchar *skipquote ();
> X
> Xmain (argc, argv)
> Xint argc;
> Xchar **argv;
> X{
> X    char **curarg;
> X    register char *cp;
> X    register char *cp1;
> X    char ignorethis;
> X
> X    progname = argv[0][0] ? argv[0] : "unifdef";
> X
> X    for (curarg = &argv[1]; --argc > 0; curarg++) {
> X	if (*(cp1 = cp = *curarg) != '-')
> X	    break;
> X	if (*++cp1 == 'i') {
> X	    ignorethis = YES;
> X	    cp1++;
> X	}
> X	else
> X	    ignorethis = NO;
> X	if (   (   *cp1 == 'd'
> X		|| *cp1 == 'u'
> X	       )
> X	    && cp1[1] != '\0'
> X	   ) {
> X	    if (nsyms >= MAXSYMS) {
> X		prname ();
> X		fprintf (stderr, "too many symbols.\n");
> X		exit (2);
> X	    }
> X	    insym[nsyms] = SYM_INACTIVE;
> X	    ignore[nsyms] = ignorethis;
> X	    true[nsyms] = *cp1 == 'd' ? YES : NO;
> X	    sym[nsyms++] = &cp1[1];
> X	}
> X	else if (ignorethis)
> X	    goto unrec;
> X	else if (strcmp (&cp[1], "t") == 0)
> X	    text = YES;
> X	else if (strcmp (&cp[1], "l") == 0)
> X	    lnblank = YES;
> X	else if (strcmp (&cp[1], "c") == 0)
> X	    complement = YES;
> X	else {
> X unrec:
> X	    prname ();
> X	    fprintf (stderr, "unrecognized option: %s\n", cp);
> X	    goto usage;
> X	}
> X    }
> X    if (nsyms == 0) {
> X usage:
> X	fprintf (stderr, "\
> XUsage: %s [-l] [-t] [-c] [[-dsym] [-usym] [-idsym] [-iusym]]... [file]\n\
> X    At least one arg from [-d -u -id -iu] is required\n", progname);
> X	exit (2);
> X    }
> X
> X    if (argc > 1) {
> X	prname ();
> X	fprintf (stderr, "can only do one file.\n");
> X    }
> X    else if (argc == 1) {
> X	filename = *curarg;
> X	if ((input = fopen (filename, "r")) != NULL) {
> X	    pfile();
> X	    (void) fclose (input);
> X	}
> X	else {
> X	    prname ();
> X	    fprintf (stderr, "can't open %s\n", *curarg);
> X	}
> X    }
> X    else {
> X	filename = "[stdin]";
> X	input = stdin;
> X	pfile();
> X    }
> X
> X    (void) fflush (stdout);
> X    exit (exitstat);
> X}
> X
> X/* types of input lines: */
> Xtypedef int Linetype;
> X#define LT_PLAIN       0   /* ordinary line */
> X#define LT_TRUE        1   /* a true  #ifdef of a symbol known to us */
> X#define LT_FALSE       2   /* a false #ifdef of a symbol known to us */
> X#define LT_OTHER       3   /* an #ifdef of a symbol not known to us */
> X#define LT_IF          4   /* an #ifdef of a symbol not known to us */
> X#define LT_ELSE        5   /* #else */
> X#define LT_ENDIF       6   /* #endif */
> X#define LT_LEOF        7   /* end of file */
> Xextern Linetype checkline ();
> X
> Xtypedef int Reject_level;
> XReject_level reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
> X#define REJ_NO          0
> X#define REJ_IGNORE      1
> X#define REJ_YES         2
> X
> Xint linenum BSS;    /* current line number */
> Xint stqcline BSS;   /* start of current coment or quote */
> Xchar *errs[] = {
> X#define NO_ERR      0
> X			"",
> X#define END_ERR     1
> X			"",
> X#define ELSE_ERR    2
> X			"Inappropriate else",
> X#define ENDIF_ERR   3
> X			"Inappropriate endif",
> X#define IEOF_ERR    4
> X			"Premature EOF in ifdef",
> X#define CEOF_ERR    5
> X			"Premature EOF in comment",
> X#define Q1EOF_ERR   6
> X			"Premature EOF in quoted character",
> X#define Q2EOF_ERR   7
> X			"Premature EOF in quoted string"
> X};
> X
> X/* States for inif arg to doif */
> X#define IN_NONE 0
> X#define IN_IF   1
> X#define IN_ELSE 2
> X
> Xpfile ()
> X{
> X    reject = REJ_NO;
> X    (void) doif (-1, IN_NONE, reject, 0);
> X    return;
> X}
> X
> Xdoif (thissym, inif, prevreject, depth)
> Xregister int thissym;   /* index of the symbol who was last ifdef'ed */
> Xint inif;               /* YES or NO we are inside an ifdef */
> XReject_level prevreject;/* previous value of reject */
> Xint depth;              /* depth of ifdef's */
> X{
> X    register Linetype lineval;
> X    register Reject_level thisreject;
> X    int doret;          /* tmp return value of doif */
> X    int cursym;         /* index of the symbol returned by checkline */
> X    int stline;         /* line number when called this time */
> X
> X    stline = linenum;
> X    for (;;) {
> X	switch (lineval = checkline (&cursym)) {
> X	case LT_PLAIN:
> X	    flushline (YES);
> X	    break;
> X
> X	case LT_TRUE:
> X	case LT_FALSE:
> X	    thisreject = reject;
> X	    if (lineval == LT_TRUE)
> X		insym[cursym] = SYM_TRUE;
> X	    else {
> X		if (reject != REJ_YES)
> X		    reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
> X		insym[cursym] = SYM_FALSE;
> X	    }
> X	    if (ignore[cursym])
> X		flushline (YES);
> X	    else {
> X		exitstat = 1;
> X		flushline (NO);
> X	    }
> X	    if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
> X		return error (doret, stline, depth);
> X    	    break;
> X
> X	case LT_IF:
> X	case LT_OTHER:
> X	    flushline (YES);
> X	    if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
> X		return error (doret, stline, depth);
> X	    break;
> X
> X	case LT_ELSE:
> X	    if (inif != IN_IF)
> X		return error (ELSE_ERR, linenum, depth);
> X	    inif = IN_ELSE;
> X	    if (thissym >= 0) {
> X		if (insym[thissym] == SYM_TRUE) {
> X		    reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
> X		    insym[thissym] = SYM_FALSE;
> X		}
> X		else { /* (insym[thissym] == SYM_FALSE) */
> X		    reject = prevreject;
> X		    insym[thissym] = SYM_TRUE;
> X		}
> X		if (!ignore[thissym]) {
> X		    flushline (NO);
> X		    break;
> X		}
> X	    }
> X	    flushline (YES);
> X	    break;
> X
> X	case LT_ENDIF:
> X	    if (inif == IN_NONE)
> X		return error (ENDIF_ERR, linenum, depth);
> X	    if (thissym >= 0) {
> X		insym[thissym] = SYM_INACTIVE;
> X		reject = prevreject;
> X		if (!ignore[thissym]) {
> X		    flushline (NO);
> X		    return NO_ERR;
> X		}
> X	    }
> X	    flushline (YES);
> X	    return NO_ERR;
> X
> X	case LT_LEOF: {
> X	    int err;
> X	    err =   incomment
> X		  ? CEOF_ERR
> X		  : inquote == QUOTE_SINGLE
> X		  ? Q1EOF_ERR
> X		  : inquote == QUOTE_DOUBLE
> X		  ? Q2EOF_ERR
> X		  : NO_ERR;
> X	    if (inif != IN_NONE) {
> X		if (err != NO_ERR)
> X		    (void) error (err, stqcline, depth);
> X		return error (IEOF_ERR, stline, depth);
> X	    }
> X	    else if (err != NO_ERR)
> X		return error (err, stqcline, depth);
> X	    else
> X		return NO_ERR;
> X	    }
> X	}
> X    }
> X}
> X
> X#define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
> X
> X#define MAXLINE 256
> Xchar tline[MAXLINE] BSS;
> X
> XLinetype
> Xcheckline (cursym)
> Xint *cursym;
> X{
> X    register char *cp;
> X    register char *symp;
> X    register char chr;
> X    char *scp;
> X    Linetype retval;
> X    int symind;
> X#   define KWSIZE 8
> X    char keyword[KWSIZE];
> X
> X    linenum++;
> X    if (getlin (tline, sizeof tline, input, NO) == EOF)
> X	return LT_LEOF;
> X
> X    retval = LT_PLAIN;
> X    if (   *(cp = tline) != '#'
> X	|| incomment
> X	|| inquote == QUOTE_SINGLE
> X	|| inquote == QUOTE_DOUBLE
> X       )
> X	goto eol;
> X
> X    cp = skipcomment (++cp);
> X    symp = keyword;
> X    while (!endsym (*cp)) {
> X	*symp = *cp++;
> X	if (++symp >= &keyword[KWSIZE])
> X	    goto eol;
> X    }
> X    *symp = '\0';
> X
> X    if (strcmp (keyword, "ifdef") == 0) {
> X	retval = YES;
> X	goto ifdef;
> X    }
> X    else if (strcmp (keyword, "ifndef") == 0) {
> X	retval = NO;
> X ifdef:
> X	scp = cp = skipcomment (++cp);
> X	if (incomment) {
> X	    retval = LT_PLAIN;
> X	    goto eol;
> X	}
> X	for (symind = 0; ; ) {
> X	    if (insym[symind] == SYM_INACTIVE) {
> X		for ( symp = sym[symind], cp = scp
> X		    ; *symp && *cp == *symp
> X		    ; cp++, symp++
> X		    )
> X		    continue;
> X		chr = *cp;
> X		if (*symp == '\0' && endsym (chr)) {
> X		    *cursym = symind;
> X		    retval = (retval ^ true[symind]) ? LT_FALSE : LT_TRUE;
> X		    break;
> X		}
> X	    }
> X	    if (++symind >= nsyms) {
> X		retval = LT_OTHER;
> X		break;
> X	    }
> X	}
> X    }
> X    else if (strcmp (keyword, "if") == 0)
> X	retval = LT_IF;
> X    else if (strcmp (keyword, "else") == 0)
> X	retval = LT_ELSE;
> X    else if (strcmp (keyword, "endif") == 0)
> X	retval = LT_ENDIF;
> X
> X eol:
> X    if (!text && reject == REJ_NO)
> X	for (; *cp; ) {
> X	    if (incomment)
> X		cp = skipcomment (cp);
> X	    else if (inquote == QUOTE_SINGLE)
> X		cp = skipquote (cp, QUOTE_SINGLE);
> X	    else if (inquote == QUOTE_DOUBLE)
> X		cp = skipquote (cp, QUOTE_DOUBLE);
> X	    else if (*cp == '/' && cp[1] == '*')
> X		cp = skipcomment (cp);
> X	    else if (*cp == '\'')
> X		cp = skipquote (cp, QUOTE_SINGLE);
> X	    else if (*cp == '"')
> X		cp = skipquote (cp, QUOTE_DOUBLE);
> X	    else
> X		cp++;
> X	}
> X    return retval;
> X}
> X
> X/*  Skip over comments and stop at the next charaacter
> X/*  position that is not whitespace.
> X/**/
> Xchar *
> Xskipcomment (cp)
> Xregister char *cp;
> X{
> X    if (incomment)
> X	goto inside;
> X    for (;; cp++) {
> X        while (*cp == ' ' || *cp == '\t')
> X            cp++;
> X	if (text)
> X            return cp;
> X	if (   cp[0] != '/'
> X	    || cp[1] != '*'
> X	   )
> X            return cp;
> X	cp += 2;
> X	if (!incomment) {
> X	    incomment = YES;
> X	    stqcline = linenum;
> X	}
> X inside:
> X	for (;;) {
> X	    for (; *cp != '*'; cp++)
> X		if (*cp == '\0')
> X		    return cp;
> X	    if (*++cp == '/')
> X		break;
> X	}
> X	incomment = NO;
> X    }
> X}
> X
> X/*  Skip over a quoted string or character and stop at the next charaacter
> X/*  position that is not whitespace.
> X/**/
> Xchar *
> Xskipquote (cp, type)
> Xregister char *cp;
> Xregister int type;
> X{
> X    register char qchar;
> X
> X    qchar = type == QUOTE_SINGLE ? '\'' : '"';
> X
> X    if (inquote == type)
> X	goto inside;
> X    for (;; cp++) {
> X	if (*cp != qchar)
> X	    return cp;
> X	cp++;
> X	inquote = type;
> X	stqcline = linenum;
> X inside:
> X	for (; ; cp++) {
> X	    if (*cp == qchar)
> X		break;
> X	    if (   *cp == '\0'
> X		|| *cp == '\\'
> X		&& *++cp == '\0'
> X	       )
> X		return cp;
> X	}
> X	inquote = QUOTE_NONE;
> X    }
> X}
> X
> X/*
> X/*   special getlin - treats form-feed as an end-of-line
> X/*                    and expands tabs if asked for
> X/*
> X/**/
> Xgetlin (line, maxline, inp, expandtabs)
> Xregister char *line;
> Xint maxline;
> XFILE *inp;
> Xint expandtabs;
> X{
> X    int tmp;
> X    register int num;
> X    register int chr;
> X#ifdef FFSPECIAL
> X    static char havechar = NO;  /* have leftover char from last time */
> X    static char svchar BSS;
> X#endif
> X
> X    num = 0;
> X#ifdef FFSPECIAL
> X    if (havechar) {
> X	havechar = NO;
> X	chr = svchar;
> X	goto ent;
> X    }
> X#endif
> X    while (num + 8 < maxline) {   /* leave room for tab */
> X        chr = getc (inp);
> X	if (isprint (chr)) {
> X#ifdef FFSPECIAL
> X ent:
> X#endif
> X	    *line++ = chr;
> X	    num++;
> X	}
> X	else
> X	    switch (chr) {
> X	    case EOF:
> X		return EOF;
> X
> X	    case '\t':
> X		if (expandtabs) {
> X		    num += tmp = 8 - (num & 7);
> X		    do
> X			*line++ = ' ';
> X		    while (--tmp);
> X		    break;
> X		} 
> X            default:
> X                *line++ = chr;
> X                num++;
> X		break;
> X
> X	    case '\n':
> X                *line = '\n';
> X                num++;
> X                goto end;
> X    
> X#ifdef FFSPECIAL
> X	    case '\f':
> X		if (++num == 1)
> X		    *line = '\f';
> X		else {
> X		    *line = '\n';
> X		    havechar = YES;
> X                    svchar = chr;
> X                }
> X                goto end;
> X#endif
> X	    }
> X    }
> X end:
> X    *++line = '\0';
> X    return num;
> X}
> X
> Xflushline (keep)
> XBool keep;
> X{
> X    if ((keep && reject != REJ_YES) ^ complement)
> X	putlin (tline, stdout);
> X    else if (lnblank)
> X	putlin ("\n", stdout);
> X    return;
> X}
> X
> X/*
> X/*  putlin - for tools
> X/*
> X/**/
> Xputlin (line, fio)
> Xregister char *line;
> Xregister FILE *fio;
> X{
> X    register char chr;
> X
> X    while (chr = *line++)
> X	putc (chr, fio);
> X    return;
> X}
> X
> Xprname ()
> X{
> X    fprintf (stderr, "%s: ", progname);
> X    return;
> X}
> X
> Xint
> Xerror (err, line, depth)
> X{
> X    if (err == END_ERR)
> X	return err;
> X
> X    prname ();
> X
> X#ifndef TESTING
> X    fprintf (stderr, "Error in %s line %d: %s.\n",
> X	     filename, line, errs[err]);
> X#endif
> X
> X#ifdef TESTING
> X    fprintf (stderr, "Error in %s line %d: %s. ",
> X	     filename, line, errs[err]);
> X    fprintf (stderr, "ifdef depth: %d\n", depth);
> X#endif
> X
> X    exitstat = 2;
> X    return depth > 1 ? IEOF_ERR : END_ERR;
> X}
> SHAR_EOF
> if test 12319 -ne "`wc -c 'unifdef.c'`"
> then
> 	echo shar: error transmitting "'unifdef.c'" '(should have been 12319 characters)'
> fi
> #	End of shell archive
> exit 0
> -- 
> The best way to have a 		Usenet: [decvax|ihnp4]!utzoo!yetti!oz
> good idea is to have a 		Bitnet: oz@[yusol|yuyetti].BITNET
> lot of ideas.			Phonet: [416] 736-5053 x 3976

*** REPLACE THIS LINE WITH YOUR MESSAGE ***