121639Sdist /* 221639Sdist * Copyright (c) 1980 Regents of the University of California. 3*34664Sbostic * All rights reserved. 4*34664Sbostic * 5*34664Sbostic * Redistribution and use in source and binary forms are permitted 6*34664Sbostic * provided that this notice is preserved and that due credit is given 7*34664Sbostic * to the University of California at Berkeley. The name of the University 8*34664Sbostic * may not be used to endorse or promote products derived from this 9*34664Sbostic * software without specific prior written permission. This software 10*34664Sbostic * is provided ``as is'' without express or implied warranty. 1121639Sdist */ 1221639Sdist 1321639Sdist #ifndef lint 14*34664Sbostic static char sccsid[] = "@(#)touch.c 5.2 (Berkeley) 06/06/88"; 15*34664Sbostic #endif /* not lint */ 1621639Sdist 171460Sroot #include <stdio.h> 181460Sroot #include <ctype.h> 191460Sroot #include <sys/types.h> 201460Sroot #include <sys/stat.h> 211460Sroot #include <signal.h> 221460Sroot #include "error.h" 231460Sroot 245595Srrh /* 255595Srrh * Iterate through errors 265595Srrh */ 275595Srrh #define EITERATE(p, fv, i) for (p = fv[i]; p < fv[i+1]; p++) 285595Srrh #define ECITERATE(ei, p, lb) for (ei = lb; p = errors[ei],ei < nerrors; ei++) 295595Srrh 305595Srrh #define FILEITERATE(fi, lb) for (fi = lb; fi <= nfiles; fi++) 315595Srrh int touchstatus = Q_YES; 325595Srrh 331460Sroot findfiles(nerrors, errors, r_nfiles, r_files) 345595Srrh int nerrors; 355595Srrh Eptr *errors; 365595Srrh int *r_nfiles; 375595Srrh Eptr ***r_files; 381460Sroot { 395595Srrh int nfiles; 405595Srrh Eptr **files; 411460Sroot 425595Srrh char *name; 435595Srrh reg int ei; 445595Srrh int fi; 455595Srrh reg Eptr errorp; 465595Srrh 475595Srrh nfiles = countfiles(errors); 485595Srrh 495595Srrh files = (Eptr**)Calloc(nfiles + 3, sizeof (Eptr*)); 501460Sroot touchedfiles = (boolean *)Calloc(nfiles+3, sizeof(boolean)); 511460Sroot /* 525595Srrh * Now, partition off the error messages 531460Sroot * into those that are synchronization, discarded or 541460Sroot * not specific to any file, and those that were 551460Sroot * nulled or true errors. 561460Sroot */ 571460Sroot files[0] = &errors[0]; 585595Srrh ECITERATE(ei, errorp, 0){ 595595Srrh if ( ! (NOTSORTABLE(errorp->error_e_class))) 605595Srrh break; 611460Sroot } 621460Sroot /* 635595Srrh * Now, and partition off all error messages 641460Sroot * for a given file. 651460Sroot */ 665595Srrh files[1] = &errors[ei]; 671460Sroot touchedfiles[0] = touchedfiles[1] = FALSE; 685595Srrh name = "\1"; 695595Srrh fi = 1; 705595Srrh ECITERATE(ei, errorp, ei){ 715595Srrh if ( (errorp->error_e_class == C_NULLED) 725595Srrh || (errorp->error_e_class == C_TRUE) ){ 735595Srrh if (strcmp(errorp->error_text[0], name) != 0){ 745595Srrh name = errorp->error_text[0]; 755595Srrh touchedfiles[fi] = FALSE; 765595Srrh files[fi] = &errors[ei]; 775595Srrh fi++; 781460Sroot } 791460Sroot } 801460Sroot } 815595Srrh files[fi] = &errors[nerrors]; 821460Sroot *r_nfiles = nfiles; 831460Sroot *r_files = files; 841460Sroot } 851460Sroot 865595Srrh int countfiles(errors) 875595Srrh Eptr *errors; 885595Srrh { 895595Srrh char *name; 905595Srrh int ei; 915595Srrh reg Eptr errorp; 925595Srrh 935595Srrh int nfiles; 945595Srrh nfiles = 0; 955595Srrh name = "\1"; 965595Srrh ECITERATE(ei, errorp, 0){ 975595Srrh if (SORTABLE(errorp->error_e_class)){ 985595Srrh if (strcmp(errorp->error_text[0],name) != 0){ 995595Srrh nfiles++; 1005595Srrh name = errorp->error_text[0]; 1015595Srrh } 1025595Srrh } 1035595Srrh } 1045595Srrh return(nfiles); 1055595Srrh } 1061460Sroot char *class_table[] = { 1071460Sroot /*C_UNKNOWN 0 */ "Unknown", 1081460Sroot /*C_IGNORE 1 */ "ignore", 1091460Sroot /*C_SYNC 2 */ "synchronization", 1101460Sroot /*C_DISCARD 3 */ "discarded", 1111460Sroot /*C_NONSPEC 4 */ "non specific", 1121460Sroot /*C_THISFILE 5 */ "specific to this file", 1131460Sroot /*C_NULLED 6 */ "nulled", 1141460Sroot /*C_TRUE 7 */ "true", 1151460Sroot /*C_DUPL 8 */ "duplicated" 1161460Sroot }; 1171460Sroot 1181460Sroot int class_count[C_LAST - C_FIRST] = {0}; 1191460Sroot 1201460Sroot filenames(nfiles, files) 1211460Sroot int nfiles; 1225595Srrh Eptr **files; 1231460Sroot { 1245595Srrh reg int fi; 1255595Srrh char *sep = " "; 1265595Srrh extern char *class_table[]; 1275595Srrh int someerrors; 1281460Sroot 1291460Sroot /* 1305595Srrh * first, simply dump out errors that 1311460Sroot * don't pertain to any file 1321460Sroot */ 1335595Srrh someerrors = nopertain(files); 1345595Srrh 1351460Sroot if (nfiles){ 1361460Sroot someerrors++; 1375595Srrh fprintf(stdout, terse 1385595Srrh ? "%d file%s" 1395595Srrh : "%d file%s contain%s errors", 1405595Srrh nfiles, plural(nfiles), verbform(nfiles)); 1415595Srrh if (!terse){ 1425595Srrh FILEITERATE(fi, 1){ 1435595Srrh fprintf(stdout, "%s\"%s\" (%d)", 1445595Srrh sep, (*files[fi])->error_text[0], 1455595Srrh files[fi+1] - files[fi]); 1465595Srrh sep = ", "; 1475595Srrh } 1481460Sroot } 1491460Sroot fprintf(stdout, "\n"); 1501460Sroot } 1511460Sroot if (!someerrors) 1521460Sroot fprintf(stdout, "No errors.\n"); 1531460Sroot } 1541460Sroot 1555595Srrh /* 1565595Srrh * Dump out errors that don't pertain to any file 1575595Srrh */ 1585595Srrh int nopertain(files) 1595595Srrh Eptr **files; 1605595Srrh { 1615595Srrh int type; 1625595Srrh int someerrors = 0; 1635595Srrh reg Eptr *erpp; 1645595Srrh reg Eptr errorp; 1655595Srrh 1665595Srrh if (files[1] - files[0] <= 0) 1675595Srrh return(0); 1685595Srrh for(type = C_UNKNOWN; NOTSORTABLE(type); type++){ 1695595Srrh if (class_count[type] <= 0) 1705595Srrh continue; 1715595Srrh if (type > C_SYNC) 1725595Srrh someerrors++; 1735595Srrh if (terse){ 1745595Srrh fprintf(stdout, "\t%d %s errors NOT PRINTED\n", 1755595Srrh class_count[type], class_table[type]); 1765595Srrh } else { 1775595Srrh fprintf(stdout, "\n\t%d %s errors follow\n", 1785595Srrh class_count[type], class_table[type]); 1795595Srrh EITERATE(erpp, files, 0){ 1805595Srrh errorp = *erpp; 1815595Srrh if (errorp->error_e_class == type){ 1825595Srrh errorprint(stdout, errorp, TRUE); 1835595Srrh } 1845595Srrh } 1855595Srrh } 1865595Srrh } 1875595Srrh return(someerrors); 1885595Srrh } 1895595Srrh 1901460Sroot extern boolean notouch; 1911460Sroot 1921460Sroot boolean touchfiles(nfiles, files, r_edargc, r_edargv) 1931460Sroot int nfiles; 1945595Srrh Eptr **files; 1951460Sroot int *r_edargc; 1961460Sroot char ***r_edargv; 1971460Sroot { 1985595Srrh char *name; 1995595Srrh reg Eptr errorp; 2005595Srrh reg int fi; 2015595Srrh reg Eptr *erpp; 2025595Srrh int ntrueerrors; 2035595Srrh boolean scribbled; 2045595Srrh int n_pissed_on; /* # of file touched*/ 2055595Srrh int spread; 2061462Sroot 2075595Srrh FILEITERATE(fi, 1){ 2085595Srrh name = (*files[fi])->error_text[0]; 2095595Srrh spread = files[fi+1] - files[fi]; 2105595Srrh fprintf(stdout, terse 2115595Srrh ? "\"%s\" has %d error%s, " 2125595Srrh : "\nFile \"%s\" has %d error%s.\n" 2135595Srrh , name ,spread ,plural(spread)); 2141460Sroot /* 2151460Sroot * First, iterate through all error messages in this file 2161460Sroot * to see how many of the error messages really will 2171460Sroot * get inserted into the file. 2181460Sroot */ 2195595Srrh ntrueerrors = 0; 2205595Srrh EITERATE(erpp, files, fi){ 2211460Sroot errorp = *erpp; 2221460Sroot if (errorp->error_e_class == C_TRUE) 2231460Sroot ntrueerrors++; 2241460Sroot } 2255595Srrh fprintf(stdout, terse 2265595Srrh ? "insert %d\n" 2275595Srrh : "\t%d of these errors can be inserted into the file.\n", 2281460Sroot ntrueerrors); 2291460Sroot 2305595Srrh hackfile(name, files, fi, ntrueerrors); 2315595Srrh } 2321460Sroot scribbled = FALSE; 2335595Srrh n_pissed_on = 0; 2345595Srrh FILEITERATE(fi, 1){ 2355595Srrh scribbled |= touchedfiles[fi]; 2361460Sroot n_pissed_on++; 2371460Sroot } 2381460Sroot if (scribbled){ 2391460Sroot /* 2401460Sroot * Construct an execv argument 2411460Sroot */ 2425595Srrh execvarg(n_pissed_on, r_edargc, r_edargv); 2431460Sroot return(TRUE); 2441460Sroot } else { 2455595Srrh if (!terse) 2465595Srrh fprintf(stdout, "You didn't touch any files.\n"); 2471460Sroot return(FALSE); 2481460Sroot } 2495595Srrh } 2501460Sroot 2515595Srrh hackfile(name, files, ix, nerrors) 2525595Srrh char *name; 2535595Srrh Eptr **files; 2545595Srrh int ix; 2555595Srrh { 2565595Srrh boolean previewed; 2575595Srrh int errordest; /* where errors go*/ 2585595Srrh 25917212Sralph if (!oktotouch(name)) { 26017212Sralph previewed = FALSE; 26117212Sralph errordest = TOSTDOUT; 26217212Sralph } else { 26317212Sralph previewed = preview(name, nerrors, files, ix); 26417212Sralph errordest = settotouch(name); 26517212Sralph } 2665595Srrh 2675595Srrh if (errordest != TOSTDOUT) 2685595Srrh touchedfiles[ix] = TRUE; 2695595Srrh 2705595Srrh if (previewed && (errordest == TOSTDOUT)) 2715595Srrh return; 2725595Srrh 2735595Srrh diverterrors(name, errordest, files, ix, previewed, nerrors); 2745595Srrh 2756612Srrh if (errordest == TOTHEFILE){ 2766612Srrh /* 2776612Srrh * overwrite the original file 2786612Srrh */ 2796612Srrh writetouched(1); 2806612Srrh } 2815595Srrh } 2825595Srrh 2835595Srrh boolean preview(name, nerrors, files, ix) 2845595Srrh char *name; 2855595Srrh int nerrors; 2865595Srrh Eptr **files; 2875595Srrh int ix; 2885595Srrh { 2895595Srrh int back; 2905595Srrh reg Eptr *erpp; 2915595Srrh 2925595Srrh if (nerrors <= 0) 29317212Sralph return(FALSE); 29417212Sralph back = FALSE; 2955595Srrh if(query){ 2965595Srrh switch(inquire(terse 2975595Srrh ? "Preview? " 2985595Srrh : "Do you want to preview the errors first? ")){ 2995595Srrh case Q_YES: 3005595Srrh case Q_yes: 30117212Sralph back = TRUE; 3025595Srrh EITERATE(erpp, files, ix){ 3035595Srrh errorprint(stdout, *erpp, TRUE); 3045595Srrh } 3055595Srrh if (!terse) 3065595Srrh fprintf(stdout, "\n"); 3075595Srrh default: 3085595Srrh break; 3095595Srrh } 3105595Srrh } 3115595Srrh return(back); 3125595Srrh } 3135595Srrh 3145595Srrh int settotouch(name) 3155595Srrh char *name; 3165595Srrh { 3175595Srrh int dest = TOSTDOUT; 3185595Srrh 3195595Srrh if (query){ 3205595Srrh switch(touchstatus = inquire(terse 3215595Srrh ? "Touch? " 3225595Srrh : "Do you want to touch file \"%s\"? ", 3235595Srrh name)){ 3245595Srrh case Q_NO: 3255595Srrh case Q_no: 3265595Srrh return(dest); 3275595Srrh default: 3285595Srrh break; 3295595Srrh } 3305595Srrh } 3315595Srrh 3325595Srrh switch(probethisfile(name)){ 3335595Srrh case F_NOTREAD: 3345595Srrh dest = TOSTDOUT; 3355595Srrh fprintf(stdout, terse 3365595Srrh ? "\"%s\" unreadable\n" 3375595Srrh : "File \"%s\" is unreadable\n", 3385595Srrh name); 3395595Srrh break; 3405595Srrh case F_NOTWRITE: 3415595Srrh dest = TOSTDOUT; 3425595Srrh fprintf(stdout, terse 3435595Srrh ? "\"%s\" unwritable\n" 3445595Srrh : "File \"%s\" is unwritable\n", 3455595Srrh name); 3465595Srrh break; 3475595Srrh case F_NOTEXIST: 3485595Srrh dest = TOSTDOUT; 3495595Srrh fprintf(stdout, terse 3505595Srrh ? "\"%s\" not found\n" 3515595Srrh : "Can't find file \"%s\" to insert error messages into.\n", 3525595Srrh name); 3535595Srrh break; 3545595Srrh default: 3555595Srrh dest = edit(name) ? TOSTDOUT : TOTHEFILE; 3565595Srrh break; 3575595Srrh } 3585595Srrh return(dest); 3595595Srrh } 3605595Srrh 3615595Srrh diverterrors(name, dest, files, ix, previewed, nterrors) 3625595Srrh char *name; 3635595Srrh int dest; 3645595Srrh Eptr **files; 3655595Srrh int ix; 3665595Srrh boolean previewed; 3675595Srrh int nterrors; 3685595Srrh { 3695595Srrh int nerrors; 3705595Srrh reg Eptr *erpp; 3715595Srrh reg Eptr errorp; 3725595Srrh 3735595Srrh nerrors = files[ix+1] - files[ix]; 3745595Srrh 3755595Srrh if ( (nerrors != nterrors) 3765595Srrh && (!previewed) ){ 3775595Srrh fprintf(stdout, terse 3785595Srrh ? "Uninserted errors\n" 3795595Srrh : ">>Uninserted errors for file \"%s\" follow.\n", 3805595Srrh name); 3815595Srrh } 3825595Srrh 3835595Srrh EITERATE(erpp, files, ix){ 3845595Srrh errorp = *erpp; 3855595Srrh if (errorp->error_e_class != C_TRUE){ 3865595Srrh if (previewed || touchstatus == Q_NO) 3875595Srrh continue; 3885595Srrh errorprint(stdout, errorp, TRUE); 3895595Srrh continue; 3905595Srrh } 3915595Srrh switch (dest){ 3925595Srrh case TOSTDOUT: 3935595Srrh if (previewed || touchstatus == Q_NO) 3945595Srrh continue; 3955595Srrh errorprint(stdout,errorp, TRUE); 3965595Srrh break; 3975595Srrh case TOTHEFILE: 3985595Srrh insert(errorp->error_line); 3995595Srrh text(errorp, FALSE); 4005595Srrh break; 4015595Srrh } 4025595Srrh } 4035595Srrh } 4045595Srrh 4055595Srrh int oktotouch(filename) 4061460Sroot char *filename; 4071460Sroot { 4081460Sroot extern char *suffixlist; 4095595Srrh reg char *src; 4105595Srrh reg char *pat; 4111460Sroot char *osrc; 4121460Sroot 4131460Sroot pat = suffixlist; 4141460Sroot if (pat == 0) 4151460Sroot return(0); 4161460Sroot if (*pat == '*') 4171460Sroot return(1); 4181460Sroot while (*pat++ != '.') 4191460Sroot continue; 4201460Sroot --pat; /* point to the period */ 4211460Sroot 4221460Sroot for (src = &filename[strlen(filename)], --src; 4231460Sroot (src > filename) && (*src != '.'); --src) 4241460Sroot continue; 4251460Sroot if (*src != '.') 4261460Sroot return(0); 4271460Sroot 4281460Sroot for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){ 4291460Sroot for (; *src /* not at end of the source */ 4301460Sroot && *pat /* not off end of pattern */ 4311460Sroot && *pat != '.' /* not off end of sub pattern */ 4321460Sroot && *pat != '*' /* not wild card */ 4331460Sroot && *src == *pat; /* and equal... */ 4341460Sroot src++, pat++) 4351460Sroot continue; 4361460Sroot if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*')) 4371460Sroot return(1); 4381460Sroot if (*src != 0 && *pat == '*') 4391460Sroot return(1); 4401460Sroot while (*pat && *pat != '.') 4411460Sroot pat++; 4421460Sroot if (! *pat) 4431460Sroot return(0); 4441460Sroot } 4451460Sroot return(0); 4461460Sroot } 4475595Srrh /* 4485595Srrh * Construct an execv argument 4495595Srrh * We need 1 argument for the editor's name 4505595Srrh * We need 1 argument for the initial search string 4515595Srrh * We need n_pissed_on arguments for the file names 4525595Srrh * We need 1 argument that is a null for execv. 4535595Srrh * The caller fills in the editor's name. 4545595Srrh * We fill in the initial search string. 4555595Srrh * We fill in the arguments, and the null. 4565595Srrh */ 4575595Srrh execvarg(n_pissed_on, r_argc, r_argv) 4585595Srrh int n_pissed_on; 4595595Srrh int *r_argc; 4605595Srrh char ***r_argv; 4615595Srrh { 4625595Srrh Eptr p; 4635595Srrh char *sep; 4645595Srrh int fi; 4651460Sroot 4665595Srrh (*r_argv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *)); 4675595Srrh (*r_argc) = n_pissed_on + 2; 4685595Srrh (*r_argv)[1] = "+1;/###/"; 4695595Srrh n_pissed_on = 2; 4705595Srrh if (!terse){ 4715595Srrh fprintf(stdout, "You touched file(s):"); 4725595Srrh sep = " "; 4735595Srrh } 4745595Srrh FILEITERATE(fi, 1){ 4755595Srrh if (!touchedfiles[fi]) 4765595Srrh continue; 4775595Srrh p = *(files[fi]); 4785595Srrh if (!terse){ 4795595Srrh fprintf(stdout,"%s\"%s\"", sep, p->error_text[0]); 4805595Srrh sep = ", "; 4815595Srrh } 4825595Srrh (*r_argv)[n_pissed_on++] = p->error_text[0]; 4835595Srrh } 4845595Srrh if (!terse) 4855595Srrh fprintf(stdout, "\n"); 4865595Srrh (*r_argv)[n_pissed_on] = 0; 4875595Srrh } 4885595Srrh 4891460Sroot FILE *o_touchedfile; /* the old file */ 4901460Sroot FILE *n_touchedfile; /* the new file */ 4911460Sroot char *o_name; 4926612Srrh char n_name[64]; 4936612Srrh char *canon_name = "/tmp/ErrorXXXXXX"; 4941460Sroot int o_lineno; 4951460Sroot int n_lineno; 4961460Sroot boolean tempfileopen = FALSE; 4971460Sroot /* 4981460Sroot * open the file; guaranteed to be both readable and writable 4991460Sroot * Well, if it isn't, then return TRUE if something failed 5001460Sroot */ 5011460Sroot boolean edit(name) 5021460Sroot char *name; 5031460Sroot { 5041460Sroot o_name = name; 5051460Sroot if ( (o_touchedfile = fopen(name, "r")) == NULL){ 5061460Sroot fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n", 5071460Sroot processname, name); 5081460Sroot return(TRUE); 5091460Sroot } 5105595Srrh (void)strcpy(n_name, canon_name); 5115595Srrh (void)mktemp(n_name); 5121460Sroot if ( (n_touchedfile = fopen(n_name, "w")) == NULL){ 5131460Sroot fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n", 5141460Sroot processname, name); 5151460Sroot return(TRUE); 5161460Sroot } 5171460Sroot tempfileopen = TRUE; 5181460Sroot n_lineno = 0; 5191460Sroot o_lineno = 0; 5201460Sroot return(FALSE); 5211460Sroot } 5221460Sroot /* 5231460Sroot * Position to the line (before, after) the line given by place 5241460Sroot */ 5255595Srrh char edbuf[BUFSIZ]; 5261460Sroot insert(place) 5271460Sroot int place; 5281460Sroot { 5291460Sroot --place; /* always insert messages before the offending line*/ 5301460Sroot for(; o_lineno < place; o_lineno++, n_lineno++){ 5315595Srrh if(fgets(edbuf, BUFSIZ, o_touchedfile) == NULL) 5321460Sroot return; 5335595Srrh fputs(edbuf, n_touchedfile); 5341460Sroot } 5351460Sroot } 5361460Sroot 5375595Srrh text(p, use_all) 5385595Srrh reg Eptr p; 5395595Srrh boolean use_all; 5401460Sroot { 5411460Sroot int offset = use_all ? 0 : 2; 5425595Srrh 5435595Srrh fputs(lang_table[p->error_language].lang_incomment, n_touchedfile); 5441460Sroot fprintf(n_touchedfile, "%d [%s] ", 5455595Srrh p->error_line, 5465595Srrh lang_table[p->error_language].lang_name); 5475595Srrh wordvprint(n_touchedfile, p->error_lgtext-offset, p->error_text+offset); 5485595Srrh fputs(lang_table[p->error_language].lang_outcomment,n_touchedfile); 5491460Sroot n_lineno++; 5501460Sroot } 5511460Sroot 5526612Srrh /* 5536612Srrh * write the touched file to its temporary copy, 5546612Srrh * then bring the temporary in over the local file 5556612Srrh */ 5566612Srrh writetouched(overwrite) 5576612Srrh int overwrite; 5581460Sroot { 5596612Srrh reg int nread; 5606612Srrh reg FILE *localfile; 5616612Srrh reg FILE *tmpfile; 5626612Srrh int botch; 5639309Srrh int oktorm; 5645595Srrh 5659309Srrh botch = 0; 5669309Srrh oktorm = 1; 5675595Srrh while((nread = fread(edbuf, 1, sizeof(edbuf), o_touchedfile)) != NULL){ 5689309Srrh if (nread != fwrite(edbuf, 1, nread, n_touchedfile)){ 5699309Srrh /* 5709309Srrh * Catastrophe in temporary area: file system full? 5719309Srrh */ 5729309Srrh botch = 1; 5739309Srrh fprintf(stderr, 5749309Srrh "%s: write failure: No errors inserted in \"%s\"\n", 5759309Srrh processname, o_name); 5769309Srrh } 5771460Sroot } 5781460Sroot fclose(n_touchedfile); 5791460Sroot fclose(o_touchedfile); 5806612Srrh /* 5816612Srrh * Now, copy the temp file back over the original 5826612Srrh * file, thus preserving links, etc 5836612Srrh */ 5849309Srrh if (botch == 0 && overwrite){ 5856612Srrh botch = 0; 5866612Srrh localfile = NULL; 5876612Srrh tmpfile = NULL; 5886612Srrh if ((localfile = fopen(o_name, "w")) == NULL){ 5896612Srrh fprintf(stderr, 5906612Srrh "%s: Can't open file \"%s\" to overwrite.\n", 5916612Srrh processname, o_name); 5926612Srrh botch++; 5936612Srrh } 5946612Srrh if ((tmpfile = fopen(n_name, "r")) == NULL){ 5956612Srrh fprintf(stderr, "%s: Can't open file \"%s\" to read.\n", 5966612Srrh processname, n_name); 5976612Srrh botch++; 5986612Srrh } 5999309Srrh if (!botch) 6009309Srrh oktorm = mustoverwrite(localfile, tmpfile); 6016612Srrh if (localfile != NULL) 6026612Srrh fclose(localfile); 6036612Srrh if (tmpfile != NULL) 6046612Srrh fclose(tmpfile); 6056612Srrh } 6069309Srrh if (oktorm == 0){ 6079309Srrh fprintf(stderr, "%s: Catastrophe: A copy of \"%s\: was saved in \"%s\"\n", 6089309Srrh processname, o_name, n_name); 6099309Srrh exit(1); 6109309Srrh } 6116612Srrh /* 6126612Srrh * Kiss the temp file good bye 6136612Srrh */ 6141460Sroot unlink(n_name); 6151460Sroot tempfileopen = FALSE; 6166612Srrh return(TRUE); 6171460Sroot } 6189309Srrh /* 6199309Srrh * return 1 if the tmpfile can be removed after writing it out 6209309Srrh */ 6219309Srrh int mustoverwrite(preciousfile, tmpfile) 6229309Srrh FILE *preciousfile; 6239309Srrh FILE *tmpfile; 6249309Srrh { 6259309Srrh int nread; 6265595Srrh 6279309Srrh while((nread = fread(edbuf, 1, sizeof(edbuf), tmpfile)) != NULL){ 6289309Srrh if (mustwrite(edbuf, nread, preciousfile) == 0) 6299309Srrh return(0); 6309309Srrh } 6319309Srrh return(1); 6329309Srrh } 6339309Srrh /* 6349309Srrh * return 0 on catastrophe 6359309Srrh */ 6369309Srrh mustwrite(base, n, preciousfile) 6379309Srrh char *base; 6389309Srrh int n; 6399309Srrh FILE *preciousfile; 6409309Srrh { 6419309Srrh int nwrote; 6429309Srrh 6439309Srrh if (n <= 0) 6449309Srrh return(1); 6459309Srrh nwrote = fwrite(base, 1, n, preciousfile); 6469309Srrh if (nwrote == n) 6479309Srrh return(1); 6489309Srrh perror(processname); 6499309Srrh switch(inquire(terse 6509309Srrh ? "Botch overwriting: retry? " 6519309Srrh : "Botch overwriting the source file: retry? ")){ 6529309Srrh case Q_YES: 6539309Srrh case Q_yes: 6549309Srrh mustwrite(base + nwrote, n - nwrote, preciousfile); 6559309Srrh return(1); 6569309Srrh case Q_NO: 6579309Srrh case Q_no: 6589309Srrh switch(inquire("Are you sure? ")){ 6599309Srrh case Q_YES: 6609309Srrh case Q_yes: 6619309Srrh return(0); 6629309Srrh case Q_NO: 6639309Srrh case Q_no: 6649309Srrh mustwrite(base + nwrote, n - nwrote, preciousfile); 6659309Srrh return(1); 6669309Srrh } 66716564Sralph default: 66816564Sralph return(0); 6699309Srrh } 6709309Srrh } 6719309Srrh 6721460Sroot onintr() 6731460Sroot { 6745595Srrh switch(inquire(terse 6755595Srrh ? "\nContinue? " 6765595Srrh : "\nInterrupt: Do you want to continue? ")){ 6775595Srrh case Q_YES: 6785595Srrh case Q_yes: 6791460Sroot signal(SIGINT, onintr); 6801460Sroot return; 6815595Srrh default: 6826612Srrh if (tempfileopen){ 6836612Srrh /* 6846612Srrh * Don't overwrite the original file! 6856612Srrh */ 6866612Srrh writetouched(0); 6876612Srrh } 6885595Srrh exit(1); 6891460Sroot } 6905595Srrh /*NOTREACHED*/ 6911460Sroot } 6925595Srrh 6931460Sroot errorprint(place, errorp, print_all) 6941460Sroot FILE *place; 6955595Srrh Eptr errorp; 6961460Sroot boolean print_all; 6971460Sroot { 6981460Sroot int offset = print_all ? 0 : 2; 6991460Sroot 7001460Sroot if (errorp->error_e_class == C_IGNORE) 7011460Sroot return; 7021460Sroot fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name); 7031460Sroot wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset); 7041460Sroot putc('\n', place); 7051460Sroot } 7061460Sroot 7075595Srrh int inquire(fmt, a1, a2) 7081460Sroot char *fmt; 7091460Sroot /*VARARGS1*/ 7101460Sroot { 7111460Sroot char buffer[128]; 71216564Sralph 71316564Sralph if (queryfile == NULL) 71416564Sralph return(0); 7151460Sroot for(;;){ 7161460Sroot do{ 7171460Sroot fflush(stdout); 7181460Sroot fprintf(stderr, fmt, a1, a2); 7191460Sroot fflush(stderr); 7201460Sroot } while (fgets(buffer, 127, queryfile) == NULL); 7215595Srrh switch(buffer[0]){ 7225595Srrh case 'Y': return(Q_YES); 7235595Srrh case 'y': return(Q_yes); 7245595Srrh case 'N': return(Q_NO); 7255595Srrh case 'n': return(Q_no); 7265595Srrh default: fprintf(stderr, "Yes or No only!\n"); 7275595Srrh } 7281460Sroot } 7291460Sroot } 7301460Sroot 7315595Srrh int probethisfile(name) 7325595Srrh char *name; 7331460Sroot { 7341460Sroot struct stat statbuf; 7355595Srrh if (stat(name, &statbuf) < 0) 7365595Srrh return(F_NOTEXIST); 7375595Srrh if((statbuf.st_mode & S_IREAD) == 0) 7385595Srrh return(F_NOTREAD); 7395595Srrh if((statbuf.st_mode & S_IWRITE) == 0) 7405595Srrh return(F_NOTWRITE); 7415595Srrh return(F_TOUCHIT); 7421460Sroot } 743