1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <stdio.h> 29 #include <ctype.h> 30 #include <signal.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include "error.h" 35 36 FILE *errorfile; 37 FILE *queryfile; 38 int nerrors = 0; 39 Eptr er_head; 40 Eptr *errors; 41 42 int nfiles = 0; 43 Eptr **files; /* array of pointers into errors */ 44 int language = INCC; 45 46 char *currentfilename = "????"; 47 char *processname; 48 char im_on[] = "/dev/tty"; /* my tty name */ 49 50 boolean query = FALSE; /* query the operator if touch files */ 51 boolean notouch = FALSE; /* don't touch ANY files */ 52 boolean terse = FALSE; /* Terse output */ 53 54 char *suffixlist = ".*"; /* initially, can touch any file */ 55 56 static void try(char *name, int argc, char **argv); 57 static void forkvi(int argc, char **argv); 58 static int errorsort(const void *arg1, const void *arg2); 59 60 61 /* 62 * error [-I ignorename] [-n] [-q] [-t suffixlist] [-s] [-v] [infile] 63 * 64 * -T: terse output 65 * 66 * -I: the following name, `ignorename' contains a list of 67 * function names that are not to be treated as hard errors. 68 * Default: ~/.errorsrc 69 * 70 * -n: don't touch ANY files! 71 * 72 * -q: The user is to be queried before touching each 73 * file; if not specified, all files with hard, non 74 * ignorable errors are touched (assuming they can be). 75 * 76 * -t: touch only files ending with the list of suffices, each 77 * suffix preceded by a dot. 78 * eg, -t .c.y.l 79 * will touch only files ending with .c, .y or .l 80 * 81 * -s: print a summary of the error's categories. 82 * 83 * -v: after touching all files, overlay vi(1), ex(1) or ed(1) 84 * on top of error, entered in the first file with 85 * an error in it, with the appropriate editor 86 * set up to use the "next" command to get the other 87 * files containing errors. 88 * 89 * -p: (obsolete: for older versions of pi without bug 90 * fix regarding printing out the name of the main file 91 * with an error in it) 92 * Take the following argument and use it as the name of 93 * the pascal source file, suffix .p 94 * 95 * -E: show the errors in sorted order; intended for 96 * debugging. 97 * 98 * -S: show the errors in unsorted order 99 * (as they come from the error file) 100 * 101 * infile: The error messages come from this file. 102 * Default: stdin 103 */ 104 int 105 main(int argc, char *argv[]) 106 { 107 char *cp; 108 char *ignorename = 0; 109 int ed_argc; 110 char **ed_argv; /* return from touchfiles */ 111 boolean show_errors = FALSE; 112 boolean Show_Errors = FALSE; 113 boolean pr_summary = FALSE; 114 boolean edit_files = FALSE; 115 116 processname = argv[0]; 117 118 errorfile = stdin; 119 if (argc > 1) { 120 for (; (argc > 1) && (argv[1][0] == '-'); argc--, argv++) { 121 for (cp = argv[1] + 1; *cp; cp++) { 122 switch (*cp) { 123 default: 124 (void) fprintf(stderr, 125 "%s: -%c: Unknown flag\n", 126 processname, *cp); 127 break; 128 case 'n': 129 notouch = TRUE; 130 break; 131 case 'q': 132 query = TRUE; 133 break; 134 case 'S': 135 Show_Errors = TRUE; 136 break; 137 case 's': 138 pr_summary = TRUE; 139 break; 140 case 'v': 141 edit_files = TRUE; 142 break; 143 case 'T': 144 terse = TRUE; 145 break; 146 case 't': 147 *cp-- = 0; 148 argv++; 149 argc--; 150 if (argc > 1) { 151 suffixlist = argv[1]; 152 } 153 break; 154 case 'I': /* ignore file name */ 155 *cp-- = 0; 156 argv++; 157 argc--; 158 if (argc > 1) 159 ignorename = argv[1]; 160 break; 161 } 162 } 163 } 164 } 165 if (notouch) 166 suffixlist = 0; 167 if (argc > 1) { 168 if (argc > 3) { 169 (void) fprintf(stderr, 170 "%s: Only takes 0 or 1 arguments\n", 171 processname); 172 exit(3); 173 } 174 if ((errorfile = fopen(argv[1], "r")) == NULL) { 175 (void) fprintf(stderr, 176 "%s: %s: No such file or directory for " 177 "reading errors.\n", processname, argv[1]); 178 exit(4); 179 } 180 } 181 if ((queryfile = fopen(im_on, "r")) == NULL) { 182 if (query) { 183 (void) fprintf(stderr, 184 "%s: Can't open \"%s\" to query the user.\n", 185 processname, im_on); 186 exit(9); 187 } 188 } 189 if (signal(SIGINT, onintr) == SIG_IGN) 190 (void) signal(SIGINT, SIG_IGN); 191 if (signal(SIGTERM, onintr) == SIG_IGN) 192 (void) signal(SIGTERM, SIG_IGN); 193 getignored(ignorename); 194 eaterrors(&nerrors, &errors); 195 if (Show_Errors) 196 printerrors(TRUE, nerrors, errors); 197 qsort(errors, nerrors, sizeof (Eptr), errorsort); 198 if (show_errors) 199 printerrors(FALSE, nerrors, errors); 200 findfiles(nerrors, errors, &nfiles, &files); 201 if (pr_summary) { 202 if (nunknown) 203 (void) fprintf(stdout, 204 "%d Errors are unclassifiable.\n", 205 nunknown); 206 if (nignore) 207 (void) fprintf(stdout, 208 "%d Errors are classifiable, but totally " 209 "discarded.\n", nignore); 210 if (nsyncerrors) 211 (void) fprintf(stdout, 212 "%d Errors are synchronization errors.\n", 213 nsyncerrors); 214 if (nignore) 215 (void) fprintf(stdout, 216 "%d Errors are discarded because they " 217 "refer to sacrosanct files.\n", ndiscard); 218 if (nnulled) 219 (void) fprintf(stdout, 220 "%d Errors are nulled because they refer " 221 "to specific functions.\n", nnulled); 222 if (nnonspec) 223 (void) fprintf(stdout, 224 "%d Errors are not specific to any file.\n", 225 nnonspec); 226 if (nthisfile) 227 (void) fprintf(stdout, 228 "%d Errors are specific to a given file, " 229 "but not to a line.\n", nthisfile); 230 if (ntrue) 231 (void) fprintf(stdout, 232 "%d Errors are true errors, and can be " 233 "inserted into the files.\n", ntrue); 234 } 235 filenames(nfiles, files); 236 (void) fflush(stdout); 237 if (touchfiles(nfiles, files, &ed_argc, &ed_argv) && edit_files) 238 forkvi(ed_argc, ed_argv); 239 return (0); 240 } 241 242 static void 243 forkvi(int argc, char **argv) 244 { 245 if (query) { 246 switch (inquire(terse 247 ? "Edit? " 248 : "Do you still want to edit the files you touched? ")) { 249 case Q_NO: 250 case Q_no: 251 return; 252 default: 253 break; 254 } 255 } 256 /* 257 * ed_agument's first argument is 258 * a vi/ex compatabile search argument 259 * to find the first occurance of ### 260 */ 261 try("vi", argc, argv); 262 try("ex", argc, argv); 263 try("ed", argc-1, argv+1); 264 (void) fprintf(stdout, "Can't find any editors.\n"); 265 } 266 267 static void 268 try(char *name, int argc, char **argv) 269 { 270 argv[0] = name; 271 wordvprint(stdout, argc, argv); 272 (void) fprintf(stdout, "\n"); 273 (void) fflush(stderr); 274 (void) fflush(stdout); 275 (void) sleep(2); 276 if (freopen(im_on, "r", stdin) == NULL) 277 return; 278 if (freopen(im_on, "w", stdout) == NULL) 279 return; 280 (void) execvp(name, argv); 281 } 282 283 static int 284 errorsort(const void *arg1, const void *arg2) 285 { 286 Eptr *epp1 = (Eptr *)arg1; 287 Eptr *epp2 = (Eptr *)arg2; 288 Eptr ep1, ep2; 289 int order; 290 291 /* 292 * Sort by: 293 * 1) synchronization, non specific, discarded errors first; 294 * 2) nulled and true errors last 295 * a) grouped by similar file names 296 * 1) grouped in ascending line number 297 */ 298 ep1 = *epp1; ep2 = *epp2; 299 if (ep1 == 0 || ep2 == 0) 300 return (0); 301 if ((NOTSORTABLE(ep1->error_e_class)) ^ 302 (NOTSORTABLE(ep2->error_e_class))) { 303 return (NOTSORTABLE(ep1->error_e_class) ? -1 : 1); 304 } 305 if (NOTSORTABLE(ep1->error_e_class)) /* then both are */ 306 return (ep1->error_no - ep2->error_no); 307 order = strcmp(ep1->error_text[0], ep2->error_text[0]); 308 if (order == 0) { 309 return (ep1->error_line - ep2->error_line); 310 } 311 return (order); 312 } 313