summaryrefslogtreecommitdiff
path: root/usr.bin/unifdef
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/unifdef
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/unifdef')
-rw-r--r--usr.bin/unifdef/Makefile6
-rw-r--r--usr.bin/unifdef/unifdef.1167
-rw-r--r--usr.bin/unifdef/unifdef.c654
3 files changed, 827 insertions, 0 deletions
diff --git a/usr.bin/unifdef/Makefile b/usr.bin/unifdef/Makefile
new file mode 100644
index 00000000000..88450d25a3d
--- /dev/null
+++ b/usr.bin/unifdef/Makefile
@@ -0,0 +1,6 @@
+# $NetBSD: Makefile,v 1.3 1994/12/07 00:33:47 jtc Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= unifdef
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/unifdef/unifdef.1 b/usr.bin/unifdef/unifdef.1
new file mode 100644
index 00000000000..3e862297258
--- /dev/null
+++ b/usr.bin/unifdef/unifdef.1
@@ -0,0 +1,167 @@
+.\" $NetBSD: unifdef.1,v 1.4 1994/12/07 00:33:48 jtc Exp $
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Dave Yost.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)unifdef.1 8.2 (Berkeley) 4/1/94
+.\"
+.Dd April 1, 1994
+.Dt UNIFDEF 1
+.Os BSD 4.3
+.Sh NAME
+.Nm unifdef
+.Nd remove ifdef'ed lines
+.Sh SYNOPSIS
+.Nm unifdef
+.Op Fl clt
+.Oo
+.Fl D Ns Ar sym
+.Fl U Ns Ar sym
+.Fl iD Ns Ar sym
+.Fl iD Ns Ar sym
+.Oc
+.Ar ...
+.Op Ar file
+.Sh DESCRIPTION
+.Nm Unifdef
+is useful for removing ifdef'ed lines
+from a file while otherwise leaving the file alone.
+.Nm Unifdef
+acts on
+#ifdef, #ifndef, #else, and #endif lines,
+and it knows only enough about C
+to know when one of these is inactive
+because it is inside
+a comment,
+or a single or double quote.
+Parsing for quotes is very simplistic:
+when it finds an open quote,
+it ignores everything (except escaped quotes)
+until it finds a close quote, and
+it will not complain if it gets
+to the end of a line and finds no backslash for continuation.
+.Pp
+Available options:
+.Bl -tag -width Ds -compact
+.It Fl D Ns Ar sym
+.It Fl U Ns Ar sym
+Specify which symbols to define or undefine.
+and the lines inside those ifdefs will be copied to the output or removed as
+appropriate.
+The ifdef, ifndef, else, and endif lines associated with
+.Ar sym
+will also be removed.
+Ifdefs involving symbols you don't specify
+and ``#if'' control lines
+are untouched and copied out
+along with their associated
+ifdef, else, and endif lines.
+If an ifdef X occurs nested inside another ifdef X, then the
+inside ifdef is treated as if it were an unrecognized symbol.
+If the same symbol appears in more than one argument,
+the last occurrence dominates.
+.Pp
+.It Fl c
+If the
+.Fl c
+flag is specified,
+then the operation of
+.Nm unifdef
+is complemented,
+i.e. the lines that would have been removed or blanked
+are retained and vice versa.
+.Pp
+.It Fl l
+Replace removed lines with blank lines
+instead of deleting them.
+.It Fl t
+Disables parsing for C comments and quotes, which is useful
+for plain text.
+.Pp
+.It Fl iD Ns Ar sym
+.It Fl iU Ns Ar sym
+Ignore ifdefs.
+If your C code uses ifdefs to delimit non-C lines,
+such as comments
+or code which is under construction,
+then you must tell
+.Nm unifdef
+which symbols are used for that purpose so that it won't try to parse
+for quotes and comments
+inside those ifdefs.
+One specifies ignored ifdefs with
+.Fl iD Ns Ar sym
+and
+.Fl iU Ns Ar sym
+similar to
+.Fl D Ns Ar sym
+and
+.Fl U Ns Ar sym
+above.
+.El
+.Pp
+.Nm Unifdef
+copies its output to
+.Em stdout
+and will take its input from
+.Em stdin
+if no
+.Ar file
+argument is given.
+.Pp
+.Nm Unifdef
+works nicely with the
+.Fl D Ns Ar sym
+option added to
+.Xr diff 1
+as of the 4.1 Berkeley Software Distribution.
+.Sh SEE ALSO
+.Xr diff 1
+.Sh DIAGNOSTICS
+Inappropriate else or endif.
+.br
+Premature
+.Tn EOF
+with line numbers of the unterminated #ifdefs.
+.Pp
+Exit status is 0 if output is exact copy of input, 1 if not, 2 if trouble.
+.Sh BUGS
+Should try to deal with ``#if'' lines.
+.Pp
+Doesn't work correctly if input contains null characters.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.bin/unifdef/unifdef.c b/usr.bin/unifdef/unifdef.c
new file mode 100644
index 00000000000..8b331b72890
--- /dev/null
+++ b/usr.bin/unifdef/unifdef.c
@@ -0,0 +1,654 @@
+/* $NetBSD: unifdef.c,v 1.4 1994/12/20 01:44:07 jtc Exp $ */
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dave Yost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)unifdef.c 8.1 (Berkeley) 6/6/93";
+#endif
+static char rcsid[] = "$NetBSD: unifdef.c,v 1.4 1994/12/20 01:44:07 jtc Exp $";
+#endif /* not lint */
+
+/*
+ * unifdef - remove ifdef'ed lines
+ *
+ * Warning: will not work correctly if input contains null characters.
+ *
+ * Wishlist:
+ * provide an option which will append the name of the
+ * appropriate symbol after #else's and #endif's
+ * provide an option which will check symbols after
+ * #else's and #endif's to see that they match their
+ * corresponding #ifdef or #ifndef
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#define BSS
+FILE *input;
+#ifndef YES
+#define YES 1
+#define NO 0
+#endif/*YES */
+typedef int Bool;
+
+char *progname BSS;
+char *filename BSS;
+char text BSS; /* -t option in effect: this is a text file */
+char lnblank BSS; /* -l option in effect: blank deleted lines */
+char complement BSS; /* -c option in effect: complement the operation */
+
+#define MAXSYMS 100
+char *symname[MAXSYMS] BSS; /* symbol name */
+char true[MAXSYMS] BSS; /* -Dsym */
+char ignore[MAXSYMS] BSS; /* -iDsym or -iUsym */
+char insym[MAXSYMS] BSS; /* state: false, inactive, true */
+#define SYM_INACTIVE 0 /* symbol is currently inactive */
+#define SYM_FALSE 1 /* symbol is currently false */
+#define SYM_TRUE 2 /* symbol is currently true */
+
+char nsyms BSS;
+char incomment BSS; /* inside C comment */
+
+#define QUOTE_NONE 0
+#define QUOTE_SINGLE 1
+#define QUOTE_DOUBLE 2
+char inquote BSS; /* inside single or double quotes */
+int exitstat BSS;
+
+int error __P((int, int, int));
+int findsym __P((char *));
+void flushline __P((Bool));
+int getlin __P((char *, int, FILE *, int));
+void pfile __P((void));
+void prname __P((void));
+char *skipcomment __P((char *));
+char *skipquote __P((char *, int));
+
+int
+main (argc, argv)
+int argc;
+char **argv;
+{
+ char **curarg;
+ register char *cp;
+ register char *cp1;
+ char ignorethis;
+
+ progname = argv[0][0] ? argv[0] : "unifdef";
+
+ for (curarg = &argv[1]; --argc > 0; curarg++) {
+ if (*(cp1 = cp = *curarg) != '-')
+ break;
+ if (*++cp1 == 'i') {
+ ignorethis = YES;
+ cp1++;
+ } else
+ ignorethis = NO;
+ if ( ( *cp1 == 'D'
+ || *cp1 == 'U'
+ )
+ && cp1[1] != '\0'
+ ) {
+ register int symind;
+
+ if ((symind = findsym (&cp1[1])) < 0) {
+ if (nsyms >= MAXSYMS) {
+ prname ();
+ fprintf (stderr, "too many symbols.\n");
+ exit (2);
+ }
+ symind = nsyms++;
+ symname[symind] = &cp1[1];
+ insym[symind] = SYM_INACTIVE;
+ }
+ ignore[symind] = ignorethis;
+ true[symind] = *cp1 == 'D' ? YES : NO;
+ } else if (ignorethis)
+ goto unrec;
+ else if (strcmp (&cp[1], "t") == 0)
+ text = YES;
+ else if (strcmp (&cp[1], "l") == 0)
+ lnblank = YES;
+ else if (strcmp (&cp[1], "c") == 0)
+ complement = YES;
+ else {
+ unrec:
+ prname ();
+ fprintf (stderr, "unrecognized option: %s\n", cp);
+ goto usage;
+ }
+ }
+ if (nsyms == 0) {
+ usage:
+ fprintf (stderr, "\
+Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]]... [file]\n\
+ At least one arg from [-D -U -iD -iU] is required\n", progname);
+ exit (2);
+ }
+
+ if (argc > 1) {
+ prname ();
+ fprintf (stderr, "can only do one file.\n");
+ } else if (argc == 1) {
+ filename = *curarg;
+ if ((input = fopen (filename, "r")) != NULL) {
+ pfile();
+ (void) fclose (input);
+ } else {
+ prname ();
+ fprintf (stderr, "can't open ");
+ perror(*curarg);
+ }
+ } else {
+ filename = "[stdin]";
+ input = stdin;
+ pfile();
+ }
+
+ (void) fflush (stdout);
+ exit (exitstat);
+}
+
+/* types of input lines: */
+typedef int Linetype;
+#define LT_PLAIN 0 /* ordinary line */
+#define LT_TRUE 1 /* a true #ifdef of a symbol known to us */
+#define LT_FALSE 2 /* a false #ifdef of a symbol known to us */
+#define LT_OTHER 3 /* an #ifdef of a symbol not known to us */
+#define LT_IF 4 /* an #ifdef of a symbol not known to us */
+#define LT_ELSE 5 /* #else */
+#define LT_ENDIF 6 /* #endif */
+#define LT_LEOF 7 /* end of file */
+Linetype checkline __P((int *));
+
+typedef int Reject_level;
+Reject_level reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */
+#define REJ_NO 0
+#define REJ_IGNORE 1
+#define REJ_YES 2
+int doif __P((int, int, Reject_level, int));
+
+int linenum BSS; /* current line number */
+int stqcline BSS; /* start of current coment or quote */
+char *errs[] = {
+#define NO_ERR 0
+ "",
+#define END_ERR 1
+ "",
+#define ELSE_ERR 2
+ "Inappropriate else",
+#define ENDIF_ERR 3
+ "Inappropriate endif",
+#define IEOF_ERR 4
+ "Premature EOF in ifdef",
+#define CEOF_ERR 5
+ "Premature EOF in comment",
+#define Q1EOF_ERR 6
+ "Premature EOF in quoted character",
+#define Q2EOF_ERR 7
+ "Premature EOF in quoted string"
+};
+
+/* States for inif arg to doif */
+#define IN_NONE 0
+#define IN_IF 1
+#define IN_ELSE 2
+
+void
+pfile ()
+{
+ reject = REJ_NO;
+ (void) doif (-1, IN_NONE, reject, 0);
+ return;
+}
+
+int
+doif (thissym, inif, prevreject, depth)
+register int thissym; /* index of the symbol who was last ifdef'ed */
+int inif; /* YES or NO we are inside an ifdef */
+Reject_level prevreject;/* previous value of reject */
+int depth; /* depth of ifdef's */
+{
+ register Linetype lineval;
+ register Reject_level thisreject;
+ int doret; /* tmp return value of doif */
+ int cursym; /* index of the symbol returned by checkline */
+ int stline; /* line number when called this time */
+
+ stline = linenum;
+ for (;;) {
+ switch (lineval = checkline (&cursym)) {
+ case LT_PLAIN:
+ flushline (YES);
+ break;
+
+ case LT_TRUE:
+ case LT_FALSE:
+ thisreject = reject;
+ if (lineval == LT_TRUE)
+ insym[cursym] = SYM_TRUE;
+ else {
+ if (reject != REJ_YES)
+ reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
+ insym[cursym] = SYM_FALSE;
+ }
+ if (ignore[cursym])
+ flushline (YES);
+ else {
+ exitstat = 1;
+ flushline (NO);
+ }
+ if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
+ return error (doret, stline, depth);
+ break;
+
+ case LT_IF:
+ case LT_OTHER:
+ flushline (YES);
+ if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
+ return error (doret, stline, depth);
+ break;
+
+ case LT_ELSE:
+ if (inif != IN_IF)
+ return error (ELSE_ERR, linenum, depth);
+ inif = IN_ELSE;
+ if (thissym >= 0) {
+ if (insym[thissym] == SYM_TRUE) {
+ reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
+ insym[thissym] = SYM_FALSE;
+ } else { /* (insym[thissym] == SYM_FALSE) */
+ reject = prevreject;
+ insym[thissym] = SYM_TRUE;
+ }
+ if (!ignore[thissym]) {
+ flushline (NO);
+ break;
+ }
+ }
+ flushline (YES);
+ break;
+
+ case LT_ENDIF:
+ if (inif == IN_NONE)
+ return error (ENDIF_ERR, linenum, depth);
+ if (thissym >= 0) {
+ insym[thissym] = SYM_INACTIVE;
+ reject = prevreject;
+ if (!ignore[thissym]) {
+ flushline (NO);
+ return NO_ERR;
+ }
+ }
+ flushline (YES);
+ return NO_ERR;
+
+ case LT_LEOF: {
+ int err;
+ err = incomment
+ ? CEOF_ERR
+ : inquote == QUOTE_SINGLE
+ ? Q1EOF_ERR
+ : inquote == QUOTE_DOUBLE
+ ? Q2EOF_ERR
+ : NO_ERR;
+ if (inif != IN_NONE) {
+ if (err != NO_ERR)
+ (void) error (err, stqcline, depth);
+ return error (IEOF_ERR, stline, depth);
+ } else if (err != NO_ERR)
+ return error (err, stqcline, depth);
+ else
+ return NO_ERR;
+ }
+ }
+ }
+}
+
+#define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
+
+#define MAXLINE 256
+char tline[MAXLINE] BSS;
+
+Linetype
+checkline (cursym)
+int *cursym; /* if LT_TRUE or LT_FALSE returned, set this to sym index */
+{
+ register char *cp;
+ register char *symp;
+ char *scp;
+ Linetype retval;
+# define KWSIZE 8
+ char keyword[KWSIZE];
+
+ linenum++;
+ if (getlin (tline, sizeof tline, input, NO) == EOF)
+ return LT_LEOF;
+
+ retval = LT_PLAIN;
+ if ( *(cp = tline) != '#'
+ || incomment
+ || inquote == QUOTE_SINGLE
+ || inquote == QUOTE_DOUBLE
+ )
+ goto eol;
+
+ cp = skipcomment (++cp);
+ symp = keyword;
+ while (!endsym (*cp)) {
+ *symp = *cp++;
+ if (++symp >= &keyword[KWSIZE])
+ goto eol;
+ }
+ *symp = '\0';
+
+ if (strcmp (keyword, "ifdef") == 0) {
+ retval = YES;
+ goto ifdef;
+ } else if (strcmp (keyword, "ifndef") == 0) {
+ retval = NO;
+ ifdef:
+ scp = cp = skipcomment (++cp);
+ if (incomment) {
+ retval = LT_PLAIN;
+ goto eol;
+ }
+ {
+ int symind;
+
+ if ((symind = findsym (scp)) >= 0)
+ retval = (retval ^ true[*cursym = symind])
+ ? LT_FALSE : LT_TRUE;
+ else
+ retval = LT_OTHER;
+ }
+ } else if (strcmp (keyword, "if") == 0)
+ retval = LT_IF;
+ else if (strcmp (keyword, "else") == 0)
+ retval = LT_ELSE;
+ else if (strcmp (keyword, "endif") == 0)
+ retval = LT_ENDIF;
+
+ eol:
+ if (!text && reject != REJ_IGNORE)
+ for (; *cp; ) {
+ if (incomment)
+ cp = skipcomment (cp);
+ else if (inquote == QUOTE_SINGLE)
+ cp = skipquote (cp, QUOTE_SINGLE);
+ else if (inquote == QUOTE_DOUBLE)
+ cp = skipquote (cp, QUOTE_DOUBLE);
+ else if (*cp == '/' && cp[1] == '*')
+ cp = skipcomment (cp);
+ else if (*cp == '\'')
+ cp = skipquote (cp, QUOTE_SINGLE);
+ else if (*cp == '"')
+ cp = skipquote (cp, QUOTE_DOUBLE);
+ else
+ cp++;
+ }
+ return retval;
+}
+
+/*
+ * Skip over comments and stop at the next charaacter
+ * position that is not whitespace.
+ */
+char *
+skipcomment (cp)
+register char *cp;
+{
+ if (incomment)
+ goto inside;
+ for (;; cp++) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (text)
+ return cp;
+ if ( cp[0] != '/'
+ || cp[1] != '*'
+ )
+ return cp;
+ cp += 2;
+ if (!incomment) {
+ incomment = YES;
+ stqcline = linenum;
+ }
+ inside:
+ for (;;) {
+ for (; *cp != '*'; cp++)
+ if (*cp == '\0')
+ return cp;
+ if (*++cp == '/') {
+ incomment = NO;
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Skip over a quoted string or character and stop at the next charaacter
+ * position that is not whitespace.
+ */
+char *
+skipquote (cp, type)
+register char *cp;
+register int type;
+{
+ register char qchar;
+
+ qchar = type == QUOTE_SINGLE ? '\'' : '"';
+
+ if (inquote == type)
+ goto inside;
+ for (;; cp++) {
+ if (*cp != qchar)
+ return cp;
+ cp++;
+ inquote = type;
+ stqcline = linenum;
+ inside:
+ for (; ; cp++) {
+ if (*cp == qchar)
+ break;
+ if ( *cp == '\0'
+ || *cp == '\\' && *++cp == '\0'
+ )
+ return cp;
+ }
+ inquote = QUOTE_NONE;
+ }
+}
+
+/*
+ * findsym - look for the symbol in the symbol table.
+ * if found, return symbol table index,
+ * else return -1.
+ */
+int
+findsym (str)
+char *str;
+{
+ register char *cp;
+ register char *symp;
+ register int symind;
+ register char chr;
+
+ for (symind = 0; symind < nsyms; ++symind) {
+ if (insym[symind] == SYM_INACTIVE) {
+ for ( symp = symname[symind], cp = str
+ ; *symp && *cp == *symp
+ ; cp++, symp++
+ )
+ continue;
+ chr = *cp;
+ if (*symp == '\0' && endsym (chr))
+ return symind;
+ }
+ }
+ return -1;
+}
+
+/*
+ * getlin - expands tabs if asked for
+ * and (if compiled in) treats form-feed as an end-of-line
+ */
+int
+getlin (line, maxline, inp, expandtabs)
+register char *line;
+int maxline;
+FILE *inp;
+int expandtabs;
+{
+ int tmp;
+ register int num;
+ register int chr;
+#ifdef FFSPECIAL
+ static char havechar = NO; /* have leftover char from last time */
+ static char svchar BSS;
+#endif/*FFSPECIAL */
+
+ num = 0;
+#ifdef FFSPECIAL
+ if (havechar) {
+ havechar = NO;
+ chr = svchar;
+ goto ent;
+ }
+#endif/*FFSPECIAL */
+ while (num + 8 < maxline) { /* leave room for tab */
+ chr = getc (inp);
+ if (isprint (chr)) {
+#ifdef FFSPECIAL
+ ent:
+#endif/*FFSPECIAL */
+ *line++ = chr;
+ num++;
+ } else
+ switch (chr) {
+ case EOF:
+ return EOF;
+
+ case '\t':
+ if (expandtabs) {
+ num += tmp = 8 - (num & 7);
+ do
+ *line++ = ' ';
+ while (--tmp);
+ break;
+ }
+ default:
+ *line++ = chr;
+ num++;
+ break;
+
+ case '\n':
+ *line = '\n';
+ num++;
+ goto end;
+
+#ifdef FFSPECIAL
+ case '\f':
+ if (++num == 1)
+ *line = '\f';
+ else {
+ *line = '\n';
+ havechar = YES;
+ svchar = chr;
+ }
+ goto end;
+#endif/*FFSPECIAL */
+ }
+ }
+ end:
+ *++line = '\0';
+ return num;
+}
+
+void
+flushline (keep)
+Bool keep;
+{
+ if ((keep && reject != REJ_YES) ^ complement) {
+ register char *line = tline;
+ register FILE *out = stdout;
+ register char chr;
+
+ while (chr = *line++)
+ putc (chr, out);
+ } else if (lnblank)
+ putc ('\n', stdout);
+ return;
+}
+
+void
+prname ()
+{
+ fprintf (stderr, "%s: ", progname);
+ return;
+}
+
+int
+error (err, line, depth)
+int err; /* type of error & index into error string array */
+int line; /* line number */
+int depth; /* how many ifdefs we are inside */
+{
+ if (err == END_ERR)
+ return err;
+
+ prname ();
+
+#ifndef TESTING
+ fprintf (stderr, "Error in %s line %d: %s.\n", filename, line, errs[err]);
+#else/* TESTING */
+ fprintf (stderr, "Error in %s line %d: %s. ", filename, line, errs[err]);
+ fprintf (stderr, "ifdef depth: %d\n", depth);
+#endif/*TESTING */
+
+ exitstat = 2;
+ return depth > 1 ? IEOF_ERR : END_ERR;
+}