10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate
23*291Smike_s /*
24*291Smike_s * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25*291Smike_s * Use is subject to license terms.
26*291Smike_s */
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <ctype.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/stat.h>
330Sstevel@tonic-gate #include <signal.h>
34*291Smike_s #include <string.h>
35*291Smike_s #include <stdlib.h>
36*291Smike_s #include <unistd.h>
37*291Smike_s #include <stdarg.h>
380Sstevel@tonic-gate #include "error.h"
390Sstevel@tonic-gate
40*291Smike_s static void errorprint(FILE *place, Eptr errorp, boolean print_all);
41*291Smike_s static void text(Eptr p, boolean use_all);
42*291Smike_s static void insert(int place);
43*291Smike_s static void execvarg(int n_pissed_on, int *r_argc, char ***r_argv);
44*291Smike_s static void diverterrors(char *name, int dest, Eptr **files, int ix,
45*291Smike_s boolean previewed, int nterrors);
46*291Smike_s static void hackfile(char *name, Eptr **files, int ix, int nerrors);
47*291Smike_s static int countfiles(Eptr *errors);
48*291Smike_s static int nopertain(Eptr **files);
49*291Smike_s static int oktotouch(char *filename);
50*291Smike_s static boolean preview(int nerrors, Eptr **files, int ix);
51*291Smike_s static int settotouch(char *name);
52*291Smike_s static boolean edit(char *name);
53*291Smike_s static int mustoverwrite(FILE *preciousfile, FILE *tmpfile);
54*291Smike_s static int mustwrite(char *base, int n, FILE *preciousfile);
55*291Smike_s static void writetouched(int overwrite);
560Sstevel@tonic-gate
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate * Iterate through errors
590Sstevel@tonic-gate */
60*291Smike_s #define EITERATE(p, fv, i) for (p = fv[i]; p < fv[i+1]; p++)
61*291Smike_s #define ECITERATE(ei, p, lb) \
62*291Smike_s for (ei = lb; p = errors[ei], ei < nerrors; ei++)
630Sstevel@tonic-gate
640Sstevel@tonic-gate #define FILEITERATE(fi, lb) for (fi = lb; fi <= nfiles; fi++)
650Sstevel@tonic-gate int touchstatus = Q_YES;
660Sstevel@tonic-gate
67*291Smike_s void
findfiles(int nerrors,Eptr * errors,int * r_nfiles,Eptr *** r_files)68*291Smike_s findfiles(int nerrors, Eptr *errors, int *r_nfiles, Eptr ***r_files)
690Sstevel@tonic-gate {
70*291Smike_s int nfiles;
710Sstevel@tonic-gate Eptr **files;
720Sstevel@tonic-gate
73*291Smike_s char *name;
74*291Smike_s int ei;
75*291Smike_s int fi;
76*291Smike_s Eptr errorp;
770Sstevel@tonic-gate
780Sstevel@tonic-gate nfiles = countfiles(errors);
790Sstevel@tonic-gate
80*291Smike_s files = Calloc(nfiles + 3, sizeof (Eptr*));
81*291Smike_s touchedfiles = Calloc(nfiles+3, sizeof (boolean));
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate * Now, partition off the error messages
840Sstevel@tonic-gate * into those that are synchronization, discarded or
850Sstevel@tonic-gate * not specific to any file, and those that were
860Sstevel@tonic-gate * nulled or true errors.
870Sstevel@tonic-gate */
880Sstevel@tonic-gate files[0] = &errors[0];
89*291Smike_s ECITERATE(ei, errorp, 0) {
90*291Smike_s if (!(NOTSORTABLE(errorp->error_e_class)))
910Sstevel@tonic-gate break;
920Sstevel@tonic-gate }
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate * Now, and partition off all error messages
950Sstevel@tonic-gate * for a given file.
960Sstevel@tonic-gate */
970Sstevel@tonic-gate files[1] = &errors[ei];
980Sstevel@tonic-gate touchedfiles[0] = touchedfiles[1] = FALSE;
990Sstevel@tonic-gate name = "\1";
1000Sstevel@tonic-gate fi = 1;
101*291Smike_s ECITERATE(ei, errorp, ei) {
102*291Smike_s if ((errorp->error_e_class == C_NULLED) ||
103*291Smike_s (errorp->error_e_class == C_TRUE)) {
104*291Smike_s if (strcmp(errorp->error_text[0], name) != 0) {
1050Sstevel@tonic-gate name = errorp->error_text[0];
1060Sstevel@tonic-gate touchedfiles[fi] = FALSE;
1070Sstevel@tonic-gate files[fi] = &errors[ei];
1080Sstevel@tonic-gate fi++;
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate files[fi] = &errors[nerrors];
1130Sstevel@tonic-gate *r_nfiles = nfiles;
1140Sstevel@tonic-gate *r_files = files;
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate
117*291Smike_s static int
countfiles(Eptr * errors)118*291Smike_s countfiles(Eptr *errors)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate char *name;
1210Sstevel@tonic-gate int ei;
122*291Smike_s Eptr errorp;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate int nfiles;
1250Sstevel@tonic-gate nfiles = 0;
1260Sstevel@tonic-gate name = "\1";
127*291Smike_s ECITERATE(ei, errorp, 0) {
128*291Smike_s if (SORTABLE(errorp->error_e_class)) {
129*291Smike_s if (strcmp(errorp->error_text[0], name) != 0) {
1300Sstevel@tonic-gate nfiles++;
1310Sstevel@tonic-gate name = errorp->error_text[0];
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate }
135*291Smike_s return (nfiles);
1360Sstevel@tonic-gate }
137*291Smike_s
1380Sstevel@tonic-gate char *class_table[] = {
139*291Smike_s /* C_UNKNOWN 0 */ "Unknown",
140*291Smike_s /* C_IGNORE 1 */ "ignore",
141*291Smike_s /* C_SYNC 2 */ "synchronization",
142*291Smike_s /* C_DISCARD 3 */ "discarded",
143*291Smike_s /* C_NONSPEC 4 */ "non specific",
144*291Smike_s /* C_THISFILE 5 */ "specific to this file",
145*291Smike_s /* C_NULLED 6 */ "nulled",
146*291Smike_s /* C_TRUE 7 */ "true",
147*291Smike_s /* C_DUPL 8 */ "duplicated"
1480Sstevel@tonic-gate };
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate int class_count[C_LAST - C_FIRST] = {0};
1510Sstevel@tonic-gate
152*291Smike_s void
filenames(int nfiles,Eptr ** files)153*291Smike_s filenames(int nfiles, Eptr **files)
1540Sstevel@tonic-gate {
155*291Smike_s int fi;
156*291Smike_s char *sep = " ";
157*291Smike_s int someerrors;
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate * first, simply dump out errors that
1610Sstevel@tonic-gate * don't pertain to any file
1620Sstevel@tonic-gate */
1630Sstevel@tonic-gate someerrors = nopertain(files);
1640Sstevel@tonic-gate
165*291Smike_s if (nfiles) {
1660Sstevel@tonic-gate someerrors++;
167*291Smike_s (void) fprintf(stdout, terse
1680Sstevel@tonic-gate ? "%d file%s"
1690Sstevel@tonic-gate : "%d file%s contain%s errors",
1700Sstevel@tonic-gate nfiles, plural(nfiles), verbform(nfiles));
171*291Smike_s if (!terse) {
172*291Smike_s FILEITERATE(fi, 1) {
173*291Smike_s (void) fprintf(stdout, "%s\"%s\" (%d)",
1740Sstevel@tonic-gate sep, (*files[fi])->error_text[0],
1750Sstevel@tonic-gate files[fi+1] - files[fi]);
1760Sstevel@tonic-gate sep = ", ";
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate }
179*291Smike_s (void) fprintf(stdout, "\n");
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate if (!someerrors)
182*291Smike_s (void) fprintf(stdout, "No errors.\n");
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate * Dump out errors that don't pertain to any file
1870Sstevel@tonic-gate */
188*291Smike_s static int
nopertain(Eptr ** files)189*291Smike_s nopertain(Eptr **files)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate int type;
1920Sstevel@tonic-gate int someerrors = 0;
193*291Smike_s Eptr *erpp;
194*291Smike_s Eptr errorp;
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate if (files[1] - files[0] <= 0)
197*291Smike_s return (0);
198*291Smike_s for (type = C_UNKNOWN; NOTSORTABLE(type); type++) {
1990Sstevel@tonic-gate if (class_count[type] <= 0)
2000Sstevel@tonic-gate continue;
2010Sstevel@tonic-gate if (type > C_SYNC)
2020Sstevel@tonic-gate someerrors++;
203*291Smike_s if (terse) {
204*291Smike_s (void) fprintf(stdout, "\t%d %s errors NOT PRINTED\n",
2050Sstevel@tonic-gate class_count[type], class_table[type]);
2060Sstevel@tonic-gate } else {
207*291Smike_s (void) fprintf(stdout, "\n\t%d %s errors follow\n",
2080Sstevel@tonic-gate class_count[type], class_table[type]);
209*291Smike_s EITERATE(erpp, files, 0) {
2100Sstevel@tonic-gate errorp = *erpp;
211*291Smike_s if (errorp->error_e_class == type) {
2120Sstevel@tonic-gate errorprint(stdout, errorp, TRUE);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate }
217*291Smike_s return (someerrors);
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate
220*291Smike_s boolean
touchfiles(int nfiles,Eptr ** files,int * r_edargc,char *** r_edargv)221*291Smike_s touchfiles(int nfiles, Eptr **files, int *r_edargc, char ***r_edargv)
2220Sstevel@tonic-gate {
223*291Smike_s char *name;
224*291Smike_s Eptr errorp;
225*291Smike_s int fi;
226*291Smike_s Eptr *erpp;
227*291Smike_s int ntrueerrors;
228*291Smike_s boolean scribbled;
229*291Smike_s int n_pissed_on; /* # of file touched */
230*291Smike_s int spread;
2310Sstevel@tonic-gate
232*291Smike_s FILEITERATE(fi, 1) {
2330Sstevel@tonic-gate name = (*files[fi])->error_text[0];
2340Sstevel@tonic-gate spread = files[fi+1] - files[fi];
235*291Smike_s (void) fprintf(stdout, terse
2360Sstevel@tonic-gate ? "\"%s\" has %d error%s, "
237*291Smike_s : "\nFile \"%s\" has %d error%s.\n",
238*291Smike_s name, spread, plural(spread));
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * First, iterate through all error messages in this file
2410Sstevel@tonic-gate * to see how many of the error messages really will
2420Sstevel@tonic-gate * get inserted into the file.
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate ntrueerrors = 0;
245*291Smike_s EITERATE(erpp, files, fi) {
2460Sstevel@tonic-gate errorp = *erpp;
2470Sstevel@tonic-gate if (errorp->error_e_class == C_TRUE)
2480Sstevel@tonic-gate ntrueerrors++;
2490Sstevel@tonic-gate }
250*291Smike_s (void) fprintf(stdout, terse ? "insert %d\n" :
251*291Smike_s "\t%d of these errors can be inserted into the file.\n",
252*291Smike_s ntrueerrors);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate hackfile(name, files, fi, ntrueerrors);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate scribbled = FALSE;
2570Sstevel@tonic-gate n_pissed_on = 0;
258*291Smike_s FILEITERATE(fi, 1) {
2590Sstevel@tonic-gate scribbled |= touchedfiles[fi];
2600Sstevel@tonic-gate n_pissed_on++;
2610Sstevel@tonic-gate }
262*291Smike_s if (scribbled) {
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Construct an execv argument
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate execvarg(n_pissed_on, r_edargc, r_edargv);
267*291Smike_s return (TRUE);
2680Sstevel@tonic-gate } else {
2690Sstevel@tonic-gate if (!terse)
270*291Smike_s (void) fprintf(stdout, "You didn't touch any files.\n");
271*291Smike_s return (FALSE);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
275*291Smike_s static void
hackfile(char * name,Eptr ** files,int ix,int nerrors)276*291Smike_s hackfile(char *name, Eptr **files, int ix, int nerrors)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate boolean previewed;
279*291Smike_s int errordest; /* where errors go */
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate if (!oktotouch(name)) {
2820Sstevel@tonic-gate previewed = FALSE;
2830Sstevel@tonic-gate errordest = TOSTDOUT;
2840Sstevel@tonic-gate } else {
285*291Smike_s previewed = preview(nerrors, files, ix);
2860Sstevel@tonic-gate errordest = settotouch(name);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate if (errordest != TOSTDOUT)
2900Sstevel@tonic-gate touchedfiles[ix] = TRUE;
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate if (previewed && (errordest == TOSTDOUT))
2930Sstevel@tonic-gate return;
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate diverterrors(name, errordest, files, ix, previewed, nerrors);
2960Sstevel@tonic-gate
297*291Smike_s if (errordest == TOTHEFILE) {
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate * overwrite the original file
3000Sstevel@tonic-gate */
3010Sstevel@tonic-gate writetouched(1);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate
305*291Smike_s static boolean
preview(int nerrors,Eptr ** files,int ix)306*291Smike_s preview(int nerrors, Eptr **files, int ix)
3070Sstevel@tonic-gate {
3080Sstevel@tonic-gate int back;
309*291Smike_s Eptr *erpp;
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate if (nerrors <= 0)
312*291Smike_s return (FALSE);
3130Sstevel@tonic-gate back = FALSE;
314*291Smike_s if (query) {
315*291Smike_s switch (inquire(terse
3160Sstevel@tonic-gate ? "Preview? "
317*291Smike_s : "Do you want to preview the errors first? ")) {
3180Sstevel@tonic-gate case Q_YES:
3190Sstevel@tonic-gate case Q_yes:
3200Sstevel@tonic-gate back = TRUE;
321*291Smike_s EITERATE(erpp, files, ix) {
3220Sstevel@tonic-gate errorprint(stdout, *erpp, TRUE);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate if (!terse)
325*291Smike_s (void) fprintf(stdout, "\n");
3260Sstevel@tonic-gate default:
3270Sstevel@tonic-gate break;
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate }
330*291Smike_s return (back);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate
333*291Smike_s static int
settotouch(char * name)334*291Smike_s settotouch(char *name)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate int dest = TOSTDOUT;
3370Sstevel@tonic-gate
338*291Smike_s if (query) {
339*291Smike_s switch (touchstatus = inquire(terse
3400Sstevel@tonic-gate ? "Touch? "
3410Sstevel@tonic-gate : "Do you want to touch file \"%s\"? ",
342*291Smike_s name)) {
3430Sstevel@tonic-gate case Q_NO:
3440Sstevel@tonic-gate case Q_no:
345*291Smike_s return (dest);
3460Sstevel@tonic-gate default:
3470Sstevel@tonic-gate break;
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate
351*291Smike_s switch (probethisfile(name)) {
3520Sstevel@tonic-gate case F_NOTREAD:
3530Sstevel@tonic-gate dest = TOSTDOUT;
354*291Smike_s (void) fprintf(stdout, terse
3550Sstevel@tonic-gate ? "\"%s\" unreadable\n"
3560Sstevel@tonic-gate : "File \"%s\" is unreadable\n",
3570Sstevel@tonic-gate name);
3580Sstevel@tonic-gate break;
3590Sstevel@tonic-gate case F_NOTWRITE:
3600Sstevel@tonic-gate dest = TOSTDOUT;
361*291Smike_s (void) fprintf(stdout, terse
3620Sstevel@tonic-gate ? "\"%s\" unwritable\n"
3630Sstevel@tonic-gate : "File \"%s\" is unwritable\n",
3640Sstevel@tonic-gate name);
3650Sstevel@tonic-gate break;
3660Sstevel@tonic-gate case F_NOTEXIST:
3670Sstevel@tonic-gate dest = TOSTDOUT;
368*291Smike_s (void) fprintf(stdout,
369*291Smike_s terse ? "\"%s\" not found\n" :
370*291Smike_s "Can't find file \"%s\" to insert error "
371*291Smike_s "messages into.\n",
372*291Smike_s name);
3730Sstevel@tonic-gate break;
3740Sstevel@tonic-gate default:
3750Sstevel@tonic-gate dest = edit(name) ? TOSTDOUT : TOTHEFILE;
3760Sstevel@tonic-gate break;
3770Sstevel@tonic-gate }
378*291Smike_s return (dest);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
381*291Smike_s static void
diverterrors(char * name,int dest,Eptr ** files,int ix,boolean previewed,int nterrors)382*291Smike_s diverterrors(char *name, int dest, Eptr **files, int ix,
383*291Smike_s boolean previewed, int nterrors)
3840Sstevel@tonic-gate {
3850Sstevel@tonic-gate int nerrors;
386*291Smike_s Eptr *erpp;
387*291Smike_s Eptr errorp;
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate nerrors = files[ix+1] - files[ix];
3900Sstevel@tonic-gate
391*291Smike_s if ((nerrors != nterrors) && (!previewed)) {
392*291Smike_s (void) fprintf(stdout, terse
3930Sstevel@tonic-gate ? "Uninserted errors\n"
3940Sstevel@tonic-gate : ">>Uninserted errors for file \"%s\" follow.\n",
3950Sstevel@tonic-gate name);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate
398*291Smike_s EITERATE(erpp, files, ix) {
3990Sstevel@tonic-gate errorp = *erpp;
400*291Smike_s if (errorp->error_e_class != C_TRUE) {
4010Sstevel@tonic-gate if (previewed || touchstatus == Q_NO)
4020Sstevel@tonic-gate continue;
4030Sstevel@tonic-gate errorprint(stdout, errorp, TRUE);
4040Sstevel@tonic-gate continue;
4050Sstevel@tonic-gate }
406*291Smike_s switch (dest) {
4070Sstevel@tonic-gate case TOSTDOUT:
4080Sstevel@tonic-gate if (previewed || touchstatus == Q_NO)
4090Sstevel@tonic-gate continue;
410*291Smike_s errorprint(stdout, errorp, TRUE);
4110Sstevel@tonic-gate break;
4120Sstevel@tonic-gate case TOTHEFILE:
4130Sstevel@tonic-gate insert(errorp->error_line);
4140Sstevel@tonic-gate text(errorp, FALSE);
4150Sstevel@tonic-gate break;
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
420*291Smike_s static int
oktotouch(char * filename)421*291Smike_s oktotouch(char *filename)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate extern char *suffixlist;
424*291Smike_s char *src;
425*291Smike_s char *pat;
4260Sstevel@tonic-gate char *osrc;
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate pat = suffixlist;
4290Sstevel@tonic-gate if (pat == 0)
430*291Smike_s return (0);
4310Sstevel@tonic-gate if (*pat == '*')
432*291Smike_s return (1);
4330Sstevel@tonic-gate while (*pat++ != '.')
4340Sstevel@tonic-gate continue;
4350Sstevel@tonic-gate --pat; /* point to the period */
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate for (src = &filename[strlen(filename)], --src;
438*291Smike_s (src > filename) && (*src != '.'); --src)
4390Sstevel@tonic-gate continue;
4400Sstevel@tonic-gate if (*src != '.')
441*291Smike_s return (0);
4420Sstevel@tonic-gate
443*291Smike_s for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++) {
444*291Smike_s for (; *src && /* not at end of the source */
445*291Smike_s *pat && /* not off end of pattern */
446*291Smike_s *pat != '.' && /* not off end of sub pattern */
447*291Smike_s *pat != '*' && /* not wild card */
448*291Smike_s *src == *pat; /* and equal... */
449*291Smike_s src++, pat++)
4500Sstevel@tonic-gate continue;
4510Sstevel@tonic-gate if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*'))
452*291Smike_s return (1);
4530Sstevel@tonic-gate if (*src != 0 && *pat == '*')
454*291Smike_s return (1);
4550Sstevel@tonic-gate while (*pat && *pat != '.')
4560Sstevel@tonic-gate pat++;
4570Sstevel@tonic-gate if (! *pat)
458*291Smike_s return (0);
4590Sstevel@tonic-gate }
460*291Smike_s return (0);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate /*
4630Sstevel@tonic-gate * Construct an execv argument
4640Sstevel@tonic-gate * We need 1 argument for the editor's name
4650Sstevel@tonic-gate * We need 1 argument for the initial search string
4660Sstevel@tonic-gate * We need n_pissed_on arguments for the file names
4670Sstevel@tonic-gate * We need 1 argument that is a null for execv.
4680Sstevel@tonic-gate * The caller fills in the editor's name.
4690Sstevel@tonic-gate * We fill in the initial search string.
4700Sstevel@tonic-gate * We fill in the arguments, and the null.
4710Sstevel@tonic-gate */
472*291Smike_s static void
execvarg(int n_pissed_on,int * r_argc,char *** r_argv)473*291Smike_s execvarg(int n_pissed_on, int *r_argc, char ***r_argv)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate Eptr p;
4760Sstevel@tonic-gate char *sep;
4770Sstevel@tonic-gate int fi;
4780Sstevel@tonic-gate
479*291Smike_s (*r_argv) = Calloc(n_pissed_on + 3, sizeof (char *));
4800Sstevel@tonic-gate (*r_argc) = n_pissed_on + 2;
4810Sstevel@tonic-gate (*r_argv)[1] = "+1;/###/";
4820Sstevel@tonic-gate n_pissed_on = 2;
483*291Smike_s if (!terse) {
484*291Smike_s (void) fprintf(stdout, "You touched file(s):");
4850Sstevel@tonic-gate sep = " ";
4860Sstevel@tonic-gate }
487*291Smike_s FILEITERATE(fi, 1) {
4880Sstevel@tonic-gate if (!touchedfiles[fi])
4890Sstevel@tonic-gate continue;
4900Sstevel@tonic-gate p = *(files[fi]);
491*291Smike_s if (!terse) {
492*291Smike_s (void) fprintf(stdout, "%s\"%s\"", sep,
493*291Smike_s p->error_text[0]);
4940Sstevel@tonic-gate sep = ", ";
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate (*r_argv)[n_pissed_on++] = p->error_text[0];
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate if (!terse)
499*291Smike_s (void) fprintf(stdout, "\n");
5000Sstevel@tonic-gate (*r_argv)[n_pissed_on] = 0;
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate FILE *o_touchedfile; /* the old file */
5040Sstevel@tonic-gate FILE *n_touchedfile; /* the new file */
5050Sstevel@tonic-gate char *o_name;
5060Sstevel@tonic-gate char n_name[64];
5070Sstevel@tonic-gate char *canon_name = "/tmp/ErrorXXXXXX";
5080Sstevel@tonic-gate int o_lineno;
5090Sstevel@tonic-gate int n_lineno;
5100Sstevel@tonic-gate boolean tempfileopen = FALSE;
5110Sstevel@tonic-gate /*
5120Sstevel@tonic-gate * open the file; guaranteed to be both readable and writable
5130Sstevel@tonic-gate * Well, if it isn't, then return TRUE if something failed
5140Sstevel@tonic-gate */
515*291Smike_s static boolean
edit(char * name)516*291Smike_s edit(char *name)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate o_name = name;
519*291Smike_s if ((o_touchedfile = fopen(name, "r")) == NULL) {
520*291Smike_s (void) fprintf(stderr,
521*291Smike_s "%s: Can't open file \"%s\" to touch (read).\n",
522*291Smike_s processname, name);
523*291Smike_s return (TRUE);
5240Sstevel@tonic-gate }
525*291Smike_s (void) strcpy(n_name, canon_name);
526*291Smike_s (void) mktemp(n_name);
527*291Smike_s if ((n_touchedfile = fopen(n_name, "w")) == NULL) {
528*291Smike_s (void) fprintf(stderr,
529*291Smike_s "%s: Can't open file \"%s\" to touch (write).\n",
530*291Smike_s processname, name);
531*291Smike_s return (TRUE);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate tempfileopen = TRUE;
5340Sstevel@tonic-gate n_lineno = 0;
5350Sstevel@tonic-gate o_lineno = 0;
536*291Smike_s return (FALSE);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate /*
5390Sstevel@tonic-gate * Position to the line (before, after) the line given by place
5400Sstevel@tonic-gate */
5410Sstevel@tonic-gate char edbuf[BUFSIZ];
542*291Smike_s
543*291Smike_s static void
insert(int place)544*291Smike_s insert(int place)
5450Sstevel@tonic-gate {
546*291Smike_s --place; /* always insert messages before the offending line */
547*291Smike_s for (; o_lineno < place; o_lineno++, n_lineno++) {
548*291Smike_s if (fgets(edbuf, BUFSIZ, o_touchedfile) == NULL)
5490Sstevel@tonic-gate return;
550*291Smike_s (void) fputs(edbuf, n_touchedfile);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
554*291Smike_s static void
text(Eptr p,boolean use_all)555*291Smike_s text(Eptr p, boolean use_all)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate int offset = use_all ? 0 : 2;
5580Sstevel@tonic-gate
559*291Smike_s (void) fputs(lang_table[p->error_language].lang_incomment,
560*291Smike_s n_touchedfile);
561*291Smike_s (void) fprintf(n_touchedfile, "%d [%s] ",
5620Sstevel@tonic-gate p->error_line,
5630Sstevel@tonic-gate lang_table[p->error_language].lang_name);
5640Sstevel@tonic-gate wordvprint(n_touchedfile, p->error_lgtext-offset, p->error_text+offset);
565*291Smike_s (void) fputs(lang_table[p->error_language].lang_outcomment,
566*291Smike_s n_touchedfile);
5670Sstevel@tonic-gate n_lineno++;
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate * write the touched file to its temporary copy,
5720Sstevel@tonic-gate * then bring the temporary in over the local file
5730Sstevel@tonic-gate */
574*291Smike_s static void
writetouched(int overwrite)575*291Smike_s writetouched(int overwrite)
5760Sstevel@tonic-gate {
577*291Smike_s int nread;
578*291Smike_s FILE *localfile;
579*291Smike_s FILE *tmpfile;
580*291Smike_s int botch;
581*291Smike_s int oktorm;
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate botch = 0;
5840Sstevel@tonic-gate oktorm = 1;
585*291Smike_s while ((nread = fread(edbuf, 1, sizeof (edbuf),
586*291Smike_s o_touchedfile)) != NULL) {
587*291Smike_s if (nread != fwrite(edbuf, 1, nread, n_touchedfile)) {
5880Sstevel@tonic-gate /*
5890Sstevel@tonic-gate * Catastrophe in temporary area: file system full?
5900Sstevel@tonic-gate */
5910Sstevel@tonic-gate botch = 1;
592*291Smike_s (void) fprintf(stderr,
593*291Smike_s "%s: write failure: No errors inserted in \"%s\"\n",
594*291Smike_s processname, o_name);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate }
597*291Smike_s (void) fclose(n_touchedfile);
598*291Smike_s (void) fclose(o_touchedfile);
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate * Now, copy the temp file back over the original
6010Sstevel@tonic-gate * file, thus preserving links, etc
6020Sstevel@tonic-gate */
603*291Smike_s if (botch == 0 && overwrite) {
6040Sstevel@tonic-gate botch = 0;
6050Sstevel@tonic-gate localfile = NULL;
6060Sstevel@tonic-gate tmpfile = NULL;
607*291Smike_s if ((localfile = fopen(o_name, "w")) == NULL) {
608*291Smike_s (void) fprintf(stderr,
6090Sstevel@tonic-gate "%s: Can't open file \"%s\" to overwrite.\n",
6100Sstevel@tonic-gate processname, o_name);
6110Sstevel@tonic-gate botch++;
6120Sstevel@tonic-gate }
613*291Smike_s if ((tmpfile = fopen(n_name, "r")) == NULL) {
614*291Smike_s (void) fprintf(stderr,
615*291Smike_s "%s: Can't open file \"%s\" to read.\n",
616*291Smike_s processname, n_name);
6170Sstevel@tonic-gate botch++;
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate if (!botch)
6200Sstevel@tonic-gate oktorm = mustoverwrite(localfile, tmpfile);
6210Sstevel@tonic-gate if (localfile != NULL)
622*291Smike_s (void) fclose(localfile);
6230Sstevel@tonic-gate if (tmpfile != NULL)
624*291Smike_s (void) fclose(tmpfile);
6250Sstevel@tonic-gate }
626*291Smike_s if (oktorm == 0) {
627*291Smike_s (void) fprintf(stderr,
628*291Smike_s "%s: Catastrophe: A copy of \"%s: was saved in \"%s\"\n",
629*291Smike_s processname, o_name, n_name);
6300Sstevel@tonic-gate exit(1);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate * Kiss the temp file good bye
6340Sstevel@tonic-gate */
635*291Smike_s (void) unlink(n_name);
6360Sstevel@tonic-gate tempfileopen = FALSE;
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate * return 1 if the tmpfile can be removed after writing it out
6400Sstevel@tonic-gate */
641*291Smike_s static int
mustoverwrite(FILE * preciousfile,FILE * tmpfile)642*291Smike_s mustoverwrite(FILE *preciousfile, FILE *tmpfile)
6430Sstevel@tonic-gate {
6440Sstevel@tonic-gate int nread;
6450Sstevel@tonic-gate
646*291Smike_s while ((nread = fread(edbuf, 1, sizeof (edbuf), tmpfile)) != NULL) {
6470Sstevel@tonic-gate if (mustwrite(edbuf, nread, preciousfile) == 0)
648*291Smike_s return (0);
6490Sstevel@tonic-gate }
650*291Smike_s return (1);
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate /*
6530Sstevel@tonic-gate * return 0 on catastrophe
6540Sstevel@tonic-gate */
655*291Smike_s static int
mustwrite(char * base,int n,FILE * preciousfile)656*291Smike_s mustwrite(char *base, int n, FILE *preciousfile)
6570Sstevel@tonic-gate {
6580Sstevel@tonic-gate int nwrote;
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate if (n <= 0)
661*291Smike_s return (1);
6620Sstevel@tonic-gate nwrote = fwrite(base, 1, n, preciousfile);
6630Sstevel@tonic-gate if (nwrote == n)
664*291Smike_s return (1);
6650Sstevel@tonic-gate perror(processname);
666*291Smike_s switch (inquire(terse
6670Sstevel@tonic-gate ? "Botch overwriting: retry? "
668*291Smike_s : "Botch overwriting the source file: retry? ")) {
6690Sstevel@tonic-gate case Q_YES:
6700Sstevel@tonic-gate case Q_yes:
671*291Smike_s (void) mustwrite(base + nwrote, n - nwrote, preciousfile);
672*291Smike_s return (1);
6730Sstevel@tonic-gate case Q_NO:
6740Sstevel@tonic-gate case Q_no:
675*291Smike_s switch (inquire("Are you sure? ")) {
6760Sstevel@tonic-gate case Q_YES:
6770Sstevel@tonic-gate case Q_yes:
678*291Smike_s return (0);
6790Sstevel@tonic-gate case Q_NO:
6800Sstevel@tonic-gate case Q_no:
681*291Smike_s (void) mustwrite(base + nwrote, n - nwrote,
682*291Smike_s preciousfile);
683*291Smike_s return (1);
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate default:
686*291Smike_s return (0);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate
690*291Smike_s /* ARGSUSED */
691*291Smike_s void
onintr(int sig)692*291Smike_s onintr(int sig)
6930Sstevel@tonic-gate {
694*291Smike_s switch (inquire(terse
6950Sstevel@tonic-gate ? "\nContinue? "
696*291Smike_s : "\nInterrupt: Do you want to continue? ")) {
6970Sstevel@tonic-gate case Q_YES:
6980Sstevel@tonic-gate case Q_yes:
699*291Smike_s (void) signal(SIGINT, onintr);
7000Sstevel@tonic-gate return;
7010Sstevel@tonic-gate default:
702*291Smike_s if (tempfileopen) {
7030Sstevel@tonic-gate /*
7040Sstevel@tonic-gate * Don't overwrite the original file!
7050Sstevel@tonic-gate */
7060Sstevel@tonic-gate writetouched(0);
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate exit(1);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate /*NOTREACHED*/
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate
713*291Smike_s static void
errorprint(FILE * place,Eptr errorp,boolean print_all)714*291Smike_s errorprint(FILE *place, Eptr errorp, boolean print_all)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate int offset = print_all ? 0 : 2;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate if (errorp->error_e_class == C_IGNORE)
7190Sstevel@tonic-gate return;
720*291Smike_s (void) fprintf(place, "[%s] ",
721*291Smike_s lang_table[errorp->error_language].lang_name);
722*291Smike_s wordvprint(place, errorp->error_lgtext-offset,
723*291Smike_s errorp->error_text+offset);
724*291Smike_s (void) putc('\n', place);
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate
727*291Smike_s /*PRINTFLIKE1*/
728*291Smike_s int
inquire(char * format,...)729*291Smike_s inquire(char *format, ...)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate char buffer[128];
732*291Smike_s va_list args;
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate if (queryfile == NULL)
735*291Smike_s return (0);
736*291Smike_s for (;;) {
737*291Smike_s do {
738*291Smike_s va_start(args, format);
739*291Smike_s (void) fflush(stdout);
740*291Smike_s (void) vfprintf(stderr, format, args);
741*291Smike_s (void) fflush(stderr);
742*291Smike_s va_end(args);
7430Sstevel@tonic-gate } while (fgets(buffer, 127, queryfile) == NULL);
744*291Smike_s switch (buffer[0]) {
745*291Smike_s case 'Y': return (Q_YES);
746*291Smike_s case 'y': return (Q_yes);
747*291Smike_s case 'N': return (Q_NO);
748*291Smike_s case 'n': return (Q_no);
749*291Smike_s default: (void) fprintf(stderr, "Yes or No only!\n");
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
754*291Smike_s int
probethisfile(char * name)755*291Smike_s probethisfile(char *name)
7560Sstevel@tonic-gate {
7570Sstevel@tonic-gate struct stat statbuf;
7580Sstevel@tonic-gate if (stat(name, &statbuf) < 0)
759*291Smike_s return (F_NOTEXIST);
760*291Smike_s if ((statbuf.st_mode & S_IREAD) == 0)
761*291Smike_s return (F_NOTREAD);
762*291Smike_s if ((statbuf.st_mode & S_IWRITE) == 0)
763*291Smike_s return (F_NOTWRITE);
764*291Smike_s return (F_TOUCHIT);
7650Sstevel@tonic-gate }
766