xref: /csrg-svn/usr.bin/error/main.c (revision 1457)
1*1457Sroot static	char *sccsid = "@(#)main.c	1.1 (Berkeley) 10/16/80";
2*1457Sroot #include <stdio.h>
3*1457Sroot #include <ctype.h>
4*1457Sroot #include <signal.h>
5*1457Sroot #include "error.h"
6*1457Sroot 
7*1457Sroot int	nerrors = 0;
8*1457Sroot struct	error_desc	*er_head;
9*1457Sroot struct	error_desc	**errors;
10*1457Sroot 
11*1457Sroot int	nfiles = 0;
12*1457Sroot struct	error_desc	***files;	/* array of pointers into errors*/
13*1457Sroot int	language = INCC;
14*1457Sroot 
15*1457Sroot char	*currentfilename = "????";
16*1457Sroot char	*processname;
17*1457Sroot char	*im_on;			/* my tty name */
18*1457Sroot 
19*1457Sroot boolean	query = FALSE;		/* query the operator if touch files */
20*1457Sroot boolean	notouch = FALSE;	/* don't touch ANY files */
21*1457Sroot boolean	piflag	= FALSE;	/* this is not pi */
22*1457Sroot 
23*1457Sroot char	*suffixlist = ".*";	/* initially, can touch any file */
24*1457Sroot 
25*1457Sroot int	errorsort();
26*1457Sroot int	onintr();
27*1457Sroot /*
28*1457Sroot  *	error [-I ignorename] [-n] [-q] [-t suffixlist] [-s] [-v] [infile]
29*1457Sroot  *
30*1457Sroot  *	-I:	the following name, `ignorename' contains a list of
31*1457Sroot  *		function names that are not to be treated as hard errors.
32*1457Sroot  *		Default: ~/.errorsrc
33*1457Sroot  *
34*1457Sroot  *	-n:	don't touch ANY files!
35*1457Sroot  *
36*1457Sroot  *	-q:	The user is to be queried before touching each
37*1457Sroot  *		file; if not specified, all files with hard, non
38*1457Sroot  *		ignorable errors are touched (assuming they can be).
39*1457Sroot  *
40*1457Sroot  *	-t:	touch only files ending with the list of suffices, each
41*1457Sroot  *		suffix preceded by a dot.
42*1457Sroot  *		eg, -t .c.y.l
43*1457Sroot  *		will touch only files ending with .c, .y or .l
44*1457Sroot  *
45*1457Sroot  *	-s:	print a summary of the error's categories.
46*1457Sroot  *
47*1457Sroot  *	-v:	after touching all files, overlay vi(1), ex(1) or ed(1)
48*1457Sroot  *		on top of error, entered in the first file with
49*1457Sroot  *		an error in it, with the appropriate editor
50*1457Sroot  *		set up to use the "next" command to get the other
51*1457Sroot  *		files containing errors.
52*1457Sroot  *
53*1457Sroot  *	-p:	(obsolete: for older versions of pi without bug
54*1457Sroot  *		fix regarding printing out the name of the main file
55*1457Sroot  *		with an error in it)
56*1457Sroot  *		Take the following argument and use it as the name of
57*1457Sroot  *		the pascal source file, suffix .p
58*1457Sroot  *
59*1457Sroot  *	-E:	show the errors in sorted order; intended for
60*1457Sroot  *		debugging.
61*1457Sroot  *
62*1457Sroot  *	-S:	show the errors in unsorted order
63*1457Sroot  *		(as they come from the error file)
64*1457Sroot  *
65*1457Sroot  *	infile:	The error messages come from this file.
66*1457Sroot  *		Default: stdin
67*1457Sroot  */
68*1457Sroot main(argc, argv)
69*1457Sroot 	int	argc;
70*1457Sroot 	char	*argv[];
71*1457Sroot {
72*1457Sroot 	char	*cp;
73*1457Sroot 	char	*ignorename = 0;
74*1457Sroot 	int	ed_argc;
75*1457Sroot 	char	**ed_argv;		/*return from touchfiles*/
76*1457Sroot 	boolean	show_errors = FALSE;
77*1457Sroot 	boolean	Show_Errors = FALSE;
78*1457Sroot 	boolean	pr_summary = FALSE;
79*1457Sroot 	boolean	edit_files = FALSE;
80*1457Sroot 
81*1457Sroot 	processname = argv[0];
82*1457Sroot 
83*1457Sroot 	errorfile = stdin;
84*1457Sroot 	if (argc > 1){
85*1457Sroot 		for(; (argc > 1) && (argv[1][0] == '-'); argc--, argv++){
86*1457Sroot 			for (cp = argv[1] + 1; *cp; cp++){
87*1457Sroot 				switch(*cp){
88*1457Sroot 					default:
89*1457Sroot 						fprintf(stderr, "%s: -%c: Unknown flag\n",
90*1457Sroot 							processname, *cp);
91*1457Sroot 						break;
92*1457Sroot 					case 'n':	/* no touch */
93*1457Sroot 						notouch = TRUE;
94*1457Sroot 						break;
95*1457Sroot 					case 'q':	/* query */
96*1457Sroot 						query = TRUE;
97*1457Sroot 						break;
98*1457Sroot 					case 'S':
99*1457Sroot 						Show_Errors = TRUE;
100*1457Sroot 						break;
101*1457Sroot 					case 's':	/* show summary */
102*1457Sroot 						pr_summary = TRUE;
103*1457Sroot 						break;
104*1457Sroot 					case 'v':	/* edit files */
105*1457Sroot 						edit_files = TRUE;
106*1457Sroot 						break;
107*1457Sroot #ifndef ERNIE
108*1457Sroot 					case 'p':
109*1457Sroot 						*cp-- = 0; argv++; argc--;
110*1457Sroot 						if (argc > 1){
111*1457Sroot 							currentfilename=argv[1];
112*1457Sroot 							piflag = TRUE;
113*1457Sroot 						}
114*1457Sroot 						break;
115*1457Sroot #endif
116*1457Sroot 					case 't':
117*1457Sroot 						*cp-- = 0; argv++; argc--;
118*1457Sroot 						if (argc > 1){
119*1457Sroot 							suffixlist = argv[1];
120*1457Sroot 						}
121*1457Sroot 						break;
122*1457Sroot 					case 'I':	/*ignore file name*/
123*1457Sroot 						*cp-- = 0; argv++; argc--;
124*1457Sroot 						if (argc > 1)
125*1457Sroot 							ignorename = argv[1];
126*1457Sroot 						break;
127*1457Sroot 				}	/*end of the argument switch*/
128*1457Sroot 			}	/*end of loop to consume characters after '-'*/
129*1457Sroot 		}
130*1457Sroot 	}	/* end of being at least one argument */
131*1457Sroot 	if (notouch)
132*1457Sroot 		suffixlist = 0;
133*1457Sroot 	if (argc > 1){
134*1457Sroot 		if (argc > 3){
135*1457Sroot 			fprintf(stderr, "%s: Only takes 0 or 1 arguments\n",
136*1457Sroot 				processname);
137*1457Sroot 			exit(3);
138*1457Sroot 		}
139*1457Sroot 		if ( (errorfile = fopen(argv[1], "r")) == NULL){
140*1457Sroot 			fprintf(stderr, "%s: %s: No such file or directory for reading errors.\n",
141*1457Sroot 				processname, argv[1]);
142*1457Sroot 			exit(4);
143*1457Sroot 		}
144*1457Sroot 	}
145*1457Sroot 	im_on = (char *)ttyname(2);
146*1457Sroot 	if ( (queryfile = fopen(im_on, "r")) == NULL){
147*1457Sroot 		fprintf(stderr,"%s: Can't open \"%s\" to query the user.\n",
148*1457Sroot 			processname, im_on);
149*1457Sroot 		exit(9);
150*1457Sroot 	}
151*1457Sroot 	if (signal(SIGINT, onintr) == SIG_IGN)
152*1457Sroot 		signal(SIGINT, SIG_IGN);
153*1457Sroot 	if (signal(SIGTERM, onintr) == SIG_IGN)
154*1457Sroot 		signal(SIGTERM, SIG_IGN);
155*1457Sroot 	getignored(ignorename);
156*1457Sroot 	eaterrors(&nerrors, &errors);
157*1457Sroot 	if (Show_Errors)
158*1457Sroot 		printerrors(TRUE, nerrors, errors);
159*1457Sroot 	qsort(errors, nerrors, sizeof (struct error_desc *), errorsort);
160*1457Sroot 	if (show_errors)
161*1457Sroot 		printerrors(FALSE, nerrors, errors);
162*1457Sroot 	findfiles(nerrors, errors, &nfiles, &files);
163*1457Sroot #define P(msg, arg) fprintf(stdout, msg, arg)
164*1457Sroot 	if (pr_summary){
165*1457Sroot 	    if (nunknown)
166*1457Sroot 	      P("%d Errors are unclassifiable.\n", nunknown);
167*1457Sroot 	    if (nignore)
168*1457Sroot 	      P("%d Errors are classifiable, but totally discarded.\n",nignore);
169*1457Sroot 	    if (nsyncerrors)
170*1457Sroot 	      P("%d Errors are synchronization errors.\n", nsyncerrors);
171*1457Sroot 	    if (nignore)
172*1457Sroot 	      P("%d Errors are discarded because they refer to sacrosinct files.\n", ndiscard);
173*1457Sroot 	    if (nnulled)
174*1457Sroot 	      P("%d Errors are nulled because they refer to specific functions.\n", nnulled);
175*1457Sroot 	    if (nnonspec)
176*1457Sroot 	      P("%d Errors are not specific to any file.\n", nnonspec);
177*1457Sroot 	    if (nthisfile)
178*1457Sroot 	      P("%d Errors are specific to a given file, but not to a line.\n", nthisfile);
179*1457Sroot 	    if (ntrue)
180*1457Sroot 	      P("%d Errors are true errors, and can be inserted into the files.\n", ntrue);
181*1457Sroot 	}
182*1457Sroot 	filenames(nfiles, files);
183*1457Sroot 	fflush(stdout);
184*1457Sroot 	if (touchfiles(nfiles, files, &ed_argc, &ed_argv) && edit_files){
185*1457Sroot 		if (!query ||
186*1457Sroot 			inquire("Do you still want to edit the files you touched? ")){
187*1457Sroot 			/*
188*1457Sroot 			 *	ed_agument's first argument is
189*1457Sroot 			 *	a vi/ex compatabile search argument
190*1457Sroot 			 *	to find the first occurance of ###
191*1457Sroot 			 */
192*1457Sroot 			try("vi", ed_argc, ed_argv);
193*1457Sroot 			try("ex", ed_argc, ed_argv);
194*1457Sroot 			try("ed", ed_argc-1, ed_argv+1);
195*1457Sroot 			fprintf(stdout, "Can't find any editors.\n");
196*1457Sroot 		}
197*1457Sroot 	}
198*1457Sroot }
199*1457Sroot 
200*1457Sroot try(name, argc, argv)
201*1457Sroot 	char	*name;
202*1457Sroot 	int	argc;
203*1457Sroot 	char	**argv;
204*1457Sroot {
205*1457Sroot 	argv[0] = name;
206*1457Sroot 	wordvprint(stdout, argc, argv);
207*1457Sroot 	fprintf(stdout, "\n");
208*1457Sroot 	fflush(stderr);
209*1457Sroot 	fflush(stdout);
210*1457Sroot 	sleep(2);
211*1457Sroot 	if (freopen(im_on, "r", stdin) == NULL)
212*1457Sroot 		return;
213*1457Sroot 	if (freopen(im_on, "w", stdout) == NULL)
214*1457Sroot 		return;
215*1457Sroot 	execvp(name, argv);
216*1457Sroot }
217*1457Sroot 
218*1457Sroot int errorsort(epp1, epp2)
219*1457Sroot 	struct	error_desc	**epp1, **epp2;
220*1457Sroot {
221*1457Sroot 	register	struct	error_desc	*ep1, *ep2;
222*1457Sroot 			int	order;
223*1457Sroot 	/*
224*1457Sroot 	 *	Sort by:
225*1457Sroot 	 *	1)	synchronization, non specific, discarded errors first;
226*1457Sroot 	 *	2)	nulled and true errors last
227*1457Sroot 	 *		a)	grouped by similar file names
228*1457Sroot 	 *			1)	grouped in ascending line number
229*1457Sroot 	 */
230*1457Sroot 	ep1 = *epp1; ep2 = *epp2;
231*1457Sroot 	if (ep1 == 0 || ep2 == 0)
232*1457Sroot 		return(0);
233*1457Sroot 	if ( (NOTSORTABLE(ep1->error_e_class)) ^ (NOTSORTABLE(ep2->error_e_class))){
234*1457Sroot 		return(NOTSORTABLE(ep1->error_e_class) ? -1 : 1);
235*1457Sroot 	}
236*1457Sroot 	if (NOTSORTABLE(ep1->error_e_class))	/* then both are */
237*1457Sroot 		return(ep1->error_no - ep2->error_no);
238*1457Sroot 	order = strcmp(ep1->error_text[0], ep2->error_text[0]);
239*1457Sroot 	if (order == 0){
240*1457Sroot 		return(ep1->error_line - ep2->error_line);
241*1457Sroot 	}
242*1457Sroot 	return(order);
243*1457Sroot }
244