xref: /csrg-svn/usr.bin/error/touch.c (revision 1460)
1*1460Sroot static	char *sccsid = "@(#)touch.c	1.1 (Berkeley) 10/16/80";
2*1460Sroot #include <stdio.h>
3*1460Sroot #include <ctype.h>
4*1460Sroot #include <sys/types.h>
5*1460Sroot #include <sys/stat.h>
6*1460Sroot #include <signal.h>
7*1460Sroot #include "error.h"
8*1460Sroot 
9*1460Sroot findfiles(nerrors, errors, r_nfiles, r_files)
10*1460Sroot 	int	nerrors;
11*1460Sroot 	struct	error_desc	**errors;
12*1460Sroot 	int	*r_nfiles;
13*1460Sroot 	struct	error_desc	****r_files;
14*1460Sroot {
15*1460Sroot 			int	nfiles;
16*1460Sroot 	struct	error_desc	***files;
17*1460Sroot 
18*1460Sroot 			char	*currentfilename;
19*1460Sroot 	register	int	errorindex;
20*1460Sroot 			int	fileindex;
21*1460Sroot 	register	struct	error_desc	*errorp;
22*1460Sroot 	/*
23*1460Sroot 	 *	First, go through and count all of the filenames
24*1460Sroot 	 */
25*1460Sroot 	for (errorp = errors[errorindex = 0],nfiles = 0, currentfilename = "\1";
26*1460Sroot 	     errorindex < nerrors;
27*1460Sroot 	     errorp = errors[++errorindex]){
28*1460Sroot 		if (SORTABLE(errorp->error_e_class)){
29*1460Sroot 			if (strcmp(errorp->error_text[0],currentfilename) != 0){
30*1460Sroot 				nfiles++;
31*1460Sroot 				currentfilename = errorp->error_text[0];
32*1460Sroot 			}
33*1460Sroot 		}
34*1460Sroot 	}
35*1460Sroot 	files = (struct error_desc ***)Calloc(nfiles + 3,
36*1460Sroot 		sizeof (struct error_desc**));
37*1460Sroot 	touchedfiles = (boolean	*)Calloc(nfiles+3, sizeof(boolean));
38*1460Sroot 	/*
39*1460Sroot 	 *	Now, go through and partition off the error messages
40*1460Sroot 	 *	into those that are synchronization, discarded or
41*1460Sroot 	 *	not specific to any file, and those that were
42*1460Sroot 	 *	nulled or true errors.
43*1460Sroot 	 */
44*1460Sroot 	files[0] = &errors[0];
45*1460Sroot 	for (errorp = errors[errorindex = 0], fileindex = 0;
46*1460Sroot 	     (errorindex < nerrors) &&
47*1460Sroot 		(NOTSORTABLE(errorp->error_e_class));
48*1460Sroot 	     errorp = errors[++errorindex]){
49*1460Sroot 		continue;
50*1460Sroot 	}
51*1460Sroot 	/*
52*1460Sroot 	 *	Now, go through and partition off all error messages
53*1460Sroot 	 *	for a given file.
54*1460Sroot 	 */
55*1460Sroot 	files[1] = &errors[errorindex];
56*1460Sroot 	touchedfiles[0] = touchedfiles[1] = FALSE;
57*1460Sroot 	for (errorp = errors[errorindex], currentfilename = "\1", fileindex = 1;
58*1460Sroot 	     errorindex < nerrors; errorp = errors[++errorindex]){
59*1460Sroot 		if ( (errorp->error_e_class == C_NULLED) || (errorp->error_e_class == C_TRUE) ){
60*1460Sroot 			if (strcmp(errorp->error_text[0],currentfilename) != 0){
61*1460Sroot 				currentfilename = errorp->error_text[0];
62*1460Sroot 				touchedfiles[fileindex] = FALSE;
63*1460Sroot 				files[fileindex++] = &errors[errorindex];
64*1460Sroot 			}
65*1460Sroot 		}
66*1460Sroot 	}
67*1460Sroot 	files[fileindex] = &errors[nerrors];
68*1460Sroot 	*r_nfiles = nfiles;
69*1460Sroot 	*r_files = files;
70*1460Sroot }
71*1460Sroot 
72*1460Sroot char	*class_table[] = {
73*1460Sroot 	/*C_UNKNOWN	0	*/	"Unknown",
74*1460Sroot 	/*C_IGNORE	1	*/	"ignore",
75*1460Sroot 	/*C_SYNC	2	*/	"synchronization",
76*1460Sroot 	/*C_DISCARD	3	*/	"discarded",
77*1460Sroot 	/*C_NONSPEC	4	*/	"non specific",
78*1460Sroot 	/*C_THISFILE	5	*/	"specific to this file",
79*1460Sroot 	/*C_NULLED	6	*/	"nulled",
80*1460Sroot 	/*C_TRUE	7	*/	"true",
81*1460Sroot 	/*C_DUPL	8	*/	"duplicated"
82*1460Sroot };
83*1460Sroot 
84*1460Sroot int	class_count[C_LAST - C_FIRST] = {0};
85*1460Sroot 
86*1460Sroot filenames(nfiles, files)
87*1460Sroot 	int	nfiles;
88*1460Sroot 	struct	error_desc	***files;
89*1460Sroot {
90*1460Sroot 	register	int	fileindex;
91*1460Sroot 	register	struct	error_desc	*errorp;
92*1460Sroot 	register	struct	error_desc	**erpp;
93*1460Sroot 			char	*sep = " ";
94*1460Sroot 	register	int	errortype;
95*1460Sroot 	extern		char	*class_table[];
96*1460Sroot 			int	someerrors = 0;
97*1460Sroot 
98*1460Sroot 	/*
99*1460Sroot 	 *	first, go through and simply dump out errors that
100*1460Sroot 	 *	don't pertain to any file
101*1460Sroot 	 */
102*1460Sroot 	if (files[1] - files[0] > 0){
103*1460Sroot 	    for(errortype = C_UNKNOWN; NOTSORTABLE(errortype); errortype++){
104*1460Sroot 		if (class_count[errortype] > 0){
105*1460Sroot 			if (errortype > C_SYNC)
106*1460Sroot 				someerrors++;
107*1460Sroot 			fprintf(stdout, "\n\t%d %s errors follow:\n",
108*1460Sroot 				class_count[errortype], class_table[errortype]);
109*1460Sroot 			for (errorp = *(erpp = files[0]);
110*1460Sroot 			     erpp < files[1];
111*1460Sroot 			     errorp = (*++erpp)){
112*1460Sroot 				if (errorp->error_e_class == errortype)
113*1460Sroot 					errorprint(stdout, errorp, TRUE);
114*1460Sroot 			}
115*1460Sroot 		}
116*1460Sroot 	    }
117*1460Sroot 	}
118*1460Sroot 	if (nfiles){
119*1460Sroot 		someerrors++;
120*1460Sroot 		fprintf(stdout, "%d files contain errors:", nfiles);
121*1460Sroot 		for (fileindex = 1; fileindex <= nfiles; fileindex++){
122*1460Sroot 			fprintf(stdout, "%s\"%s\" (%d)",
123*1460Sroot 				sep, (*files[fileindex])->error_text[0],
124*1460Sroot 				files[fileindex+1] - files[fileindex]);
125*1460Sroot 			sep = ", ";
126*1460Sroot 		}
127*1460Sroot 		fprintf(stdout, "\n");
128*1460Sroot 	}
129*1460Sroot 	if (!someerrors)
130*1460Sroot 		fprintf(stdout, "No errors.\n");
131*1460Sroot }
132*1460Sroot 
133*1460Sroot extern	boolean	notouch;
134*1460Sroot 
135*1460Sroot boolean touchfiles(nfiles, files, r_edargc, r_edargv)
136*1460Sroot 	int	nfiles;
137*1460Sroot 	struct	error_desc	***files;
138*1460Sroot 	int	*r_edargc;
139*1460Sroot 	char	***r_edargv;
140*1460Sroot {
141*1460Sroot 			char	*currentfilename;
142*1460Sroot 	register	struct	error_desc	*errorp;
143*1460Sroot 	register	int	fileindex;
144*1460Sroot 	register	struct	error_desc	**erpp;
145*1460Sroot 			int		ntrueerrors;
146*1460Sroot 			int		errordest;	/* where errors go*/
147*1460Sroot 			char		*sep;
148*1460Sroot 			boolean		scribbled;
149*1460Sroot 			int		n_pissed_on;	/* how many files touched*/
150*1460Sroot 	for (fileindex = 1; fileindex <= nfiles; fileindex++){
151*1460Sroot 		fprintf(stdout, "\nFile \"%s\" has %d total error messages.\n",
152*1460Sroot 			currentfilename = (*files[fileindex])->error_text[0],
153*1460Sroot 			files[fileindex+1] - files[fileindex]);
154*1460Sroot 		/*
155*1460Sroot 		 *	First, iterate through all error messages in this file
156*1460Sroot 		 *	to see how many of the error messages really will
157*1460Sroot 		 *	get inserted into the file.
158*1460Sroot 		 */
159*1460Sroot 		for (erpp = files[fileindex], ntrueerrors = 0;
160*1460Sroot 		     erpp < files[fileindex+1];
161*1460Sroot 		     erpp++){
162*1460Sroot 			errorp = *erpp;
163*1460Sroot 			if (errorp->error_e_class == C_TRUE)
164*1460Sroot 				ntrueerrors++;
165*1460Sroot 		}
166*1460Sroot 		fprintf(stdout,"\t%d of these errors can be inserted into the file.\n",
167*1460Sroot 			ntrueerrors);
168*1460Sroot 
169*1460Sroot 		/*
170*1460Sroot 		 *	What does the operator want?
171*1460Sroot 		 */
172*1460Sroot 		errordest = TOSTDOUT;
173*1460Sroot 		if (oktotouch(currentfilename) && (ntrueerrors > 0) ){
174*1460Sroot 			if (query && inquire("Do you want to preview the errors first?")){
175*1460Sroot 				for (erpp = files[fileindex];
176*1460Sroot 				     erpp < files[fileindex + 1];
177*1460Sroot 				     erpp++){
178*1460Sroot 					errorprint(stdout, *erpp, TRUE);
179*1460Sroot 				}
180*1460Sroot 				fprintf(stdout, "\n");
181*1460Sroot 			}
182*1460Sroot 			if (   !query
183*1460Sroot 			    || inquire("Do you want to touch file \"%s\"? ",
184*1460Sroot 					currentfilename)
185*1460Sroot 			){
186*1460Sroot 				errordest = TOTHEFILE;
187*1460Sroot 				if (!probethisfile(currentfilename)){
188*1460Sroot 					errordest = TOSTDOUT;
189*1460Sroot 					fprintf(stdout,
190*1460Sroot 					 "Can't find file \"%s\" to insert error messages into.\n",
191*1460Sroot 						currentfilename);
192*1460Sroot 				} else {
193*1460Sroot 					if (edit(currentfilename))
194*1460Sroot 						errordest = TOSTDOUT;
195*1460Sroot 					else
196*1460Sroot 						touchedfiles[fileindex] = TRUE;
197*1460Sroot 				}
198*1460Sroot 			}
199*1460Sroot 		}
200*1460Sroot 		/*
201*1460Sroot 		 *	go through and print each error message,
202*1460Sroot 		 *	diverting to the right place
203*1460Sroot 		 */
204*1460Sroot 		if ( (files[fileindex+1] - files[fileindex]) != ntrueerrors)
205*1460Sroot 			fprintf(stdout,
206*1460Sroot 			    ">>Uninserted error messages for file \"%s\" follow.\n",
207*1460Sroot 			    currentfilename);
208*1460Sroot 		for (erpp = files[fileindex];erpp < files[fileindex+1];erpp++){
209*1460Sroot 			errorp = *erpp;
210*1460Sroot 			if (errorp->error_e_class == C_TRUE){
211*1460Sroot 				switch (errordest){
212*1460Sroot 				  case TOSTDOUT:
213*1460Sroot 					errorprint(stdout, errorp, TRUE);
214*1460Sroot 					  break;
215*1460Sroot 				  case TOTHEFILE:
216*1460Sroot 					insert(errorp->error_line);
217*1460Sroot 					text(errorp, FALSE);
218*1460Sroot 					break;
219*1460Sroot 				}	/* switch */
220*1460Sroot 			} else {
221*1460Sroot 				errorprint(stdout, errorp, TRUE);
222*1460Sroot 			}
223*1460Sroot 		}	/* end of walking through all errors*/
224*1460Sroot 		if (errordest == TOTHEFILE){
225*1460Sroot 			writetouched();
226*1460Sroot 		}
227*1460Sroot 	}	/* end of walking through all files*/
228*1460Sroot 	scribbled = FALSE;
229*1460Sroot 	for (n_pissed_on = 0, fileindex = 1; fileindex <= nfiles; fileindex++){
230*1460Sroot 		scribbled |= touchedfiles[fileindex];
231*1460Sroot 		n_pissed_on++;
232*1460Sroot 	}
233*1460Sroot 	if (scribbled){
234*1460Sroot 		/*
235*1460Sroot 		 *	Construct an execv argument
236*1460Sroot 		 *	We need 1 argument for the editor's name
237*1460Sroot 		 *	We need 1 argument for the initial search string
238*1460Sroot 		 *	We need n_pissed_on arguments for the file names
239*1460Sroot 		 *	We need 1 argument that is a null for execv.
240*1460Sroot 		 *	The caller fills in the editor's name.
241*1460Sroot 		 *	We fill in the initial search string.
242*1460Sroot 		 *	We fill in the arguments, and the null.
243*1460Sroot 		 */
244*1460Sroot 		(*r_edargv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *));
245*1460Sroot 		(*r_edargc) =  n_pissed_on + 2;
246*1460Sroot 		(*r_edargv)[1] = "+/###/";
247*1460Sroot 		n_pissed_on = 2;
248*1460Sroot 		fprintf(stdout, "You touched file(s):");
249*1460Sroot 		sep = " ";
250*1460Sroot 		for (fileindex = 1; fileindex <= nfiles; fileindex++){
251*1460Sroot 			if (!touchedfiles[fileindex])
252*1460Sroot 				continue;
253*1460Sroot 			errorp = *(files[fileindex]);
254*1460Sroot 			fprintf(stdout,"%s\"%s\"", sep, errorp->error_text[0]);
255*1460Sroot 			sep = ", ";
256*1460Sroot 			(*r_edargv)[n_pissed_on++] = errorp->error_text[0];
257*1460Sroot 		}
258*1460Sroot 		fprintf(stdout, "\n");
259*1460Sroot 		(*r_edargv)[n_pissed_on] = 0;
260*1460Sroot 		return(TRUE);
261*1460Sroot 	} else {
262*1460Sroot 		fprintf(stdout, "You didn't touch any files.\n");
263*1460Sroot 		return(FALSE);
264*1460Sroot 	}
265*1460Sroot 
266*1460Sroot }	/* end of touchfiles*/
267*1460Sroot int	oktotouch(filename)
268*1460Sroot 	char	*filename;
269*1460Sroot {
270*1460Sroot 	extern		char	*suffixlist;
271*1460Sroot 	register	char	*src;
272*1460Sroot 	register	char	*pat;
273*1460Sroot 			char	*osrc;
274*1460Sroot 
275*1460Sroot 	pat = suffixlist;
276*1460Sroot 	if (pat == 0)
277*1460Sroot 		return(0);
278*1460Sroot 	if (*pat == '*')
279*1460Sroot 		return(1);
280*1460Sroot 	while (*pat++ != '.')
281*1460Sroot 		continue;
282*1460Sroot 	--pat;		/* point to the period */
283*1460Sroot 
284*1460Sroot 	for (src = &filename[strlen(filename)], --src;
285*1460Sroot 	     (src > filename) && (*src != '.'); --src)
286*1460Sroot 		continue;
287*1460Sroot 	if (*src != '.')
288*1460Sroot 		return(0);
289*1460Sroot 
290*1460Sroot 	for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){
291*1460Sroot 		for (;   *src			/* not at end of the source */
292*1460Sroot 		      && *pat			/* not off end of pattern */
293*1460Sroot 		      && *pat != '.'		/* not off end of sub pattern */
294*1460Sroot 		      && *pat != '*'		/* not wild card */
295*1460Sroot 		      && *src == *pat;		/* and equal... */
296*1460Sroot 		      src++, pat++)
297*1460Sroot 			continue;
298*1460Sroot 		if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*'))
299*1460Sroot 			return(1);
300*1460Sroot 		if (*src != 0 && *pat == '*')
301*1460Sroot 			return(1);
302*1460Sroot 		while (*pat && *pat != '.')
303*1460Sroot 			pat++;
304*1460Sroot 		if (! *pat)
305*1460Sroot 			return(0);
306*1460Sroot 	}
307*1460Sroot 	return(0);
308*1460Sroot }
309*1460Sroot 
310*1460Sroot FILE	*o_touchedfile;	/* the old file */
311*1460Sroot FILE	*n_touchedfile;	/* the new file */
312*1460Sroot char	*o_name;
313*1460Sroot char	n_name[32];
314*1460Sroot char	*canon_name = "ErrorXXXXXX";
315*1460Sroot int	o_lineno;
316*1460Sroot int	n_lineno;
317*1460Sroot boolean	tempfileopen = FALSE;
318*1460Sroot /*
319*1460Sroot  *	open the file; guaranteed to be both readable and writable
320*1460Sroot  *	Well, if it isn't, then return TRUE if something failed
321*1460Sroot  */
322*1460Sroot boolean edit(name)
323*1460Sroot 	char	*name;
324*1460Sroot {
325*1460Sroot 	o_name = name;
326*1460Sroot 	if ( (o_touchedfile = fopen(name, "r")) == NULL){
327*1460Sroot 		fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n",
328*1460Sroot 			processname, name);
329*1460Sroot 		return(TRUE);
330*1460Sroot 	}
331*1460Sroot 	strcpy(n_name, canon_name);
332*1460Sroot 	mktemp(n_name);
333*1460Sroot 	if ( (n_touchedfile = fopen(n_name, "w")) == NULL){
334*1460Sroot 		fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n",
335*1460Sroot 			processname, name);
336*1460Sroot 		return(TRUE);
337*1460Sroot 	}
338*1460Sroot 	tempfileopen = TRUE;
339*1460Sroot 	n_lineno = 0;
340*1460Sroot 	o_lineno = 0;
341*1460Sroot 	return(FALSE);
342*1460Sroot }
343*1460Sroot /*
344*1460Sroot  *	Position to the line (before, after) the line given by place
345*1460Sroot  */
346*1460Sroot char	edbuffer[BUFSIZ];
347*1460Sroot insert(place)
348*1460Sroot 	int	place;
349*1460Sroot {
350*1460Sroot 	--place;	/* always insert messages before the offending line*/
351*1460Sroot 	for(; o_lineno < place; o_lineno++, n_lineno++){
352*1460Sroot 		if(fgets(edbuffer, BUFSIZ, o_touchedfile) == NULL)
353*1460Sroot 			return;
354*1460Sroot 		fputs(edbuffer, n_touchedfile);
355*1460Sroot 	}
356*1460Sroot }
357*1460Sroot 
358*1460Sroot text(errorp, use_all)
359*1460Sroot 	register	struct	error_desc	*errorp;
360*1460Sroot 	boolean	use_all;
361*1460Sroot {
362*1460Sroot 	int	offset = use_all ? 0 : 2;
363*1460Sroot 	fputs(lang_table[errorp->error_language].lang_incomment, n_touchedfile);
364*1460Sroot 	fprintf(n_touchedfile, "%d [%s] ",
365*1460Sroot 		errorp->error_line,
366*1460Sroot 		lang_table[errorp->error_language].lang_name);
367*1460Sroot 	wordvprint(n_touchedfile,
368*1460Sroot 		errorp->error_lgtext-offset, errorp->error_text+offset);
369*1460Sroot 	fputs(lang_table[errorp->error_language].lang_outcomment,n_touchedfile);
370*1460Sroot 	n_lineno++;
371*1460Sroot }
372*1460Sroot 
373*1460Sroot writetouched()
374*1460Sroot {
375*1460Sroot 	int	bytes_read;
376*1460Sroot 	for(; (bytes_read = fread(edbuffer, 1, sizeof(edbuffer), o_touchedfile))!= NULL; ){
377*1460Sroot 		fwrite(edbuffer, 1, bytes_read, n_touchedfile);
378*1460Sroot 	}
379*1460Sroot 	fclose(n_touchedfile);
380*1460Sroot 	fclose(o_touchedfile);
381*1460Sroot 	unlink(o_name);
382*1460Sroot 	link(n_name, o_name);
383*1460Sroot 	unlink(n_name);
384*1460Sroot 	tempfileopen = FALSE;
385*1460Sroot }
386*1460Sroot onintr()
387*1460Sroot {
388*1460Sroot 	if (inquire("\nInterrupt: Do you want to continue?")){
389*1460Sroot 		signal(SIGINT, onintr);
390*1460Sroot 		return;
391*1460Sroot 	}
392*1460Sroot 	if (tempfileopen)
393*1460Sroot 		writetouched();
394*1460Sroot 	exit(1);
395*1460Sroot }
396*1460Sroot errorprint(place, errorp, print_all)
397*1460Sroot 	FILE	*place;
398*1460Sroot 	struct	error_desc	*errorp;
399*1460Sroot 	boolean	print_all;
400*1460Sroot {
401*1460Sroot 	int	offset = print_all ? 0 : 2;
402*1460Sroot 
403*1460Sroot 	if (errorp->error_e_class == C_IGNORE)
404*1460Sroot 		return;
405*1460Sroot 	fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name);
406*1460Sroot 	wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset);
407*1460Sroot 	putc('\n', place);
408*1460Sroot }
409*1460Sroot 
410*1460Sroot boolean inquire(fmt, a1, a2)
411*1460Sroot 	char	*fmt;
412*1460Sroot 	/*VARARGS1*/
413*1460Sroot {
414*1460Sroot 	char	buffer[128];
415*1460Sroot 	char	ch;
416*1460Sroot 	for(;;){
417*1460Sroot 		do{
418*1460Sroot 			fflush(stdout);
419*1460Sroot 			fprintf(stderr, fmt, a1, a2);
420*1460Sroot 			fflush(stderr);
421*1460Sroot 		} while (fgets(buffer, 127, queryfile) == NULL);
422*1460Sroot 		ch = buffer[0];
423*1460Sroot 		if (ch == 'Y' || ch == 'y')
424*1460Sroot 			return(TRUE);
425*1460Sroot 		if (ch == 'N' || ch == 'n')
426*1460Sroot 			return(FALSE);
427*1460Sroot 		fprintf(stderr, "Yes or No only!\n");
428*1460Sroot 	}
429*1460Sroot }
430*1460Sroot 
431*1460Sroot boolean probethisfile(currentfilename)
432*1460Sroot 	char	*currentfilename;
433*1460Sroot {
434*1460Sroot 	struct stat statbuf;
435*1460Sroot 	if (stat(currentfilename, &statbuf) != 0)
436*1460Sroot 		return(FALSE);
437*1460Sroot 	if ( (statbuf.st_mode&S_IREAD) && (statbuf.st_mode&S_IWRITE))
438*1460Sroot 		return(TRUE);
439*1460Sroot 	return(FALSE);
440*1460Sroot }
441