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