|
|
1.1 root 1: static char *sccsid = "@(#)errortouch.c 1.5 (Berkeley) 11/20/82";
2: #include <stdio.h>
3: #include <ctype.h>
4: #include <sys/types.h>
5: #include <sys/stat.h>
6: #include <signal.h>
7: #include "error.h"
8:
9: /*
10: * Iterate through errors
11: */
12: #define EITERATE(p, fv, i) for (p = fv[i]; p < fv[i+1]; p++)
13: #define ECITERATE(ei, p, lb) for (ei = lb; p = errors[ei],ei < nerrors; ei++)
14:
15: #define FILEITERATE(fi, lb) for (fi = lb; fi <= nfiles; fi++)
16: int touchstatus = Q_YES;
17:
18: findfiles(nerrors, errors, r_nfiles, r_files)
19: int nerrors;
20: Eptr *errors;
21: int *r_nfiles;
22: Eptr ***r_files;
23: {
24: int nfiles;
25: Eptr **files;
26:
27: char *name;
28: reg int ei;
29: int fi;
30: reg Eptr errorp;
31:
32: nfiles = countfiles(errors);
33:
34: files = (Eptr**)Calloc(nfiles + 3, sizeof (Eptr*));
35: touchedfiles = (boolean *)Calloc(nfiles+3, sizeof(boolean));
36: /*
37: * Now, partition off the error messages
38: * into those that are synchronization, discarded or
39: * not specific to any file, and those that were
40: * nulled or true errors.
41: */
42: files[0] = &errors[0];
43: ECITERATE(ei, errorp, 0){
44: if ( ! (NOTSORTABLE(errorp->error_e_class)))
45: break;
46: }
47: /*
48: * Now, and partition off all error messages
49: * for a given file.
50: */
51: files[1] = &errors[ei];
52: touchedfiles[0] = touchedfiles[1] = FALSE;
53: name = "\1";
54: fi = 1;
55: ECITERATE(ei, errorp, ei){
56: if ( (errorp->error_e_class == C_NULLED)
57: || (errorp->error_e_class == C_TRUE) ){
58: if (strcmp(errorp->error_text[0], name) != 0){
59: name = errorp->error_text[0];
60: touchedfiles[fi] = FALSE;
61: files[fi] = &errors[ei];
62: fi++;
63: }
64: }
65: }
66: files[fi] = &errors[nerrors];
67: *r_nfiles = nfiles;
68: *r_files = files;
69: }
70:
71: int countfiles(errors)
72: Eptr *errors;
73: {
74: char *name;
75: int ei;
76: reg Eptr errorp;
77:
78: int nfiles;
79: nfiles = 0;
80: name = "\1";
81: ECITERATE(ei, errorp, 0){
82: if (SORTABLE(errorp->error_e_class)){
83: if (strcmp(errorp->error_text[0],name) != 0){
84: nfiles++;
85: name = errorp->error_text[0];
86: }
87: }
88: }
89: return(nfiles);
90: }
91: char *class_table[] = {
92: /*C_UNKNOWN 0 */ "Unknown",
93: /*C_IGNORE 1 */ "ignore",
94: /*C_SYNC 2 */ "synchronization",
95: /*C_DISCARD 3 */ "discarded",
96: /*C_NONSPEC 4 */ "non specific",
97: /*C_THISFILE 5 */ "specific to this file",
98: /*C_NULLED 6 */ "nulled",
99: /*C_TRUE 7 */ "true",
100: /*C_DUPL 8 */ "duplicated"
101: };
102:
103: int class_count[C_LAST - C_FIRST] = {0};
104:
105: filenames(nfiles, files)
106: int nfiles;
107: Eptr **files;
108: {
109: reg int fi;
110: char *sep = " ";
111: extern char *class_table[];
112: int someerrors;
113:
114: /*
115: * first, simply dump out errors that
116: * don't pertain to any file
117: */
118: someerrors = nopertain(files);
119:
120: if (nfiles){
121: someerrors++;
122: fprintf(stdout, terse
123: ? "%d file%s"
124: : "%d file%s contain%s errors",
125: nfiles, plural(nfiles), verbform(nfiles));
126: if (!terse){
127: FILEITERATE(fi, 1){
128: fprintf(stdout, "%s\"%s\" (%d)",
129: sep, (*files[fi])->error_text[0],
130: files[fi+1] - files[fi]);
131: sep = ", ";
132: }
133: }
134: fprintf(stdout, "\n");
135: }
136: if (!someerrors)
137: fprintf(stdout, "No errors.\n");
138: }
139:
140: /*
141: * Dump out errors that don't pertain to any file
142: */
143: int nopertain(files)
144: Eptr **files;
145: {
146: int type;
147: int someerrors = 0;
148: reg Eptr *erpp;
149: reg Eptr errorp;
150:
151: if (files[1] - files[0] <= 0)
152: return(0);
153: for(type = C_UNKNOWN; NOTSORTABLE(type); type++){
154: if (class_count[type] <= 0)
155: continue;
156: if (type > C_SYNC)
157: someerrors++;
158: if (terse){
159: fprintf(stdout, "\t%d %s errors NOT PRINTED\n",
160: class_count[type], class_table[type]);
161: } else {
162: fprintf(stdout, "\n\t%d %s errors follow\n",
163: class_count[type], class_table[type]);
164: EITERATE(erpp, files, 0){
165: errorp = *erpp;
166: if (errorp->error_e_class == type){
167: errorprint(stdout, errorp, TRUE);
168: }
169: }
170: }
171: }
172: return(someerrors);
173: }
174:
175: extern boolean notouch;
176:
177: boolean touchfiles(nfiles, files, r_edargc, r_edargv)
178: int nfiles;
179: Eptr **files;
180: int *r_edargc;
181: char ***r_edargv;
182: {
183: char *name;
184: reg Eptr errorp;
185: reg int fi;
186: reg Eptr *erpp;
187: int ntrueerrors;
188: boolean scribbled;
189: int n_pissed_on; /* # of file touched*/
190: int spread;
191:
192: FILEITERATE(fi, 1){
193: name = (*files[fi])->error_text[0];
194: spread = files[fi+1] - files[fi];
195: fprintf(stdout, terse
196: ? "\"%s\" has %d error%s, "
197: : "\nFile \"%s\" has %d error%s.\n"
198: , name ,spread ,plural(spread));
199: /*
200: * First, iterate through all error messages in this file
201: * to see how many of the error messages really will
202: * get inserted into the file.
203: */
204: ntrueerrors = 0;
205: EITERATE(erpp, files, fi){
206: errorp = *erpp;
207: if (errorp->error_e_class == C_TRUE)
208: ntrueerrors++;
209: }
210: fprintf(stdout, terse
211: ? "insert %d\n"
212: : "\t%d of these errors can be inserted into the file.\n",
213: ntrueerrors);
214:
215: hackfile(name, files, fi, ntrueerrors);
216: }
217: scribbled = FALSE;
218: n_pissed_on = 0;
219: FILEITERATE(fi, 1){
220: scribbled |= touchedfiles[fi];
221: n_pissed_on++;
222: }
223: if (scribbled){
224: /*
225: * Construct an execv argument
226: */
227: execvarg(n_pissed_on, r_edargc, r_edargv);
228: return(TRUE);
229: } else {
230: if (!terse)
231: fprintf(stdout, "You didn't touch any files.\n");
232: return(FALSE);
233: }
234: }
235:
236: hackfile(name, files, ix, nerrors)
237: char *name;
238: Eptr **files;
239: int ix;
240: {
241: boolean previewed;
242: int errordest; /* where errors go*/
243:
244: previewed = preview(name, nerrors, files, ix);
245:
246: errordest = settotouch(name);
247:
248: if (errordest != TOSTDOUT)
249: touchedfiles[ix] = TRUE;
250:
251: if (previewed && (errordest == TOSTDOUT))
252: return;
253:
254: diverterrors(name, errordest, files, ix, previewed, nerrors);
255:
256: if (errordest == TOTHEFILE){
257: /*
258: * overwrite the original file
259: */
260: writetouched(1);
261: }
262: }
263:
264: boolean preview(name, nerrors, files, ix)
265: char *name;
266: int nerrors;
267: Eptr **files;
268: int ix;
269: {
270: int back;
271: reg Eptr *erpp;
272:
273: if (!oktotouch(name))
274: return(false);
275: if (nerrors <= 0)
276: return(false);
277: back = false;
278: if(query){
279: switch(inquire(terse
280: ? "Preview? "
281: : "Do you want to preview the errors first? ")){
282: case Q_YES:
283: case Q_yes:
284: back = true;
285: EITERATE(erpp, files, ix){
286: errorprint(stdout, *erpp, TRUE);
287: }
288: if (!terse)
289: fprintf(stdout, "\n");
290: default:
291: break;
292: }
293: }
294: return(back);
295: }
296:
297: int settotouch(name)
298: char *name;
299: {
300: int dest = TOSTDOUT;
301:
302: if (query){
303: switch(touchstatus = inquire(terse
304: ? "Touch? "
305: : "Do you want to touch file \"%s\"? ",
306: name)){
307: case Q_NO:
308: case Q_no:
309: return(dest);
310: default:
311: break;
312: }
313: }
314:
315: switch(probethisfile(name)){
316: case F_NOTREAD:
317: dest = TOSTDOUT;
318: fprintf(stdout, terse
319: ? "\"%s\" unreadable\n"
320: : "File \"%s\" is unreadable\n",
321: name);
322: break;
323: case F_NOTWRITE:
324: dest = TOSTDOUT;
325: fprintf(stdout, terse
326: ? "\"%s\" unwritable\n"
327: : "File \"%s\" is unwritable\n",
328: name);
329: break;
330: case F_NOTEXIST:
331: dest = TOSTDOUT;
332: fprintf(stdout, terse
333: ? "\"%s\" not found\n"
334: : "Can't find file \"%s\" to insert error messages into.\n",
335: name);
336: break;
337: default:
338: dest = edit(name) ? TOSTDOUT : TOTHEFILE;
339: break;
340: }
341: return(dest);
342: }
343:
344: diverterrors(name, dest, files, ix, previewed, nterrors)
345: char *name;
346: int dest;
347: Eptr **files;
348: int ix;
349: boolean previewed;
350: int nterrors;
351: {
352: int nerrors;
353: reg Eptr *erpp;
354: reg Eptr errorp;
355:
356: nerrors = files[ix+1] - files[ix];
357:
358: if ( (nerrors != nterrors)
359: && (!previewed) ){
360: fprintf(stdout, terse
361: ? "Uninserted errors\n"
362: : ">>Uninserted errors for file \"%s\" follow.\n",
363: name);
364: }
365:
366: EITERATE(erpp, files, ix){
367: errorp = *erpp;
368: if (errorp->error_e_class != C_TRUE){
369: if (previewed || touchstatus == Q_NO)
370: continue;
371: errorprint(stdout, errorp, TRUE);
372: continue;
373: }
374: switch (dest){
375: case TOSTDOUT:
376: if (previewed || touchstatus == Q_NO)
377: continue;
378: errorprint(stdout,errorp, TRUE);
379: break;
380: case TOTHEFILE:
381: insert(errorp->error_line);
382: text(errorp, FALSE);
383: break;
384: }
385: }
386: }
387:
388: int oktotouch(filename)
389: char *filename;
390: {
391: extern char *suffixlist;
392: reg char *src;
393: reg char *pat;
394: char *osrc;
395:
396: pat = suffixlist;
397: if (pat == 0)
398: return(0);
399: if (*pat == '*')
400: return(1);
401: while (*pat++ != '.')
402: continue;
403: --pat; /* point to the period */
404:
405: for (src = &filename[strlen(filename)], --src;
406: (src > filename) && (*src != '.'); --src)
407: continue;
408: if (*src != '.')
409: return(0);
410:
411: for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){
412: for (; *src /* not at end of the source */
413: && *pat /* not off end of pattern */
414: && *pat != '.' /* not off end of sub pattern */
415: && *pat != '*' /* not wild card */
416: && *src == *pat; /* and equal... */
417: src++, pat++)
418: continue;
419: if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*'))
420: return(1);
421: if (*src != 0 && *pat == '*')
422: return(1);
423: while (*pat && *pat != '.')
424: pat++;
425: if (! *pat)
426: return(0);
427: }
428: return(0);
429: }
430: /*
431: * Construct an execv argument
432: * We need 1 argument for the editor's name
433: * We need 1 argument for the initial search string
434: * We need n_pissed_on arguments for the file names
435: * We need 1 argument that is a null for execv.
436: * The caller fills in the editor's name.
437: * We fill in the initial search string.
438: * We fill in the arguments, and the null.
439: */
440: execvarg(n_pissed_on, r_argc, r_argv)
441: int n_pissed_on;
442: int *r_argc;
443: char ***r_argv;
444: {
445: Eptr p;
446: char *sep;
447: int fi;
448:
449: (*r_argv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *));
450: (*r_argc) = n_pissed_on + 2;
451: (*r_argv)[1] = "+1;/###/";
452: n_pissed_on = 2;
453: if (!terse){
454: fprintf(stdout, "You touched file(s):");
455: sep = " ";
456: }
457: FILEITERATE(fi, 1){
458: if (!touchedfiles[fi])
459: continue;
460: p = *(files[fi]);
461: if (!terse){
462: fprintf(stdout,"%s\"%s\"", sep, p->error_text[0]);
463: sep = ", ";
464: }
465: (*r_argv)[n_pissed_on++] = p->error_text[0];
466: }
467: if (!terse)
468: fprintf(stdout, "\n");
469: (*r_argv)[n_pissed_on] = 0;
470: }
471:
472: FILE *o_touchedfile; /* the old file */
473: FILE *n_touchedfile; /* the new file */
474: char *o_name;
475: char n_name[64];
476: char *canon_name = "/tmp/ErrorXXXXXX";
477: int o_lineno;
478: int n_lineno;
479: boolean tempfileopen = FALSE;
480: /*
481: * open the file; guaranteed to be both readable and writable
482: * Well, if it isn't, then return TRUE if something failed
483: */
484: boolean edit(name)
485: char *name;
486: {
487: o_name = name;
488: if ( (o_touchedfile = fopen(name, "r")) == NULL){
489: fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n",
490: processname, name);
491: return(TRUE);
492: }
493: (void)strcpy(n_name, canon_name);
494: (void)mktemp(n_name);
495: if ( (n_touchedfile = fopen(n_name, "w")) == NULL){
496: fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n",
497: processname, name);
498: return(TRUE);
499: }
500: tempfileopen = TRUE;
501: n_lineno = 0;
502: o_lineno = 0;
503: return(FALSE);
504: }
505: /*
506: * Position to the line (before, after) the line given by place
507: */
508: char edbuf[BUFSIZ];
509: insert(place)
510: int place;
511: {
512: --place; /* always insert messages before the offending line*/
513: for(; o_lineno < place; o_lineno++, n_lineno++){
514: if(fgets(edbuf, BUFSIZ, o_touchedfile) == NULL)
515: return;
516: fputs(edbuf, n_touchedfile);
517: }
518: }
519:
520: text(p, use_all)
521: reg Eptr p;
522: boolean use_all;
523: {
524: int offset = use_all ? 0 : 2;
525:
526: fputs(lang_table[p->error_language].lang_incomment, n_touchedfile);
527: fprintf(n_touchedfile, "%d [%s] ",
528: p->error_line,
529: lang_table[p->error_language].lang_name);
530: wordvprint(n_touchedfile, p->error_lgtext-offset, p->error_text+offset);
531: fputs(lang_table[p->error_language].lang_outcomment,n_touchedfile);
532: n_lineno++;
533: }
534:
535: /*
536: * write the touched file to its temporary copy,
537: * then bring the temporary in over the local file
538: */
539: writetouched(overwrite)
540: int overwrite;
541: {
542: reg int nread;
543: reg FILE *localfile;
544: reg FILE *tmpfile;
545: int botch;
546: int oktorm;
547:
548: botch = 0;
549: oktorm = 1;
550: while((nread = fread(edbuf, 1, sizeof(edbuf), o_touchedfile)) != NULL){
551: if (nread != fwrite(edbuf, 1, nread, n_touchedfile)){
552: /*
553: * Catastrophe in temporary area: file system full?
554: */
555: botch = 1;
556: fprintf(stderr,
557: "%s: write failure: No errors inserted in \"%s\"\n",
558: processname, o_name);
559: }
560: }
561: fclose(n_touchedfile);
562: fclose(o_touchedfile);
563: /*
564: * Now, copy the temp file back over the original
565: * file, thus preserving links, etc
566: */
567: if (botch == 0 && overwrite){
568: botch = 0;
569: localfile = NULL;
570: tmpfile = NULL;
571: if ((localfile = fopen(o_name, "w")) == NULL){
572: fprintf(stderr,
573: "%s: Can't open file \"%s\" to overwrite.\n",
574: processname, o_name);
575: botch++;
576: }
577: if ((tmpfile = fopen(n_name, "r")) == NULL){
578: fprintf(stderr, "%s: Can't open file \"%s\" to read.\n",
579: processname, n_name);
580: botch++;
581: }
582: if (!botch)
583: oktorm = mustoverwrite(localfile, tmpfile);
584: if (localfile != NULL)
585: fclose(localfile);
586: if (tmpfile != NULL)
587: fclose(tmpfile);
588: }
589: if (oktorm == 0){
590: fprintf(stderr, "%s: Catastrophe: A copy of \"%s\: was saved in \"%s\"\n",
591: processname, o_name, n_name);
592: exit(1);
593: }
594: /*
595: * Kiss the temp file good bye
596: */
597: unlink(n_name);
598: tempfileopen = FALSE;
599: return(TRUE);
600: }
601: /*
602: * return 1 if the tmpfile can be removed after writing it out
603: */
604: int mustoverwrite(preciousfile, tmpfile)
605: FILE *preciousfile;
606: FILE *tmpfile;
607: {
608: int nread;
609:
610: while((nread = fread(edbuf, 1, sizeof(edbuf), tmpfile)) != NULL){
611: if (mustwrite(edbuf, nread, preciousfile) == 0)
612: return(0);
613: }
614: return(1);
615: }
616: /*
617: * return 0 on catastrophe
618: */
619: mustwrite(base, n, preciousfile)
620: char *base;
621: int n;
622: FILE *preciousfile;
623: {
624: int nwrote;
625:
626: if (n <= 0)
627: return(1);
628: nwrote = fwrite(base, 1, n, preciousfile);
629: if (nwrote == n)
630: return(1);
631: perror(processname);
632: switch(inquire(terse
633: ? "Botch overwriting: retry? "
634: : "Botch overwriting the source file: retry? ")){
635: case Q_YES:
636: case Q_yes:
637: mustwrite(base + nwrote, n - nwrote, preciousfile);
638: return(1);
639: case Q_NO:
640: case Q_no:
641: switch(inquire("Are you sure? ")){
642: case Q_YES:
643: case Q_yes:
644: return(0);
645: case Q_NO:
646: case Q_no:
647: mustwrite(base + nwrote, n - nwrote, preciousfile);
648: return(1);
649: }
650: }
651: }
652:
653: onintr()
654: {
655: switch(inquire(terse
656: ? "\nContinue? "
657: : "\nInterrupt: Do you want to continue? ")){
658: case Q_YES:
659: case Q_yes:
660: signal(SIGINT, onintr);
661: return;
662: default:
663: if (tempfileopen){
664: /*
665: * Don't overwrite the original file!
666: */
667: writetouched(0);
668: }
669: exit(1);
670: }
671: /*NOTREACHED*/
672: }
673:
674: errorprint(place, errorp, print_all)
675: FILE *place;
676: Eptr errorp;
677: boolean print_all;
678: {
679: int offset = print_all ? 0 : 2;
680:
681: if (errorp->error_e_class == C_IGNORE)
682: return;
683: fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name);
684: wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset);
685: putc('\n', place);
686: }
687:
688: int inquire(fmt, a1, a2)
689: char *fmt;
690: /*VARARGS1*/
691: {
692: char buffer[128];
693: for(;;){
694: do{
695: fflush(stdout);
696: fprintf(stderr, fmt, a1, a2);
697: fflush(stderr);
698: } while (fgets(buffer, 127, queryfile) == NULL);
699: switch(buffer[0]){
700: case 'Y': return(Q_YES);
701: case 'y': return(Q_yes);
702: case 'N': return(Q_NO);
703: case 'n': return(Q_no);
704: default: fprintf(stderr, "Yes or No only!\n");
705: }
706: }
707: }
708:
709: int probethisfile(name)
710: char *name;
711: {
712: struct stat statbuf;
713: if (stat(name, &statbuf) < 0)
714: return(F_NOTEXIST);
715: if((statbuf.st_mode & S_IREAD) == 0)
716: return(F_NOTREAD);
717: if((statbuf.st_mode & S_IWRITE) == 0)
718: return(F_NOTWRITE);
719: return(F_TOUCHIT);
720: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.