xref: /csrg-svn/usr.bin/error/touch.c (revision 1462)
1*1462Sroot static	char *sccsid = "@(#)touch.c	1.2 (Berkeley) 10/16/80";
21460Sroot #include <stdio.h>
31460Sroot #include <ctype.h>
41460Sroot #include <sys/types.h>
51460Sroot #include <sys/stat.h>
61460Sroot #include <signal.h>
71460Sroot #include "error.h"
81460Sroot 
91460Sroot findfiles(nerrors, errors, r_nfiles, r_files)
101460Sroot 	int	nerrors;
111460Sroot 	struct	error_desc	**errors;
121460Sroot 	int	*r_nfiles;
131460Sroot 	struct	error_desc	****r_files;
141460Sroot {
151460Sroot 			int	nfiles;
161460Sroot 	struct	error_desc	***files;
171460Sroot 
181460Sroot 			char	*currentfilename;
191460Sroot 	register	int	errorindex;
201460Sroot 			int	fileindex;
211460Sroot 	register	struct	error_desc	*errorp;
221460Sroot 	/*
231460Sroot 	 *	First, go through and count all of the filenames
241460Sroot 	 */
251460Sroot 	for (errorp = errors[errorindex = 0],nfiles = 0, currentfilename = "\1";
261460Sroot 	     errorindex < nerrors;
271460Sroot 	     errorp = errors[++errorindex]){
281460Sroot 		if (SORTABLE(errorp->error_e_class)){
291460Sroot 			if (strcmp(errorp->error_text[0],currentfilename) != 0){
301460Sroot 				nfiles++;
311460Sroot 				currentfilename = errorp->error_text[0];
321460Sroot 			}
331460Sroot 		}
341460Sroot 	}
351460Sroot 	files = (struct error_desc ***)Calloc(nfiles + 3,
361460Sroot 		sizeof (struct error_desc**));
371460Sroot 	touchedfiles = (boolean	*)Calloc(nfiles+3, sizeof(boolean));
381460Sroot 	/*
391460Sroot 	 *	Now, go through and partition off the error messages
401460Sroot 	 *	into those that are synchronization, discarded or
411460Sroot 	 *	not specific to any file, and those that were
421460Sroot 	 *	nulled or true errors.
431460Sroot 	 */
441460Sroot 	files[0] = &errors[0];
451460Sroot 	for (errorp = errors[errorindex = 0], fileindex = 0;
461460Sroot 	     (errorindex < nerrors) &&
471460Sroot 		(NOTSORTABLE(errorp->error_e_class));
481460Sroot 	     errorp = errors[++errorindex]){
491460Sroot 		continue;
501460Sroot 	}
511460Sroot 	/*
521460Sroot 	 *	Now, go through and partition off all error messages
531460Sroot 	 *	for a given file.
541460Sroot 	 */
551460Sroot 	files[1] = &errors[errorindex];
561460Sroot 	touchedfiles[0] = touchedfiles[1] = FALSE;
571460Sroot 	for (errorp = errors[errorindex], currentfilename = "\1", fileindex = 1;
581460Sroot 	     errorindex < nerrors; errorp = errors[++errorindex]){
591460Sroot 		if ( (errorp->error_e_class == C_NULLED) || (errorp->error_e_class == C_TRUE) ){
601460Sroot 			if (strcmp(errorp->error_text[0],currentfilename) != 0){
611460Sroot 				currentfilename = errorp->error_text[0];
621460Sroot 				touchedfiles[fileindex] = FALSE;
631460Sroot 				files[fileindex++] = &errors[errorindex];
641460Sroot 			}
651460Sroot 		}
661460Sroot 	}
671460Sroot 	files[fileindex] = &errors[nerrors];
681460Sroot 	*r_nfiles = nfiles;
691460Sroot 	*r_files = files;
701460Sroot }
711460Sroot 
721460Sroot char	*class_table[] = {
731460Sroot 	/*C_UNKNOWN	0	*/	"Unknown",
741460Sroot 	/*C_IGNORE	1	*/	"ignore",
751460Sroot 	/*C_SYNC	2	*/	"synchronization",
761460Sroot 	/*C_DISCARD	3	*/	"discarded",
771460Sroot 	/*C_NONSPEC	4	*/	"non specific",
781460Sroot 	/*C_THISFILE	5	*/	"specific to this file",
791460Sroot 	/*C_NULLED	6	*/	"nulled",
801460Sroot 	/*C_TRUE	7	*/	"true",
811460Sroot 	/*C_DUPL	8	*/	"duplicated"
821460Sroot };
831460Sroot 
841460Sroot int	class_count[C_LAST - C_FIRST] = {0};
851460Sroot 
861460Sroot filenames(nfiles, files)
871460Sroot 	int	nfiles;
881460Sroot 	struct	error_desc	***files;
891460Sroot {
901460Sroot 	register	int	fileindex;
911460Sroot 	register	struct	error_desc	*errorp;
921460Sroot 	register	struct	error_desc	**erpp;
931460Sroot 			char	*sep = " ";
941460Sroot 	register	int	errortype;
951460Sroot 	extern		char	*class_table[];
961460Sroot 			int	someerrors = 0;
971460Sroot 
981460Sroot 	/*
991460Sroot 	 *	first, go through and simply dump out errors that
1001460Sroot 	 *	don't pertain to any file
1011460Sroot 	 */
1021460Sroot 	if (files[1] - files[0] > 0){
1031460Sroot 	    for(errortype = C_UNKNOWN; NOTSORTABLE(errortype); errortype++){
1041460Sroot 		if (class_count[errortype] > 0){
1051460Sroot 			if (errortype > C_SYNC)
1061460Sroot 				someerrors++;
1071460Sroot 			fprintf(stdout, "\n\t%d %s errors follow:\n",
1081460Sroot 				class_count[errortype], class_table[errortype]);
1091460Sroot 			for (errorp = *(erpp = files[0]);
1101460Sroot 			     erpp < files[1];
1111460Sroot 			     errorp = (*++erpp)){
1121460Sroot 				if (errorp->error_e_class == errortype)
1131460Sroot 					errorprint(stdout, errorp, TRUE);
1141460Sroot 			}
1151460Sroot 		}
1161460Sroot 	    }
1171460Sroot 	}
1181460Sroot 	if (nfiles){
1191460Sroot 		someerrors++;
1201460Sroot 		fprintf(stdout, "%d files contain errors:", nfiles);
1211460Sroot 		for (fileindex = 1; fileindex <= nfiles; fileindex++){
1221460Sroot 			fprintf(stdout, "%s\"%s\" (%d)",
1231460Sroot 				sep, (*files[fileindex])->error_text[0],
1241460Sroot 				files[fileindex+1] - files[fileindex]);
1251460Sroot 			sep = ", ";
1261460Sroot 		}
1271460Sroot 		fprintf(stdout, "\n");
1281460Sroot 	}
1291460Sroot 	if (!someerrors)
1301460Sroot 		fprintf(stdout, "No errors.\n");
1311460Sroot }
1321460Sroot 
1331460Sroot extern	boolean	notouch;
1341460Sroot 
1351460Sroot boolean touchfiles(nfiles, files, r_edargc, r_edargv)
1361460Sroot 	int	nfiles;
1371460Sroot 	struct	error_desc	***files;
1381460Sroot 	int	*r_edargc;
1391460Sroot 	char	***r_edargv;
1401460Sroot {
1411460Sroot 			char	*currentfilename;
1421460Sroot 	register	struct	error_desc	*errorp;
1431460Sroot 	register	int	fileindex;
1441460Sroot 	register	struct	error_desc	**erpp;
1451460Sroot 			int		ntrueerrors;
1461460Sroot 			int		errordest;	/* where errors go*/
1471460Sroot 			char		*sep;
1481460Sroot 			boolean		scribbled;
149*1462Sroot 			int		n_pissed_on;	/* # of file touched*/
150*1462Sroot 			int		previewed;
151*1462Sroot 
1521460Sroot 	for (fileindex = 1; fileindex <= nfiles; fileindex++){
1531460Sroot 		fprintf(stdout, "\nFile \"%s\" has %d total error messages.\n",
1541460Sroot 			currentfilename = (*files[fileindex])->error_text[0],
1551460Sroot 			files[fileindex+1] - files[fileindex]);
1561460Sroot 		/*
1571460Sroot 		 *	First, iterate through all error messages in this file
1581460Sroot 		 *	to see how many of the error messages really will
1591460Sroot 		 *	get inserted into the file.
1601460Sroot 		 */
1611460Sroot 		for (erpp = files[fileindex], ntrueerrors = 0;
1621460Sroot 		     erpp < files[fileindex+1];
1631460Sroot 		     erpp++){
1641460Sroot 			errorp = *erpp;
1651460Sroot 			if (errorp->error_e_class == C_TRUE)
1661460Sroot 				ntrueerrors++;
1671460Sroot 		}
1681460Sroot 		fprintf(stdout,"\t%d of these errors can be inserted into the file.\n",
1691460Sroot 			ntrueerrors);
1701460Sroot 
1711460Sroot 		/*
1721460Sroot 		 *	What does the operator want?
1731460Sroot 		 */
174*1462Sroot 		previewed = 0;
1751460Sroot 		errordest = TOSTDOUT;
1761460Sroot 		if (oktotouch(currentfilename) && (ntrueerrors > 0) ){
1771460Sroot 			if (query && inquire("Do you want to preview the errors first?")){
178*1462Sroot 				previewed = 1;
1791460Sroot 				for (erpp = files[fileindex];
1801460Sroot 				     erpp < files[fileindex + 1];
1811460Sroot 				     erpp++){
1821460Sroot 					errorprint(stdout, *erpp, TRUE);
1831460Sroot 				}
1841460Sroot 				fprintf(stdout, "\n");
1851460Sroot 			}
1861460Sroot 			if (   !query
1871460Sroot 			    || inquire("Do you want to touch file \"%s\"? ",
1881460Sroot 					currentfilename)
1891460Sroot 			){
1901460Sroot 				errordest = TOTHEFILE;
1911460Sroot 				if (!probethisfile(currentfilename)){
1921460Sroot 					errordest = TOSTDOUT;
1931460Sroot 					fprintf(stdout,
1941460Sroot 					 "Can't find file \"%s\" to insert error messages into.\n",
1951460Sroot 						currentfilename);
1961460Sroot 				} else {
1971460Sroot 					if (edit(currentfilename))
1981460Sroot 						errordest = TOSTDOUT;
1991460Sroot 					else
2001460Sroot 						touchedfiles[fileindex] = TRUE;
2011460Sroot 				}
2021460Sroot 			}
2031460Sroot 		}
204*1462Sroot 		if (previewed && (errordest == TOSTDOUT))
205*1462Sroot 			continue;		/* with the next file */
2061460Sroot 		/*
2071460Sroot 		 *	go through and print each error message,
2081460Sroot 		 *	diverting to the right place
2091460Sroot 		 */
2101460Sroot 		if ( (files[fileindex+1] - files[fileindex]) != ntrueerrors)
211*1462Sroot 			if (!previewed) fprintf(stdout,
2121460Sroot 			    ">>Uninserted error messages for file \"%s\" follow.\n",
2131460Sroot 			    currentfilename);
2141460Sroot 		for (erpp = files[fileindex];erpp < files[fileindex+1];erpp++){
2151460Sroot 			errorp = *erpp;
2161460Sroot 			if (errorp->error_e_class == C_TRUE){
2171460Sroot 				switch (errordest){
2181460Sroot 				  case TOSTDOUT:
219*1462Sroot 					if (!previewed)
220*1462Sroot 						errorprint(stdout,errorp, TRUE);
221*1462Sroot 					break;
2221460Sroot 				  case TOTHEFILE:
2231460Sroot 					insert(errorp->error_line);
2241460Sroot 					text(errorp, FALSE);
2251460Sroot 					break;
2261460Sroot 				}	/* switch */
2271460Sroot 			} else {
228*1462Sroot 				if (!previewed)
229*1462Sroot 					errorprint(stdout, errorp, TRUE);
2301460Sroot 			}
2311460Sroot 		}	/* end of walking through all errors*/
2321460Sroot 		if (errordest == TOTHEFILE){
2331460Sroot 			writetouched();
2341460Sroot 		}
2351460Sroot 	}	/* end of walking through all files*/
2361460Sroot 	scribbled = FALSE;
2371460Sroot 	for (n_pissed_on = 0, fileindex = 1; fileindex <= nfiles; fileindex++){
2381460Sroot 		scribbled |= touchedfiles[fileindex];
2391460Sroot 		n_pissed_on++;
2401460Sroot 	}
2411460Sroot 	if (scribbled){
2421460Sroot 		/*
2431460Sroot 		 *	Construct an execv argument
2441460Sroot 		 *	We need 1 argument for the editor's name
2451460Sroot 		 *	We need 1 argument for the initial search string
2461460Sroot 		 *	We need n_pissed_on arguments for the file names
2471460Sroot 		 *	We need 1 argument that is a null for execv.
2481460Sroot 		 *	The caller fills in the editor's name.
2491460Sroot 		 *	We fill in the initial search string.
2501460Sroot 		 *	We fill in the arguments, and the null.
2511460Sroot 		 */
2521460Sroot 		(*r_edargv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *));
2531460Sroot 		(*r_edargc) =  n_pissed_on + 2;
2541460Sroot 		(*r_edargv)[1] = "+/###/";
2551460Sroot 		n_pissed_on = 2;
2561460Sroot 		fprintf(stdout, "You touched file(s):");
2571460Sroot 		sep = " ";
2581460Sroot 		for (fileindex = 1; fileindex <= nfiles; fileindex++){
2591460Sroot 			if (!touchedfiles[fileindex])
2601460Sroot 				continue;
2611460Sroot 			errorp = *(files[fileindex]);
2621460Sroot 			fprintf(stdout,"%s\"%s\"", sep, errorp->error_text[0]);
2631460Sroot 			sep = ", ";
2641460Sroot 			(*r_edargv)[n_pissed_on++] = errorp->error_text[0];
2651460Sroot 		}
2661460Sroot 		fprintf(stdout, "\n");
2671460Sroot 		(*r_edargv)[n_pissed_on] = 0;
2681460Sroot 		return(TRUE);
2691460Sroot 	} else {
2701460Sroot 		fprintf(stdout, "You didn't touch any files.\n");
2711460Sroot 		return(FALSE);
2721460Sroot 	}
2731460Sroot 
2741460Sroot }	/* end of touchfiles*/
2751460Sroot int	oktotouch(filename)
2761460Sroot 	char	*filename;
2771460Sroot {
2781460Sroot 	extern		char	*suffixlist;
2791460Sroot 	register	char	*src;
2801460Sroot 	register	char	*pat;
2811460Sroot 			char	*osrc;
2821460Sroot 
2831460Sroot 	pat = suffixlist;
2841460Sroot 	if (pat == 0)
2851460Sroot 		return(0);
2861460Sroot 	if (*pat == '*')
2871460Sroot 		return(1);
2881460Sroot 	while (*pat++ != '.')
2891460Sroot 		continue;
2901460Sroot 	--pat;		/* point to the period */
2911460Sroot 
2921460Sroot 	for (src = &filename[strlen(filename)], --src;
2931460Sroot 	     (src > filename) && (*src != '.'); --src)
2941460Sroot 		continue;
2951460Sroot 	if (*src != '.')
2961460Sroot 		return(0);
2971460Sroot 
2981460Sroot 	for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){
2991460Sroot 		for (;   *src			/* not at end of the source */
3001460Sroot 		      && *pat			/* not off end of pattern */
3011460Sroot 		      && *pat != '.'		/* not off end of sub pattern */
3021460Sroot 		      && *pat != '*'		/* not wild card */
3031460Sroot 		      && *src == *pat;		/* and equal... */
3041460Sroot 		      src++, pat++)
3051460Sroot 			continue;
3061460Sroot 		if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*'))
3071460Sroot 			return(1);
3081460Sroot 		if (*src != 0 && *pat == '*')
3091460Sroot 			return(1);
3101460Sroot 		while (*pat && *pat != '.')
3111460Sroot 			pat++;
3121460Sroot 		if (! *pat)
3131460Sroot 			return(0);
3141460Sroot 	}
3151460Sroot 	return(0);
3161460Sroot }
3171460Sroot 
3181460Sroot FILE	*o_touchedfile;	/* the old file */
3191460Sroot FILE	*n_touchedfile;	/* the new file */
3201460Sroot char	*o_name;
3211460Sroot char	n_name[32];
3221460Sroot char	*canon_name = "ErrorXXXXXX";
3231460Sroot int	o_lineno;
3241460Sroot int	n_lineno;
3251460Sroot boolean	tempfileopen = FALSE;
3261460Sroot /*
3271460Sroot  *	open the file; guaranteed to be both readable and writable
3281460Sroot  *	Well, if it isn't, then return TRUE if something failed
3291460Sroot  */
3301460Sroot boolean edit(name)
3311460Sroot 	char	*name;
3321460Sroot {
3331460Sroot 	o_name = name;
3341460Sroot 	if ( (o_touchedfile = fopen(name, "r")) == NULL){
3351460Sroot 		fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n",
3361460Sroot 			processname, name);
3371460Sroot 		return(TRUE);
3381460Sroot 	}
3391460Sroot 	strcpy(n_name, canon_name);
3401460Sroot 	mktemp(n_name);
3411460Sroot 	if ( (n_touchedfile = fopen(n_name, "w")) == NULL){
3421460Sroot 		fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n",
3431460Sroot 			processname, name);
3441460Sroot 		return(TRUE);
3451460Sroot 	}
3461460Sroot 	tempfileopen = TRUE;
3471460Sroot 	n_lineno = 0;
3481460Sroot 	o_lineno = 0;
3491460Sroot 	return(FALSE);
3501460Sroot }
3511460Sroot /*
3521460Sroot  *	Position to the line (before, after) the line given by place
3531460Sroot  */
3541460Sroot char	edbuffer[BUFSIZ];
3551460Sroot insert(place)
3561460Sroot 	int	place;
3571460Sroot {
3581460Sroot 	--place;	/* always insert messages before the offending line*/
3591460Sroot 	for(; o_lineno < place; o_lineno++, n_lineno++){
3601460Sroot 		if(fgets(edbuffer, BUFSIZ, o_touchedfile) == NULL)
3611460Sroot 			return;
3621460Sroot 		fputs(edbuffer, n_touchedfile);
3631460Sroot 	}
3641460Sroot }
3651460Sroot 
3661460Sroot text(errorp, use_all)
3671460Sroot 	register	struct	error_desc	*errorp;
3681460Sroot 	boolean	use_all;
3691460Sroot {
3701460Sroot 	int	offset = use_all ? 0 : 2;
3711460Sroot 	fputs(lang_table[errorp->error_language].lang_incomment, n_touchedfile);
3721460Sroot 	fprintf(n_touchedfile, "%d [%s] ",
3731460Sroot 		errorp->error_line,
3741460Sroot 		lang_table[errorp->error_language].lang_name);
3751460Sroot 	wordvprint(n_touchedfile,
3761460Sroot 		errorp->error_lgtext-offset, errorp->error_text+offset);
3771460Sroot 	fputs(lang_table[errorp->error_language].lang_outcomment,n_touchedfile);
3781460Sroot 	n_lineno++;
3791460Sroot }
3801460Sroot 
3811460Sroot writetouched()
3821460Sroot {
3831460Sroot 	int	bytes_read;
3841460Sroot 	for(; (bytes_read = fread(edbuffer, 1, sizeof(edbuffer), o_touchedfile))!= NULL; ){
3851460Sroot 		fwrite(edbuffer, 1, bytes_read, n_touchedfile);
3861460Sroot 	}
3871460Sroot 	fclose(n_touchedfile);
3881460Sroot 	fclose(o_touchedfile);
3891460Sroot 	unlink(o_name);
3901460Sroot 	link(n_name, o_name);
3911460Sroot 	unlink(n_name);
3921460Sroot 	tempfileopen = FALSE;
3931460Sroot }
3941460Sroot onintr()
3951460Sroot {
3961460Sroot 	if (inquire("\nInterrupt: Do you want to continue?")){
3971460Sroot 		signal(SIGINT, onintr);
3981460Sroot 		return;
3991460Sroot 	}
4001460Sroot 	if (tempfileopen)
4011460Sroot 		writetouched();
4021460Sroot 	exit(1);
4031460Sroot }
4041460Sroot errorprint(place, errorp, print_all)
4051460Sroot 	FILE	*place;
4061460Sroot 	struct	error_desc	*errorp;
4071460Sroot 	boolean	print_all;
4081460Sroot {
4091460Sroot 	int	offset = print_all ? 0 : 2;
4101460Sroot 
4111460Sroot 	if (errorp->error_e_class == C_IGNORE)
4121460Sroot 		return;
4131460Sroot 	fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name);
4141460Sroot 	wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset);
4151460Sroot 	putc('\n', place);
4161460Sroot }
4171460Sroot 
4181460Sroot boolean inquire(fmt, a1, a2)
4191460Sroot 	char	*fmt;
4201460Sroot 	/*VARARGS1*/
4211460Sroot {
4221460Sroot 	char	buffer[128];
4231460Sroot 	char	ch;
4241460Sroot 	for(;;){
4251460Sroot 		do{
4261460Sroot 			fflush(stdout);
4271460Sroot 			fprintf(stderr, fmt, a1, a2);
4281460Sroot 			fflush(stderr);
4291460Sroot 		} while (fgets(buffer, 127, queryfile) == NULL);
4301460Sroot 		ch = buffer[0];
4311460Sroot 		if (ch == 'Y' || ch == 'y')
4321460Sroot 			return(TRUE);
4331460Sroot 		if (ch == 'N' || ch == 'n')
4341460Sroot 			return(FALSE);
4351460Sroot 		fprintf(stderr, "Yes or No only!\n");
4361460Sroot 	}
4371460Sroot }
4381460Sroot 
4391460Sroot boolean probethisfile(currentfilename)
4401460Sroot 	char	*currentfilename;
4411460Sroot {
4421460Sroot 	struct stat statbuf;
4431460Sroot 	if (stat(currentfilename, &statbuf) != 0)
4441460Sroot 		return(FALSE);
4451460Sroot 	if ( (statbuf.st_mode&S_IREAD) && (statbuf.st_mode&S_IWRITE))
4461460Sroot 		return(TRUE);
4471460Sroot 	return(FALSE);
4481460Sroot }
449