[BACK]Return to touch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / error

Annotation of src/usr.bin/error/touch.c, Revision 1.8

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