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