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 #pragma ident "%Z%%M% %I% %E% SMI"
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include "error.h"
37
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
main(int argc,char * argv[])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
forkvi(int argc,char ** argv)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
try(char * name,int argc,char ** argv)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
errorsort(const void * arg1,const void * arg2)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