summaryrefslogtreecommitdiffstats
path: root/usr.bin/error
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:33:43 +0000
committerrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:33:43 +0000
commitf9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch)
treeadd7e996bac5289cdc55e6935750c352505560a9 /usr.bin/error
parentbe22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff)
downloadFreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip
FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/error')
-rw-r--r--usr.bin/error/Makefile6
-rw-r--r--usr.bin/error/error.1304
-rw-r--r--usr.bin/error/error.h224
-rw-r--r--usr.bin/error/filter.c194
-rw-r--r--usr.bin/error/input.c548
-rw-r--r--usr.bin/error/main.c287
-rw-r--r--usr.bin/error/pathnames.h43
-rw-r--r--usr.bin/error/pi.c404
-rw-r--r--usr.bin/error/subr.c423
-rw-r--r--usr.bin/error/touch.c768
10 files changed, 3201 insertions, 0 deletions
diff --git a/usr.bin/error/Makefile b/usr.bin/error/Makefile
new file mode 100644
index 0000000..4ec0ba0
--- /dev/null
+++ b/usr.bin/error/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= error
+SRCS= main.c input.c pi.c subr.c filter.c touch.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/error/error.1 b/usr.bin/error/error.1
new file mode 100644
index 0000000..ad7adf8
--- /dev/null
+++ b/usr.bin/error/error.1
@@ -0,0 +1,304 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" @(#)error.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt ERROR 1
+.Os BSD 4
+.Sh NAME
+.Nm error
+.Nd analyze and disperse compiler error messages
+.Sh SYNOPSIS
+.Nm error
+.Op Fl n
+.Op Fl s
+.Op Fl q
+.Op Fl v
+.Op Fl t Ar suffixlist
+.Op Fl I Ar ignorefile
+.Op name
+.Sh DESCRIPTION
+.Nm Error
+analyzes and optionally disperses the diagnostic error messages
+produced by a number of compilers and language processors to the source
+file and line where the errors occurred. It can replace the painful,
+traditional methods of scribbling abbreviations of errors on paper, and
+permits error messages and source code to be viewed simultaneously
+without machinations of multiple windows in a screen editor.
+.Pp
+Options are:
+.Bl -tag -width Ds
+.It Fl n
+Do
+.Em not
+touch any files; all error messages are sent to the
+standard output.
+.It Fl q
+The user is
+.Ar queried
+whether s/he wants to touch the file.
+A ``y'' or ``n'' to the question is necessary to continue.
+Absence of the
+.Fl q
+option implies that all referenced files
+(except those referring to discarded error messages)
+are to be touched.
+.It Fl v
+After all files have been touched,
+overlay the visual editor
+.Xr \&vi 1
+with it set up to edit all files touched,
+and positioned in the first touched file at the first error.
+If
+.Xr \&vi 1
+can't be found, try
+.Xr \&ex 1
+or
+.Xr \&ed 1
+from standard places.
+.It Fl t
+Take the following argument as a suffix list.
+Files whose suffixes do not appear in the suffix list are not touched.
+The suffix list is dot separated, and ``*'' wildcards work.
+Thus the suffix list:
+.Pp
+.Dl ".c.y.foo*.h"
+.Pp
+allows
+.Nm error
+to touch files ending with ``.c'', ``.y'', ``.foo*'' and ``.y''.
+.It Fl s
+Print out
+.Em statistics
+regarding the error categorization.
+Not too useful.
+.El
+.Pp
+.Nm Error
+looks at the error messages,
+either from the specified file
+.Ar name
+or from the standard input,
+and attempts to determine which
+language processor produced each error message,
+determines the source file and line number to which the error message refers,
+determines if the error message is to be ignored or not,
+and inserts the (possibly slightly modified) error message into
+the source file as a comment on the line preceding to which the
+line the error message refers.
+Error messages which can't be categorized by language processor
+or content are not inserted into any file,
+but are sent to the standard output.
+.Nm Error
+touches source files only after all input has been read.
+.Pp
+.Nm Error
+is intended to be run
+with its standard input
+connected via a pipe to the error message source.
+Some language processors put error messages on their standard error file;
+others put their messages on the standard output.
+Hence, both error sources should be piped together into
+.Nm error .
+For example, when using the
+.Xr csh 1
+syntax,
+.Pp
+.Dl make \-s lint \&| error \-q \-v
+.Pp
+will analyze all the error messages produced
+by whatever programs
+.Xr make 1
+runs when making lint.
+.Pp
+.Nm Error
+knows about the error messages produced by:
+.Xr make 1 ,
+.Xr \&cc 1 ,
+.Xr cpp 1 ,
+.Xr ccom 1 ,
+.Xr \&as 1 ,
+.Xr \&ld 1 ,
+.Xr lint 1 ,
+.Xr \&pi 1 ,
+.Xr \&pc 1 ,
+.Xr f77 1 ,
+and
+.Em DEC Western Research Modula\-2 .
+.Nm Error
+knows a standard format for error messages produced by
+the language processors,
+so is sensitive to changes in these formats.
+For all languages except
+.Em Pascal ,
+error messages are restricted to be on one line.
+Some error messages refer to more than one line in more than
+one files;
+.Nm error
+will duplicate the error message and insert it at
+all of the places referenced.
+.Pp
+.Nm Error
+will do one of six things with error messages.
+.Bl -tag -width Em synchronize
+.It Em synchronize
+Some language processors produce short errors describing
+which file it is processing.
+.Nm Error
+uses these to determine the file name for languages that
+don't include the file name in each error message.
+These synchronization messages are consumed entirely by
+.Nm error .
+.It Em discard
+Error messages from
+.Xr lint 1
+that refer to one of the two
+.Xr lint 1
+libraries,
+.Pa /usr/libdata/lint/llib-lc
+and
+.Pa /usr/libdata/lint/llib-port
+are discarded,
+to prevent accidently touching these libraries.
+Again, these error messages are consumed entirely by
+.Nm error .
+.It Em nullify
+Error messages from
+.Xr lint 1
+can be nullified if they refer to a specific function,
+which is known to generate diagnostics which are not interesting.
+Nullified error messages are not inserted into the source file,
+but are written to the standard output.
+The names of functions to ignore are taken from
+either the file named
+.Pa .errorrc
+in the users's home directory,
+or from the file named by the
+.Fl I
+option.
+If the file does not exist,
+no error messages are nullified.
+If the file does exist, there must be one function
+name per line.
+.It Em not file specific
+Error messages that can't be intuited are grouped together,
+and written to the standard output before any files are touched.
+They will not be inserted into any source file.
+.It Em file specific
+Error message that refer to a specific file,
+but to no specific line,
+are written to the standard output when
+that file is touched.
+.It Em true errors
+Error messages that can be intuited are candidates for
+insertion into the file to which they refer.
+.El
+.Pp
+Only true error messages are candidates for inserting into
+the file they refer to.
+Other error messages are consumed entirely by
+.Nm error
+or are written to the standard output.
+.Nm Error
+inserts the error messages into the source file on the line
+preceding the line the language processor found in error.
+Each error message is turned into a one line comment for the
+language,
+and is internally flagged
+with the string ``###'' at
+the beginning of the error,
+and ``%%%'' at the end of the error.
+This makes pattern searching for errors easier with an editor,
+and allows the messages to be easily removed.
+In addition, each error message contains the source line number
+for the line the message refers to.
+A reasonably formatted source program can be recompiled
+with the error messages still in it,
+without having the error messages themselves cause future errors.
+For poorly formatted source programs in free format languages,
+such as C or Pascal,
+it is possible to insert a comment into another comment,
+which can wreak havoc with a future compilation.
+To avoid this, programs with comments and source
+on the same line should be formatted
+so that language statements appear before comments.
+.Pp
+.Nm Error
+catches interrupt and terminate signals,
+and if in the insertion phase,
+will orderly terminate what it is doing.
+.Sh FILES
+.Bl -tag -width ~/.errorrc -compact
+.It Pa ~/.errorrc
+function names to ignore for
+.Xr lint 1
+error messages
+.It Pa /dev/tty
+user's teletype
+.El
+.Sh HISTORY
+The
+.Nm error
+command
+appeared in
+.Bx 4.0 .
+.Sh AUTHOR
+Robert Henry
+.Sh BUGS
+.Pp
+Opens the teletype directly to do user querying.
+.Pp
+Source files with links make a new copy of the file with
+only one link to it.
+.Pp
+Changing a language processor's format of error messages
+may cause
+.Nm error
+to not understand the error message.
+.Pp
+.Nm Error ,
+since it is purely mechanical,
+will not filter out subsequent errors caused by `floodgating'
+initiated by one syntactically trivial error.
+Humans are still much better at discarding these related errors.
+.Pp
+Pascal error messages belong after the lines affected
+(error puts them before). The alignment of the `\\' marking
+the point of error is also disturbed by
+.Nm error .
+.Pp
+.Nm Error
+was designed for work on
+.Tn CRT Ns 's
+at reasonably high speed.
+It is less pleasant on slow speed terminals, and has never been
+used on hardcopy terminals.
diff --git a/usr.bin/error/error.h b/usr.bin/error/error.h
new file mode 100644
index 0000000..7ceb2a2
--- /dev/null
+++ b/usr.bin/error/error.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ *
+ * @(#)error.h 8.1 (Berkeley) 6/6/93
+ */
+
+typedef int boolean;
+#define reg register
+
+#define TRUE 1
+#define FALSE 0
+
+#define true 1
+#define false 0
+/*
+ * Descriptors for the various languages we know about.
+ * If you touch these, also touch lang_table
+ */
+#define INUNKNOWN 0
+#define INCPP 1
+#define INCC 2
+#define INAS 3
+#define INLD 4
+#define INLINT 5
+#define INF77 6
+#define INPI 7
+#define INPC 8
+#define INFRANZ 9
+#define INLISP 10
+#define INVAXIMA 11
+#define INRATFOR 12
+#define INLEX 13
+#define INYACC 14
+#define INAPL 15
+#define INMAKE 16
+#define INRI 17
+#define INTROFF 18
+#define INMOD2 19
+
+extern int language;
+/*
+ * We analyze each line in the error message file, and
+ * attempt to categorize it by type, as well as language.
+ * Here are the type descriptors.
+ */
+typedef int Errorclass;
+
+#define C_FIRST 0 /* first error category */
+#define C_UNKNOWN 0 /* must be zero */
+#define C_IGNORE 1 /* ignore the message; used for pi */
+#define C_SYNC 2 /* synchronization errors */
+#define C_DISCARD 3 /* touches dangerous files, so discard */
+#define C_NONSPEC 4 /* not specific to any file */
+#define C_THISFILE 5 /* specific to this file, but at no line */
+#define C_NULLED 6 /* refers to special func; so null */
+#define C_TRUE 7 /* fits into true error format */
+#define C_DUPL 8 /* sub class only; duplicated error message */
+#define C_LAST 9 /* last error category */
+
+#define SORTABLE(x) (!(NOTSORTABLE(x)))
+#define NOTSORTABLE(x) (x <= C_NONSPEC)
+/*
+ * Resources to count and print out the error categories
+ */
+extern char *class_table[];
+extern int class_count[];
+
+#define nunknown class_count[C_UNKNOWN]
+#define nignore class_count[C_IGNORE]
+#define nsyncerrors class_count[C_SYNC]
+#define ndiscard class_count[C_DISCARD]
+#define nnonspec class_count[C_NONSPEC]
+#define nthisfile class_count[C_THISFILE]
+#define nnulled class_count[C_NULLED]
+#define ntrue class_count[C_TRUE]
+#define ndupl class_count[C_DUPL]
+
+/* places to put the error complaints */
+
+#define TOTHEFILE 1 /* touch the file */
+#define TOSTDOUT 2 /* just print them out (ho-hum) */
+
+FILE *errorfile; /* where error file comes from */
+FILE *queryfile; /* where the query responses from the user come from*/
+
+extern char *currentfilename;
+extern char *processname;
+extern char *scriptname;
+
+extern boolean query;
+extern boolean terse;
+int inquire(); /* inquire for yes/no */
+/*
+ * codes for inquire() to return
+ */
+#define Q_NO 1 /* 'N' */
+#define Q_no 2 /* 'n' */
+#define Q_YES 3 /* 'Y' */
+#define Q_yes 4 /* 'y' */
+
+int probethisfile();
+/*
+ * codes for probethisfile to return
+ */
+#define F_NOTEXIST 1
+#define F_NOTREAD 2
+#define F_NOTWRITE 3
+#define F_TOUCHIT 4
+
+/*
+ * Describes attributes about a language
+ */
+struct lang_desc{
+ char *lang_name;
+ char *lang_incomment; /* one of the following defines */
+ char *lang_outcomment; /* one of the following defines */
+};
+extern struct lang_desc lang_table[];
+
+#define CINCOMMENT "/*###"
+#define COUTCOMMENT "%%%*/\n"
+#define FINCOMMENT "C###"
+#define FOUTCOMMENT "%%%\n"
+#define NEWLINE "%%%\n"
+#define PIINCOMMENT "(*###"
+#define PIOUTCOMMENT "%%%*)\n"
+#define LISPINCOMMENT ";###"
+#define ASINCOMMENT "####"
+#define RIINCOMMENT CINCOMMENT
+#define RIOUTCOMMENT COUTCOMMENT
+#define TROFFINCOMMENT ".\\\"###"
+#define TROFFOUTCOMMENT NEWLINE
+#define MOD2INCOMMENT "(*###"
+#define MOD2OUTCOMMENT "%%%*)\n"
+/*
+ * Defines and resources for determing if a given line
+ * is to be discarded because it refers to a file not to
+ * be touched, or if the function reference is to a
+ * function the user doesn't want recorded.
+ */
+
+#define ERRORNAME "/.errorrc"
+int nignored;
+char **names_ignored;
+/*
+ * Structure definition for a full error
+ */
+typedef struct edesc Edesc;
+typedef Edesc *Eptr;
+
+struct edesc{
+ Eptr error_next; /*linked together*/
+ int error_lgtext; /* how many on the right hand side*/
+ char **error_text; /* the right hand side proper*/
+ Errorclass error_e_class; /* error category of this error*/
+ Errorclass error_s_class; /* sub descriptor of error_e_class*/
+ int error_language; /* the language for this error*/
+ int error_position; /* oridinal position */
+ int error_line; /* discovered line number*/
+ int error_no; /* sequence number on input */
+};
+/*
+ * Resources for the true errors
+ */
+extern int nerrors;
+extern Eptr er_head;
+extern Eptr *errors;
+/*
+ * Resources for each of the files mentioned
+ */
+extern int nfiles;
+extern Eptr **files; /* array of pointers into errors*/
+boolean *touchedfiles; /* which files we touched */
+/*
+ * The langauge the compilation is in, as intuited from
+ * the flavor of error messages analyzed.
+ */
+extern int langauge;
+extern char *currentfilename;
+/*
+ * Functional forwards
+ */
+char *Calloc();
+char *strsave();
+char *clobberfirst();
+char lastchar();
+char firstchar();
+char next_lastchar();
+char **wordvsplice();
+int wordvcmp();
+boolean persperdexplode();
+/*
+ * Printing hacks
+ */
+char *plural(), *verbform();
diff --git a/usr.bin/error/filter.c b/usr.bin/error/filter.c
new file mode 100644
index 0000000..40cf00d
--- /dev/null
+++ b/usr.bin/error/filter.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 sccsid[] = "@(#)filter.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "pathnames.h"
+
+char *lint_libs[] = {
+ IG_FILE1,
+ IG_FILE2,
+ IG_FILE3,
+ IG_FILE4,
+ 0
+};
+extern char* processname;
+int lexsort();
+/*
+ * Read the file ERRORNAME of the names of functions in lint
+ * to ignore complaints about.
+ */
+getignored(auxname)
+ char *auxname;
+{
+ reg int i;
+ FILE *fyle;
+ char inbuffer[256];
+ int uid;
+ char filename[128];
+ char *username;
+ struct passwd *passwdentry;
+
+ nignored = 0;
+ if (auxname == 0){ /* use the default */
+ if ( (username = (char *)getlogin()) == NULL){
+ username = "Unknown";
+ uid = getuid();
+ if ( (passwdentry = (struct passwd *)getpwuid(uid)) == NULL){
+ return;
+ }
+ } else {
+ if ( (passwdentry = (struct passwd *)getpwnam(username)) == NULL)
+ return;
+ }
+ strcpy(filename, passwdentry->pw_dir);
+ (void)strcat(filename, ERRORNAME);
+ } else
+ (void)strcpy(filename, auxname);
+#ifdef FULLDEBUG
+ printf("Opening file \"%s\" to read names to ignore.\n",
+ filename);
+#endif
+ if ( (fyle = fopen(filename, "r")) == NULL){
+#ifdef FULLDEBUG
+ fprintf(stderr, "%s: Can't open file \"%s\"\n",
+ processname, filename);
+#endif
+ return;
+ }
+ /*
+ * Make the first pass through the file, counting lines
+ */
+ for (nignored = 0; fgets(inbuffer, 255, fyle) != NULL; nignored++)
+ continue;
+ names_ignored = (char **)Calloc(nignored+1, sizeof (char *));
+ fclose(fyle);
+ if (freopen(filename, "r", fyle) == NULL){
+#ifdef FULLDEBUG
+ fprintf(stderr, "%s: Failure to open \"%s\" for second read.\n",
+ processname, filename);
+#endif
+ nignored = 0;
+ return;
+ }
+ for (i=0; i < nignored && (fgets (inbuffer, 255, fyle) != NULL); i++){
+ names_ignored[i] = strsave(inbuffer);
+ (void)substitute(names_ignored[i], '\n', '\0');
+ }
+ qsort(names_ignored, nignored, sizeof *names_ignored, lexsort);
+#ifdef FULLDEBUG
+ printf("Names to ignore follow.\n");
+ for (i=0; i < nignored; i++){
+ printf("\tIgnore: %s\n", names_ignored[i]);
+ }
+#endif
+}
+
+int lexsort(cpp1, cpp2)
+ char **cpp1, **cpp2;
+{
+ return(strcmp(*cpp1, *cpp2));
+}
+
+int search_ignore(key)
+ char *key;
+{
+ reg int ub, lb;
+ reg int halfway;
+ int order;
+
+ if (nignored == 0)
+ return(-1);
+ for(lb = 0, ub = nignored - 1; ub >= lb; ){
+ halfway = (ub + lb)/2;
+ if ( (order = strcmp(key, names_ignored[halfway])) == 0)
+ return(halfway);
+ if (order < 0) /*key is less than probe, throw away above*/
+ ub = halfway - 1;
+ else
+ lb = halfway + 1;
+ }
+ return(-1);
+}
+
+/*
+ * Tell if the error text is to be ignored.
+ * The error must have been canonicalized, with
+ * the file name the zeroth entry in the errorv,
+ * and the linenumber the second.
+ * Return the new categorization of the error class.
+ */
+Errorclass discardit(errorp)
+ reg Eptr errorp;
+{
+ int language;
+ reg int i;
+ Errorclass errorclass = errorp->error_e_class;
+
+ switch(errorclass){
+ case C_SYNC:
+ case C_NONSPEC:
+ case C_UNKNOWN: return(errorclass);
+ default: ;
+ }
+ if(errorp->error_lgtext < 2){
+ return(C_NONSPEC);
+ }
+ language = errorp->error_language;
+ if(language == INLINT){
+ if (errorclass != C_NONSPEC){ /* no file */
+ for(i=0; lint_libs[i] != 0; i++){
+ if (strcmp(errorp->error_text[0], lint_libs[i]) == 0){
+ return(C_DISCARD);
+ }
+ }
+ }
+ /* check if the argument to the error message is to be ignored*/
+ if (ispunct(lastchar(errorp->error_text[2])))
+ clob_last(errorp->error_text[2], '\0');
+ if (search_ignore(errorp->error_text[errorclass == C_NONSPEC ? 0 : 2]) >= 0){
+ return(C_NULLED);
+ }
+ }
+ return(errorclass);
+}
diff --git a/usr.bin/error/input.c b/usr.bin/error/input.c
new file mode 100644
index 0000000..a83013a
--- /dev/null
+++ b/usr.bin/error/input.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+
+int wordc; /* how long the current error message is */
+char **wordv; /* the actual error message */
+
+int nerrors;
+int language;
+
+Errorclass onelong();
+Errorclass cpp();
+Errorclass pccccom(); /* Portable C Compiler C Compiler */
+Errorclass richieccom(); /* Richie Compiler for 11 */
+Errorclass lint0();
+Errorclass lint1();
+Errorclass lint2();
+Errorclass lint3();
+Errorclass make();
+Errorclass f77();
+Errorclass pi();
+Errorclass ri();
+Errorclass troff();
+Errorclass mod2();
+/*
+ * Eat all of the lines in the input file, attempting to categorize
+ * them by their various flavors
+ */
+static char inbuffer[BUFSIZ];
+
+eaterrors(r_errorc, r_errorv)
+ int *r_errorc;
+ Eptr **r_errorv;
+{
+ extern boolean piflag;
+ Errorclass errorclass = C_SYNC;
+
+ for (;;){
+ if (fgets(inbuffer, BUFSIZ, errorfile) == NULL)
+ break;
+ wordvbuild(inbuffer, &wordc, &wordv);
+ /*
+ * for convience, convert wordv to be 1 based, instead
+ * of 0 based.
+ */
+ wordv -= 1;
+ if ( wordc > 0 &&
+ ((( errorclass = onelong() ) != C_UNKNOWN)
+ || (( errorclass = cpp() ) != C_UNKNOWN)
+ || (( errorclass = pccccom() ) != C_UNKNOWN)
+ || (( errorclass = richieccom() ) != C_UNKNOWN)
+ || (( errorclass = lint0() ) != C_UNKNOWN)
+ || (( errorclass = lint1() ) != C_UNKNOWN)
+ || (( errorclass = lint2() ) != C_UNKNOWN)
+ || (( errorclass = lint3() ) != C_UNKNOWN)
+ || (( errorclass = make() ) != C_UNKNOWN)
+ || (( errorclass = f77() ) != C_UNKNOWN)
+ || ((errorclass = pi() ) != C_UNKNOWN)
+ || (( errorclass = ri() )!= C_UNKNOWN)
+ || (( errorclass = mod2() )!= C_UNKNOWN)
+ || (( errorclass = troff() )!= C_UNKNOWN))
+ ) ;
+ else
+ errorclass = catchall();
+ if (wordc)
+ erroradd(wordc, wordv+1, errorclass, C_UNKNOWN);
+ }
+#ifdef FULLDEBUG
+ printf("%d errorentrys\n", nerrors);
+#endif
+ arrayify(r_errorc, r_errorv, er_head);
+}
+
+/*
+ * create a new error entry, given a zero based array and count
+ */
+erroradd(errorlength, errorv, errorclass, errorsubclass)
+ int errorlength;
+ char **errorv;
+ Errorclass errorclass;
+ Errorclass errorsubclass;
+{
+ reg Eptr newerror;
+ reg char *cp;
+
+ if (errorclass == C_TRUE){
+ /* check canonicalization of the second argument*/
+ for(cp = errorv[1]; *cp && isdigit(*cp); cp++)
+ continue;
+ errorclass = (*cp == '\0') ? C_TRUE : C_NONSPEC;
+#ifdef FULLDEBUG
+ if (errorclass != C_TRUE)
+ printf("The 2nd word, \"%s\" is not a number.\n",
+ errorv[1]);
+#endif
+ }
+ if (errorlength > 0){
+ newerror = (Eptr)Calloc(1, sizeof(Edesc));
+ newerror->error_language = language; /* language is global */
+ newerror->error_text = errorv;
+ newerror->error_lgtext = errorlength;
+ if (errorclass == C_TRUE)
+ newerror->error_line = atoi(errorv[1]);
+ newerror->error_e_class = errorclass;
+ newerror->error_s_class = errorsubclass;
+ switch(newerror->error_e_class = discardit(newerror)){
+ case C_SYNC: nsyncerrors++; break;
+ case C_DISCARD: ndiscard++; break;
+ case C_NULLED: nnulled++; break;
+ case C_NONSPEC: nnonspec++; break;
+ case C_THISFILE: nthisfile++; break;
+ case C_TRUE: ntrue++; break;
+ case C_UNKNOWN: nunknown++; break;
+ case C_IGNORE: nignore++; break;
+ }
+ newerror->error_next = er_head;
+ er_head = newerror;
+ newerror->error_no = nerrors++;
+ } /* length > 0 */
+}
+
+Errorclass onelong()
+{
+ char **nwordv;
+ if ( (wordc == 1) && (language != INLD) ){
+ /*
+ * We have either:
+ * a) file name from cc
+ * b) Assembler telling world that it is complaining
+ * c) Noise from make ("Stop.")
+ * c) Random noise
+ */
+ wordc = 0;
+ if (strcmp(wordv[1], "Stop.") == 0){
+ language = INMAKE; return(C_SYNC);
+ }
+ if (strcmp(wordv[1], "Assembler:") == 0){
+ /* assembler always alerts us to what happened*/
+ language = INAS; return(C_SYNC);
+ } else
+ if (strcmp(wordv[1], "Undefined:") == 0){
+ /* loader complains about unknown symbols*/
+ language = INLD; return(C_SYNC);
+ }
+ if (lastchar(wordv[1]) == ':'){
+ /* cc tells us what file we are in */
+ currentfilename = wordv[1];
+ (void)substitute(currentfilename, ':', '\0');
+ language = INCC; return(C_SYNC);
+ }
+ } else
+ if ( (wordc == 1) && (language == INLD) ){
+ nwordv = (char **)Calloc(4, sizeof(char *));
+ nwordv[0] = "ld:";
+ nwordv[1] = wordv[1];
+ nwordv[2] = "is";
+ nwordv[3] = "undefined.";
+ wordc = 4;
+ wordv = nwordv - 1;
+ return(C_NONSPEC);
+ } else
+ if (wordc == 1){
+ return(C_SYNC);
+ }
+ return(C_UNKNOWN);
+} /* end of one long */
+
+Errorclass cpp()
+{
+ /*
+ * Now attempt a cpp error message match
+ * Examples:
+ * ./morse.h: 23: undefined control
+ * morsesend.c: 229: MAGNIBBL: argument mismatch
+ * morsesend.c: 237: MAGNIBBL: argument mismatch
+ * test1.c: 6: undefined control
+ */
+ if ( (language != INLD) /* loader errors have almost same fmt*/
+ && (lastchar(wordv[1]) == ':')
+ && (isdigit(firstchar(wordv[2])))
+ && (lastchar(wordv[2]) == ':') ){
+ language = INCPP;
+ clob_last(wordv[1], '\0');
+ clob_last(wordv[2], '\0');
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+} /*end of cpp*/
+
+Errorclass pccccom()
+{
+ /*
+ * Now attempt a ccom error message match:
+ * Examples:
+ * "morsesend.c", line 237: operands of & have incompatible types
+ * "test.c", line 7: warning: old-fashioned initialization: use =
+ * "subdir.d/foo2.h", line 1: illegal initialization
+ */
+ if ( (firstchar(wordv[1]) == '"')
+ && (lastchar(wordv[1]) == ',')
+ && (next_lastchar(wordv[1]) == '"')
+ && (strcmp(wordv[2],"line") == 0)
+ && (isdigit(firstchar(wordv[3])))
+ && (lastchar(wordv[3]) == ':') ){
+ clob_last(wordv[1], '\0'); /* drop last , */
+ clob_last(wordv[1], '\0'); /* drop last " */
+ wordv[1]++; /* drop first " */
+ clob_last(wordv[3], '\0'); /* drop : on line number */
+ wordv[2] = wordv[1]; /* overwrite "line" */
+ wordv++; /*compensate*/
+ wordc--;
+ currentfilename = wordv[1];
+ language = INCC;
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+} /* end of ccom */
+/*
+ * Do the error message from the Richie C Compiler for the PDP11,
+ * which has this source:
+ *
+ * if (filename[0])
+ * fprintf(stderr, "%s:", filename);
+ * fprintf(stderr, "%d: ", line);
+ *
+ */
+Errorclass richieccom()
+{
+ reg char *cp;
+ reg char **nwordv;
+ char *file;
+
+ if (lastchar(wordv[1]) == ':'){
+ cp = wordv[1] + strlen(wordv[1]) - 1;
+ while (isdigit(*--cp))
+ continue;
+ if (*cp == ':'){
+ clob_last(wordv[1], '\0'); /* last : */
+ *cp = '\0'; /* first : */
+ file = wordv[1];
+ nwordv = wordvsplice(1, wordc, wordv+1);
+ nwordv[0] = file;
+ nwordv[1] = cp + 1;
+ wordc += 1;
+ wordv = nwordv - 1;
+ language = INCC;
+ currentfilename = wordv[1];
+ return(C_TRUE);
+ }
+ }
+ return(C_UNKNOWN);
+}
+
+Errorclass lint0()
+{
+ reg char **nwordv;
+ char *line, *file;
+ /*
+ * Attempt a match for the new lint style normal compiler
+ * error messages, of the form
+ *
+ * printf("%s(%d): %s\n", filename, linenumber, message);
+ */
+ if (wordc >= 2){
+ if ( (lastchar(wordv[1]) == ':')
+ && (next_lastchar(wordv[1]) == ')')
+ ) {
+ clob_last(wordv[1], '\0'); /* colon */
+ if (persperdexplode(wordv[1], &line, &file)){
+ nwordv = wordvsplice(1, wordc, wordv+1);
+ nwordv[0] = file; /* file name */
+ nwordv[1] = line; /* line number */
+ wordc += 1;
+ wordv = nwordv - 1;
+ language = INLINT;
+ return(C_TRUE);
+ }
+ wordv[1][strlen(wordv[1])] = ':';
+ }
+ }
+ return (C_UNKNOWN);
+}
+
+Errorclass lint1()
+{
+ char *line1, *line2;
+ char *file1, *file2;
+ char **nwordv1, **nwordv2;
+
+ /*
+ * Now, attempt a match for the various errors that lint
+ * can complain about.
+ *
+ * Look first for type 1 lint errors
+ */
+ if (wordc > 1 && strcmp(wordv[wordc-1], "::") == 0){
+ /*
+ * %.7s, arg. %d used inconsistently %s(%d) :: %s(%d)
+ * %.7s value used inconsistently %s(%d) :: %s(%d)
+ * %.7s multiply declared %s(%d) :: %s(%d)
+ * %.7s value declared inconsistently %s(%d) :: %s(%d)
+ * %.7s function value type must be declared before use %s(%d) :: %s(%d)
+ */
+ language = INLINT;
+ if (wordc > 2
+ && (persperdexplode(wordv[wordc], &line2, &file2))
+ && (persperdexplode(wordv[wordc-2], &line1, &file1)) ){
+ nwordv1 = wordvsplice(2, wordc, wordv+1);
+ nwordv2 = wordvsplice(2, wordc, wordv+1);
+ nwordv1[0] = file1; nwordv1[1] = line1;
+ erroradd(wordc+2, nwordv1, C_TRUE, C_DUPL); /* takes 0 based*/
+ nwordv2[0] = file2; nwordv2[1] = line2;
+ wordc = wordc + 2;
+ wordv = nwordv2 - 1; /* 1 based */
+ return(C_TRUE);
+ }
+ }
+ return(C_UNKNOWN);
+} /* end of lint 1*/
+
+Errorclass lint2()
+{
+ char *file;
+ char *line;
+ char **nwordv;
+ /*
+ * Look for type 2 lint errors
+ *
+ * %.7s used( %s(%d) ), but not defined
+ * %.7s defined( %s(%d) ), but never used
+ * %.7s declared( %s(%d) ), but never used or defined
+ *
+ * bufp defined( "./metric.h"(10) ), but never used
+ */
+ if ( (lastchar(wordv[2]) == '(' /* ')' */ )
+ && (strcmp(wordv[4], "),") == 0) ){
+ language = INLINT;
+ if (persperdexplode(wordv[3], &line, &file)){
+ nwordv = wordvsplice(2, wordc, wordv+1);
+ nwordv[0] = file; nwordv[1] = line;
+ wordc = wordc + 2;
+ wordv = nwordv - 1; /* 1 based */
+ return(C_TRUE);
+ }
+ }
+ return(C_UNKNOWN);
+} /* end of lint 2*/
+
+char *Lint31[4] = {"returns", "value", "which", "is"};
+char *Lint32[6] = {"value", "is", "used,", "but", "none", "returned"};
+Errorclass lint3()
+{
+ if ( (wordvcmp(wordv+2, 4, Lint31) == 0)
+ || (wordvcmp(wordv+2, 6, Lint32) == 0) ){
+ language = INLINT;
+ return(C_NONSPEC);
+ }
+ return(C_UNKNOWN);
+}
+
+/*
+ * Special word vectors for use by F77 recognition
+ */
+char *F77_fatal[3] = {"Compiler", "error", "line"};
+char *F77_error[3] = {"Error", "on", "line"};
+char *F77_warning[3] = {"Warning", "on", "line"};
+char *F77_no_ass[3] = {"Error.","No","assembly."};
+f77()
+{
+ char **nwordv;
+ /*
+ * look for f77 errors:
+ * Error messages from /usr/src/cmd/f77/error.c, with
+ * these printf formats:
+ *
+ * Compiler error line %d of %s: %s
+ * Error on line %d of %s: %s
+ * Warning on line %d of %s: %s
+ * Error. No assembly.
+ */
+ if (wordc == 3 && wordvcmp(wordv+1, 3, F77_no_ass) == 0) {
+ wordc = 0;
+ return(C_SYNC);
+ }
+ if (wordc < 6)
+ return(C_UNKNOWN);
+ if ( (lastchar(wordv[6]) == ':')
+ &&(
+ (wordvcmp(wordv+1, 3, F77_fatal) == 0)
+ || (wordvcmp(wordv+1, 3, F77_error) == 0)
+ || (wordvcmp(wordv+1, 3, F77_warning) == 0) )
+ ){
+ language = INF77;
+ nwordv = wordvsplice(2, wordc, wordv+1);
+ nwordv[0] = wordv[6];
+ clob_last(nwordv[0],'\0');
+ nwordv[1] = wordv[4];
+ wordc += 2;
+ wordv = nwordv - 1; /* 1 based */
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+} /* end of f77 */
+
+char *Make_Croak[3] = {"***", "Error", "code"};
+char *Make_NotRemade[5] = {"not", "remade", "because", "of", "errors"};
+Errorclass make()
+{
+ if (wordvcmp(wordv+1, 3, Make_Croak) == 0){
+ language = INMAKE;
+ return(C_SYNC);
+ }
+ if (wordvcmp(wordv+2, 5, Make_NotRemade) == 0){
+ language = INMAKE;
+ return(C_SYNC);
+ }
+ return(C_UNKNOWN);
+}
+Errorclass ri()
+{
+/*
+ * Match an error message produced by ri; here is the
+ * procedure yanked from the distributed version of ri
+ * April 24, 1980.
+ *
+ * serror(str, x1, x2, x3)
+ * char str[];
+ * char *x1, *x2, *x3;
+ * {
+ * extern int yylineno;
+ *
+ * putc('"', stdout);
+ * fputs(srcfile, stdout);
+ * putc('"', stdout);
+ * fprintf(stdout, " %d: ", yylineno);
+ * fprintf(stdout, str, x1, x2, x3);
+ * fprintf(stdout, "\n");
+ * synerrs++;
+ * }
+ */
+ if ( (firstchar(wordv[1]) == '"')
+ &&(lastchar(wordv[1]) == '"')
+ &&(lastchar(wordv[2]) == ':')
+ &&(isdigit(firstchar(wordv[2]))) ){
+ clob_last(wordv[1], '\0'); /* drop the last " */
+ wordv[1]++; /* skip over the first " */
+ clob_last(wordv[2], '\0');
+ language = INRI;
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+}
+
+Errorclass catchall()
+{
+ /*
+ * Catches random things.
+ */
+ language = INUNKNOWN;
+ return(C_NONSPEC);
+} /* end of catch all*/
+
+Errorclass troff()
+{
+ /*
+ * troff source error message, from eqn, bib, tbl...
+ * Just like pcc ccom, except uses `'
+ */
+ if ( (firstchar(wordv[1]) == '`')
+ && (lastchar(wordv[1]) == ',')
+ && (next_lastchar(wordv[1]) == '\'')
+ && (strcmp(wordv[2],"line") == 0)
+ && (isdigit(firstchar(wordv[3])))
+ && (lastchar(wordv[3]) == ':') ){
+ clob_last(wordv[1], '\0'); /* drop last , */
+ clob_last(wordv[1], '\0'); /* drop last " */
+ wordv[1]++; /* drop first " */
+ clob_last(wordv[3], '\0'); /* drop : on line number */
+ wordv[2] = wordv[1]; /* overwrite "line" */
+ wordv++; /*compensate*/
+ currentfilename = wordv[1];
+ language = INTROFF;
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+}
+Errorclass mod2()
+{
+ /*
+ * for decwrl modula2 compiler (powell)
+ */
+ if ( ( (strcmp(wordv[1], "!!!") == 0) /* early version */
+ ||(strcmp(wordv[1], "File") == 0)) /* later version */
+ && (lastchar(wordv[2]) == ',') /* file name */
+ && (strcmp(wordv[3], "line") == 0)
+ && (isdigit(firstchar(wordv[4]))) /* line number */
+ && (lastchar(wordv[4]) == ':') /* line number */
+ ){
+ clob_last(wordv[2], '\0'); /* drop last , on file name */
+ clob_last(wordv[4], '\0'); /* drop last : on line number */
+ wordv[3] = wordv[2]; /* file name on top of "line" */
+ wordv += 2;
+ wordc -= 2;
+ currentfilename = wordv[1];
+ language = INMOD2;
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+}
diff --git a/usr.bin/error/main.c b/usr.bin/error/main.c
new file mode 100644
index 0000000..fe20c37
--- /dev/null
+++ b/usr.bin/error/main.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "pathnames.h"
+
+int nerrors = 0;
+Eptr er_head;
+Eptr *errors;
+
+int nfiles = 0;
+Eptr **files; /* array of pointers into errors*/
+int language = INCC;
+
+char *currentfilename = "????";
+char *processname;
+char im_on[] = _PATH_TTY; /* my tty name */
+
+boolean query = FALSE; /* query the operator if touch files */
+boolean notouch = FALSE; /* don't touch ANY files */
+boolean piflag = FALSE; /* this is not pi */
+boolean terse = FALSE; /* Terse output */
+
+char *suffixlist = ".*"; /* initially, can touch any file */
+
+int errorsort();
+void onintr();
+/*
+ * error [-I ignorename] [-n] [-q] [-t suffixlist] [-s] [-v] [infile]
+ *
+ * -T: terse output
+ *
+ * -I: the following name, `ignorename' contains a list of
+ * function names that are not to be treated as hard errors.
+ * Default: ~/.errorsrc
+ *
+ * -n: don't touch ANY files!
+ *
+ * -q: The user is to be queried before touching each
+ * file; if not specified, all files with hard, non
+ * ignorable errors are touched (assuming they can be).
+ *
+ * -t: touch only files ending with the list of suffices, each
+ * suffix preceded by a dot.
+ * eg, -t .c.y.l
+ * will touch only files ending with .c, .y or .l
+ *
+ * -s: print a summary of the error's categories.
+ *
+ * -v: after touching all files, overlay vi(1), ex(1) or ed(1)
+ * on top of error, entered in the first file with
+ * an error in it, with the appropriate editor
+ * set up to use the "next" command to get the other
+ * files containing errors.
+ *
+ * -p: (obsolete: for older versions of pi without bug
+ * fix regarding printing out the name of the main file
+ * with an error in it)
+ * Take the following argument and use it as the name of
+ * the pascal source file, suffix .p
+ *
+ * -E: show the errors in sorted order; intended for
+ * debugging.
+ *
+ * -S: show the errors in unsorted order
+ * (as they come from the error file)
+ *
+ * infile: The error messages come from this file.
+ * Default: stdin
+ */
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *cp;
+ char *ignorename = 0;
+ int ed_argc;
+ char **ed_argv; /*return from touchfiles*/
+ boolean show_errors = FALSE;
+ boolean Show_Errors = FALSE;
+ boolean pr_summary = FALSE;
+ boolean edit_files = FALSE;
+
+ processname = argv[0];
+
+ errorfile = stdin;
+ if (argc > 1) for(; (argc > 1) && (argv[1][0] == '-'); argc--, argv++){
+ for (cp = argv[1] + 1; *cp; cp++) switch(*cp){
+ default:
+ fprintf(stderr, "%s: -%c: Unknown flag\n",
+ processname, *cp);
+ break;
+
+ case 'n': notouch = TRUE; break;
+ case 'q': query = TRUE; break;
+ case 'S': Show_Errors = TRUE; break;
+ case 's': pr_summary = TRUE; break;
+ case 'v': edit_files = TRUE; break;
+ case 'T': terse = TRUE; break;
+ case 't':
+ *cp-- = 0; argv++; argc--;
+ if (argc > 1){
+ suffixlist = argv[1];
+ }
+ break;
+ case 'I': /*ignore file name*/
+ *cp-- = 0; argv++; argc--;
+ if (argc > 1)
+ ignorename = argv[1];
+ break;
+ }
+ }
+ if (notouch)
+ suffixlist = 0;
+ if (argc > 1){
+ if (argc > 3){
+ fprintf(stderr, "%s: Only takes 0 or 1 arguments\n",
+ processname);
+ exit(3);
+ }
+ if ( (errorfile = fopen(argv[1], "r")) == NULL){
+ fprintf(stderr, "%s: %s: No such file or directory for reading errors.\n",
+ processname, argv[1]);
+ exit(4);
+ }
+ }
+ if ( (queryfile = fopen(im_on, "r")) == NULL){
+ if (query){
+ fprintf(stderr,
+ "%s: Can't open \"%s\" to query the user.\n",
+ processname, im_on);
+ exit(9);
+ }
+ }
+ if (signal(SIGINT, onintr) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+ if (signal(SIGTERM, onintr) == SIG_IGN)
+ signal(SIGTERM, SIG_IGN);
+ getignored(ignorename);
+ eaterrors(&nerrors, &errors);
+ if (Show_Errors)
+ printerrors(TRUE, nerrors, errors);
+ qsort(errors, nerrors, sizeof(Eptr), errorsort);
+ if (show_errors)
+ printerrors(FALSE, nerrors, errors);
+ findfiles(nerrors, errors, &nfiles, &files);
+#define P(msg, arg) fprintf(stdout, msg, arg)
+ if (pr_summary){
+ if (nunknown)
+ P("%d Errors are unclassifiable.\n", nunknown);
+ if (nignore)
+ P("%d Errors are classifiable, but totally discarded.\n",nignore);
+ if (nsyncerrors)
+ P("%d Errors are synchronization errors.\n", nsyncerrors);
+ if (nignore)
+ P("%d Errors are discarded because they refer to sacrosinct files.\n", ndiscard);
+ if (nnulled)
+ P("%d Errors are nulled because they refer to specific functions.\n", nnulled);
+ if (nnonspec)
+ P("%d Errors are not specific to any file.\n", nnonspec);
+ if (nthisfile)
+ P("%d Errors are specific to a given file, but not to a line.\n", nthisfile);
+ if (ntrue)
+ P("%d Errors are true errors, and can be inserted into the files.\n", ntrue);
+ }
+ filenames(nfiles, files);
+ fflush(stdout);
+ if (touchfiles(nfiles, files, &ed_argc, &ed_argv) && edit_files)
+ forkvi(ed_argc, ed_argv);
+}
+
+forkvi(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (query){
+ switch(inquire(terse
+ ? "Edit? "
+ : "Do you still want to edit the files you touched? ")){
+ case Q_NO:
+ case Q_no:
+ return;
+ default:
+ break;
+ }
+ }
+ /*
+ * ed_agument's first argument is
+ * a vi/ex compatabile search argument
+ * to find the first occurance of ###
+ */
+ try("vi", argc, argv);
+ try("ex", argc, argv);
+ try("ed", argc-1, argv+1);
+ fprintf(stdout, "Can't find any editors.\n");
+}
+
+try(name, argc, argv)
+ char *name;
+ int argc;
+ char **argv;
+{
+ argv[0] = name;
+ wordvprint(stdout, argc, argv);
+ fprintf(stdout, "\n");
+ fflush(stderr);
+ fflush(stdout);
+ sleep(2);
+ if (freopen(im_on, "r", stdin) == NULL)
+ return;
+ if (freopen(im_on, "w", stdout) == NULL)
+ return;
+ execvp(name, argv);
+}
+
+int errorsort(epp1, epp2)
+ Eptr *epp1, *epp2;
+{
+ reg Eptr ep1, ep2;
+ int order;
+ /*
+ * Sort by:
+ * 1) synchronization, non specific, discarded errors first;
+ * 2) nulled and true errors last
+ * a) grouped by similar file names
+ * 1) grouped in ascending line number
+ */
+ ep1 = *epp1; ep2 = *epp2;
+ if (ep1 == 0 || ep2 == 0)
+ return(0);
+ if ( (NOTSORTABLE(ep1->error_e_class)) ^ (NOTSORTABLE(ep2->error_e_class))){
+ return(NOTSORTABLE(ep1->error_e_class) ? -1 : 1);
+ }
+ if (NOTSORTABLE(ep1->error_e_class)) /* then both are */
+ return(ep1->error_no - ep2->error_no);
+ order = strcmp(ep1->error_text[0], ep2->error_text[0]);
+ if (order == 0){
+ return(ep1->error_line - ep2->error_line);
+ }
+ return(order);
+}
diff --git a/usr.bin/error/pathnames.h b/usr.bin/error/pathnames.h
new file mode 100644
index 0000000..add09fb
--- /dev/null
+++ b/usr.bin/error/pathnames.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#define IG_FILE1 "llib-lc"
+#define IG_FILE2 "llib-port"
+#define IG_FILE3 "/usr/lib/llib-lc"
+#define IG_FILE4 "/usr/lib/llib-port"
+#undef _PATH_TMP
+#define _PATH_TMP "/tmp/ErrorXXXXXX"
diff --git a/usr.bin/error/pi.c b/usr.bin/error/pi.c
new file mode 100644
index 0000000..67778a4
--- /dev/null
+++ b/usr.bin/error/pi.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 sccsid[] = "@(#)pi.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "error.h"
+
+extern char *currentfilename;
+static char *c_linenumber;
+static char *unk_hdr[] = {"In", "program", "???"};
+static char **c_header = &unk_hdr[0];
+
+/*
+ * Attempt to handle error messages produced by pi (and by pc)
+ *
+ * problem #1: There is no file name available when a file does not
+ * use a #include; this will have to be given to error
+ * in the command line.
+ * problem #2: pi doesn't always tell you what line number
+ * a error refers to; for example during the tree
+ * walk phase of code generation and error detection,
+ * an error can refer to "variable foo in procedure bletch"
+ * without giving a line number
+ * problem #3: line numbers, when available, are attached to
+ * the source line, along with the source line itself
+ * These line numbers must be extracted, and
+ * the source line thrown away.
+ * problem #4: Some error messages produce more than one line number
+ * on the same message.
+ * There are only two (I think):
+ * %s undefined on line%s
+ * %s improperly used on line%s
+ * here, the %s makes line plural or singular.
+ *
+ * Here are the error strings used in pi version 1.2 that can refer
+ * to a file name or line number:
+ *
+ * Multiply defined label in case, lines %d and %d
+ * Goto %s from line %d is into a structured statement
+ * End matched %s on line %d
+ * Inserted keyword end matching %s on line %d
+ *
+ * Here are the general pi patterns recognized:
+ * define piptr == -.*^-.*
+ * define msg = .*
+ * define digit = [0-9]
+ * definename = .*
+ * define date_format letter*3 letter*3 (digit | (digit digit))
+ * (digit | (digit digit)):digit*2 digit*4
+ *
+ * {e,E} (piptr) (msg) Encounter an error during textual scan
+ * E {digit}* - (msg) Have an error message that refers to a new line
+ * E - msg Have an error message that refers to current
+ * function, program or procedure
+ * (date_format) (name): When switch compilation files
+ * ... (msg) When refer to the previous line
+ * 'In' ('procedure'|'function'|'program') (name):
+ * pi is now complaining about 2nd pass errors.
+ *
+ * Here is the output from a compilation
+ *
+ *
+ * 2 var i:integer;
+ * e --------------^--- Inserted ';'
+ * E 2 - All variables must be declared in one var part
+ * E 5 - Include filename must end in .i
+ * Mon Apr 21 15:56 1980 test.h:
+ * 2 begin
+ * e ------^--- Inserted ';'
+ * Mon Apr 21 16:06 1980 test.p:
+ * E 2 - Function type must be specified
+ * 6 procedure foo(var x:real);
+ * e ------^--- Inserted ';'
+ * In function bletch:
+ * E - No assignment to the function variable
+ * w - variable x is never used
+ * E 6 - foo is already defined in this block
+ * In procedure foo:
+ * w - variable x is neither used nor set
+ * 9 z : = 23;
+ * E --------------^--- Undefined variable
+ * 10 y = [1];
+ * e ----------------^--- Inserted ':'
+ * 13 z := 345.;
+ * e -----------------------^--- Digits required after decimal point
+ * E 10 - Constant set involved in non set context
+ * E 11 - Type clash: real is incompatible with integer
+ * ... Type of expression clashed with type of variable in assignment
+ * E 12 - Parameter type not identical to type of var parameter x of foo
+ * In program mung:
+ * w - variable y is never used
+ * w - type foo is never used
+ * w - function bletch is never used
+ * E - z undefined on lines 9 13
+ */
+char *Months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct","Nov", "Dec",
+ 0
+};
+char *Days[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0
+};
+char *Piroutines[] = {
+ "program", "function", "procedure", 0
+};
+
+
+static boolean structured, multiple;
+
+char *pi_Endmatched[] = {"End", "matched"};
+char *pi_Inserted[] = {"Inserted", "keyword", "end", "matching"};
+
+char *pi_multiple[] = {"Mutiply", "defined", "label", "in", "case,", "line"};
+char *pi_structured[] = {"is", "into", "a", "structured", "statement"};
+
+char *pi_und1[] = {"undefined", "on", "line"};
+char *pi_und2[] = {"undefined", "on", "lines"};
+char *pi_imp1[] = {"improperly", "used", "on", "line"};
+char *pi_imp2[] = {"improperly", "used", "on", "lines"};
+
+boolean alldigits(string)
+ reg char *string;
+{
+ for (; *string && isdigit(*string); string++)
+ continue;
+ return(*string == '\0');
+}
+boolean instringset(member, set)
+ char *member;
+ reg char **set;
+{
+ for(; *set; set++){
+ if (strcmp(*set, member) == 0)
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+boolean isdateformat(wordc, wordv)
+ int wordc;
+ char **wordv;
+{
+ return(
+ (wordc == 5)
+ && (instringset(wordv[0], Days))
+ && (instringset(wordv[1], Months))
+ && (alldigits(wordv[2]))
+ && (alldigits(wordv[4])) );
+}
+
+boolean piptr(string)
+ reg char *string;
+{
+ if (*string != '-')
+ return(FALSE);
+ while (*string && *string == '-')
+ string++;
+ if (*string != '^')
+ return(FALSE);
+ string++;
+ while (*string && *string == '-')
+ string++;
+ return(*string == '\0');
+}
+
+extern int wordc;
+extern char **wordv;
+
+Errorclass pi()
+{
+ char **nwordv;
+
+ if (wordc < 2)
+ return (C_UNKNOWN);
+ if ( ( strlen(wordv[1]) == 1)
+ && ( (wordv[1][0] == 'e') || (wordv[1][0] == 'E') )
+ && ( piptr(wordv[2]) )
+ ) {
+ boolean longpiptr = 0;
+ /*
+ * We have recognized a first pass error of the form:
+ * letter ------^---- message
+ *
+ * turn into an error message of the form:
+ *
+ * file line 'pascal errortype' letter \n |---- message
+ * or of the form:
+ * file line letter |---- message
+ * when there are strlen("(*[pi]") or more
+ * preceding '-' on the error pointer.
+ *
+ * Where the | is intended to be a down arrow, so that
+ * the pi error messages can be inserted above the
+ * line in error, instead of below. (All of the other
+ * langauges put thier messages before the source line,
+ * instead of after it as does pi.)
+ *
+ * where the pointer to the error has been truncated
+ * by 6 characters to account for the fact that
+ * the pointer points into a tab preceded input line.
+ */
+ language = INPI;
+ (void)substitute(wordv[2], '^', '|');
+ longpiptr = position(wordv[2],'|') > (6+8);
+ nwordv = wordvsplice(longpiptr ? 2 : 4, wordc, wordv+1);
+ nwordv[0] = strsave(currentfilename);
+ nwordv[1] = strsave(c_linenumber);
+ if (!longpiptr){
+ nwordv[2] = "pascal errortype";
+ nwordv[3] = wordv[1];
+ nwordv[4] = strsave("%%%\n");
+ if (strlen(nwordv[5]) > (8-2)) /* this is the pointer */
+ nwordv[5] += (8-2); /* bump over 6 characters */
+ }
+ wordv = nwordv - 1; /* convert to 1 based */
+ wordc += longpiptr ? 2 : 4;
+ return(C_TRUE);
+ }
+ if ( (wordc >= 4)
+ && (strlen(wordv[1]) == 1)
+ && ( (*wordv[1] == 'E') || (*wordv[1] == 'w') || (*wordv[1] == 'e') )
+ && (alldigits(wordv[2]))
+ && (strlen(wordv[3]) == 1)
+ && (wordv[3][0] == '-')
+ ){
+ /*
+ * Message of the form: letter linenumber - message
+ * Turn into form: filename linenumber letter - message
+ */
+ language = INPI;
+ nwordv = wordvsplice(1, wordc, wordv + 1);
+ nwordv[0] = strsave(currentfilename);
+ nwordv[1] = wordv[2];
+ nwordv[2] = wordv[1];
+ c_linenumber = wordv[2];
+ wordc += 1;
+ wordv = nwordv - 1;
+ return(C_TRUE);
+ }
+ if ( (wordc >= 3)
+ && (strlen(wordv[1]) == 1)
+ && ( (*(wordv[1]) == 'E') || (*(wordv[1]) == 'w') || (*(wordv[1]) == 'e') )
+ && (strlen(wordv[2]) == 1)
+ && (wordv[2][0] == '-')
+ ) {
+ /*
+ * Message of the form: letter - message
+ * This happens only when we are traversing the tree
+ * during the second pass of pi, and discover semantic
+ * errors.
+ *
+ * We have already (presumably) saved the header message
+ * and can now construct a nulled error message for the
+ * current file.
+ *
+ * Turns into a message of the form:
+ * filename (header) letter - message
+ *
+ * First, see if it is a message referring to more than
+ * one line number. Only of the form:
+ * %s undefined on line%s
+ * %s improperly used on line%s
+ */
+ boolean undefined = 0;
+ int wordindex;
+
+ language = INPI;
+ if ( (undefined = (wordvcmp(wordv+2, 3, pi_und1) == 0) )
+ || (undefined = (wordvcmp(wordv+2, 3, pi_und2) == 0) )
+ || (wordvcmp(wordv+2, 4, pi_imp1) == 0)
+ || (wordvcmp(wordv+2, 4, pi_imp2) == 0)
+ ){
+ for (wordindex = undefined ? 5 : 6; wordindex <= wordc;
+ wordindex++){
+ nwordv = wordvsplice(2, undefined ? 2 : 3, wordv+1);
+ nwordv[0] = strsave(currentfilename);
+ nwordv[1] = wordv[wordindex];
+ if (wordindex != wordc)
+ erroradd(undefined ? 4 : 5, nwordv,
+ C_TRUE, C_UNKNOWN);
+ }
+ wordc = undefined ? 4 : 5;
+ wordv = nwordv - 1;
+ return(C_TRUE);
+ }
+
+ nwordv = wordvsplice(1+3, wordc, wordv+1);
+ nwordv[0] = strsave(currentfilename);
+ nwordv[1] = strsave(c_header[0]);
+ nwordv[2] = strsave(c_header[1]);
+ nwordv[3] = strsave(c_header[2]);
+ wordv = nwordv - 1;
+ wordc += 1 + 3;
+ return(C_THISFILE);
+ }
+ if (strcmp(wordv[1], "...") == 0){
+ /*
+ * have a continuation error message
+ * of the form: ... message
+ * Turn into form : filename linenumber message
+ */
+ language = INPI;
+ nwordv = wordvsplice(1, wordc, wordv+1);
+ nwordv[0] = strsave(currentfilename);
+ nwordv[1] = strsave(c_linenumber);
+ wordv = nwordv - 1;
+ wordc += 1;
+ return(C_TRUE);
+ }
+ if( (wordc == 6)
+ && (lastchar(wordv[6]) == ':')
+ && (isdateformat(5, wordv + 1))
+ ){
+ /*
+ * Have message that tells us we have changed files
+ */
+ language = INPI;
+ currentfilename = strsave(wordv[6]);
+ clob_last(currentfilename, '\0');
+ return(C_SYNC);
+ }
+ if( (wordc == 3)
+ && (strcmp(wordv[1], "In") == 0)
+ && (lastchar(wordv[3]) == ':')
+ && (instringset(wordv[2], Piroutines))
+ ) {
+ language = INPI;
+ c_header = wordvsplice(0, wordc, wordv+1);
+ return(C_SYNC);
+ }
+ /*
+ * now, check for just the line number followed by the text
+ */
+ if (alldigits(wordv[1])){
+ language = INPI;
+ c_linenumber = wordv[1];
+ return(C_IGNORE);
+ }
+ /*
+ * Attempt to match messages refering to a line number
+ *
+ * Multiply defined label in case, lines %d and %d
+ * Goto %s from line %d is into a structured statement
+ * End matched %s on line %d
+ * Inserted keyword end matching %s on line %d
+ */
+ multiple = structured = 0;
+ if (
+ ( (wordc == 6) && (wordvcmp(wordv+1, 2, pi_Endmatched) == 0))
+ || ( (wordc == 8) && (wordvcmp(wordv+1, 4, pi_Inserted) == 0))
+ || ( multiple = ((wordc == 9) && (wordvcmp(wordv+1,6, pi_multiple) == 0) ) )
+ || ( structured = ((wordc == 10) && (wordvcmp(wordv+6,5, pi_structured) == 0 ) ))
+ ){
+ language = INPI;
+ nwordv = wordvsplice(2, wordc, wordv+1);
+ nwordv[0] = strsave(currentfilename);
+ nwordv[1] = structured ? wordv [5] : wordv[wordc];
+ wordc += 2;
+ wordv = nwordv - 1;
+ if (!multiple)
+ return(C_TRUE);
+ erroradd(wordc, nwordv, C_TRUE, C_UNKNOWN);
+ nwordv = wordvsplice(0, wordc, nwordv);
+ nwordv[1] = wordv[wordc - 2];
+ return(C_TRUE);
+ }
+ return(C_UNKNOWN);
+}
diff --git a/usr.bin/error/subr.c b/usr.bin/error/subr.c
new file mode 100644
index 0000000..6346e04
--- /dev/null
+++ b/usr.bin/error/subr.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+/*
+ * Arrayify a list of rules
+ */
+arrayify(e_length, e_array, header)
+ int *e_length;
+ Eptr **e_array;
+ Eptr header;
+{
+ reg Eptr errorp;
+ reg Eptr *array;
+ reg int listlength;
+ reg int listindex;
+
+ for (errorp = header, listlength = 0;
+ errorp; errorp = errorp->error_next, listlength++)
+ continue;
+ array = (Eptr*)Calloc(listlength+1, sizeof (Eptr));
+ for(listindex = 0, errorp = header;
+ listindex < listlength;
+ listindex++, errorp = errorp->error_next){
+ array[listindex] = errorp;
+ errorp->error_position = listindex;
+ }
+ array[listindex] = (Eptr)0;
+ *e_length = listlength;
+ *e_array = array;
+}
+
+/*VARARGS1*/
+error(msg, a1, a2, a3)
+ char *msg;
+{
+ fprintf(stderr, "Error: ");
+ fprintf(stderr, msg, a1, a2, a3);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ fflush(stderr);
+ exit(6);
+}
+/*ARGSUSED*/
+char *Calloc(nelements, size)
+ int nelements;
+ int size;
+{
+ char *back;
+ if ( (back = (char *)calloc(nelements, size)) == (char *)NULL){
+ error("Ran out of memory.\n");
+ exit(1);
+ }
+ return(back);
+}
+
+char *strsave(instring)
+ char *instring;
+{
+ char *outstring;
+ (void)strcpy(outstring = (char *)Calloc(1, strlen(instring) + 1),
+ instring);
+ return(outstring);
+}
+/*
+ * find the position of a given character in a string
+ * (one based)
+ */
+int position(string, ch)
+ reg char *string;
+ reg char ch;
+{
+ reg int i;
+ if (string)
+ for (i=1; *string; string++, i++){
+ if (*string == ch)
+ return(i);
+ }
+ return(-1);
+}
+/*
+ * clobber the first occurance of ch in string by the new character
+ */
+char *substitute(string, chold, chnew)
+ char *string;
+ char chold, chnew;
+{
+ reg char *cp = string;
+
+ if (cp)
+ while (*cp){
+ if (*cp == chold){
+ *cp = chnew;
+ break;
+ }
+ cp++;
+ }
+ return(string);
+}
+
+char lastchar(string)
+ char *string;
+{
+ int length;
+ if (string == 0) return('\0');
+ length = strlen(string);
+ if (length >= 1)
+ return(string[length-1]);
+ else
+ return('\0');
+}
+
+char firstchar(string)
+ char *string;
+{
+ if (string)
+ return(string[0]);
+ else
+ return('\0');
+}
+
+char next_lastchar(string)
+ char *string;
+{
+ int length;
+ if (string == 0) return('\0');
+ length = strlen(string);
+ if (length >= 2)
+ return(string[length - 2]);
+ else
+ return('\0');
+}
+
+clob_last(string, newstuff)
+ char *string, newstuff;
+{
+ int length = 0;
+ if (string)
+ length = strlen(string);
+ if (length >= 1)
+ string[length - 1] = newstuff;
+}
+
+/*
+ * parse a string that is the result of a format %s(%d)
+ * return TRUE if this is of the proper format
+ */
+boolean persperdexplode(string, r_perd, r_pers)
+ char *string;
+ char **r_perd, **r_pers;
+{
+ reg char *cp;
+ int length = 0;
+
+ if (string)
+ length = strlen(string);
+ if ( (length >= 4)
+ && (string[length - 1] == ')' ) ){
+ for (cp = &string[length - 2];
+ (isdigit(*cp)) && (*cp != '(');
+ --cp)
+ continue;
+ if (*cp == '('){
+ string[length - 1] = '\0'; /* clobber the ) */
+ *r_perd = strsave(cp+1);
+ string[length - 1] = ')';
+ *cp = '\0'; /* clobber the ( */
+ *r_pers = strsave(string);
+ *cp = '(';
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+/*
+ * parse a quoted string that is the result of a format \"%s\"(%d)
+ * return TRUE if this is of the proper format
+ */
+boolean qpersperdexplode(string, r_perd, r_pers)
+ char *string;
+ char **r_perd, **r_pers;
+{
+ reg char *cp;
+ int length = 0;
+
+ if (string)
+ length = strlen(string);
+ if ( (length >= 4)
+ && (string[length - 1] == ')' ) ){
+ for (cp = &string[length - 2];
+ (isdigit(*cp)) && (*cp != '(');
+ --cp)
+ continue;
+ if (*cp == '(' && *(cp - 1) == '"'){
+ string[length - 1] = '\0';
+ *r_perd = strsave(cp+1);
+ string[length - 1] = ')';
+ *(cp - 1) = '\0'; /* clobber the " */
+ *r_pers = strsave(string + 1);
+ *(cp - 1) = '"';
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+static char cincomment[] = CINCOMMENT;
+static char coutcomment[] = COUTCOMMENT;
+static char fincomment[] = FINCOMMENT;
+static char foutcomment[] = FOUTCOMMENT;
+static char newline[] = NEWLINE;
+static char piincomment[] = PIINCOMMENT;
+static char pioutcomment[] = PIOUTCOMMENT;
+static char lispincomment[] = LISPINCOMMENT;
+static char riincomment[] = RIINCOMMENT;
+static char rioutcomment[] = RIOUTCOMMENT;
+static char troffincomment[] = TROFFINCOMMENT;
+static char troffoutcomment[] = TROFFOUTCOMMENT;
+static char mod2incomment[] = MOD2INCOMMENT;
+static char mod2outcomment[] = MOD2OUTCOMMENT;
+
+struct lang_desc lang_table[] = {
+ /*INUNKNOWN 0*/ "unknown", cincomment, coutcomment,
+ /*INCPP 1*/ "cpp", cincomment, coutcomment,
+ /*INCC 2*/ "cc", cincomment, coutcomment,
+ /*INAS 3*/ "as", ASINCOMMENT, newline,
+ /*INLD 4*/ "ld", cincomment, coutcomment,
+ /*INLINT 5*/ "lint", cincomment, coutcomment,
+ /*INF77 6*/ "f77", fincomment, foutcomment,
+ /*INPI 7*/ "pi", piincomment, pioutcomment,
+ /*INPC 8*/ "pc", piincomment, pioutcomment,
+ /*INFRANZ 9*/ "franz",lispincomment, newline,
+ /*INLISP 10*/ "lisp", lispincomment, newline,
+ /*INVAXIMA 11*/ "vaxima",lispincomment,newline,
+ /*INRATFOR 12*/ "ratfor",fincomment, foutcomment,
+ /*INLEX 13*/ "lex", cincomment, coutcomment,
+ /*INYACC 14*/ "yacc", cincomment, coutcomment,
+ /*INAPL 15*/ "apl", ".lm", newline,
+ /*INMAKE 16*/ "make", ASINCOMMENT, newline,
+ /*INRI 17*/ "ri", riincomment, rioutcomment,
+ /*INTROFF 18*/ "troff",troffincomment,troffoutcomment,
+ /*INMOD2 19*/ "mod2", mod2incomment, mod2outcomment,
+ 0, 0, 0
+};
+
+printerrors(look_at_subclass, errorc, errorv)
+ boolean look_at_subclass;
+ int errorc;
+ Eptr errorv[];
+{
+ reg int i;
+ reg Eptr errorp;
+
+ for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]){
+ if (errorp->error_e_class == C_IGNORE)
+ continue;
+ if (look_at_subclass && errorp->error_s_class == C_DUPL)
+ continue;
+ printf("Error %d, (%s error) [%s], text = \"",
+ i,
+ class_table[errorp->error_e_class],
+ lang_table[errorp->error_language].lang_name);
+ wordvprint(stdout,errorp->error_lgtext,errorp->error_text);
+ printf("\"\n");
+ }
+}
+
+wordvprint(fyle, wordc, wordv)
+ FILE *fyle;
+ int wordc;
+ char *wordv[];
+{
+ int i;
+ char *sep = "";
+
+ for(i = 0; i < wordc; i++)
+ if (wordv[i]) {
+ fprintf(fyle, "%s%s",sep,wordv[i]);
+ sep = " ";
+ }
+}
+
+/*
+ * Given a string, parse it into a number of words, and build
+ * a wordc wordv combination pointing into it.
+ */
+wordvbuild(string, r_wordc, r_wordv)
+ char *string;
+ int *r_wordc;
+ char ***r_wordv;
+{
+ reg char *cp;
+ char *saltedbuffer;
+ char **wordv;
+ int wordcount;
+ int wordindex;
+
+ saltedbuffer = strsave(string);
+ for (wordcount = 0, cp = saltedbuffer; *cp; wordcount++){
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ break;
+ while (!isspace(*cp))
+ cp++;
+ }
+ wordv = (char **)Calloc(wordcount + 1, sizeof (char *));
+ for (cp=saltedbuffer,wordindex=0; wordcount; wordindex++,--wordcount){
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ break;
+ wordv[wordindex] = cp;
+ while(!isspace(*cp))
+ cp++;
+ *cp++ = '\0';
+ }
+ if (wordcount != 0)
+ error("Initial miscount of the number of words in a line\n");
+ wordv[wordindex] = (char *)0;
+#ifdef FULLDEBUG
+ for (wordcount = 0; wordcount < wordindex; wordcount++)
+ printf("Word %d = \"%s\"\n", wordcount, wordv[wordcount]);
+ printf("\n");
+#endif
+ *r_wordc = wordindex;
+ *r_wordv = wordv;
+}
+/*
+ * Compare two 0 based wordvectors
+ */
+int wordvcmp(wordv1, wordc, wordv2)
+ char **wordv1;
+ int wordc;
+ char **wordv2;
+{
+ reg int i;
+ int back;
+ for (i = 0; i < wordc; i++){
+ if (wordv1[i] == 0 || wordv2[i] == 0)
+ return(-1);
+ if (back = strcmp(wordv1[i], wordv2[i])){
+ return(back);
+ }
+ }
+ return(0); /* they are equal */
+}
+
+/*
+ * splice a 0 basedword vector onto the tail of a
+ * new wordv, allowing the first emptyhead slots to be empty
+ */
+char **wordvsplice(emptyhead, wordc, wordv)
+ int emptyhead;
+ int wordc;
+ char **wordv;
+{
+ reg char **nwordv;
+ int nwordc = emptyhead + wordc;
+ reg int i;
+
+ nwordv = (char **)Calloc(nwordc, sizeof (char *));
+ for (i = 0; i < emptyhead; i++)
+ nwordv[i] = 0;
+ for(i = emptyhead; i < nwordc; i++){
+ nwordv[i] = wordv[i-emptyhead];
+ }
+ return(nwordv);
+}
+/*
+ * plural'ize and verb forms
+ */
+static char *S = "s";
+static char *N = "";
+char *plural(n)
+ int n;
+{
+ return( n > 1 ? S : N);
+}
+char *verbform(n)
+ int n;
+{
+ return( n > 1 ? N : S);
+}
+
diff --git a/usr.bin/error/touch.c b/usr.bin/error/touch.c
new file mode 100644
index 0000000..b4348a1
--- /dev/null
+++ b/usr.bin/error/touch.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "pathnames.h"
+
+/*
+ * Iterate through errors
+ */
+#define EITERATE(p, fv, i) for (p = fv[i]; p < fv[i+1]; p++)
+#define ECITERATE(ei, p, lb) for (ei = lb; p = errors[ei],ei < nerrors; ei++)
+
+#define FILEITERATE(fi, lb) for (fi = lb; fi <= nfiles; fi++)
+int touchstatus = Q_YES;
+
+findfiles(nerrors, errors, r_nfiles, r_files)
+ int nerrors;
+ Eptr *errors;
+ int *r_nfiles;
+ Eptr ***r_files;
+{
+ int nfiles;
+ Eptr **files;
+
+ char *name;
+ reg int ei;
+ int fi;
+ reg Eptr errorp;
+
+ nfiles = countfiles(errors);
+
+ files = (Eptr**)Calloc(nfiles + 3, sizeof (Eptr*));
+ touchedfiles = (boolean *)Calloc(nfiles+3, sizeof(boolean));
+ /*
+ * Now, partition off the error messages
+ * into those that are synchronization, discarded or
+ * not specific to any file, and those that were
+ * nulled or true errors.
+ */
+ files[0] = &errors[0];
+ ECITERATE(ei, errorp, 0){
+ if ( ! (NOTSORTABLE(errorp->error_e_class)))
+ break;
+ }
+ /*
+ * Now, and partition off all error messages
+ * for a given file.
+ */
+ files[1] = &errors[ei];
+ touchedfiles[0] = touchedfiles[1] = FALSE;
+ name = "\1";
+ fi = 1;
+ ECITERATE(ei, errorp, ei){
+ if ( (errorp->error_e_class == C_NULLED)
+ || (errorp->error_e_class == C_TRUE) ){
+ if (strcmp(errorp->error_text[0], name) != 0){
+ name = errorp->error_text[0];
+ touchedfiles[fi] = FALSE;
+ files[fi] = &errors[ei];
+ fi++;
+ }
+ }
+ }
+ files[fi] = &errors[nerrors];
+ *r_nfiles = nfiles;
+ *r_files = files;
+}
+
+int countfiles(errors)
+ Eptr *errors;
+{
+ char *name;
+ int ei;
+ reg Eptr errorp;
+
+ int nfiles;
+ nfiles = 0;
+ name = "\1";
+ ECITERATE(ei, errorp, 0){
+ if (SORTABLE(errorp->error_e_class)){
+ if (strcmp(errorp->error_text[0],name) != 0){
+ nfiles++;
+ name = errorp->error_text[0];
+ }
+ }
+ }
+ return(nfiles);
+}
+char *class_table[] = {
+ /*C_UNKNOWN 0 */ "Unknown",
+ /*C_IGNORE 1 */ "ignore",
+ /*C_SYNC 2 */ "synchronization",
+ /*C_DISCARD 3 */ "discarded",
+ /*C_NONSPEC 4 */ "non specific",
+ /*C_THISFILE 5 */ "specific to this file",
+ /*C_NULLED 6 */ "nulled",
+ /*C_TRUE 7 */ "true",
+ /*C_DUPL 8 */ "duplicated"
+};
+
+int class_count[C_LAST - C_FIRST] = {0};
+
+filenames(nfiles, files)
+ int nfiles;
+ Eptr **files;
+{
+ reg int fi;
+ char *sep = " ";
+ extern char *class_table[];
+ int someerrors;
+
+ /*
+ * first, simply dump out errors that
+ * don't pertain to any file
+ */
+ someerrors = nopertain(files);
+
+ if (nfiles){
+ someerrors++;
+ fprintf(stdout, terse
+ ? "%d file%s"
+ : "%d file%s contain%s errors",
+ nfiles, plural(nfiles), verbform(nfiles));
+ if (!terse){
+ FILEITERATE(fi, 1){
+ fprintf(stdout, "%s\"%s\" (%d)",
+ sep, (*files[fi])->error_text[0],
+ files[fi+1] - files[fi]);
+ sep = ", ";
+ }
+ }
+ fprintf(stdout, "\n");
+ }
+ if (!someerrors)
+ fprintf(stdout, "No errors.\n");
+}
+
+/*
+ * Dump out errors that don't pertain to any file
+ */
+int nopertain(files)
+ Eptr **files;
+{
+ int type;
+ int someerrors = 0;
+ reg Eptr *erpp;
+ reg Eptr errorp;
+
+ if (files[1] - files[0] <= 0)
+ return(0);
+ for(type = C_UNKNOWN; NOTSORTABLE(type); type++){
+ if (class_count[type] <= 0)
+ continue;
+ if (type > C_SYNC)
+ someerrors++;
+ if (terse){
+ fprintf(stdout, "\t%d %s errors NOT PRINTED\n",
+ class_count[type], class_table[type]);
+ } else {
+ fprintf(stdout, "\n\t%d %s errors follow\n",
+ class_count[type], class_table[type]);
+ EITERATE(erpp, files, 0){
+ errorp = *erpp;
+ if (errorp->error_e_class == type){
+ errorprint(stdout, errorp, TRUE);
+ }
+ }
+ }
+ }
+ return(someerrors);
+}
+
+extern boolean notouch;
+
+boolean touchfiles(nfiles, files, r_edargc, r_edargv)
+ int nfiles;
+ Eptr **files;
+ int *r_edargc;
+ char ***r_edargv;
+{
+ char *name;
+ reg Eptr errorp;
+ reg int fi;
+ reg Eptr *erpp;
+ int ntrueerrors;
+ boolean scribbled;
+ int n_pissed_on; /* # of file touched*/
+ int spread;
+
+ FILEITERATE(fi, 1){
+ name = (*files[fi])->error_text[0];
+ spread = files[fi+1] - files[fi];
+ fprintf(stdout, terse
+ ? "\"%s\" has %d error%s, "
+ : "\nFile \"%s\" has %d error%s.\n"
+ , name ,spread ,plural(spread));
+ /*
+ * First, iterate through all error messages in this file
+ * to see how many of the error messages really will
+ * get inserted into the file.
+ */
+ ntrueerrors = 0;
+ EITERATE(erpp, files, fi){
+ errorp = *erpp;
+ if (errorp->error_e_class == C_TRUE)
+ ntrueerrors++;
+ }
+ fprintf(stdout, terse
+ ? "insert %d\n"
+ : "\t%d of these errors can be inserted into the file.\n",
+ ntrueerrors);
+
+ hackfile(name, files, fi, ntrueerrors);
+ }
+ scribbled = FALSE;
+ n_pissed_on = 0;
+ FILEITERATE(fi, 1){
+ scribbled |= touchedfiles[fi];
+ n_pissed_on++;
+ }
+ if (scribbled){
+ /*
+ * Construct an execv argument
+ */
+ execvarg(n_pissed_on, r_edargc, r_edargv);
+ return(TRUE);
+ } else {
+ if (!terse)
+ fprintf(stdout, "You didn't touch any files.\n");
+ return(FALSE);
+ }
+}
+
+hackfile(name, files, ix, nerrors)
+ char *name;
+ Eptr **files;
+ int ix;
+{
+ boolean previewed;
+ int errordest; /* where errors go*/
+
+ if (!oktotouch(name)) {
+ previewed = FALSE;
+ errordest = TOSTDOUT;
+ } else {
+ previewed = preview(name, nerrors, files, ix);
+ errordest = settotouch(name);
+ }
+
+ if (errordest != TOSTDOUT)
+ touchedfiles[ix] = TRUE;
+
+ if (previewed && (errordest == TOSTDOUT))
+ return;
+
+ diverterrors(name, errordest, files, ix, previewed, nerrors);
+
+ if (errordest == TOTHEFILE){
+ /*
+ * overwrite the original file
+ */
+ writetouched(1);
+ }
+}
+
+boolean preview(name, nerrors, files, ix)
+ char *name;
+ int nerrors;
+ Eptr **files;
+ int ix;
+{
+ int back;
+ reg Eptr *erpp;
+
+ if (nerrors <= 0)
+ return(FALSE);
+ back = FALSE;
+ if(query){
+ switch(inquire(terse
+ ? "Preview? "
+ : "Do you want to preview the errors first? ")){
+ case Q_YES:
+ case Q_yes:
+ back = TRUE;
+ EITERATE(erpp, files, ix){
+ errorprint(stdout, *erpp, TRUE);
+ }
+ if (!terse)
+ fprintf(stdout, "\n");
+ default:
+ break;
+ }
+ }
+ return(back);
+}
+
+int settotouch(name)
+ char *name;
+{
+ int dest = TOSTDOUT;
+
+ if (query){
+ switch(touchstatus = inquire(terse
+ ? "Touch? "
+ : "Do you want to touch file \"%s\"? ",
+ name)){
+ case Q_NO:
+ case Q_no:
+ return(dest);
+ default:
+ break;
+ }
+ }
+
+ switch(probethisfile(name)){
+ case F_NOTREAD:
+ dest = TOSTDOUT;
+ fprintf(stdout, terse
+ ? "\"%s\" unreadable\n"
+ : "File \"%s\" is unreadable\n",
+ name);
+ break;
+ case F_NOTWRITE:
+ dest = TOSTDOUT;
+ fprintf(stdout, terse
+ ? "\"%s\" unwritable\n"
+ : "File \"%s\" is unwritable\n",
+ name);
+ break;
+ case F_NOTEXIST:
+ dest = TOSTDOUT;
+ fprintf(stdout, terse
+ ? "\"%s\" not found\n"
+ : "Can't find file \"%s\" to insert error messages into.\n",
+ name);
+ break;
+ default:
+ dest = edit(name) ? TOSTDOUT : TOTHEFILE;
+ break;
+ }
+ return(dest);
+}
+
+diverterrors(name, dest, files, ix, previewed, nterrors)
+ char *name;
+ int dest;
+ Eptr **files;
+ int ix;
+ boolean previewed;
+ int nterrors;
+{
+ int nerrors;
+ reg Eptr *erpp;
+ reg Eptr errorp;
+
+ nerrors = files[ix+1] - files[ix];
+
+ if ( (nerrors != nterrors)
+ && (!previewed) ){
+ fprintf(stdout, terse
+ ? "Uninserted errors\n"
+ : ">>Uninserted errors for file \"%s\" follow.\n",
+ name);
+ }
+
+ EITERATE(erpp, files, ix){
+ errorp = *erpp;
+ if (errorp->error_e_class != C_TRUE){
+ if (previewed || touchstatus == Q_NO)
+ continue;
+ errorprint(stdout, errorp, TRUE);
+ continue;
+ }
+ switch (dest){
+ case TOSTDOUT:
+ if (previewed || touchstatus == Q_NO)
+ continue;
+ errorprint(stdout,errorp, TRUE);
+ break;
+ case TOTHEFILE:
+ insert(errorp->error_line);
+ text(errorp, FALSE);
+ break;
+ }
+ }
+}
+
+int oktotouch(filename)
+ char *filename;
+{
+ extern char *suffixlist;
+ reg char *src;
+ reg char *pat;
+ char *osrc;
+
+ pat = suffixlist;
+ if (pat == 0)
+ return(0);
+ if (*pat == '*')
+ return(1);
+ while (*pat++ != '.')
+ continue;
+ --pat; /* point to the period */
+
+ for (src = &filename[strlen(filename)], --src;
+ (src > filename) && (*src != '.'); --src)
+ continue;
+ if (*src != '.')
+ return(0);
+
+ for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){
+ for (; *src /* not at end of the source */
+ && *pat /* not off end of pattern */
+ && *pat != '.' /* not off end of sub pattern */
+ && *pat != '*' /* not wild card */
+ && *src == *pat; /* and equal... */
+ src++, pat++)
+ continue;
+ if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*'))
+ return(1);
+ if (*src != 0 && *pat == '*')
+ return(1);
+ while (*pat && *pat != '.')
+ pat++;
+ if (! *pat)
+ return(0);
+ }
+ return(0);
+}
+/*
+ * Construct an execv argument
+ * We need 1 argument for the editor's name
+ * We need 1 argument for the initial search string
+ * We need n_pissed_on arguments for the file names
+ * We need 1 argument that is a null for execv.
+ * The caller fills in the editor's name.
+ * We fill in the initial search string.
+ * We fill in the arguments, and the null.
+ */
+execvarg(n_pissed_on, r_argc, r_argv)
+ int n_pissed_on;
+ int *r_argc;
+ char ***r_argv;
+{
+ Eptr p;
+ char *sep;
+ int fi;
+
+ (*r_argv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *));
+ (*r_argc) = n_pissed_on + 2;
+ (*r_argv)[1] = "+1;/###/";
+ n_pissed_on = 2;
+ if (!terse){
+ fprintf(stdout, "You touched file(s):");
+ sep = " ";
+ }
+ FILEITERATE(fi, 1){
+ if (!touchedfiles[fi])
+ continue;
+ p = *(files[fi]);
+ if (!terse){
+ fprintf(stdout,"%s\"%s\"", sep, p->error_text[0]);
+ sep = ", ";
+ }
+ (*r_argv)[n_pissed_on++] = p->error_text[0];
+ }
+ if (!terse)
+ fprintf(stdout, "\n");
+ (*r_argv)[n_pissed_on] = 0;
+}
+
+FILE *o_touchedfile; /* the old file */
+FILE *n_touchedfile; /* the new file */
+char *o_name;
+char n_name[64];
+char *canon_name = _PATH_TMP;
+int o_lineno;
+int n_lineno;
+boolean tempfileopen = FALSE;
+/*
+ * open the file; guaranteed to be both readable and writable
+ * Well, if it isn't, then return TRUE if something failed
+ */
+boolean edit(name)
+ char *name;
+{
+ o_name = name;
+ if ( (o_touchedfile = fopen(name, "r")) == NULL){
+ fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n",
+ processname, name);
+ return(TRUE);
+ }
+ (void)strcpy(n_name, canon_name);
+ (void)mktemp(n_name);
+ if ( (n_touchedfile = fopen(n_name, "w")) == NULL){
+ fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n",
+ processname, name);
+ return(TRUE);
+ }
+ tempfileopen = TRUE;
+ n_lineno = 0;
+ o_lineno = 0;
+ return(FALSE);
+}
+/*
+ * Position to the line (before, after) the line given by place
+ */
+char edbuf[BUFSIZ];
+insert(place)
+ int place;
+{
+ --place; /* always insert messages before the offending line*/
+ for(; o_lineno < place; o_lineno++, n_lineno++){
+ if(fgets(edbuf, BUFSIZ, o_touchedfile) == NULL)
+ return;
+ fputs(edbuf, n_touchedfile);
+ }
+}
+
+text(p, use_all)
+ reg Eptr p;
+ boolean use_all;
+{
+ int offset = use_all ? 0 : 2;
+
+ fputs(lang_table[p->error_language].lang_incomment, n_touchedfile);
+ fprintf(n_touchedfile, "%d [%s] ",
+ p->error_line,
+ lang_table[p->error_language].lang_name);
+ wordvprint(n_touchedfile, p->error_lgtext-offset, p->error_text+offset);
+ fputs(lang_table[p->error_language].lang_outcomment,n_touchedfile);
+ n_lineno++;
+}
+
+/*
+ * write the touched file to its temporary copy,
+ * then bring the temporary in over the local file
+ */
+writetouched(overwrite)
+ int overwrite;
+{
+ reg int nread;
+ reg FILE *localfile;
+ reg FILE *tmpfile;
+ int botch;
+ int oktorm;
+
+ botch = 0;
+ oktorm = 1;
+ while((nread = fread(edbuf, 1, sizeof(edbuf), o_touchedfile)) != NULL){
+ if (nread != fwrite(edbuf, 1, nread, n_touchedfile)){
+ /*
+ * Catastrophe in temporary area: file system full?
+ */
+ botch = 1;
+ fprintf(stderr,
+ "%s: write failure: No errors inserted in \"%s\"\n",
+ processname, o_name);
+ }
+ }
+ fclose(n_touchedfile);
+ fclose(o_touchedfile);
+ /*
+ * Now, copy the temp file back over the original
+ * file, thus preserving links, etc
+ */
+ if (botch == 0 && overwrite){
+ botch = 0;
+ localfile = NULL;
+ tmpfile = NULL;
+ if ((localfile = fopen(o_name, "w")) == NULL){
+ fprintf(stderr,
+ "%s: Can't open file \"%s\" to overwrite.\n",
+ processname, o_name);
+ botch++;
+ }
+ if ((tmpfile = fopen(n_name, "r")) == NULL){
+ fprintf(stderr, "%s: Can't open file \"%s\" to read.\n",
+ processname, n_name);
+ botch++;
+ }
+ if (!botch)
+ oktorm = mustoverwrite(localfile, tmpfile);
+ if (localfile != NULL)
+ fclose(localfile);
+ if (tmpfile != NULL)
+ fclose(tmpfile);
+ }
+ if (oktorm == 0){
+ fprintf(stderr, "%s: Catastrophe: A copy of \"%s\": was saved in \"%s\"\n",
+ processname, o_name, n_name);
+ exit(1);
+ }
+ /*
+ * Kiss the temp file good bye
+ */
+ unlink(n_name);
+ tempfileopen = FALSE;
+ return(TRUE);
+}
+/*
+ * return 1 if the tmpfile can be removed after writing it out
+ */
+int mustoverwrite(preciousfile, tmpfile)
+ FILE *preciousfile;
+ FILE *tmpfile;
+{
+ int nread;
+
+ while((nread = fread(edbuf, 1, sizeof(edbuf), tmpfile)) != NULL){
+ if (mustwrite(edbuf, nread, preciousfile) == 0)
+ return(0);
+ }
+ return(1);
+}
+/*
+ * return 0 on catastrophe
+ */
+mustwrite(base, n, preciousfile)
+ char *base;
+ int n;
+ FILE *preciousfile;
+{
+ int nwrote;
+
+ if (n <= 0)
+ return(1);
+ nwrote = fwrite(base, 1, n, preciousfile);
+ if (nwrote == n)
+ return(1);
+ perror(processname);
+ switch(inquire(terse
+ ? "Botch overwriting: retry? "
+ : "Botch overwriting the source file: retry? ")){
+ case Q_YES:
+ case Q_yes:
+ mustwrite(base + nwrote, n - nwrote, preciousfile);
+ return(1);
+ case Q_NO:
+ case Q_no:
+ switch(inquire("Are you sure? ")){
+ case Q_YES:
+ case Q_yes:
+ return(0);
+ case Q_NO:
+ case Q_no:
+ mustwrite(base + nwrote, n - nwrote, preciousfile);
+ return(1);
+ }
+ default:
+ return(0);
+ }
+}
+
+void
+onintr()
+{
+ switch(inquire(terse
+ ? "\nContinue? "
+ : "\nInterrupt: Do you want to continue? ")){
+ case Q_YES:
+ case Q_yes:
+ signal(SIGINT, onintr);
+ return;
+ default:
+ if (tempfileopen){
+ /*
+ * Don't overwrite the original file!
+ */
+ writetouched(0);
+ }
+ exit(1);
+ }
+ /*NOTREACHED*/
+}
+
+errorprint(place, errorp, print_all)
+ FILE *place;
+ Eptr errorp;
+ boolean print_all;
+{
+ int offset = print_all ? 0 : 2;
+
+ if (errorp->error_e_class == C_IGNORE)
+ return;
+ fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name);
+ wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset);
+ putc('\n', place);
+}
+
+int inquire(fmt, a1, a2)
+ char *fmt;
+ /*VARARGS1*/
+{
+ char buffer[128];
+
+ if (queryfile == NULL)
+ return(0);
+ for(;;){
+ do{
+ fflush(stdout);
+ fprintf(stderr, fmt, a1, a2);
+ fflush(stderr);
+ } while (fgets(buffer, 127, queryfile) == NULL);
+ switch(buffer[0]){
+ case 'Y': return(Q_YES);
+ case 'y': return(Q_yes);
+ case 'N': return(Q_NO);
+ case 'n': return(Q_no);
+ default: fprintf(stderr, "Yes or No only!\n");
+ }
+ }
+}
+
+int probethisfile(name)
+ char *name;
+{
+ struct stat statbuf;
+ if (stat(name, &statbuf) < 0)
+ return(F_NOTEXIST);
+ if((statbuf.st_mode & S_IREAD) == 0)
+ return(F_NOTREAD);
+ if((statbuf.st_mode & S_IWRITE) == 0)
+ return(F_NOTWRITE);
+ return(F_TOUCHIT);
+}
OpenPOWER on IntegriCloud