* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)touch.c 5.1 (Berkeley) %G%";
#define EITERATE(p, fv, i) for (p = fv[i]; p < fv[i+1]; p++)
#define ECITERATE(ei, p, lb) for (ei = lb; p = errors[ei],ei < nerrors; ei++)
#define FILEITERATE(fi, lb) for (fi = lb; fi <= nfiles; fi++)
findfiles(nerrors
, errors
, r_nfiles
, r_files
)
nfiles
= countfiles(errors
);
files
= (Eptr
**)Calloc(nfiles
+ 3, sizeof (Eptr
*));
touchedfiles
= (boolean
*)Calloc(nfiles
+3, sizeof(boolean
));
* Now, partition off the error messages
* into those that are synchronization, discarded or
* not specific to any file, and those that were
ECITERATE(ei
, errorp
, 0){
if ( ! (NOTSORTABLE(errorp
->error_e_class
)))
* Now, and partition off all error messages
touchedfiles
[0] = touchedfiles
[1] = FALSE
;
ECITERATE(ei
, errorp
, ei
){
if ( (errorp
->error_e_class
== C_NULLED
)
|| (errorp
->error_e_class
== C_TRUE
) ){
if (strcmp(errorp
->error_text
[0], name
) != 0){
name
= errorp
->error_text
[0];
touchedfiles
[fi
] = FALSE
;
files
[fi
] = &errors
[nerrors
];
ECITERATE(ei
, errorp
, 0){
if (SORTABLE(errorp
->error_e_class
)){
if (strcmp(errorp
->error_text
[0],name
) != 0){
name
= errorp
->error_text
[0];
/*C_UNKNOWN 0 */ "Unknown",
/*C_IGNORE 1 */ "ignore",
/*C_SYNC 2 */ "synchronization",
/*C_DISCARD 3 */ "discarded",
/*C_NONSPEC 4 */ "non specific",
/*C_THISFILE 5 */ "specific to this file",
/*C_NULLED 6 */ "nulled",
/*C_DUPL 8 */ "duplicated"
int class_count
[C_LAST
- C_FIRST
] = {0};
extern char *class_table
[];
* first, simply dump out errors that
* don't pertain to any file
someerrors
= nopertain(files
);
: "%d file%s contain%s errors",
nfiles
, plural(nfiles
), verbform(nfiles
));
fprintf(stdout
, "%s\"%s\" (%d)",
sep
, (*files
[fi
])->error_text
[0],
files
[fi
+1] - files
[fi
]);
fprintf(stdout
, "No errors.\n");
* Dump out errors that don't pertain to any file
if (files
[1] - files
[0] <= 0)
for(type
= C_UNKNOWN
; NOTSORTABLE(type
); type
++){
if (class_count
[type
] <= 0)
fprintf(stdout
, "\t%d %s errors NOT PRINTED\n",
class_count
[type
], class_table
[type
]);
fprintf(stdout
, "\n\t%d %s errors follow\n",
class_count
[type
], class_table
[type
]);
EITERATE(erpp
, files
, 0){
if (errorp
->error_e_class
== type
){
errorprint(stdout
, errorp
, TRUE
);
boolean
touchfiles(nfiles
, files
, r_edargc
, r_edargv
)
int n_pissed_on
; /* # of file touched*/
name
= (*files
[fi
])->error_text
[0];
spread
= files
[fi
+1] - files
[fi
];
? "\"%s\" has %d error%s, "
: "\nFile \"%s\" has %d error%s.\n"
, name
,spread
,plural(spread
));
* First, iterate through all error messages in this file
* to see how many of the error messages really will
* get inserted into the file.
EITERATE(erpp
, files
, fi
){
if (errorp
->error_e_class
== C_TRUE
)
: "\t%d of these errors can be inserted into the file.\n",
hackfile(name
, files
, fi
, ntrueerrors
);
scribbled
|= touchedfiles
[fi
];
* Construct an execv argument
execvarg(n_pissed_on
, r_edargc
, r_edargv
);
fprintf(stdout
, "You didn't touch any files.\n");
hackfile(name
, files
, ix
, nerrors
)
int errordest
; /* where errors go*/
previewed
= preview(name
, nerrors
, files
, ix
);
errordest
= settotouch(name
);
if (errordest
!= TOSTDOUT
)
if (previewed
&& (errordest
== TOSTDOUT
))
diverterrors(name
, errordest
, files
, ix
, previewed
, nerrors
);
if (errordest
== TOTHEFILE
){
* overwrite the original file
boolean
preview(name
, nerrors
, files
, ix
)
: "Do you want to preview the errors first? ")){
EITERATE(erpp
, files
, ix
){
errorprint(stdout
, *erpp
, TRUE
);
switch(touchstatus
= inquire(terse
: "Do you want to touch file \"%s\"? ",
switch(probethisfile(name
)){
: "File \"%s\" is unreadable\n",
: "File \"%s\" is unwritable\n",
: "Can't find file \"%s\" to insert error messages into.\n",
dest
= edit(name
) ? TOSTDOUT
: TOTHEFILE
;
diverterrors(name
, dest
, files
, ix
, previewed
, nterrors
)
nerrors
= files
[ix
+1] - files
[ix
];
if ( (nerrors
!= nterrors
)
: ">>Uninserted errors for file \"%s\" follow.\n",
EITERATE(erpp
, files
, ix
){
if (errorp
->error_e_class
!= C_TRUE
){
if (previewed
|| touchstatus
== Q_NO
)
errorprint(stdout
, errorp
, TRUE
);
if (previewed
|| touchstatus
== Q_NO
)
errorprint(stdout
,errorp
, TRUE
);
insert(errorp
->error_line
);
--pat
; /* point to the period */
for (src
= &filename
[strlen(filename
)], --src
;
(src
> filename
) && (*src
!= '.'); --src
)
for (src
++, pat
++, osrc
= src
; *src
&& *pat
; src
= osrc
, pat
++){
for (; *src
/* not at end of the source */
&& *pat
/* not off end of pattern */
&& *pat
!= '.' /* not off end of sub pattern */
&& *pat
!= '*' /* not wild card */
&& *src
== *pat
; /* and equal... */
if (*src
== 0 && (*pat
== 0 || *pat
== '.' || *pat
== '*'))
if (*src
!= 0 && *pat
== '*')
while (*pat
&& *pat
!= '.')
* Construct an execv argument
* We need 1 argument for the editor's name
* We need 1 argument for the initial search string
* We need n_pissed_on arguments for the file names
* We need 1 argument that is a null for execv.
* The caller fills in the editor's name.
* We fill in the initial search string.
* We fill in the arguments, and the null.
execvarg(n_pissed_on
, r_argc
, r_argv
)
(*r_argv
) = (char **)Calloc(n_pissed_on
+ 3, sizeof(char *));
(*r_argc
) = n_pissed_on
+ 2;
(*r_argv
)[1] = "+1;/###/";
fprintf(stdout
, "You touched file(s):");
fprintf(stdout
,"%s\"%s\"", sep
, p
->error_text
[0]);
(*r_argv
)[n_pissed_on
++] = p
->error_text
[0];
(*r_argv
)[n_pissed_on
] = 0;
FILE *o_touchedfile
; /* the old file */
FILE *n_touchedfile
; /* the new file */
char *canon_name
= "/tmp/ErrorXXXXXX";
boolean tempfileopen
= FALSE
;
* open the file; guaranteed to be both readable and writable
* Well, if it isn't, then return TRUE if something failed
if ( (o_touchedfile
= fopen(name
, "r")) == NULL
){
fprintf(stderr
, "%s: Can't open file \"%s\" to touch (read).\n",
(void)strcpy(n_name
, canon_name
);
if ( (n_touchedfile
= fopen(n_name
, "w")) == NULL
){
fprintf(stderr
,"%s: Can't open file \"%s\" to touch (write).\n",
* Position to the line (before, after) the line given by place
--place
; /* always insert messages before the offending line*/
for(; o_lineno
< place
; o_lineno
++, n_lineno
++){
if(fgets(edbuf
, BUFSIZ
, o_touchedfile
) == NULL
)
fputs(edbuf
, n_touchedfile
);
int offset
= use_all
? 0 : 2;
fputs(lang_table
[p
->error_language
].lang_incomment
, n_touchedfile
);
fprintf(n_touchedfile
, "%d [%s] ",
lang_table
[p
->error_language
].lang_name
);
wordvprint(n_touchedfile
, p
->error_lgtext
-offset
, p
->error_text
+offset
);
fputs(lang_table
[p
->error_language
].lang_outcomment
,n_touchedfile
);
* write the touched file to its temporary copy,
* then bring the temporary in over the local file
while((nread
= fread(edbuf
, 1, sizeof(edbuf
), o_touchedfile
)) != NULL
){
if (nread
!= fwrite(edbuf
, 1, nread
, n_touchedfile
)){
* Catastrophe in temporary area: file system full?
"%s: write failure: No errors inserted in \"%s\"\n",
* Now, copy the temp file back over the original
* file, thus preserving links, etc
if (botch
== 0 && overwrite
){
if ((localfile
= fopen(o_name
, "w")) == NULL
){
"%s: Can't open file \"%s\" to overwrite.\n",
if ((tmpfile
= fopen(n_name
, "r")) == NULL
){
fprintf(stderr
, "%s: Can't open file \"%s\" to read.\n",
oktorm
= mustoverwrite(localfile
, tmpfile
);
fprintf(stderr
, "%s: Catastrophe: A copy of \"%s\: was saved in \"%s\"\n",
processname
, o_name
, n_name
);
* Kiss the temp file good bye
* return 1 if the tmpfile can be removed after writing it out
int mustoverwrite(preciousfile
, tmpfile
)
while((nread
= fread(edbuf
, 1, sizeof(edbuf
), tmpfile
)) != NULL
){
if (mustwrite(edbuf
, nread
, preciousfile
) == 0)
* return 0 on catastrophe
mustwrite(base
, n
, preciousfile
)
nwrote
= fwrite(base
, 1, n
, preciousfile
);
? "Botch overwriting: retry? "
: "Botch overwriting the source file: retry? ")){
mustwrite(base
+ nwrote
, n
- nwrote
, preciousfile
);
switch(inquire("Are you sure? ")){
mustwrite(base
+ nwrote
, n
- nwrote
, preciousfile
);
: "\nInterrupt: Do you want to continue? ")){
* Don't overwrite the original file!
errorprint(place
, errorp
, print_all
)
int offset
= print_all
? 0 : 2;
if (errorp
->error_e_class
== C_IGNORE
)
fprintf(place
, "[%s] ", lang_table
[errorp
->error_language
].lang_name
);
wordvprint(place
,errorp
->error_lgtext
-offset
,errorp
->error_text
+offset
);
fprintf(stderr
, fmt
, a1
, a2
);
} while (fgets(buffer
, 127, queryfile
) == NULL
);
default: fprintf(stderr
, "Yes or No only!\n");
if (stat(name
, &statbuf
) < 0)
if((statbuf
.st_mode
& S_IREAD
) == 0)
if((statbuf
.st_mode
& S_IWRITE
) == 0)