add "ap" and "fp" notion, fix SUCC and PRED
[unix-history] / usr / src / usr.bin / error / touch.c
CommitLineData
bb3574aa 1static char *sccsid = "@(#)touch.c 1.2 (Berkeley) %G%";
c99ba90a
BJ
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
9findfiles(nerrors, errors, r_nfiles, r_files)
10 int nerrors;
11 struct error_desc **errors;
12 int *r_nfiles;
13 struct error_desc ****r_files;
14{
15 int nfiles;
16 struct error_desc ***files;
17
18 char *currentfilename;
19 register int errorindex;
20 int fileindex;
21 register struct error_desc *errorp;
22 /*
23 * First, go through and count all of the filenames
24 */
25 for (errorp = errors[errorindex = 0],nfiles = 0, currentfilename = "\1";
26 errorindex < nerrors;
27 errorp = errors[++errorindex]){
28 if (SORTABLE(errorp->error_e_class)){
29 if (strcmp(errorp->error_text[0],currentfilename) != 0){
30 nfiles++;
31 currentfilename = errorp->error_text[0];
32 }
33 }
34 }
35 files = (struct error_desc ***)Calloc(nfiles + 3,
36 sizeof (struct error_desc**));
37 touchedfiles = (boolean *)Calloc(nfiles+3, sizeof(boolean));
38 /*
39 * Now, go through and partition off the error messages
40 * into those that are synchronization, discarded or
41 * not specific to any file, and those that were
42 * nulled or true errors.
43 */
44 files[0] = &errors[0];
45 for (errorp = errors[errorindex = 0], fileindex = 0;
46 (errorindex < nerrors) &&
47 (NOTSORTABLE(errorp->error_e_class));
48 errorp = errors[++errorindex]){
49 continue;
50 }
51 /*
52 * Now, go through and partition off all error messages
53 * for a given file.
54 */
55 files[1] = &errors[errorindex];
56 touchedfiles[0] = touchedfiles[1] = FALSE;
57 for (errorp = errors[errorindex], currentfilename = "\1", fileindex = 1;
58 errorindex < nerrors; errorp = errors[++errorindex]){
59 if ( (errorp->error_e_class == C_NULLED) || (errorp->error_e_class == C_TRUE) ){
60 if (strcmp(errorp->error_text[0],currentfilename) != 0){
61 currentfilename = errorp->error_text[0];
62 touchedfiles[fileindex] = FALSE;
63 files[fileindex++] = &errors[errorindex];
64 }
65 }
66 }
67 files[fileindex] = &errors[nerrors];
68 *r_nfiles = nfiles;
69 *r_files = files;
70}
71
72char *class_table[] = {
73 /*C_UNKNOWN 0 */ "Unknown",
74 /*C_IGNORE 1 */ "ignore",
75 /*C_SYNC 2 */ "synchronization",
76 /*C_DISCARD 3 */ "discarded",
77 /*C_NONSPEC 4 */ "non specific",
78 /*C_THISFILE 5 */ "specific to this file",
79 /*C_NULLED 6 */ "nulled",
80 /*C_TRUE 7 */ "true",
81 /*C_DUPL 8 */ "duplicated"
82};
83
84int class_count[C_LAST - C_FIRST] = {0};
85
86filenames(nfiles, files)
87 int nfiles;
88 struct error_desc ***files;
89{
90 register int fileindex;
91 register struct error_desc *errorp;
92 register struct error_desc **erpp;
93 char *sep = " ";
94 register int errortype;
95 extern char *class_table[];
96 int someerrors = 0;
97
98 /*
99 * first, go through and simply dump out errors that
100 * don't pertain to any file
101 */
102 if (files[1] - files[0] > 0){
103 for(errortype = C_UNKNOWN; NOTSORTABLE(errortype); errortype++){
104 if (class_count[errortype] > 0){
105 if (errortype > C_SYNC)
106 someerrors++;
107 fprintf(stdout, "\n\t%d %s errors follow:\n",
108 class_count[errortype], class_table[errortype]);
109 for (errorp = *(erpp = files[0]);
110 erpp < files[1];
111 errorp = (*++erpp)){
112 if (errorp->error_e_class == errortype)
113 errorprint(stdout, errorp, TRUE);
114 }
115 }
116 }
117 }
118 if (nfiles){
119 someerrors++;
120 fprintf(stdout, "%d files contain errors:", nfiles);
121 for (fileindex = 1; fileindex <= nfiles; fileindex++){
122 fprintf(stdout, "%s\"%s\" (%d)",
123 sep, (*files[fileindex])->error_text[0],
124 files[fileindex+1] - files[fileindex]);
125 sep = ", ";
126 }
127 fprintf(stdout, "\n");
128 }
129 if (!someerrors)
130 fprintf(stdout, "No errors.\n");
131}
132
133extern boolean notouch;
134
135boolean touchfiles(nfiles, files, r_edargc, r_edargv)
136 int nfiles;
137 struct error_desc ***files;
138 int *r_edargc;
139 char ***r_edargv;
140{
141 char *currentfilename;
142 register struct error_desc *errorp;
143 register int fileindex;
144 register struct error_desc **erpp;
145 int ntrueerrors;
146 int errordest; /* where errors go*/
147 char *sep;
148 boolean scribbled;
bb3574aa
BJ
149 int n_pissed_on; /* # of file touched*/
150 int previewed;
151
c99ba90a
BJ
152 for (fileindex = 1; fileindex <= nfiles; fileindex++){
153 fprintf(stdout, "\nFile \"%s\" has %d total error messages.\n",
154 currentfilename = (*files[fileindex])->error_text[0],
155 files[fileindex+1] - files[fileindex]);
156 /*
157 * First, iterate through all error messages in this file
158 * to see how many of the error messages really will
159 * get inserted into the file.
160 */
161 for (erpp = files[fileindex], ntrueerrors = 0;
162 erpp < files[fileindex+1];
163 erpp++){
164 errorp = *erpp;
165 if (errorp->error_e_class == C_TRUE)
166 ntrueerrors++;
167 }
168 fprintf(stdout,"\t%d of these errors can be inserted into the file.\n",
169 ntrueerrors);
170
171 /*
172 * What does the operator want?
173 */
bb3574aa 174 previewed = 0;
c99ba90a
BJ
175 errordest = TOSTDOUT;
176 if (oktotouch(currentfilename) && (ntrueerrors > 0) ){
177 if (query && inquire("Do you want to preview the errors first?")){
bb3574aa 178 previewed = 1;
c99ba90a
BJ
179 for (erpp = files[fileindex];
180 erpp < files[fileindex + 1];
181 erpp++){
182 errorprint(stdout, *erpp, TRUE);
183 }
184 fprintf(stdout, "\n");
185 }
186 if ( !query
187 || inquire("Do you want to touch file \"%s\"? ",
188 currentfilename)
189 ){
190 errordest = TOTHEFILE;
191 if (!probethisfile(currentfilename)){
192 errordest = TOSTDOUT;
193 fprintf(stdout,
194 "Can't find file \"%s\" to insert error messages into.\n",
195 currentfilename);
196 } else {
197 if (edit(currentfilename))
198 errordest = TOSTDOUT;
199 else
200 touchedfiles[fileindex] = TRUE;
201 }
202 }
203 }
bb3574aa
BJ
204 if (previewed && (errordest == TOSTDOUT))
205 continue; /* with the next file */
c99ba90a
BJ
206 /*
207 * go through and print each error message,
208 * diverting to the right place
209 */
210 if ( (files[fileindex+1] - files[fileindex]) != ntrueerrors)
bb3574aa 211 if (!previewed) fprintf(stdout,
c99ba90a
BJ
212 ">>Uninserted error messages for file \"%s\" follow.\n",
213 currentfilename);
214 for (erpp = files[fileindex];erpp < files[fileindex+1];erpp++){
215 errorp = *erpp;
216 if (errorp->error_e_class == C_TRUE){
217 switch (errordest){
218 case TOSTDOUT:
bb3574aa
BJ
219 if (!previewed)
220 errorprint(stdout,errorp, TRUE);
221 break;
c99ba90a
BJ
222 case TOTHEFILE:
223 insert(errorp->error_line);
224 text(errorp, FALSE);
225 break;
226 } /* switch */
227 } else {
bb3574aa
BJ
228 if (!previewed)
229 errorprint(stdout, errorp, TRUE);
c99ba90a
BJ
230 }
231 } /* end of walking through all errors*/
232 if (errordest == TOTHEFILE){
233 writetouched();
234 }
235 } /* end of walking through all files*/
236 scribbled = FALSE;
237 for (n_pissed_on = 0, fileindex = 1; fileindex <= nfiles; fileindex++){
238 scribbled |= touchedfiles[fileindex];
239 n_pissed_on++;
240 }
241 if (scribbled){
242 /*
243 * Construct an execv argument
244 * We need 1 argument for the editor's name
245 * We need 1 argument for the initial search string
246 * We need n_pissed_on arguments for the file names
247 * We need 1 argument that is a null for execv.
248 * The caller fills in the editor's name.
249 * We fill in the initial search string.
250 * We fill in the arguments, and the null.
251 */
252 (*r_edargv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *));
253 (*r_edargc) = n_pissed_on + 2;
254 (*r_edargv)[1] = "+/###/";
255 n_pissed_on = 2;
256 fprintf(stdout, "You touched file(s):");
257 sep = " ";
258 for (fileindex = 1; fileindex <= nfiles; fileindex++){
259 if (!touchedfiles[fileindex])
260 continue;
261 errorp = *(files[fileindex]);
262 fprintf(stdout,"%s\"%s\"", sep, errorp->error_text[0]);
263 sep = ", ";
264 (*r_edargv)[n_pissed_on++] = errorp->error_text[0];
265 }
266 fprintf(stdout, "\n");
267 (*r_edargv)[n_pissed_on] = 0;
268 return(TRUE);
269 } else {
270 fprintf(stdout, "You didn't touch any files.\n");
271 return(FALSE);
272 }
273
274} /* end of touchfiles*/
275int oktotouch(filename)
276 char *filename;
277{
278 extern char *suffixlist;
279 register char *src;
280 register char *pat;
281 char *osrc;
282
283 pat = suffixlist;
284 if (pat == 0)
285 return(0);
286 if (*pat == '*')
287 return(1);
288 while (*pat++ != '.')
289 continue;
290 --pat; /* point to the period */
291
292 for (src = &filename[strlen(filename)], --src;
293 (src > filename) && (*src != '.'); --src)
294 continue;
295 if (*src != '.')
296 return(0);
297
298 for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){
299 for (; *src /* not at end of the source */
300 && *pat /* not off end of pattern */
301 && *pat != '.' /* not off end of sub pattern */
302 && *pat != '*' /* not wild card */
303 && *src == *pat; /* and equal... */
304 src++, pat++)
305 continue;
306 if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*'))
307 return(1);
308 if (*src != 0 && *pat == '*')
309 return(1);
310 while (*pat && *pat != '.')
311 pat++;
312 if (! *pat)
313 return(0);
314 }
315 return(0);
316}
317
318FILE *o_touchedfile; /* the old file */
319FILE *n_touchedfile; /* the new file */
320char *o_name;
321char n_name[32];
322char *canon_name = "ErrorXXXXXX";
323int o_lineno;
324int n_lineno;
325boolean tempfileopen = FALSE;
326/*
327 * open the file; guaranteed to be both readable and writable
328 * Well, if it isn't, then return TRUE if something failed
329 */
330boolean edit(name)
331 char *name;
332{
333 o_name = name;
334 if ( (o_touchedfile = fopen(name, "r")) == NULL){
335 fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n",
336 processname, name);
337 return(TRUE);
338 }
339 strcpy(n_name, canon_name);
340 mktemp(n_name);
341 if ( (n_touchedfile = fopen(n_name, "w")) == NULL){
342 fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n",
343 processname, name);
344 return(TRUE);
345 }
346 tempfileopen = TRUE;
347 n_lineno = 0;
348 o_lineno = 0;
349 return(FALSE);
350}
351/*
352 * Position to the line (before, after) the line given by place
353 */
354char edbuffer[BUFSIZ];
355insert(place)
356 int place;
357{
358 --place; /* always insert messages before the offending line*/
359 for(; o_lineno < place; o_lineno++, n_lineno++){
360 if(fgets(edbuffer, BUFSIZ, o_touchedfile) == NULL)
361 return;
362 fputs(edbuffer, n_touchedfile);
363 }
364}
365
366text(errorp, use_all)
367 register struct error_desc *errorp;
368 boolean use_all;
369{
370 int offset = use_all ? 0 : 2;
371 fputs(lang_table[errorp->error_language].lang_incomment, n_touchedfile);
372 fprintf(n_touchedfile, "%d [%s] ",
373 errorp->error_line,
374 lang_table[errorp->error_language].lang_name);
375 wordvprint(n_touchedfile,
376 errorp->error_lgtext-offset, errorp->error_text+offset);
377 fputs(lang_table[errorp->error_language].lang_outcomment,n_touchedfile);
378 n_lineno++;
379}
380
381writetouched()
382{
383 int bytes_read;
384 for(; (bytes_read = fread(edbuffer, 1, sizeof(edbuffer), o_touchedfile))!= NULL; ){
385 fwrite(edbuffer, 1, bytes_read, n_touchedfile);
386 }
387 fclose(n_touchedfile);
388 fclose(o_touchedfile);
389 unlink(o_name);
390 link(n_name, o_name);
391 unlink(n_name);
392 tempfileopen = FALSE;
393}
394onintr()
395{
396 if (inquire("\nInterrupt: Do you want to continue?")){
397 signal(SIGINT, onintr);
398 return;
399 }
400 if (tempfileopen)
401 writetouched();
402 exit(1);
403}
404errorprint(place, errorp, print_all)
405 FILE *place;
406 struct error_desc *errorp;
407 boolean print_all;
408{
409 int offset = print_all ? 0 : 2;
410
411 if (errorp->error_e_class == C_IGNORE)
412 return;
413 fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name);
414 wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset);
415 putc('\n', place);
416}
417
418boolean inquire(fmt, a1, a2)
419 char *fmt;
420 /*VARARGS1*/
421{
422 char buffer[128];
423 char ch;
424 for(;;){
425 do{
426 fflush(stdout);
427 fprintf(stderr, fmt, a1, a2);
428 fflush(stderr);
429 } while (fgets(buffer, 127, queryfile) == NULL);
430 ch = buffer[0];
431 if (ch == 'Y' || ch == 'y')
432 return(TRUE);
433 if (ch == 'N' || ch == 'n')
434 return(FALSE);
435 fprintf(stderr, "Yes or No only!\n");
436 }
437}
438
439boolean probethisfile(currentfilename)
440 char *currentfilename;
441{
442 struct stat statbuf;
443 if (stat(currentfilename, &statbuf) != 0)
444 return(FALSE);
445 if ( (statbuf.st_mode&S_IREAD) && (statbuf.st_mode&S_IWRITE))
446 return(TRUE);
447 return(FALSE);
448}