home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / file.c < prev    next >
C/C++ Source or Header  |  1998-09-28  |  48KB  |  2,085 lines

  1. /*    FILE.C:   for MicroEMACS
  2.  *
  3.  *    The routines in this file handle the reading, writing
  4.  *    and lookup of disk files.  All of details about the
  5.  *    reading and writing of the disk are in "fileio.c".
  6.  *
  7.  *
  8.  * $Header: /usr/build/vile/vile/RCS/file.c,v 1.234 1998/09/29 02:22:01 tom Exp $
  9.  *
  10.  */
  11.  
  12. #include    "estruct.h"
  13. #include        "edef.h"
  14.  
  15. #if SYS_WINNT
  16. #include    <io.h>            /* for mktemp */
  17. #endif
  18.  
  19. static    int    bp2swbuffer(BUFFER *bp, int ask_rerun, int lockfl);
  20. static    int    kifile(char *fname);
  21. static    int    writereg(REGION *rp, const char *fn, int msgf, BUFFER *bp, int forced);
  22. static    void    readlinesmsg(int n, int s, const char *f, int rdo);
  23.  
  24. #if OPT_DOSFILES
  25. /* give DOS the benefit of the doubt on ambiguous files */
  26. # if CRLF_LINES
  27. #  define MORETHAN >=
  28. # else
  29. #  define MORETHAN >
  30. # endif
  31. #endif
  32.  
  33. #if !(SYS_MSDOS || SYS_WIN31)
  34. static    int    quickreadf(BUFFER *bp, int *nlinep);
  35. #endif
  36.  
  37. /*--------------------------------------------------------------------------*/
  38.  
  39. /* Returns the modification time iff the path corresponds to an existing file,
  40.  * otherwise it returns zero.
  41.  */
  42. #if    defined(MDCHK_MODTIME) || SYS_VMS || SYS_UNIX
  43. time_t
  44. file_modified(char *path)
  45. {
  46.     struct stat    statbuf;
  47.     time_t        the_time = 0;
  48.  
  49.     if (stat(SL_TO_BSL(path), &statbuf) >= 0
  50. #if CC_CSETPP
  51.      && (statbuf.st_mode & S_IFREG) == S_IFREG)
  52. #else
  53.      && (statbuf.st_mode & S_IFMT) == S_IFREG)
  54. #endif
  55.     {
  56. #if SYS_VMS
  57.         the_time = statbuf.st_ctime; /* e.g., creation-time */
  58. #else
  59.         the_time = statbuf.st_mtime;
  60. #endif
  61.     }
  62.     return the_time;
  63. }
  64. #endif
  65.  
  66. #ifdef    MDCHK_MODTIME
  67. static int
  68. PromptModtime (
  69. BUFFER    *bp,
  70. char *fname,
  71. const char *question,
  72. int    iswrite)
  73. {
  74.     int status = SORTOFTRUE;
  75.     time_t current;
  76.     char prompt[NLINE];
  77.  
  78.     if (!isInternalName(bp->b_fname)
  79.      && b_val(bp, MDCHK_MODTIME)
  80.      && bp->b_active    /* only buffers that are loaded */
  81.      && same_fname(fname, bp, FALSE)
  82.      && get_modtime(bp, ¤t)) {
  83.         time_t check_against;
  84.         const char *remind, *again;
  85.         if (iswrite) {
  86.             check_against = bp->b_modtime;
  87.             remind = "Reminder: ";
  88.             again = "";
  89.         } else {
  90.             remind = "";
  91.             if (bp->b_modtime_at_warn) {
  92.                 check_against = bp->b_modtime_at_warn;
  93.                 again = "again ";
  94.             } else {
  95.                 check_against = bp->b_modtime;
  96.                 again = "";
  97.             }
  98.         }
  99.  
  100.         if (check_against != current) {
  101.             (void)lsprintf(prompt,
  102.             "%sFile for buffer \"%s\" has changed %son disk.  %s",
  103.                 remind, bp->b_bname, again, question);
  104.             if ((status = mlyesno( prompt )) != TRUE)
  105.                 mlerase();
  106.             /* avoid reprompts */
  107.             bp->b_modtime_at_warn = current;
  108.         }
  109.     }
  110.     return status;
  111. }
  112.  
  113. int
  114. ask_shouldchange(BUFFER *bp)
  115. {
  116.     int status;
  117.     status = PromptModtime(bp, bp->b_fname, "Continue", FALSE);
  118.     return (status == TRUE || status == SORTOFTRUE);
  119. }
  120.  
  121. int
  122. get_modtime (BUFFER *bp, time_t *the_time)
  123. {
  124.     if (isInternalName(bp->b_fname))
  125.         *the_time = 0;
  126.     else
  127.         *the_time = file_modified(bp->b_fname);
  128.  
  129.     return (*the_time != 0);
  130. }
  131.  
  132. void
  133. set_modtime(BUFFER *bp, char *fn)
  134. {
  135.     time_t    current;
  136.  
  137.     if (same_fname(fn, bp, FALSE) && get_modtime(bp, ¤t)) {
  138.         bp->b_modtime = current;
  139.         bp->b_modtime_at_warn = 0;
  140.     }
  141. }
  142.  
  143. int
  144. check_modtime(BUFFER *bp, char *fn)
  145. {
  146.     int status = TRUE;
  147.  
  148.     if (PromptModtime(bp, fn, "Read from disk", FALSE) == TRUE) {
  149. #if OPT_LCKFILES
  150.         /* release own lock before read the file again */
  151.         if ( global_g_val(GMDUSEFILELOCK) ) {
  152.             if (!b_val(curbp,MDLOCKED) && !b_val(curbp,MDVIEW))
  153.                 release_lock(fn);
  154.         }
  155. #endif
  156.         status = readin(fn, TRUE, bp, TRUE);
  157.     }
  158.     return status;
  159. }
  160.  
  161. static int
  162. inquire_modtime(BUFFER *bp, char *fn)
  163. {
  164.     register int status;
  165.     if ((status = PromptModtime(bp, fn, "Continue write", TRUE)) != TRUE
  166.      && (status != SORTOFTRUE)) {
  167.         mlforce("[Write aborted]");
  168.         return FALSE;
  169.     }
  170.     return TRUE;
  171. }
  172.  
  173. int
  174. check_visible_modtimes (void)
  175. {
  176.     register WINDOW *wp;
  177.  
  178.     for_each_visible_window(wp)
  179.         (void)check_modtime(wp->w_bufp, wp->w_bufp->b_fname);
  180.     return TRUE;
  181. }
  182. #endif    /* MDCHK_MODTIME */
  183.  
  184. #if SYS_UNIX || SYS_MSDOS
  185. #define    CleanToPipe()    if (fileispipe) ttclean(TRUE)
  186.  
  187. static void
  188. CleanAfterPipe (int Wrote)
  189. {
  190.     if (fileispipe == TRUE) {
  191.         ttunclean();    /* may clear the screen as a side-effect */
  192.             TTflush();
  193.         if (Wrote) pressreturn();
  194.             sgarbf = TRUE;
  195.     }
  196. }
  197.  
  198. #else /* !SYS_UNIX */
  199. #ifdef GMDW32PIPES
  200.  
  201. static void
  202. CleanToPipe(void)
  203. {
  204.     if (fileispipe)
  205.     {
  206.         kbd_erase_to_end(0);
  207.         kbd_flush();
  208.         TTkclose();
  209.     }
  210. }
  211.  
  212. static void
  213. CleanAfterPipe(int Wrote)
  214. {
  215.     if (fileispipe)
  216.     {
  217.         TTkopen();
  218.         if (global_g_val(GMDW32PIPES))
  219.         {
  220.             if (Wrote) pressreturn();
  221.             sgarbf = TRUE;
  222.         }
  223.     }
  224. }
  225.  
  226. #else /* !GMDW32PIPES */
  227. #define    CleanToPipe()        TTkclose()
  228. #define    CleanAfterPipe(f)    TTkopen()
  229. #endif
  230. #endif /* SYS_UNIX */
  231.  
  232. /*
  233.  * On faster machines, a pipe-writer will tend to keep the pipe full. This
  234.  * function is used by 'slowreadf()' to test if we've not done an update
  235.  * recently even if this is the case.
  236.  */
  237. #if SYS_UNIX && OPT_SHELL
  238. static int
  239. slowtime (time_t *refp)
  240. {
  241.     int    status = FALSE;
  242.  
  243.     if (fileispipe) {
  244.         time_t    temp = time((time_t *)0);
  245.  
  246.         status = (!ffhasdata() || (temp != *refp));
  247.         if (status)
  248.             *refp = temp;
  249.     }
  250.     return status;
  251. }
  252. #else
  253. # if SYS_WINNT
  254. #  define    slowtime(refp)    (fileispipe && !nowait_pipe_cmd && !ffhasdata())
  255. # else
  256. #  define    slowtime(refp)    (fileispipe && !ffhasdata())
  257. # endif
  258. #endif
  259.  
  260. int
  261. no_such_file(const char * fname)
  262. {
  263.     mlwarn("[No such file \"%s\"]", fname);
  264.     return FALSE;
  265. }
  266.  
  267. #if OPT_VMS_PATH
  268. static char *
  269. version_of(char *fname)
  270. {
  271.     register char    *s = strchr(fname, ';');
  272.     if (s == 0)
  273.         s = skip_string(fname);
  274.     return s;
  275. }
  276.  
  277. static int
  278. explicit_version(char *ver)
  279. {
  280.     if (*ver++ == ';') {
  281.         if (isDigit(*ver))
  282.             return TRUE;
  283.     }
  284.     return FALSE;
  285. }
  286. #endif /* OPT_VMS_PATH */
  287.  
  288. #if SYS_VMS
  289. static char *
  290. resolve_filename(BUFFER *bp)
  291. {
  292.     char    temp[NFILEN];
  293.     ch_fname(bp, fgetname(ffp, temp));
  294.     markWFMODE(bp);
  295.     return bp->b_fname;
  296. }
  297. #endif
  298.  
  299. /*
  300.  * Returns true if the given filename is the same as that of the referenced
  301.  * buffer.  The 'lengthen' parameter controls whether we assume the filename is
  302.  * already in canonical form, since that may be an expensive operation to do in
  303.  * a loop.
  304.  */
  305. int
  306. same_fname(char *fname, BUFFER *bp, int lengthen)
  307. {
  308.     char    temp[NFILEN];
  309.  
  310.     if (fname == 0
  311.      || bp->b_fname == 0
  312.      || isInternalName(fname)
  313.      || isInternalName(bp->b_fname))
  314.         return FALSE;
  315.  
  316.     if (lengthen)
  317.         fname = lengthen_path(strcpy(temp, fname));
  318.  
  319. #if OPT_VMS_PATH
  320.     /* ignore version numbers in this comparison unless both are given */
  321.     if (is_vms_pathname(fname, FALSE)) {
  322.         char    *bname = bp->b_fname,
  323.             *s = version_of(bname),
  324.             *t = version_of(fname);
  325.  
  326.         if (!explicit_version(s)
  327.          || !explicit_version(t))
  328.             if ((s-bname) == (t-fname))
  329.                 return !strncmp(fname, bname, (SIZE_T)(s-bname));
  330.     }
  331. #endif
  332.  
  333.     return !strcmp(fname, bp->b_fname);
  334. }
  335.  
  336. /*
  337.  * Set the buffer-name based on the filename
  338.  */
  339. static void
  340. set_buffer_name(BUFFER *bp)
  341. {
  342.         char bname[NBUFN];
  343.  
  344.     bp->b_bname[0] = EOS;    /* ...so 'unqname()' doesn't find me */
  345.     makename(bname, bp->b_fname);
  346.     unqname(bname);
  347.     set_bname(bp, bname);
  348.     updatelistbuffers();
  349.     markWFMODE(bp);
  350. }
  351.  
  352. /*
  353.  * Read a file into the current
  354.  * buffer. This is really easy; all you do it
  355.  * find the name of the file, and call the standard
  356.  * "read a file into the current buffer" code.
  357.  */
  358. /* ARGSUSED */
  359. int
  360. fileread(int f GCC_UNUSED, int n GCC_UNUSED)
  361. {
  362.         register int    s;
  363.     char fname[NFILEN];
  364.  
  365.     if (more_named_cmd()) {
  366.         if ((s = mlreply_file("Replace with file: ", (TBUFF **)0,
  367.                 FILEC_REREAD, fname)) != TRUE)
  368.             return s;
  369.     }
  370.     else if (!global_g_val(GMDWARNREREAD)
  371.          || ((s = mlyesno("Reread current buffer")) == TRUE)) {
  372.         (void)strcpy(fname, curbp->b_fname);
  373.         /* Check if we are rereading the unnamed-buffer if it is not
  374.          * associated with a file.
  375.          */
  376.         if (curbp->b_fname[0] == EOS
  377.            && eql_bname(curbp, UNNAMED_BufName)) {
  378.             s = bclear(curbp);
  379.             if (s == TRUE)
  380.                 mlerase();
  381.             return s;
  382.         }
  383.     } else {
  384.         return FALSE;
  385.     }
  386.  
  387. #if OPT_LCKFILES
  388.     /* release own lock before read the replaced file */
  389.     if ( global_g_val(GMDUSEFILELOCK) ) {
  390.         if (!b_val(curbp,MDLOCKED) && !b_val(curbp,MDVIEW))
  391.             release_lock(curbp->b_fname);
  392.     }
  393. #endif
  394.  
  395.     /* we want no errors or complaints, so mark it unchanged */
  396.     b_clr_changed(curbp);
  397.         s = readin(fname, TRUE, curbp, TRUE);
  398.     set_buffer_name(curbp);
  399.     return s;
  400. }
  401.  
  402. /*
  403.  * Select a file for editing.
  404.  * Look around to see if you can find the
  405.  * file in another buffer; if you can find it
  406.  * just switch to the buffer. If you cannot find
  407.  * the file, create a new buffer, read in the
  408.  * text, and switch to the new buffer.
  409.  * This is ": e"
  410.  */
  411.  
  412. TBUFF    *lastfileedited;
  413.  
  414. void
  415. set_last_file_edited(const char *f)
  416. {
  417.     tb_scopy(&lastfileedited, f);
  418. }
  419.  
  420. /* ARGSUSED */
  421. int
  422. filefind(int f GCC_UNUSED, int n GCC_UNUSED)
  423. {
  424.     register int    s;
  425.     register BUFFER *bp;
  426.  
  427.     char fname[NFILEN];
  428.     char *actual;
  429.     BUFFER *firstbp = 0;
  430.  
  431.     if ((s = mlreply_file("Find file: ", &lastfileedited,
  432.                     FILEC_READ|FILEC_EXPAND,
  433.             fname)) == TRUE) {
  434.         while ((actual = filec_expand()) != 0) {
  435.             if ((bp = getfile2bp(actual, !clexec,FALSE)) == 0)
  436.                 break;
  437.             bp->b_flag |= BFARGS;    /* treat this as an argument */
  438.             if (firstbp == 0)
  439.                 firstbp = bp;
  440.         }
  441.         if (firstbp != 0)
  442.             s = bp2swbuffer(firstbp, FALSE, TRUE);
  443.     }
  444.     return s;
  445. }
  446.  
  447. /* ARGSUSED */
  448. int
  449. viewfile(int f GCC_UNUSED, int n GCC_UNUSED)    /* visit a file in VIEW mode */
  450. {
  451.     char fname[NFILEN];    /* file user wishes to find */
  452.     register int s;        /* status return */
  453.     char    *actual;
  454.     static    TBUFF    *last;
  455.  
  456.     if ((s = mlreply_file("View file: ", &last, FILEC_READ|FILEC_EXPAND,
  457.             fname)) == TRUE) {
  458.         while ((actual = filec_expand()) != 0) {
  459.             if ((s = getfile(actual, FALSE)) != TRUE)
  460.                 break;
  461.             /* if we succeed, put it in view mode */
  462.             make_local_b_val(curwp->w_bufp,MDVIEW);
  463.             set_b_val(curwp->w_bufp,MDVIEW,TRUE);
  464.             markWFMODE(curwp->w_bufp);
  465.         }
  466.     }
  467.     return s;
  468. }
  469.  
  470. /*
  471.  * Insert a file into the current
  472.  * buffer. This is really easy; all you do it
  473.  * find the name of the file, and call the standard
  474.  * "insert a file into the current buffer" code.
  475.  */
  476. /* ARGSUSED */
  477. int
  478. insfile(int f GCC_UNUSED, int n GCC_UNUSED)
  479. {
  480.         register int    s;
  481.     char fname[NFILEN];
  482.     static    TBUFF    *last;
  483.  
  484.     if (!calledbefore) {
  485.             if ((s= mlreply_file("Insert file: ", &last,
  486.                 FILEC_READ|FILEC_PROMPT, fname)) != TRUE)
  487.                     return s;
  488.     }
  489.     if (ukb == 0)
  490.             return ifile(fname, TRUE, (FILE *)0);
  491.     else
  492.             return kifile(fname);
  493. }
  494.  
  495. BUFFER *
  496. getfile2bp(
  497. const char *fname,        /* file name to find */
  498. int ok_to_ask,
  499. int cmdline)
  500. {
  501.     register BUFFER *bp = 0;
  502.         register int    s;
  503.     char bname[NBUFN];    /* buffer name to put file */
  504.     char nfname[NFILEN];    /* canonical form of 'fname' */
  505.  
  506.     /* user may have renamed buffer to look like filename */
  507.     if (cmdline
  508.      || (bp = find_b_name(fname)) == NULL
  509.      || (strlen(fname) > (SIZE_T)NBUFN-1)) {
  510.  
  511.         /* It's not already here by that buffer name.
  512.          * Try to find it assuming we're given the file name.
  513.          */
  514.         (void)lengthen_path(strcpy(nfname, fname));
  515.         if (is_internalname(nfname)) {
  516.             mlforce("[Buffer not found]");
  517.             return 0;
  518.         }
  519.             for_each_buffer(bp) {
  520.             /* is it here by that filename? */
  521.                     if (same_fname(nfname, bp, FALSE)) {
  522.                 return bp;
  523.                     }
  524.             }
  525.         /* it's not here */
  526.             makename(bname, nfname);            /* New buffer name.     */
  527.         /* make sure the buffer name doesn't exist */
  528.         while ((bp = find_b_name(bname)) != NULL) {
  529.             if ( !b_is_changed(bp) && is_empty_buf(bp) &&
  530.                         !ffexists(bp->b_fname)) {
  531.                 /* empty and unmodified -- then it's okay
  532.                     to re-use this buffer */
  533.                 bp->b_active = FALSE;
  534.                 ch_fname(bp, nfname);
  535.                 return bp;
  536.             }
  537.             /* old buffer name conflict code */
  538.             unqname(bname);
  539.             if (!ok_to_ask || !global_g_val(GMDWARNRENAME))
  540.                 continue;
  541.             hst_glue(' ');
  542.             s = mlreply("Will use buffer name: ", bname, sizeof(bname));
  543.                     if (s == ABORT)
  544.                             return 0;
  545.             if (s == FALSE || bname[0] == EOS)
  546.                         makename(bname, fname);
  547.             }
  548.         /* okay, we've got a unique name -- create it */
  549.         if (bp==NULL && (bp=bfind(bname, 0))==NULL) {
  550.             mlwarn("[Cannot create buffer]");
  551.                     return 0;
  552.             }
  553.         /* switch and read it in. */
  554.         ch_fname(bp, nfname);
  555.     }
  556.     return bp;
  557. }
  558.  
  559. static int
  560. bp2swbuffer(BUFFER *bp, int ask_rerun, int lockfl)
  561. {
  562.     register int s;
  563.  
  564.     if ((s = (bp != 0)) != FALSE) {
  565.         if (bp->b_active) {
  566.             if (ask_rerun) {
  567.                 switch (mlyesno(
  568.                     "Old command output -- rerun")) {
  569.                 case TRUE:
  570.                     bp->b_active = FALSE;
  571.                     break;
  572.                 case ABORT:
  573.                     s = FALSE;
  574.                 default:
  575.                     mlerase();
  576.                     break;
  577.                 }
  578.             } else {
  579.                 mlwrite("[Old buffer]");
  580.             }
  581.         }
  582.  
  583. #if BEFORE
  584.         /*
  585.          * The 'swbuffer()' function will invoke 'readin()', but it
  586.          * doesn't accept the 'lockfl' parameter, so we call it here.
  587.          */
  588. /* added swbuffer_lfl() to take lockfl arg to get around this problem.  the
  589.  * readin() was happening before a lot of the buffer info was set up, so a
  590.  * user readhook couldn't use that info successfully.
  591.  * if this change appears successful, the bp2readin routine (4 lines) can
  592.  * be folded into swbuffer_lfl(), which is the only caller.  --pgf */
  593.         if (!(bp->b_active))
  594.             s = bp2readin(bp, lockfl);
  595. #endif
  596.         if (s == TRUE)
  597.             s = swbuffer_lfl(bp, lockfl);
  598.         if (s == TRUE)
  599.             curwp->w_flag |= WFMODE|WFHARD;
  600.     }
  601.  
  602.     return s;
  603. }
  604.  
  605. int
  606. getfile(
  607. char *fname,        /* file name to find */
  608. int lockfl)        /* check the file for locks? */
  609. {
  610.         register BUFFER *bp = 0;
  611.  
  612.     /* if there are no path delimiters in the name, then the user
  613.         is likely asking for an existing buffer -- try for that
  614.         first */
  615.         if ((strlen(fname) > (SIZE_T)NBUFN-1)  /* too big to be a bname */
  616.      || maybe_pathname(fname)  /* looks a lot like a filename */
  617.      || (bp = find_b_name(fname)) == NULL) {
  618.         /* oh well.  canonicalize the name, and try again */
  619.         bp = getfile2bp(fname,!clexec,FALSE);
  620.         if (!bp)
  621.             return FALSE;
  622.     }
  623.     return bp2swbuffer(bp, isShellOrPipe(bp->b_fname), lockfl);
  624. }
  625.  
  626. /*
  627.  * Scan a buffer to see if it contains more lines terminated by CR-LF than by
  628.  * LF alone.  If so, set the DOS-mode to true, otherwise false.
  629.  */
  630. #if OPT_DOSFILES
  631. /*
  632.  * If the given buffer is one that we're sourcing (e.g., with ":so"), or
  633.  * specified in initialization, we require that _all_ of the lines end with
  634.  * ^M's before deciding that it is DOS-style.  That is to protect us from
  635.  * accidentally trimming the ^M's from a :map command.
  636.  */
  637. static void
  638. apply_dosmode(BUFFER *bp, int doslines, int unixlines)
  639. {
  640.     int result;
  641.  
  642.     if (bp->b_flag & BFEXEC) {
  643.         if (doslines && !unixlines) {
  644.             result = TRUE;
  645.         } else {
  646.             result = FALSE;
  647.         }
  648.     } else {
  649.         result = (doslines MORETHAN unixlines);
  650.     }
  651.     set_b_val(bp, MDDOS, result);
  652. }
  653.  
  654. static void
  655. strip_if_dosmode(BUFFER *bp, int doslines, int unixlines)
  656. {
  657.     apply_dosmode(bp, doslines, unixlines);
  658.     if (b_val(bp, MDDOS)) {  /* if it _is_ a dos file, strip 'em */
  659.         register LINE   *lp;
  660.         for_each_line(lp,bp) {
  661.             if (llength(lp) > 0 &&
  662.                   lgetc(lp, llength(lp)-1) == '\r') {
  663.                 llength(lp)--;
  664.                 bp->b_bytecount--;
  665.             }
  666.         }
  667.     }
  668. }
  669.  
  670. static void
  671. guess_dosmode(BUFFER *bp)
  672. {
  673.     int    doslines = 0,
  674.         unixlines = 0;
  675.     register LINE *lp;
  676.  
  677.     make_local_b_val(bp, MDDOS);    /* keep it local, if not */
  678.     /* first count 'em */
  679.     for_each_line(lp,bp) {
  680.         if (llength(lp) > 0 &&
  681.                 lgetc(lp, llength(lp)-1) == '\r') {
  682.             doslines++;
  683.         } else {
  684.             unixlines++;
  685.         }
  686.     }
  687.     strip_if_dosmode(bp, doslines, unixlines);
  688.     TRACE(("guess_dosmode %d\n", b_val(bp, MDDOS)))
  689. }
  690.  
  691. /*
  692.  * Forces the current buffer to be in DOS-mode, stripping any trailing CR's.
  693.  * ( any argument forces non-DOS mode, trailing CR's still stripped )
  694.  */
  695. /*ARGSUSED*/
  696. int
  697. set_dosmode(int f, int n GCC_UNUSED)
  698. {
  699.     guess_dosmode(curbp);
  700.  
  701.     /* force dos mode on the buffer, based on the user argument */
  702.     set_b_val(curbp, MDDOS, !f);
  703.  
  704.     curwp->w_flag |= WFMODE;
  705.     return TRUE;
  706. }
  707.  
  708. /* as above, but forces unix-mode instead */
  709. /*ARGSUSED*/
  710. int
  711. set_unixmode(int f, int n)
  712. {
  713.     return set_dosmode(!f, n);
  714. }
  715. #endif
  716.  
  717. #if OPT_LCKFILES
  718. static void
  719. grab_lck_file(BUFFER *bp, char *fname)
  720. {
  721.     /* Write the lock */
  722.     if (global_g_val(GMDUSEFILELOCK)    &&
  723.         ! isShellOrPipe(fname)        &&
  724.         ! b_val(bp,MDVIEW) )
  725.     {
  726.         char    locker[100];
  727.  
  728.         if ( ! set_lock(fname,locker,sizeof(locker)) ) {
  729.             /* we didn't get it */
  730.             make_local_b_val(bp,MDVIEW);
  731.             set_b_val(bp,MDVIEW,TRUE);
  732.             make_local_b_val(bp,MDLOCKED);
  733.             set_b_val(bp,MDLOCKED,TRUE);
  734.             make_local_b_val(bp,VAL_LOCKER);
  735.             set_b_val_ptr(bp,VAL_LOCKER, strmalloc(locker));
  736.             markWFMODE(bp);
  737.         }
  738.     }
  739. }
  740. #endif
  741.  
  742. /*
  743.  *    Read file "fname" into a buffer, blowing away any text
  744.  *    found there.  Returns the final status of the read.
  745.  */
  746.  
  747. /* ARGSUSED */
  748. int
  749. readin(
  750. char    *fname,        /* name of file to read */
  751. int    lockfl,        /* check for file locks? */
  752. register BUFFER *bp,    /* read into this buffer */
  753. int    mflg)        /* print messages? */
  754. {
  755.         register WINDOW *wp;
  756.     register int    s;
  757.         int    nline;
  758.  
  759.     if (bp == 0)                /* doesn't hurt to check */
  760.         return FALSE;
  761.  
  762.     if (*fname == EOS) {
  763.         mlwrite("BUG: readin called with NULL fname");
  764.         return FALSE;
  765.     }
  766.  
  767. #if    OPT_ENCRYPT
  768.     if ((s = resetkey(bp, fname)) != TRUE)
  769.         return s;
  770. #endif
  771.  
  772.         if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
  773.                 return s;
  774.  
  775. #if    OPT_ENCRYPT
  776.     /* bclear() gets rid of local flags */
  777.     if (bp->b_key[0] != EOS) {
  778.         make_local_b_val(bp, MDCRYPT);
  779.         set_b_val(bp, MDCRYPT, TRUE);
  780.     }
  781. #endif
  782.  
  783.     b_clr_flags(bp, BFINVS|BFCHG);
  784.     ch_fname(bp,fname);
  785.     fname = bp->b_fname;        /* this may have been b_fname! */
  786. #if OPT_DOSFILES
  787.     make_local_b_val(bp, MDDOS);
  788.     /* assume that if our OS wants it, that the buffer will have CRLF
  789.      * lines.  this may change when the file is read, based on actual
  790.      * line counts, below.  otherwise, if there's an error, or the
  791.      * file doesn't exist, we will keep this default.
  792.      */
  793.     set_b_val(bp, MDDOS, CRLF_LINES);
  794. #endif
  795.     make_local_b_val(bp,MDNEWLINE);
  796.     set_b_val(bp, MDNEWLINE, TRUE);        /* assume we've got it */
  797.  
  798.         if ((s = ffropen(fname)) == FIOERR) {    /* Hard file error.      */
  799.             /* do nothing -- error has been reported,
  800.                 and it will appear as empty buffer */
  801.         /*EMPTY*/;
  802.         } else if (s == FIOFNF) {        /* File not found.      */
  803.                 if (mflg)
  804.             mlwrite("[New file]");
  805.         } else {
  806.  
  807.             if (mflg)
  808.             mlforce("[Reading %s ]", fname);
  809. #if SYS_VMS
  810.         if (!isInternalName(bp->b_fname))
  811.             fname = resolve_filename(bp);
  812. #endif
  813.         /* read the file in */
  814.             nline = 0;
  815. #if OPT_WORKING
  816.         max_working = cur_working = old_working = 0;
  817. #endif
  818. #if ! (SYS_MSDOS||SYS_WIN31)
  819.         if (fileispipe || (s = quickreadf(bp, &nline)) == FIOMEM)
  820. #endif
  821.             s = slowreadf(bp, &nline);
  822. #if OPT_WORKING
  823.         cur_working = 0;
  824. #endif
  825.         if (s == FIOERR) {
  826.             /*EMPTY*/;
  827.         } else {
  828.  
  829.             if (s == FIOFUN)    /* last line is incomplete */
  830.                 set_b_val(bp, MDNEWLINE, FALSE);
  831.             b_clr_changed(bp);
  832. #if OPT_FINDERR
  833.             if (fileispipe == TRUE)
  834.                 set_febuff(bp->b_bname);
  835. #endif
  836.                 (void)ffclose();    /* Ignore errors.       */
  837.             if (mflg)
  838.                 readlinesmsg(nline, s, fname, ffronly(fname));
  839.  
  840.             /* set view mode for read-only files */
  841.             if ((global_g_val(GMDRONLYVIEW) && ffronly(fname) )) {
  842.                 make_local_b_val(bp, MDVIEW);
  843.                 set_b_val(bp, MDVIEW, TRUE);
  844.             }
  845.             /* set read-only mode for read-only files */
  846.             if (isShellOrPipe(fname) ||
  847.                 (global_g_val(GMDRONLYRONLY) &&
  848.                         ffronly(fname) )) {
  849.                 make_local_b_val(bp, MDREADONLY);
  850.                 set_b_val(bp, MDREADONLY, TRUE);
  851.             }
  852.  
  853.             bp->b_active = TRUE;
  854.             bp->b_lines_on_disk = bp->b_linecount;
  855.         }
  856.  
  857.     }
  858.  
  859.     /*
  860.      * Set the majormode if the file's suffix matches.
  861.      */
  862.     setm_by_suffix(bp);
  863.     setm_by_preamble(bp);
  864.  
  865.     for_each_window(wp) {
  866.         if (wp->w_bufp == bp) {
  867.             wp->w_line.l = lforw(buf_head(bp));
  868.             wp->w_dot.l  = lforw(buf_head(bp));
  869.             wp->w_dot.o  = 0;
  870. #if WINMARK
  871.             wp->w_mark = nullmark;
  872. #endif
  873.             wp->w_lastdot = nullmark;
  874.             wp->w_flag |= WFMODE|WFHARD;
  875.         }
  876.     }
  877.     imply_alt(fname, FALSE, lockfl);
  878.     updatelistbuffers();
  879.  
  880. #if OPT_LCKFILES
  881.     if (lockfl && s != FIOERR)
  882.         grab_lck_file(bp,fname);
  883. #endif
  884. #if OPT_PROCEDURES
  885.     if (s <= FIOEOF) {
  886.         static int readhooking;
  887.         if (!readhooking && *readhook && !b_is_temporary(bp)) {
  888.             readhooking = TRUE;
  889.             run_procedure(readhook);
  890.             readhooking = FALSE;
  891.         }
  892.     }
  893. #endif
  894.     b_match_attrs_dirty(bp);
  895.     return (s != FIOERR);
  896. }
  897.  
  898. /*
  899.  * Read the file into a given buffer, setting dot to the first line.
  900.  */
  901. int
  902. bp2readin(BUFFER *bp, int lockfl)
  903. {
  904.     register int s = readin(bp->b_fname, lockfl, bp, TRUE);
  905.     bp->b_dot.l  = lforw(buf_head(bp));
  906.     bp->b_dot.o  = 0;
  907.     bp->b_active = TRUE;
  908.     return s;
  909. }
  910.  
  911. #if ! (SYS_MSDOS || SYS_WIN31)
  912. static int
  913. quickreadf(register BUFFER *bp, int *nlinep)
  914. {
  915.         register UCHAR *textp;
  916.         UCHAR *countp;
  917.     L_NUM nlines;
  918.         int incomplete = FALSE;
  919.     B_COUNT len, nbytes;
  920.  
  921.     if ((len = ffsize()) < 0) {
  922.             mlwarn("[Can't size file]");
  923.         return FIOERR;
  924.     }
  925.  
  926.     /* avoid malloc(0) problems down below; let slowreadf() do the work */
  927.     if (len == 0)
  928.         return FIOMEM;
  929. #if OPT_WORKING
  930.     max_working = len;
  931. #endif
  932.     /* leave an extra byte at the front, for the length of the first
  933.         line.  after that, lengths go in place of the newline at
  934.         the end of the previous line */
  935.     bp->b_ltext = castalloc(UCHAR, (ALLOC_T)(len + 2));
  936.     if (bp->b_ltext == NULL)
  937.         return FIOMEM;
  938.  
  939.     if ((len = ffread((char *)&bp->b_ltext[1], len)) < 0) {
  940.         FreeAndNull(bp->b_ltext);
  941.         mlerror("reading");
  942.         return FIOERR;
  943.     }
  944.  
  945. #if OPT_ENCRYPT
  946.     if (b_val(bp, MDCRYPT)
  947.      && bp->b_key[0]) {    /* decrypt the file */
  948.          char    temp[NPAT];
  949.         (void)strcpy(temp, bp->b_key);
  950.         ue_crypt((char *)0, 0);
  951.         ue_crypt(temp, strlen(temp));
  952.         ue_crypt((char *)&bp->b_ltext[1], (UINT)len);
  953.     }
  954. #endif
  955.  
  956.     /* loop through the buffer, replacing all newlines with the
  957.         length of the _following_ line */
  958.     bp->b_ltext_end = bp->b_ltext + len + 1;
  959.     countp = bp->b_ltext;
  960.     textp = countp + 1;
  961.     nbytes = len;
  962.         nlines = 0;
  963.  
  964.     if (textp[len-1] != '\n') {
  965.         textp[len++] = '\n';
  966.         set_b_val(bp, MDNEWLINE, FALSE);
  967.     }
  968.  
  969.     while (len--) {
  970.         if (*textp == '\n') {
  971.             if (textp - countp >= 255) {
  972.                 UCHAR *np;
  973. #if OPT_WORKING
  974.                 max_working = bp->b_ltext_end - countp;
  975. #endif
  976.                 len = (B_COUNT)(countp - bp->b_ltext);
  977.                 incomplete = TRUE;
  978.                 /* we'll re-read the rest later */
  979.                 if (len)  {
  980.                     ffseek(len);
  981.                     np = castrealloc(UCHAR, bp->b_ltext, (ALLOC_T)len);
  982.                 } else {
  983.                     np = NULL;
  984.                 }
  985.                 if (np == NULL) {
  986.                     ffrewind();
  987.                     FreeAndNull(bp->b_ltext);
  988.                     return FIOMEM;
  989.                 }
  990.                 bp->b_ltext = np;
  991.                 bp->b_ltext_end = np + len + 1;
  992.                 nbytes = len;
  993.                 break;
  994.             }
  995.             *countp = textp - countp - 1;
  996.             countp = textp;
  997.             nlines++;
  998.         }
  999.         ++textp;
  1000.     }
  1001.  
  1002.     if (nlines == 0) {
  1003.         ffrewind();
  1004.         FreeAndNull(bp->b_ltext);
  1005.         incomplete = TRUE;
  1006.     } else {
  1007.         /* allocate all of the line structs we'll need */
  1008.         bp->b_LINEs = typeallocn(LINE,nlines);
  1009.         if (bp->b_LINEs == NULL) {
  1010.             FreeAndNull(bp->b_ltext);
  1011.             ffrewind();
  1012.             return FIOMEM;
  1013.         }
  1014.         bp->b_LINEs_end = bp->b_LINEs + nlines;
  1015.         bp->b_bytecount = nbytes;
  1016.         bp->b_linecount = nlines;
  1017.         b_set_counted(bp);
  1018.  
  1019.         /* loop through the buffer again, creating
  1020.             line data structure for each line */
  1021.         {
  1022.             register LINE *lp;
  1023. #if !SMALLER
  1024.             L_NUM lineno = 0;
  1025. #endif
  1026.             lp = bp->b_LINEs;
  1027.             textp = bp->b_ltext;
  1028.             while (lp != bp->b_LINEs_end) {
  1029. #if !SMALLER
  1030.                 lp->l_number = ++lineno;
  1031. #endif
  1032.                 lp->l_used = *textp;
  1033.                 lp->l_size = *textp + 1;
  1034.                 lp->l_text = (char *)textp + 1;
  1035.                 set_lforw(lp, lp + 1);
  1036.                 if (lp != bp->b_LINEs)
  1037.                     set_lback(lp, lp - 1);
  1038.                 lsetclear(lp);
  1039.                 lp->l_nxtundo = null_ptr;
  1040.                 lp++;
  1041.                 textp += *textp + 1;
  1042.             }
  1043.             /*
  1044.             if (textp != bp->b_ltext_end - 1)
  1045.                 mlwrite("BUG: textp not equal to end %d %d",
  1046.                     textp,bp->b_ltext_end);
  1047.             */
  1048.             lp--;  /* point at last line again */
  1049.  
  1050.             /* connect the end of the list */
  1051.             set_lforw(lp, buf_head(bp));
  1052.             set_lback(buf_head(bp), lp);
  1053.  
  1054.             /* connect the front of the list */
  1055.             set_lback(bp->b_LINEs, buf_head(bp));
  1056.             set_lforw(buf_head(bp), bp->b_LINEs);
  1057.         }
  1058.     }
  1059.  
  1060.     *nlinep = nlines;
  1061.  
  1062.     if (incomplete)
  1063.         return FIOMEM;
  1064. #if OPT_DOSFILES
  1065.     if (global_b_val(MDDOS))
  1066.         guess_dosmode(bp);
  1067. #endif
  1068.     return b_val(bp, MDNEWLINE) ? FIOSUC : FIOFUN;
  1069. }
  1070.  
  1071. #endif /* ! SYS_MSDOS */
  1072.  
  1073. int
  1074. slowreadf(register BUFFER *bp, int *nlinep)
  1075. {
  1076.     int s;
  1077.     int len;
  1078. #if OPT_DOSFILES
  1079.     int    doslines = 0,
  1080.         unixlines = 0;
  1081. #endif
  1082. #if SYS_UNIX || SYS_MSDOS || SYS_WIN31 || SYS_OS2 || SYS_WINNT    /* i.e., we can read from a pipe */
  1083.     USHORT    flag = 0;
  1084.     int    done_update = FALSE;
  1085. #endif
  1086. #if SYS_UNIX && OPT_SHELL
  1087.     time_t    last_updated = time((time_t *)0);
  1088. #endif
  1089.     b_set_counted(bp);    /* make 'addline()' do the counting */
  1090. #if OPT_DOSFILES
  1091.     /*
  1092.      * There might be some pre-existing lines if quickreadf
  1093.      * read part of the file and then left the rest up to us.
  1094.      */
  1095.     make_local_b_val(bp, MDDOS);    /* keep it local, if not */
  1096.     if (global_b_val(MDDOS)) {
  1097.         register LINE   *lp;
  1098.         for_each_line(lp,bp) {
  1099.             if (llength(lp) > 0 &&
  1100.                   lgetc(lp, llength(lp)-1) == '\r') {
  1101.                 doslines++;
  1102.             } else {
  1103.                 unixlines++;
  1104.             }
  1105.         }
  1106.     }
  1107. #endif
  1108.     bp->b_lines_on_disk = 0;
  1109.         while ((s = ffgetline(&len)) <= FIOSUC) {
  1110.         bp->b_lines_on_disk += 1;
  1111. #if OPT_DOSFILES
  1112.         /*
  1113.          * Strip CR's if we are reading in DOS-mode.  Otherwise,
  1114.          * keep any CR's that we read.
  1115.          */
  1116.         if (global_b_val(MDDOS)) {
  1117.             if (len > 0 && fline[len-1] == '\r') {
  1118.                 doslines++;
  1119.             } else {
  1120.                 unixlines++;
  1121.             }
  1122.         }
  1123. #endif
  1124.         if (addline(bp,fline,len) != TRUE) {
  1125.                         s = FIOMEM;             /* Keep message on the  */
  1126.                         break;                  /* display.             */
  1127.                 }
  1128. #if SYS_UNIX || SYS_MSDOS || SYS_WIN31 || SYS_OS2 || SYS_WINNT
  1129.         else {
  1130.                     /* reading from a pipe, and internal? */
  1131.             if (slowtime(&last_updated)) {
  1132.                 register WINDOW *wp;
  1133.  
  1134.                 flag |= (WFEDIT|WFFORCE);
  1135.  
  1136.                 if (!done_update || bp->b_nwnd > 1)
  1137.                     flag |= WFHARD;
  1138.                 for_each_window(wp) {
  1139.                             if (wp->w_bufp == bp) {
  1140.                                     wp->w_line.l=
  1141.                             lforw(buf_head(bp));
  1142.                                     wp->w_dot.l =
  1143.                             lback(buf_head(bp));
  1144.                                     wp->w_dot.o = 0;
  1145.                         wp->w_flag |= flag;
  1146.                         wp->w_force = -1;
  1147.                             }
  1148.                     }
  1149.  
  1150.                 /* track changes in dosfile as lines arrive */
  1151. #if OPT_DOSFILES
  1152.                 if (global_b_val(MDDOS))
  1153.                     apply_dosmode(bp, doslines, unixlines);
  1154. #endif
  1155.                 curwp->w_flag |= WFMODE|WFKILLS;
  1156.                 if (!update(TRUE)) {
  1157.                     s = FIOERR;
  1158.                     break;
  1159.                 }
  1160. #if DISP_X11
  1161.                 /* to pick up intrc if it's been hit */
  1162.                 x_move_events();
  1163. #endif
  1164.                 done_update = TRUE;
  1165.                 flag = 0;
  1166.             } else {
  1167.                 flag |= WFHARD;
  1168.             }
  1169.  
  1170.         }
  1171. #endif
  1172.                 ++(*nlinep);
  1173.         if (s == FIOFUN) {
  1174.             set_b_val(bp, MDNEWLINE, FALSE);
  1175.             break;
  1176.         }
  1177.         }
  1178. #if OPT_DOSFILES
  1179.     if (global_b_val(MDDOS)) {
  1180.         strip_if_dosmode(bp, doslines, unixlines);
  1181.     }
  1182. #endif
  1183.     return s;
  1184. }
  1185.  
  1186. /* utility routine for no. of lines read */
  1187. static void
  1188. readlinesmsg(int n, int s, const char *f, int rdo)
  1189. {
  1190.     char fname[NFILEN];
  1191.     const char *m;
  1192.     char *short_f = shorten_path(strcpy(fname,f),TRUE);
  1193.     switch(s) {
  1194.         case FIOFUN:    m = "INCOMPLETE LINE, ";break;
  1195.         case FIOERR:    m = "I/O ERROR, ";    break;
  1196.         case FIOMEM:    m = "OUT OF MEMORY, ";    break;
  1197.         case FIOABRT:    m = "ABORTED, ";    break;
  1198.         default:    m = "";            break;
  1199.     }
  1200.     if (!global_b_val(MDTERSE))
  1201.         mlwrite("[%sRead %d line%s from \"%s\"%s]", m,
  1202.             n, PLURAL(n), short_f, rdo ? "  (read-only)":"" );
  1203.     else
  1204.         mlforce("[%s%d lines]",m,n);
  1205. }
  1206.  
  1207. /*
  1208.  * Take a (null-terminated) file name, and from it
  1209.  * fabricate a buffer name. This routine knows
  1210.  * about the syntax of file names on the target system.
  1211.  * I suppose that this information could be put in
  1212.  * a better place than a line of code.
  1213.  */
  1214.  
  1215. void
  1216. makename(char *bname, const char *fname)
  1217. {
  1218.     register char *fcp;
  1219.         register char *bcp;
  1220.     register int j;
  1221.     char    temp[NFILEN];
  1222.  
  1223.     fcp = skip_string(strcpy(temp, fname));
  1224. #if OPT_VMS_PATH
  1225.     if (is_vms_pathname(temp, TRUE)) {
  1226.         (void)strcpy(bname, "NoName");
  1227.         return;
  1228.     }
  1229.     if (is_vms_pathname(temp, FALSE)) {
  1230.         for (;
  1231.             fcp > temp && !strchr(":]", fcp[-1]);
  1232.                 fcp--)
  1233.                 ;
  1234.         (void)strncpy0(bname, fcp, NBUFN);
  1235.         strip_version (bname);
  1236.         (void)mklower(bname);
  1237.         return;
  1238.     }
  1239. #endif
  1240.     /* trim trailing whitespace */
  1241.     while (fcp != temp && (isBlank(fcp[-1])
  1242. #if SYS_UNIX || OPT_MSDOS_PATH    /* trim trailing slashes as well */
  1243.                      || is_slashc(fcp[-1])
  1244. #endif
  1245.                             ) )
  1246.                 *(--fcp) = EOS;
  1247.     fcp = temp;
  1248.     /* trim leading whitespace */
  1249.     while (isBlank(*fcp))
  1250.         fcp++;
  1251.  
  1252. #if     SYS_UNIX || SYS_MSDOS || SYS_WIN31 || SYS_VMS || SYS_OS2 || SYS_WINNT
  1253.     bcp = bname;
  1254.     if (isShellOrPipe(fcp)) {
  1255.         /* ...it's a shell command; bname is first word */
  1256.         *bcp++ = SCRTCH_LEFT[0];
  1257.         *bcp++ = SHPIPE_LEFT[0];
  1258.         do {
  1259.             ++fcp;
  1260.         } while (isSpace(*fcp));
  1261.         (void)strncpy0(bcp, fcp, (SIZE_T)(NBUFN - (bcp - bname)));
  1262.         for (j = 4; (j < NBUFN) && isPrint(*bcp); j++) {
  1263.             bcp++;
  1264.         }
  1265.         (void) strcpy(bcp, SCRTCH_RIGHT);
  1266.         return;
  1267.     }
  1268.  
  1269.     (void)strncpy0(bcp, pathleaf(fcp), (SIZE_T)(NBUFN - (bcp - bname)));
  1270.  
  1271. #if    SYS_UNIX
  1272.     /* UNIX filenames can have any characters (other than EOS!).  Refuse
  1273.      * (rightly) to deal with leading/trailing blanks, but allow embedded
  1274.      * blanks.  For this special case, ensure that the buffer name has no
  1275.      * blanks, otherwise it is difficult to reference from commands.
  1276.      */
  1277.     for (j = 0; j < NBUFN; j++) {
  1278.         if (*bcp == EOS)
  1279.             break;
  1280.         if (isSpace(*bcp))
  1281.             *bcp = '-';
  1282.         bcp++;
  1283.     }
  1284. #endif
  1285.  
  1286. #else    /* !(SYS_UNIX||SYS_VMS||SYS_MSDOS) */
  1287.  
  1288.     bcp = skip_string(fcp);
  1289.     {
  1290.         register char *cp2 = bname;
  1291.         strcpy0(bname, bcp, NBUFN);
  1292.         cp2 = strchr(bname, ':');
  1293.         if (cp2) *cp2 = EOS;
  1294.     }
  1295. #endif
  1296. }
  1297.  
  1298.  
  1299. void
  1300. unqname(    /* make sure a buffer name is unique */
  1301. char *name)    /* name to check on */
  1302. {
  1303.     register SIZE_T    j;
  1304.     char newname[NBUFN * 2];
  1305.     char suffixbuf[NBUFN];
  1306.     int suffixlen;
  1307.     int adjust;
  1308.     int i = 0;
  1309.     SIZE_T k;
  1310.  
  1311.     j = strlen(name);
  1312.     if (j == 0)
  1313.         j = strlen(strcpy(name, "NoName"));
  1314.  
  1315.     /* check to see if it is in the buffer list */
  1316.     strcpy(newname, name);
  1317.     adjust = is_scratchname(newname);
  1318.     while (find_b_name(newname) != NULL) {
  1319.         /* from "foo" create "foo-1" or "foo-a1b5" */
  1320.         /* from "thisisamuchlongernam" create
  1321.             "thisisamuchlongern-1" or
  1322.             "thisisamuchlong-a1b5" */
  1323.         /* that is, put suffix at end if it fits, or else
  1324.             overwrite some of the name to make it fit */
  1325.         /* the suffix is in "base 36" */
  1326.         suffixlen = (int)(lsprintf(suffixbuf,"-%r", 36, ++i) - suffixbuf);
  1327.         k = NBUFN - 1 - suffixlen;
  1328.         if (j < k)
  1329.             k = j;
  1330.         if (adjust) {
  1331.             strcpy(&newname[k-1], suffixbuf);
  1332.             strcat(newname, SCRTCH_RIGHT);
  1333.         } else
  1334.             strcpy(&newname[k], suffixbuf);
  1335.     }
  1336.     strncpy0(name, newname, NBUFN);
  1337. }
  1338.  
  1339. /*
  1340.  * Ask for a file name, and write the
  1341.  * contents of the current buffer to that file.
  1342.  */
  1343. int
  1344. filewrite(int f, int n)
  1345. {
  1346.         register int    s;
  1347.         char            fname[NFILEN];
  1348.     int         forced = (f && n == SPECIAL_BANG_ARG);
  1349.  
  1350.     if (more_named_cmd()) {
  1351.             if ((s= mlreply_file("Write to file: ", (TBUFF **)0,
  1352.                 FILEC_WRITE, fname)) != TRUE)
  1353.                     return s;
  1354.         } else
  1355.         (void) strcpy(fname, curbp->b_fname);
  1356.  
  1357.         if ((s=writeout(fname,curbp,forced,TRUE)) == TRUE)
  1358.         unchg_buff(curbp, 0);
  1359.         return s;
  1360. }
  1361.  
  1362. /*
  1363.  * Save the contents of the current
  1364.  * buffer in its associatd file.
  1365.  * Error if there is no remembered file
  1366.  * name for the buffer.
  1367.  */
  1368. /* ARGSUSED */
  1369. int
  1370. filesave(int f, int n)
  1371. {
  1372.         register int    s;
  1373.     int forced = (f && n == SPECIAL_BANG_ARG); /* then it was :w! */
  1374.  
  1375.         if (curbp->b_fname[0] == EOS) {        /* Must have a name.    */
  1376.                 mlwarn("[No file name]");
  1377.                 return FALSE;
  1378.         }
  1379.  
  1380.         if ((s=writeout(curbp->b_fname,curbp,forced,TRUE)) == TRUE)
  1381.         unchg_buff(curbp, 0);
  1382.         return s;
  1383. }
  1384.  
  1385. static void
  1386. setup_file_region(BUFFER *bp, REGION *rp)
  1387. {
  1388.     (void)bsizes(bp);    /* make sure we have current count */
  1389.     /* starting at the beginning of the buffer */
  1390.     rp->r_orig.l = lforw(buf_head(bp));
  1391.         rp->r_orig.o = 0;
  1392.         rp->r_size   = bp->b_bytecount;
  1393.         rp->r_end    = bp->b_line;
  1394. }
  1395.  
  1396. /*
  1397.  * Write a whole file
  1398.  */
  1399. int
  1400. writeout(const char *fn, BUFFER *bp, int forced, int msgf)
  1401. {
  1402.         REGION region;
  1403.  
  1404.     setup_file_region(bp, ®ion);
  1405.  
  1406.     return writereg(®ion, fn, msgf, bp, forced);
  1407. }
  1408.  
  1409. /*
  1410.  * Write the currently-selected region (i.e., the range of lines from DOT to
  1411.  * MK, inclusive).
  1412.  */
  1413. int
  1414. writeregion(void)
  1415. {
  1416.         REGION region;
  1417.     int status;
  1418.         char fname[NFILEN];
  1419.  
  1420.     if (end_named_cmd()) {
  1421.         if (mlyesno("Okay to write [possible] partial range") != TRUE) {
  1422.             mlwrite("Range not written");
  1423.             return FALSE;
  1424.         }
  1425.         (void)strcpy(fname, curbp->b_fname);
  1426.     } else {
  1427.             if ((status = mlreply_file("Write region to file: ",
  1428.             (TBUFF **)0, FILEC_WRITE|FILEC_PROMPT, fname)) != TRUE)
  1429.                     return status;
  1430.         }
  1431.         if ((status=getregion(®ion)) == TRUE)
  1432.         status = writereg(®ion, fname, TRUE, curbp, FALSE);
  1433.     return status;
  1434. }
  1435.  
  1436.  
  1437. static int
  1438. writereg(
  1439. REGION    *rp,
  1440. const char  *given_fn,
  1441. int     msgf,
  1442. BUFFER    *bp,
  1443. int    forced)
  1444. {
  1445.         register int    s;
  1446.         register LINE   *lp;
  1447.         register int    nline;
  1448.     register int i;
  1449.     char    fname[NFILEN], *fn;
  1450.     B_COUNT    nchar;
  1451.     const char * ending =
  1452. #if OPT_DOSFILES
  1453.             b_val(bp, MDDOS) ? "\r\n" : "\n"
  1454. #else
  1455.             "\n"
  1456. #endif    /* OPT_DOSFILES */
  1457.         ;
  1458.     C_NUM    offset = rp->r_orig.o;
  1459.  
  1460.     /* this is adequate as long as we cannot write parts of lines */
  1461.     int    whole_file = (rp->r_orig.l == lforw(buf_head(bp)))
  1462.               && (rp->r_end.l == buf_head(bp));
  1463.  
  1464.     if (is_internalname(given_fn)) {
  1465.         mlwarn("[No filename]");
  1466.         return FALSE;
  1467.     }
  1468.  
  1469.     if (!forced && b_val(bp,MDREADONLY)) {
  1470.         mlwarn("[Buffer mode is \"readonly\"]");
  1471.         return FALSE;
  1472.     }
  1473.  
  1474.     if (isShellOrPipe(given_fn)
  1475.      && bp->b_fname != 0
  1476.      && !strcmp(given_fn, bp->b_fname)
  1477.      && mlyesno("Are you sure (this was a pipe-read)") != TRUE) {
  1478.         mlwrite("File not written");
  1479.         return FALSE;
  1480.     }
  1481.  
  1482. #if OPT_PROCEDURES
  1483.     {
  1484.         static int writehooking;
  1485.  
  1486.         if (!writehooking && *writehook) {
  1487.             writehooking = TRUE;
  1488.             run_procedure(writehook);
  1489.             writehooking = FALSE;
  1490.  
  1491.             /*
  1492.              * The write-hook may have modified the buffer.  Assume
  1493.              * the worst, and reconstruct the region.
  1494.              */
  1495.             (void)bsizes(bp);
  1496.             if (whole_file
  1497.              || line_no(bp, rp->r_orig.l) > bp->b_linecount
  1498.              || line_no(bp, rp->r_end.l)  > bp->b_linecount) {
  1499.             setup_file_region(bp, rp);
  1500.             } else {
  1501.             DOT = rp->r_orig;
  1502.             MK  = rp->r_end;
  1503.             (void)getregion(rp);
  1504.             }
  1505.             offset = rp->r_orig.o;
  1506.         }
  1507.     }
  1508. #endif
  1509.  
  1510.     fn = lengthen_path(strcpy(fname, given_fn));
  1511.     if (same_fname(fn, bp, FALSE) && b_val(bp,MDVIEW)) {
  1512.         mlwarn("[Can't write-back from view mode]");
  1513.         return FALSE;
  1514.     }
  1515.  
  1516. #if    OPT_ENCRYPT
  1517.     if ((s = resetkey(curbp, fn)) != TRUE)
  1518.         return s;
  1519. #endif
  1520.  
  1521. #ifdef MDCHK_MODTIME
  1522.     if ( ! inquire_modtime( bp, fn ) )
  1523.         return FALSE;
  1524. #endif
  1525.         if ((s=ffwopen(fn,forced)) != FIOSUC)       /* Open writes message. */
  1526.                 return FALSE;
  1527.  
  1528.     /* tell us we're writing */
  1529.     if (msgf == TRUE)
  1530.         mlwrite("[Writing...]");
  1531.  
  1532.     if (isShellOrPipe(given_fn)) {
  1533.         beginDisplay();
  1534.         CleanToPipe();
  1535.     }
  1536.  
  1537.         lp = rp->r_orig.l;
  1538.         nline = 0;                              /* Number of lines     */
  1539.         nchar = 0;                              /* Number of chars     */
  1540.  
  1541.     /* first (maybe partial) line and succeeding whole lines */
  1542.         while ((rp->r_size+offset) >= llength(lp)+1) {
  1543.         register C_NUM    len = llength(lp) - offset;
  1544.         register char    *text = lp->l_text + offset;
  1545.  
  1546.         /* If this is the last line (and no fragment will be written
  1547.          * after the line), allow 'newline' mode to suppress the
  1548.          * trailing newline.
  1549.          */
  1550.         if ((rp->r_size -= (len + 1)) <= 0
  1551.          && !b_val(bp,MDNEWLINE))
  1552.             ending = "";
  1553.                 if ((s = ffputline(text, len, ending)) != FIOSUC)
  1554.             goto out;
  1555.  
  1556.                 ++nline;
  1557.         nchar += len + 1;
  1558.         offset = 0;
  1559.                 lp = lforw(lp);
  1560.         }
  1561.  
  1562.     /* last line (fragment) */
  1563.     if (rp->r_size > 0) {
  1564.         for (i = 0; i < rp->r_size; i++)
  1565.                 if ((s = ffputc(lgetc(lp,i))) != FIOSUC)
  1566.                         goto out;
  1567.         nchar += rp->r_size;
  1568.         ++nline;    /* it _looks_ like a line */
  1569.     }
  1570.  
  1571.  out:
  1572.         if (s == FIOSUC) {                      /* No write error.      */
  1573. #if SYS_VMS
  1574.         if (same_fname(fn, bp, FALSE))
  1575.             fn = resolve_filename(bp);
  1576. #endif
  1577.                 s = ffclose();
  1578.                 if (s == FIOSUC && msgf) {      /* No close error.      */
  1579.             if (!global_b_val(MDTERSE)) {
  1580.                 char *aname;
  1581.                 const char *action;
  1582.                 if ((aname = is_appendname(fn)) != 0) {
  1583.                     fn = aname;
  1584.                     action = "Appended";
  1585.                 } else {
  1586.                     action = "Wrote";
  1587.                 }
  1588.                 mlforce("[%s %d line%s %ld char%s to \"%s\"]",
  1589.                     action, nline, PLURAL(nline),
  1590.                     nchar, PLURAL(nchar), fn);
  1591.             } else {
  1592.                 mlforce("[%d lines]", nline);
  1593.             }
  1594.                 }
  1595.         } else {                                /* Ignore close error   */
  1596.                 (void)ffclose();                /* if a write error.    */
  1597.     }
  1598.     if (whole_file) {
  1599.         bp->b_linecount =
  1600.             bp->b_lines_on_disk = nline;
  1601.     }
  1602.  
  1603.     if (isShellOrPipe(given_fn)) {
  1604.         CleanAfterPipe(TRUE);
  1605.         endofDisplay();
  1606.     }
  1607.  
  1608.         if (s != FIOSUC)                        /* Some sort of error.  */
  1609.                 return FALSE;
  1610.  
  1611. #ifdef MDCHK_MODTIME
  1612.     set_modtime(bp, fn);
  1613. #endif
  1614.     /*
  1615.      * If we've written the unnamed-buffer, rename it according to the file.
  1616.      * FIXME: maybe we should do this to all internal-names?
  1617.      */
  1618.     if (whole_file
  1619.      && eql_bname(bp, UNNAMED_BufName)
  1620.      && find_b_file(fname) == 0) {
  1621.           ch_fname(bp, fname);
  1622.         set_buffer_name(bp);
  1623.     }
  1624.  
  1625.     imply_alt(fn, whole_file, FALSE);
  1626.         return TRUE;
  1627. }
  1628.  
  1629. /*
  1630.  * This function writes the kill register to a file
  1631.  * Uses the file management routines in the
  1632.  * "fileio.c" package. The number of lines written is
  1633.  * displayed.
  1634.  */
  1635. int
  1636. kwrite(char *fn, int msgf)
  1637. {
  1638.     register KILL *kp;        /* pointer into kill register */
  1639.     register int    nline;
  1640.     register int    s;
  1641.     register int    c;
  1642.     register int    i;
  1643.     register char    *sp;    /* pointer into string to insert */
  1644.  
  1645.     /* make sure there is something to put */
  1646.     if (kbs[ukb].kbufh == NULL) {
  1647.         if (msgf) mlforce("Nothing to write");
  1648.         return FALSE;        /* not an error, just nothing */
  1649.     }
  1650.  
  1651. #if    OPT_ENCRYPT
  1652.     if ((s = resetkey(curbp, fn)) != TRUE)
  1653.         return s;
  1654. #endif
  1655.     if ((s=ffwopen(fn,FALSE)) != FIOSUC) {    /* Open writes message. */
  1656.         return FALSE;
  1657.     }
  1658.     /* tell us we're writing */
  1659.     if (msgf == TRUE)
  1660.         mlwrite("[Writing...]");
  1661.     nline = 0;                /* Number of lines.    */
  1662.  
  1663.     kp = kbs[ukb].kbufh;
  1664.     while (kp != NULL) {
  1665.         i = KbSize(ukb,kp);
  1666.         sp = (char *)kp->d_chunk;
  1667.         while (i--) {
  1668.             if ((c = *sp++) == '\n')
  1669.                 nline++;
  1670.             if ((s = ffputc(c)) != FIOSUC)
  1671.                 break;
  1672.         }
  1673.         kp = kp->d_next;
  1674.     }
  1675.     if (s == FIOSUC) {            /* No write error.    */
  1676.         s = ffclose();
  1677.         if (s == FIOSUC && msgf) {    /* No close error.    */
  1678.             if (!global_b_val(MDTERSE))
  1679.                 mlwrite("[Wrote %d line%s to %s ]",
  1680.                     nline, PLURAL(nline), fn);
  1681.             else
  1682.                 mlforce("[%d lines]", nline);
  1683.         }
  1684.     } else    {                /* Ignore close error    */
  1685.         (void)ffclose();        /* if a write error.    */
  1686.     }
  1687.     if (s != FIOSUC)            /* Some sort of error.    */
  1688.         return FALSE;
  1689.     return TRUE;
  1690. }
  1691.  
  1692.  
  1693. /*
  1694.  * The command allows the user
  1695.  * to modify the file name associated with
  1696.  * the current buffer. It is like the "f" command
  1697.  * in UNIX "ed". The operation is simple; just zap
  1698.  * the name in the BUFFER structure, and mark the windows
  1699.  * as needing an update. You can type a blank line at the
  1700.  * prompt if you wish.
  1701.  */
  1702. /* ARGSUSED */
  1703. int
  1704. filename(int f GCC_UNUSED, int n GCC_UNUSED)
  1705. {
  1706.         register int    s;
  1707.         char            fname[NFILEN];
  1708.  
  1709.     if (end_named_cmd()) {
  1710.         return showcpos(FALSE,1);
  1711.     }
  1712.  
  1713.         if ((s = mlreply_file("Name: ", (TBUFF **)0, FILEC_UNKNOWN, fname))
  1714.                         == ABORT)
  1715.                 return s;
  1716.         if (s == FALSE)
  1717.                 return s;
  1718.     make_global_b_val(curbp,MDVIEW); /* no longer read only mode */
  1719. #if OPT_LCKFILES
  1720.     if ( global_g_val(GMDUSEFILELOCK) ) {
  1721.         if (!b_val(curbp,MDLOCKED) && !b_val(curbp,MDVIEW))
  1722.             release_lock(curbp->b_fname);
  1723.         ch_fname(curbp, fname);
  1724.         make_global_b_val(curbp,MDLOCKED);
  1725.         make_global_b_val(curbp,VAL_LOCKER);
  1726.         grab_lck_file(curbp, fname);
  1727.     } else
  1728. #endif
  1729.      ch_fname(curbp, fname);
  1730.     curwp->w_flag |= WFMODE;
  1731.     updatelistbuffers();
  1732.         return TRUE;
  1733. }
  1734.  
  1735. /*
  1736.  * Insert file "fname" into the current
  1737.  * buffer, Called by insert file command. Return the final
  1738.  * status of the read.
  1739.  */
  1740. int
  1741. ifile(char *fname, int belowthisline, FILE *haveffp)
  1742. {
  1743.     register LINEPTR prevp;
  1744.     register LINEPTR newlp;
  1745.     register LINEPTR nextp;
  1746.         register BUFFER *bp;
  1747.         register int    s;
  1748.         int    nbytes;
  1749.         register int    nline;
  1750.  
  1751.         bp = curbp;                             /* Cheap.               */
  1752.     b_clr_flags(bp, BFINVS);        /* we are not temporary*/
  1753.     if (!haveffp) {
  1754.             if ((s=ffropen(fname)) == FIOERR) /* Hard file open.      */
  1755.                     goto out;
  1756.             if (s == FIOFNF)        /* File not found.      */
  1757.             return no_such_file(fname);
  1758. #if    OPT_ENCRYPT
  1759.         if ((s = resetkey(curbp, fname)) != TRUE)
  1760.             return s;
  1761. #endif
  1762.             mlwrite("[Inserting...]");
  1763.         CleanToPipe();
  1764.  
  1765.     } else { /* we already have the file pointer */
  1766.         ffp = haveffp;
  1767.     }
  1768.     prevp = DOT.l;
  1769.     DOT.o = 0;
  1770.     MK = DOT;
  1771.  
  1772.     nline = 0;
  1773.     nextp = null_ptr;
  1774.     while ((s=ffgetline(&nbytes)) <= FIOSUC) {
  1775. #if OPT_DOSFILES
  1776.         if (b_val(curbp,MDDOS)
  1777.          && (nbytes > 0)
  1778.          && fline[nbytes-1] == '\r')
  1779.             nbytes--;
  1780. #endif
  1781.         if (!belowthisline) {
  1782.             nextp = prevp;
  1783.             prevp = lback(prevp);
  1784.         }
  1785.  
  1786.         if (add_line_at(curbp, prevp, fline, nbytes) != TRUE) {
  1787.             s = FIOMEM;        /* Keep message on the    */
  1788.             break;            /* display.        */
  1789.         }
  1790.         newlp = lforw(prevp);
  1791.         tag_for_undo(newlp);
  1792.         prevp = belowthisline ? newlp : nextp;
  1793.         ++nline;
  1794.         if (s < FIOSUC)
  1795.             break;
  1796.     }
  1797.     if (!haveffp) {
  1798.         CleanAfterPipe(FALSE);
  1799.         (void)ffclose();        /* Ignore errors.    */
  1800.         readlinesmsg(nline,s,fname,FALSE);
  1801.     }
  1802. out:
  1803.     /* advance to the next line and mark the window for changes */
  1804.     DOT.l = lforw(DOT.l);
  1805.  
  1806.     /* copy window parameters back to the buffer structure */
  1807.     copy_traits(&(curbp->b_wtraits), &(curwp->w_traits));
  1808.  
  1809.     imply_alt(fname, FALSE, FALSE);
  1810.     chg_buff (curbp, WFHARD);
  1811.  
  1812.     return (s != FIOERR);
  1813. }
  1814.  
  1815. /*
  1816.  * Insert file "fname" into the kill register
  1817.  * Called by insert file command. Return the final
  1818.  * status of the read.
  1819.  */
  1820. static int
  1821. kifile(char *fname)
  1822. {
  1823.         register int    i;
  1824.         register int    s;
  1825.         register int    nline;
  1826.         int    nbytes;
  1827.  
  1828.     ksetup();
  1829.         if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  1830.                 goto out;
  1831.         if (s == FIOFNF)            /* File not found.      */
  1832.         return no_such_file(fname);
  1833.  
  1834.         nline = 0;
  1835. #if    OPT_ENCRYPT
  1836.     if ((s = resetkey(curbp, fname)) == TRUE)
  1837. #endif
  1838.     {
  1839.             mlwrite("[Reading...]");
  1840.         CleanToPipe();
  1841.         while ((s=ffgetline(&nbytes)) <= FIOSUC) {
  1842.             for (i=0; i<nbytes; ++i)
  1843.                 if (!kinsert(fline[i]))
  1844.                     return FIOMEM;
  1845.             if ((s == FIOSUC) && !kinsert('\n'))
  1846.                 return FIOMEM;
  1847.             ++nline;
  1848.             if (s < FIOSUC)
  1849.                 break;
  1850.         }
  1851.         CleanAfterPipe(FALSE);
  1852.     }
  1853.     kdone();
  1854.         (void)ffclose();                        /* Ignore errors.       */
  1855.     readlinesmsg(nline,s,fname,FALSE);
  1856.  
  1857. out:
  1858.     return (s != FIOERR);
  1859. }
  1860.  
  1861. #if SYS_UNIX
  1862. static const char *mailcmds[] = {
  1863.     "/usr/lib/sendmail",
  1864.     "/sbin/sendmail",
  1865.     "/usr/sbin/sendmail",
  1866.     "/bin/mail",
  1867.     0
  1868. };
  1869. #endif
  1870.  
  1871. /* called on hangups, interrupts, and quits */
  1872. /* This code is definitely not production quality, or probably very
  1873.     robust, or probably very secure.  I whipped it up to save
  1874.     myself while debugging...        pgf */
  1875. /* on the other hand, it has limped along for well over six years now :-/ */
  1876.  
  1877. SIGT
  1878. imdying(int ACTUAL_SIG_ARGS)
  1879. {
  1880.     static char dirnam[NSTRING] = "";
  1881. #if SYS_UNIX
  1882.     static const char *tbl[] = {
  1883.         "/var/tmp",
  1884.         "/usr/tmp",
  1885.         "/tmp"
  1886.         "."
  1887.     };
  1888. #endif
  1889.     char filnam[NFILEN];
  1890.     BUFFER *bp;
  1891. #if SYS_UNIX
  1892.     char cmd[NFILEN+250];
  1893.     char *np;
  1894. #endif
  1895.     static int wrote = 0;
  1896. #if HAVE_MKDIR && !SYS_MSDOS && !SYS_OS2
  1897.     static int created = FALSE;
  1898. #else
  1899.     char temp[NFILEN];
  1900. #endif
  1901.     static    int    i_am_dead;
  1902.  
  1903. #if SYS_APOLLO
  1904.     extern    char    *getlogin(void);
  1905. #endif    /* SYS_APOLLO */
  1906.  
  1907. #if OPT_WORKING && defined(SIGALRM)
  1908.     setup_handler(SIGALRM, SIG_IGN);
  1909. #endif
  1910.  
  1911.     if (i_am_dead++)    /* prevent recursive faults */
  1912.         _exit(signo);
  1913.  
  1914. #if SYS_APOLLO
  1915.     (void)lsprintf(cmd,
  1916.         "(echo signal %d killed vile;/com/tb %d)| /bin/mail %s",
  1917.         signo, getpid(), getlogin());
  1918.     (void)system(cmd);
  1919. #endif    /* SYS_APOLLO */
  1920.  
  1921.     /* write all modified buffers to the temp directory */
  1922.     set_global_g_val(GMDIMPLYBUFF,FALSE);    /* avoid side-effects! */
  1923.     for_each_buffer(bp) {
  1924.         if (!b_is_temporary(bp) &&
  1925.             bp->b_active == TRUE &&
  1926.             b_is_changed(bp)) {
  1927. #if HAVE_MKDIR && !SYS_MSDOS && !SYS_OS2
  1928.             if (!created) {
  1929. #if SYS_UNIX
  1930.                 if ((np = getenv("TMPDIR")) != 0
  1931.                  && strlen(np) < 32
  1932.                  && is_directory(np)) {
  1933.                     strcpy(dirnam, np);
  1934.                 } else {
  1935.                     unsigned n;
  1936.                     for (n = 0; n < TABLESIZE(tbl); n++) {
  1937.                         strcpy(dirnam, tbl[n]);
  1938.                         if (is_directory(dirnam)) {
  1939.                             break;
  1940.                         }
  1941.                     }
  1942.                 }
  1943. #else
  1944.                 strcpy(dirnam, "");
  1945. #endif
  1946.                 (void)pathcat(dirnam, dirnam, "vileDXXXXXX");
  1947.                 (void)mktemp(dirnam);
  1948.                 if(mkdir(dirnam,0700) != 0) {
  1949.                     tidy_exit(BADEXIT);
  1950.                 }
  1951.                 created = TRUE;
  1952.             }
  1953.             (void)pathcat(filnam, dirnam, bp->b_bname);
  1954. #else
  1955.             (void)pathcat(filnam, dirnam,
  1956.                 strcat(strcpy(temp, "V"), bp->b_bname));
  1957. #endif
  1958.             set_b_val(bp,MDVIEW,FALSE);
  1959.             if (writeout(filnam,bp,TRUE,FALSE) != TRUE) {
  1960.                 tidy_exit(BADEXIT);
  1961.             }
  1962.             wrote++;
  1963.         }
  1964.     }
  1965. #if SYS_UNIX
  1966.     if (wrote) {
  1967.         const char **mailcmdp;
  1968.         struct stat sb;
  1969.         /* choose the first mail sender we can find.
  1970.            it used to be you could rely on /bin/mail being
  1971.            a simple mailer, but no more.  and sendmail has
  1972.            been moving around too. */
  1973.         for (mailcmdp = mailcmds; *mailcmdp != 0; mailcmdp++) {
  1974.             if (stat(*mailcmdp, &sb) == 0)
  1975.                 break;
  1976.         }
  1977.         if (*mailcmdp &&
  1978.             ((np = getenv("LOGNAME")) != 0 ||
  1979.                 (np = getenv("USER")) != 0)) {
  1980. #if HAVE_GETHOSTNAME
  1981.             char hostname[128];
  1982.             if (gethostname(hostname, sizeof(hostname)) < 0)
  1983.                 (void)strcpy(hostname, "unknown");
  1984.             hostname[sizeof(hostname)-1] = EOS;
  1985. #endif
  1986.             (void)lsprintf(cmd,
  1987.              "( %s%s; %s; %s; %s%d; %s%s; %s%s; %s%s%s ) | %s %s",
  1988.             "echo To: ", np,
  1989.             "echo Subject: vile died, files saved",
  1990.             "echo ",
  1991.             "echo vile died due to signal ", signo,
  1992. #if HAVE_GETHOSTNAME
  1993.             "echo on host ", hostname,
  1994. #else
  1995.             "echo ", "",
  1996. #endif
  1997.             "echo the following files were saved in directory ",
  1998.             dirnam,
  1999. #if HAVE_MKDIR
  2000.             /* reverse sort so '.' comes last, in case it
  2001.              * terminates the mail message early */
  2002.             "ls -a ", dirnam, " | sort -r",
  2003. #else
  2004.             "ls ", dirnam, "/V*",
  2005. #endif
  2006.             *mailcmdp, np);
  2007.             (void)system(cmd);
  2008.         }
  2009.     }
  2010.     if (signo > 2) {
  2011.         ttclean(FALSE);
  2012.         abort();
  2013.     }
  2014. #else
  2015.     if (wrote) {
  2016.         fprintf(stderr, "vile died: Files saved in directory %s\n",
  2017.                     dirnam);
  2018.     }
  2019. #endif
  2020.  
  2021.     tidy_exit(wrote ? BADEXIT : GOODEXIT);
  2022.     /* NOTREACHED */
  2023.     SIGRET;
  2024. }
  2025.  
  2026. void
  2027. markWFMODE(BUFFER *bp)
  2028. {
  2029.     register WINDOW *wp;    /* scan for windows that need updating */
  2030.         for_each_visible_window(wp) {
  2031.                 if (wp->w_bufp == bp)
  2032.                         wp->w_flag |= WFMODE;
  2033.         }
  2034. }
  2035.  
  2036. #if    OPT_ENCRYPT
  2037. int
  2038. resetkey(        /* reset the encryption key if needed */
  2039. BUFFER    *bp,
  2040. const char *fname)
  2041. {
  2042.     register int s;    /* return status */
  2043.  
  2044.     /* turn off the encryption flag */
  2045.     cryptflag = FALSE;
  2046.  
  2047.     /* if we are in crypt mode */
  2048.     if (b_val(bp, MDCRYPT)) {
  2049.         char    temp[NFILEN];
  2050.  
  2051.         /* don't automatically inherit key from other buffers */
  2052.         if (bp->b_key[0] != EOS
  2053.          && strcmp(lengthen_path(strcpy(temp, fname)), bp->b_fname)) {
  2054.             char    prompt[80];
  2055.             (void)lsprintf(prompt,
  2056.                 "Use crypt-key from %s", bp->b_bname);
  2057.             s = mlyesno(prompt);
  2058.             if (s != TRUE)
  2059.                 return (s == FALSE);
  2060.         }
  2061.  
  2062.         /* make a key if we don't have one */
  2063.         if (bp->b_key[0] == EOS) {
  2064.             s = ue_makekey(bp->b_key, sizeof(bp->b_key));
  2065.             if (s != TRUE)
  2066.                 return (s == FALSE);
  2067.         }
  2068.  
  2069.         /* let others know... */
  2070.         cryptflag = TRUE;
  2071.  
  2072.         /* and set up the key to be used! */
  2073.         /* de-encrypt it */
  2074.         ue_crypt((char *)0, 0);
  2075.         ue_crypt(bp->b_key, strlen(bp->b_key));
  2076.  
  2077.         /* re-encrypt it...seeding it to start */
  2078.         ue_crypt((char *)0, 0);
  2079.         ue_crypt(bp->b_key, strlen(bp->b_key));
  2080.     }
  2081.  
  2082.     return TRUE;
  2083. }
  2084. #endif
  2085.