diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
commit | f9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch) | |
tree | add7e996bac5289cdc55e6935750c352505560a9 /usr.bin/error | |
parent | be22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff) | |
download | FreeBSD-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/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/error/error.1 | 304 | ||||
-rw-r--r-- | usr.bin/error/error.h | 224 | ||||
-rw-r--r-- | usr.bin/error/filter.c | 194 | ||||
-rw-r--r-- | usr.bin/error/input.c | 548 | ||||
-rw-r--r-- | usr.bin/error/main.c | 287 | ||||
-rw-r--r-- | usr.bin/error/pathnames.h | 43 | ||||
-rw-r--r-- | usr.bin/error/pi.c | 404 | ||||
-rw-r--r-- | usr.bin/error/subr.c | 423 | ||||
-rw-r--r-- | usr.bin/error/touch.c | 768 |
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); +} |