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