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