1 /* $NetBSD: main.c,v 1.9 2004/02/13 17:56:17 wiz Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 41 #endif 42 __RCSID("$NetBSD: main.c,v 1.9 2004/02/13 17:56:17 wiz Exp $"); 43 #endif /* not lint */ 44 45 #include <signal.h> 46 #include <unistd.h> 47 #include <stdio.h> 48 #include <ctype.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include "error.h" 52 #include "pathnames.h" 53 54 FILE *errorfile; /* where error file comes from */ 55 FILE *queryfile; /* where the query responses from the user come from*/ 56 57 int nignored; 58 char **names_ignored; 59 60 int nerrors = 0; 61 Eptr er_head; 62 Eptr *errors; 63 64 int nfiles = 0; 65 Eptr **files; /* array of pointers into errors*/ 66 boolean *touchedfiles; /* which files we touched */ 67 int language = INCC; 68 69 char *currentfilename = "????"; 70 char *processname; 71 char im_on[] = _PATH_TTY; /* my tty name */ 72 73 boolean query = FALSE; /* query the operator if touch files */ 74 boolean notouch = FALSE; /* don't touch ANY files */ 75 boolean piflag = FALSE; /* this is not pi */ 76 boolean terse = FALSE; /* Terse output */ 77 78 char *suffixlist = ".*"; /* initially, can touch any file */ 79 80 int errorsort(const void *, const void *); 81 void forkvi(int, char **); 82 int main(int, char **); 83 void try(char *, int, char **); 84 85 /* 86 * error [-I ignorename] [-n] [-q] [-t suffixlist] [-s] [-v] [infile] 87 * 88 * -T: terse output 89 * 90 * -I: the following name, `ignorename' contains a list of 91 * function names that are not to be treated as hard errors. 92 * Default: ~/.errorsrc 93 * 94 * -n: don't touch ANY files! 95 * 96 * -q: The user is to be queried before touching each 97 * file; if not specified, all files with hard, non 98 * ignorable errors are touched (assuming they can be). 99 * 100 * -t: touch only files ending with the list of suffixes, each 101 * suffix preceded by a dot. 102 * eg, -t .c.y.l 103 * will touch only files ending with .c, .y or .l 104 * 105 * -s: print a summary of the error's categories. 106 * 107 * -v: after touching all files, overlay vi(1), ex(1) or ed(1) 108 * on top of error, entered in the first file with 109 * an error in it, with the appropriate editor 110 * set up to use the "next" command to get the other 111 * files containing errors. 112 * 113 * -p: (obsolete: for older versions of pi without bug 114 * fix regarding printing out the name of the main file 115 * with an error in it) 116 * Take the following argument and use it as the name of 117 * the pascal source file, suffix .p 118 * 119 * -E: show the errors in sorted order; intended for 120 * debugging. 121 * 122 * -S: show the errors in unsorted order 123 * (as they come from the error file) 124 * 125 * infile: The error messages come from this file. 126 * Default: stdin 127 */ 128 int 129 main(int argc, char **argv) 130 { 131 char *cp; 132 char *ignorename = 0; 133 int ed_argc; 134 char **ed_argv; /*return from touchfiles*/ 135 boolean show_errors = FALSE; 136 boolean Show_Errors = FALSE; 137 boolean pr_summary = FALSE; 138 boolean edit_files = FALSE; 139 140 processname = argv[0]; 141 142 errorfile = stdin; 143 if (argc > 1) for(; (argc > 1) && (argv[1][0] == '-'); argc--, argv++){ 144 for (cp = argv[1] + 1; *cp; cp++) switch(*cp){ 145 default: 146 fprintf(stderr, "%s: -%c: Unknown flag\n", 147 processname, *cp); 148 break; 149 150 case 'n': notouch = TRUE; break; 151 case 'q': query = TRUE; break; 152 case 'S': Show_Errors = TRUE; break; 153 case 's': pr_summary = TRUE; break; 154 case 'v': edit_files = TRUE; break; 155 case 'T': terse = TRUE; break; 156 case 't': 157 *cp-- = 0; argv++; argc--; 158 if (argc > 1){ 159 suffixlist = argv[1]; 160 } 161 break; 162 case 'I': /*ignore file name*/ 163 *cp-- = 0; argv++; argc--; 164 if (argc > 1) 165 ignorename = argv[1]; 166 break; 167 } 168 } 169 if (notouch) 170 suffixlist = 0; 171 if (argc > 1){ 172 if (argc > 3){ 173 fprintf(stderr, "%s: Only takes 0 or 1 arguments\n", 174 processname); 175 exit(3); 176 } 177 if ( (errorfile = fopen(argv[1], "r")) == NULL){ 178 fprintf(stderr, "%s: %s: No such file or directory for reading errors.\n", 179 processname, argv[1]); 180 exit(4); 181 } 182 } 183 if ( (queryfile = fopen(im_on, "r")) == NULL){ 184 if (query){ 185 fprintf(stderr, 186 "%s: Can't open \"%s\" to query the user.\n", 187 processname, im_on); 188 exit(9); 189 } 190 } 191 if (signal(SIGINT, onintr) == SIG_IGN) 192 signal(SIGINT, SIG_IGN); 193 if (signal(SIGTERM, onintr) == SIG_IGN) 194 signal(SIGTERM, SIG_IGN); 195 getignored(ignorename); 196 eaterrors(&nerrors, &errors); 197 if (Show_Errors) 198 printerrors(TRUE, nerrors, errors); 199 qsort(errors, nerrors, sizeof(Eptr), errorsort); 200 if (show_errors) 201 printerrors(FALSE, nerrors, errors); 202 findfiles(nerrors, errors, &nfiles, &files); 203 #define P(msg, arg) fprintf(stdout, msg, arg) 204 if (pr_summary){ 205 if (nunknown) 206 P("%d Errors are unclassifiable.\n", nunknown); 207 if (nignore) 208 P("%d Errors are classifiable, but totally discarded.\n",nignore); 209 if (nsyncerrors) 210 P("%d Errors are synchronization errors.\n", nsyncerrors); 211 if (nignore) 212 P("%d Errors are discarded because they refer to sacrosinct files.\n", ndiscard); 213 if (nnulled) 214 P("%d Errors are nulled because they refer to specific functions.\n", nnulled); 215 if (nnonspec) 216 P("%d Errors are not specific to any file.\n", nnonspec); 217 if (nthisfile) 218 P("%d Errors are specific to a given file, but not to a line.\n", nthisfile); 219 if (ntrue) 220 P("%d Errors are true errors, and can be inserted into the files.\n", ntrue); 221 } 222 filenames(nfiles, files); 223 fflush(stdout); 224 if (touchfiles(nfiles, files, &ed_argc, &ed_argv) && edit_files) 225 forkvi(ed_argc, ed_argv); 226 return (0); 227 } 228 229 void 230 forkvi(int argc, char **argv) 231 { 232 if (query){ 233 switch(inquire(terse 234 ? "Edit? " 235 : "Do you still want to edit the files you touched? ")){ 236 case Q_NO: 237 case Q_no: 238 return; 239 default: 240 break; 241 } 242 } 243 /* 244 * ed_agument's first argument is 245 * a vi/ex compatible search argument 246 * to find the first occurance of ### 247 */ 248 try("vi", argc, argv); 249 try("ex", argc, argv); 250 try("ed", argc-1, argv+1); 251 fprintf(stdout, "Can't find any editors.\n"); 252 } 253 254 void 255 try(char *name, int argc, char **argv) 256 { 257 argv[0] = name; 258 wordvprint(stdout, argc, argv); 259 fprintf(stdout, "\n"); 260 fflush(stderr); 261 fflush(stdout); 262 sleep(2); 263 if (freopen(im_on, "r", stdin) == NULL) 264 return; 265 if (freopen(im_on, "w", stdout) == NULL) 266 return; 267 execvp(name, argv); 268 } 269 270 int errorsort(const void *x1, const void *x2) 271 { 272 Eptr *epp1 = (Eptr *)x1, *epp2 = (Eptr *)x2; 273 Eptr ep1, ep2; 274 int order; 275 /* 276 * Sort by: 277 * 1) synchronization, non specific, discarded errors first; 278 * 2) nulled and true errors last 279 * a) grouped by similar file names 280 * 1) grouped in ascending line number 281 */ 282 ep1 = *epp1; ep2 = *epp2; 283 if (ep1 == 0 || ep2 == 0) 284 return(0); 285 if ( (NOTSORTABLE(ep1->error_e_class)) ^ (NOTSORTABLE(ep2->error_e_class))){ 286 return(NOTSORTABLE(ep1->error_e_class) ? -1 : 1); 287 } 288 if (NOTSORTABLE(ep1->error_e_class)) /* then both are */ 289 return(ep1->error_no - ep2->error_no); 290 order = strcmp(ep1->error_text[0], ep2->error_text[0]); 291 if (order == 0){ 292 return(ep1->error_line - ep2->error_line); 293 } 294 return(order); 295 } 296