home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / error / touch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-12  |  16.6 KB  |  769 lines

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