main.c revision 1.21 1 /* $NetBSD: main.c,v 1.21 2011/08/17 13:11:22 christos 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\
35 The Regents of the University of California. All rights reserved.");
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.21 2011/08/17 13:11:22 christos 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 <err.h>
52 #include "error.h"
53 #include "pathnames.h"
54
55 FILE *errorfile; /* where error file comes from */
56 FILE *queryfile; /* input for the query responses from the user */
57
58 int nignored;
59 char **names_ignored;
60
61 size_t filelevel = 0;
62 int nerrors = 0;
63 Eptr er_head;
64 static Eptr *errors;
65
66 int nfiles = 0;
67 Eptr **files; /* array of pointers into errors*/
68 boolean *touchedfiles; /* which files we touched */
69 int language = INCC;
70
71 char default_currentfilename[] = "????";
72 char *currentfilename = default_currentfilename;
73
74 boolean query = false; /* query the operator if touch files */
75 boolean terse = false; /* Terse output */
76
77 static char im_on[] = _PATH_TTY; /* my tty name */
78 static boolean notouch = false; /* don't touch ANY files */
79
80 const char *suffixlist = ".*"; /* initially, can touch any file */
81
82 static int errorsort(const void *, const void *);
83 static void forkvi(int, char **);
84 static void try(const char *, int, char **);
85 static void usage(void) __attribute__((__noreturn__));
86
87 /*
88 * error [-nqSsTv] [-I <ignorename>] [-t <suffixlist>] [-p <level>] <infile>
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 * -p: take the next argument as the number of levels to skip
97 * from the filename, like perl.
98 *
99 * -q: The user is to be queried before touching each
100 * file; if not specified, all files with hard, non
101 * ignorable errors are touched (assuming they can be).
102 *
103 * -S: show the errors in unsorted order
104 * (as they come from the error file)
105 *
106 * -s: print a summary of the error's categories.
107 *
108 * -T: terse output
109 *
110 * -t: touch only files ending with the list of suffixes, each
111 * suffix preceded by a dot.
112 * eg, -t .c.y.l
113 * will touch only files ending with .c, .y or .l
114 *
115 * -v: after touching all files, overlay vi(1), ex(1) or ed(1)
116 * on top of error, entered in the first file with
117 * an error in it, with the appropriate editor
118 * set up to use the "next" command to get the other
119 * files containing errors.
120 *
121 * infile: The error messages come from this file.
122 * Default: stdin
123 */
124 int
125 main(int argc, char **argv)
126 {
127 int c;
128 char *ignorename = 0;
129 int ed_argc;
130 char **ed_argv; /* return from touchfiles */
131 boolean show_errors = false;
132 boolean Show_Errors = false;
133 boolean pr_summary = false;
134 boolean edit_files = false;
135
136 setprogname(argv[0]);
137
138 errorfile = stdin;
139 while ((c = getopt(argc, argv, "I:np:qSsTt:v")) != -1)
140 switch (c) {
141 case 'I': /*ignore file name*/
142 ignorename = optarg;
143 break;
144 case 'n':
145 notouch = true;
146 break;
147 case 'p':
148 filelevel = (size_t)strtol(optarg, NULL, 0);
149 break;
150 case 'q':
151 query = true;
152 break;
153 case 'S':
154 Show_Errors = true;
155 break;
156 case 's':
157 pr_summary = true;
158 break;
159 case 'T':
160 terse = true;
161 break;
162 case 't':
163 suffixlist = optarg;
164 break;
165 case 'v':
166 edit_files = true;
167 break;
168 default:
169 usage();
170 }
171
172 argv += optind;
173 argc -= optind;
174
175 switch (argc) {
176 case 0:
177 break;
178 case 1:
179 if ((errorfile = fopen(argv[0], "r")) == NULL)
180 err(1, "Cannot open `%s' to read errors", argv[0]);
181 break;
182 default:
183 usage();
184 }
185
186 if (notouch)
187 suffixlist = 0;
188
189
190 if ((queryfile = fopen(im_on, "r")) == NULL) {
191 if (query)
192 err(1, "Cannot open `%s' to query the user", im_on);
193 }
194 if (signal(SIGINT, onintr) == SIG_IGN)
195 signal(SIGINT, SIG_IGN);
196 if (signal(SIGTERM, onintr) == SIG_IGN)
197 signal(SIGTERM, SIG_IGN);
198 getignored(ignorename);
199 eaterrors(&nerrors, &errors);
200 if (Show_Errors)
201 printerrors(true, nerrors, errors);
202 qsort(errors, nerrors, sizeof(Eptr), errorsort);
203 if (show_errors)
204 printerrors(false, nerrors, errors);
205 findfiles(nerrors, errors, &nfiles, &files);
206 #define P(msg, arg) fprintf(stdout, msg, arg)
207 if (pr_summary) {
208 if (nunknown)
209 P("%d Errors are unclassifiable.\n", nunknown);
210 if (nignore)
211 P("%d Errors are classifiable, but totally "
212 "discarded.\n", nignore);
213 if (nsyncerrors)
214 P("%d Errors are synchronization errors.\n",
215 nsyncerrors);
216 if (nignore)
217 P("%d Errors are discarded because they refer to "
218 "sacrosinct files.\n", ndiscard);
219 if (nnulled)
220 P("%d Errors are nulled because they refer to specific "
221 "functions.\n", nnulled);
222 if (nnonspec)
223 P("%d Errors are not specific to any file.\n",
224 nnonspec);
225 if (nthisfile)
226 P("%d Errors are specific to a given file, but not "
227 "to a line.\n", nthisfile);
228 if (ntrue)
229 P("%d Errors are true errors, and can be inserted "
230 "into the files.\n", ntrue);
231 }
232 filenames(nfiles, files);
233 fflush(stdout);
234 if (touchfiles(nfiles, files, &ed_argc, &ed_argv) && edit_files)
235 forkvi(ed_argc, ed_argv);
236 return 0;
237 }
238
239 static void
240 forkvi(int argc, char **argv)
241 {
242 if (query) {
243 switch (inquire(terse
244 ? "Edit? "
245 : "Do you still want to edit the files you touched? ")) {
246 case Q_error:
247 case Q_NO:
248 case Q_no:
249 return;
250 default:
251 break;
252 }
253 }
254 /*
255 * ed_agument's first argument is
256 * a vi/ex compatible search argument
257 * to find the first occurrence of ###
258 */
259 try("vi", argc, argv);
260 try("ex", argc, argv);
261 try("ed", argc-1, argv+1);
262 fprintf(stdout, "Can't find any editors.\n");
263 }
264
265 static void
266 try(const char *name, int argc, char **argv)
267 {
268 argv[0] = __UNCONST(name);
269 wordvprint(stdout, argc, argv);
270 fprintf(stdout, "\n");
271 fflush(stderr);
272 fflush(stdout);
273 sleep(2);
274 if (freopen(im_on, "r", stdin) == NULL)
275 return;
276 if (freopen(im_on, "w", stdout) == NULL)
277 return;
278 execvp(name, argv);
279 }
280
281 static int
282 errorsort(const void *x1, const void *x2)
283 {
284 const Eptr *epp1 = x1;
285 const Eptr *epp2 = x2;
286 Eptr ep1, ep2;
287 int order;
288
289 /*
290 * Sort by:
291 * 1) synchronization, non specific, discarded errors first;
292 * 2) nulled and true errors last
293 * a) grouped by similar file names
294 * 1) grouped in ascending line number
295 */
296 ep1 = *epp1; ep2 = *epp2;
297 if (ep1 == 0 || ep2 == 0)
298 return 0;
299 if (NOTSORTABLE(ep1->error_e_class) ^ NOTSORTABLE(ep2->error_e_class)) {
300 return NOTSORTABLE(ep1->error_e_class) ? -1 : 1;
301 }
302 if (NOTSORTABLE(ep1->error_e_class)) /* then both are */
303 return ep1->error_no - ep2->error_no;
304 order = strcmp(ep1->error_text[0], ep2->error_text[0]);
305 if (order == 0) {
306 return ep1->error_line - ep2->error_line;
307 }
308 return order;
309 }
310
311 static void
312 usage(void)
313 {
314 fprintf(stderr, "Usage: %s [-nqSsTv] [-I ignorefile] "
315 "[-p filelevel] [-t suffixlist] [name]\n", getprogname());
316 exit(1);
317 }
318