home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / elvis184.zip / src / tmp.c < prev    next >
C/C++ Source or Header  |  1995-05-26  |  19KB  |  865 lines

  1. /* tmp.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    1500 SW Park #326
  6.  *    Portland OR, 97201
  7.  *    kirkenda@cs.pdx.edu
  8.  *
  9.  * Modified by Tom Bodoh 02/10/93 to preserve the protection of previous
  10.  * version of the edited file instead of using the user default protection.
  11.  */
  12.  
  13.  
  14. /* This file contains functions which create & readback a TMPFILE */
  15.  
  16.  
  17. #ifdef AIX
  18. # define _XOPEN_SOURCE
  19. # include <sys/mode.h>
  20. # include <sys/stat.h>
  21. #endif
  22. #include "config.h"
  23. #include "vi.h"
  24. #if TOS
  25. # include <stat.h>
  26. #else
  27. # if OSK
  28. #  include "osk.h"
  29. # else
  30. #  if AMIGA
  31. #   include "amistat.h"
  32. #  else
  33. #   include <sys/stat.h>
  34. #  endif
  35. # endif
  36. #endif
  37. #if TURBOC
  38. # include <process.h>
  39. #endif
  40.  
  41. #ifndef NO_MODELINES
  42. static void do_modelines(l, stop)
  43.     long    l;    /* line number to start at */
  44.     long    stop;    /* line number to stop at */
  45. {
  46.     char    *str;    /* used to scan through the line */
  47.     char    *start;    /* points to the start of the line */
  48.     char    buf[80];
  49.  
  50.     /* if modelines are disabled, then do nothing */
  51.     if (!*o_modelines)
  52.     {
  53.         return;
  54.     }
  55.  
  56.     /* for each line... */
  57.     for (; l <= stop; l++)
  58.     {
  59.         /* for each position in the line.. */
  60.         for (str = fetchline(l); *str; str++)
  61.         {
  62.             /* if it is the start of a modeline command... */
  63.             if ((str[0] == 'e' && str[1] == 'x'
  64.               || str[0] == 'v' && str[1] == 'i')
  65.               && str[2] == ':')
  66.             {
  67.                 start = str += 3;
  68.  
  69.                 /* find the end */
  70.                 for (str = start + strlen(start); *--str != ':'; )
  71.                 {
  72.                 }
  73.  
  74.                 /* if it is a well-formed modeline, execute it */
  75.                 if (str > start && str - start < sizeof buf)
  76.                 {
  77.                     strncpy(buf, start, (int)(str - start));
  78.                     buf[(int)(str - start)] = '\0';
  79.                     doexcmd(buf, '\\');
  80.                     break;
  81.                 }
  82.             }
  83.         }
  84.     }
  85. }
  86. #endif
  87.  
  88.  
  89. /* The FAIL() macro prints an error message and then exits. */
  90. #define FAIL(why,arg)    mode = MODE_EX; msg(why, arg); endwin(); exit(9)
  91.  
  92. /* This is the name of the temp file */
  93. static char    tmpname[80];
  94.  
  95. /* This function creates the temp file and copies the original file into it.
  96.  * Returns if successful, or stops execution if it fails.
  97.  */
  98. int tmpstart(filename)
  99.     char        *filename; /* name of the original file */
  100. {
  101.     int        origfd;    /* fd used for reading the original file */
  102.     struct stat    statb;    /* stat buffer, used to examine inode */
  103.     REG BLK        *this;    /* pointer to the current block buffer */
  104.     REG BLK        *next;    /* pointer to the next block buffer */
  105.     int        inbuf;    /* number of characters in a buffer */
  106.     int        nread;    /* number of bytes read */
  107.     REG int        j, k;
  108.     int        i;
  109.     long        nbytes;
  110.  
  111.     /* switching to a different file certainly counts as a change */
  112.     changes++;
  113.     redraw(MARK_UNSET, FALSE);
  114.  
  115.     /* open the original file for reading */
  116.     *origname = '\0';
  117.     if (filename && *filename)
  118.     {
  119.         strcpy(origname, filename);
  120.         origfd = open(origname, O_RDONLY);
  121.         if (origfd < 0 && errno != ENOENT)
  122.         {
  123.             msg("Can't open \"%s\"", origname);
  124.             return tmpstart("");
  125.         }
  126.         if (origfd >= 0)
  127.         {
  128.             if (stat(origname, &statb) < 0)
  129.             {
  130.                 FAIL("Can't stat \"%s\"", origname);
  131.             }
  132. #if TOS
  133.             if (origfd >= 0 && (statb.st_mode & S_IJDIR))
  134. #else
  135. # if OSK
  136.             if (origfd >= 0 && (statb.st_mode & S_IFDIR))
  137. # else
  138.             if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG)
  139. # endif
  140. #endif
  141.             {
  142.                 msg("\"%s\" is not a regular file", origname);
  143.                 return tmpstart("");
  144.             }
  145.         }
  146.         else
  147.         {
  148.             stat(".", &statb);
  149.         }
  150.         if (origfd >= 0)
  151.         {
  152.             origtime = statb.st_mtime;
  153. #if OSK
  154.             if (*o_readonly || !(statb.st_mode &
  155.                   ((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE :
  156.                   ((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE)))))
  157. #endif
  158. #if AMIGA || MSDOS || OS2
  159.             if (*o_readonly || !(statb.st_mode & S_IWRITE))
  160. #endif
  161. #if TOS
  162. # ifdef __GNUC__ 
  163.             if (*o_readonly || !(statb.st_mode & S_IWRITE))
  164. # else
  165.             if (*o_readonly || (statb.st_mode & S_IJRON))
  166. # endif
  167. #endif
  168. #if ANY_UNIX
  169.             if (*o_readonly || !(statb.st_mode &
  170.                   ((geteuid() == 0) ? 0222 :
  171.                   ((statb.st_uid != geteuid() ? 0022 : 0200)))))
  172. #endif
  173. #if VMS
  174.             if (*o_readonly)
  175. #endif
  176.             {
  177.                 setflag(file, READONLY);
  178.             }
  179.         }
  180.         else
  181.         {
  182.             origtime = 0L;
  183.         }
  184.     }
  185.     else
  186.     {
  187.         origfd = -1;
  188.         origtime = 0L;
  189.         stat(".", &statb);
  190.     }
  191.  
  192.     /* make a name for the tmp file */
  193.     do
  194.     {
  195.         tmpnum++;
  196. #if MSDOS || TOS || OS2
  197.         /* MS-Dos doesn't allow multiple slashes, but supports drives
  198.          * with current directories.
  199.          * This relies on TMPNAME beginning with "%s\\"!!!!
  200.          */
  201.         strcpy(tmpname, o_directory);
  202.         if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
  203.             tmpname[i++]=SLASH;
  204.         sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum);
  205. #else
  206.         sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
  207. #endif
  208.     } while (access(tmpname, 0) == 0);
  209.  
  210.     /* !!! RACE CONDITION HERE - some other process with the same PID could
  211.      * create the temp file between the access() call and the creat() call.
  212.      * This could happen in a couple of ways:
  213.      * - different workstation may share the same temp dir via NFS.  Each
  214.      *   workstation could have a process with the same number.
  215.      * - The DOS version may be running multiple times on the same physical
  216.      *   machine in different virtual machines.  The DOS pid number will
  217.      *   be the same on all virtual machines.
  218.      *
  219.      * This race condition could be fixed by replacing access(tmpname, 0)
  220.      * with open(tmpname, O_CREAT|O_EXCL, 0600), if we could only be sure
  221.      * that open() *always* used modern UNIX semantics.
  222.      */
  223.  
  224.     /* create the temp file */
  225. #if ANY_UNIX
  226.     close(creat(tmpname, 0600));        /* only we can read it */
  227. #else
  228.     close(creat(tmpname, FILEPERMS));    /* anybody body can read it, alas */
  229. #endif
  230.     tmpfd = open(tmpname, O_RDWR | O_BINARY);
  231.     if (tmpfd < 0)
  232.     {
  233.         FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory);
  234.         return 1;
  235.     }
  236.  
  237.     /* allocate space for the header in the file */
  238.     if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) < BLKSIZE
  239.      || write(tmpfd, tmpblk.c, (unsigned)BLKSIZE) < BLKSIZE)
  240.     {
  241.         FAIL("Error writing headers to \"%s\"", tmpname);
  242.     }
  243.  
  244. #ifndef NO_RECYCLE
  245.     /* initialize the block allocator */
  246.     /* This must already be done here, before the first attempt
  247.      * to write to the new file! GB */
  248.     garbage();
  249. #endif
  250.  
  251.     /* initialize lnum[] */
  252.     for (i = 1; i < MAXBLKS; i++)
  253.     {
  254.         lnum[i] = INFINITY;
  255.     }
  256.     lnum[0] = 0;
  257.  
  258.     /* if there is no original file, then create a 1-line file */
  259.     if (origfd < 0)
  260.     {
  261.         *o_newfile = TRUE;
  262.  
  263.         hdr.n[0] = 0;    /* invalid inode# denotes new file */
  264.  
  265.         this = blkget(1);     /* get the new text block */
  266.         strcpy(this->c, "\n");    /* put a line in it */
  267.  
  268.         lnum[1] = 1L;    /* block 1 ends with line 1 */
  269.         nlines = 1L;    /* there is 1 line in the file */
  270.         nbytes = 1L;
  271.  
  272.         if (*origname)
  273.         {
  274.             msg("\"%s\" [NEW FILE]  1 line, 1 char", origname);
  275.         }
  276.         else
  277.         {
  278.             msg("\"[NO FILE]\"  1 line, 1 char");
  279.         }
  280.     }
  281.     else /* there is an original file -- read it in */
  282.     {
  283.         nbytes = nlines = 0;
  284.         *o_newfile = FALSE;
  285.  
  286.         /* preallocate 1 "next" buffer */
  287.         i = 1;
  288.         next = blkget(i);
  289.         inbuf = 0;
  290.  
  291.         /* loop, moving blocks from orig to tmp */
  292.         for (;;)
  293.         {
  294.             /* "next" buffer becomes "this" buffer */
  295.             this = next;
  296.  
  297.             /* read [more] text into this block */
  298.             nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
  299.             if (nread < 0)
  300.             {
  301.                 close(origfd);
  302.                 close(tmpfd);
  303.                 tmpfd = -1;
  304.                 unlink(tmpname);
  305.                 FAIL("Error reading \"%s\"", origname);
  306.             }
  307.  
  308.             /* convert NUL characters to something else */
  309.             for (j = k = inbuf; k < inbuf + nread; k++)
  310.             {
  311.                 if (!this->c[k])
  312.                 {
  313.                     setflag(file, HADNUL);
  314.                     this->c[j++] = 0x80;
  315.                 }
  316. #ifndef CRUNCH
  317.                 else if (*o_beautify && this->c[k] < ' ' && this->c[k] >= 1)
  318.                 {
  319.                     if (this->c[k] == '\t'
  320.                      || this->c[k] == '\n'
  321.                      || this->c[k] == '\f')
  322.                     {
  323.                         this->c[j++] = this->c[k];
  324.                     }
  325.                     else if (this->c[k] == '\b')
  326.                     {
  327.                         /* delete '\b', but complain */
  328.                         setflag(file, HADBS);
  329.                     }
  330.                     /* else silently delete control char */
  331.                 }
  332. #endif
  333.                 else
  334.                 {
  335.                     this->c[j++] = this->c[k];
  336.                 }
  337.             }
  338.             inbuf = j;
  339.  
  340.             /* if the buffer is empty, quit */
  341.             if (inbuf == 0)
  342.             {
  343.                 goto FoundEOF;
  344.             }
  345.  
  346. #if MSDOS || TOS || OS2
  347. /* BAH! MS text mode read fills inbuf, then compresses eliminating \r
  348.    but leaving garbage at end of buf. The same is true for TURBOC. GB. */
  349.  
  350.             memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
  351. #endif
  352.  
  353.             /* search backward for last newline */
  354.             for (k = inbuf; --k >= 0 && this->c[k] != '\n';)
  355.             {
  356.             }
  357.             if (k++ < 0)
  358.             {
  359.                 if (inbuf >= BLKSIZE - 1)
  360.                 {
  361.                     k = 80;
  362.                 }
  363.                 else
  364.                 {
  365.                     k = inbuf;
  366.                 }
  367.             }
  368.  
  369.             /* allocate next buffer */
  370.             if (i >= MAXBLKS - 2)
  371.             {
  372.                 FAIL("File too big.  Limit is approx %ld kbytes.", MAXBLKS * BLKSIZE / 1024L);
  373.             }
  374.             next = blkget(++i);
  375.  
  376.             /* move fragmentary last line to next buffer */
  377.             inbuf -= k;
  378.             for (j = 0; k < BLKSIZE; j++, k++)
  379.             {
  380.                 next->c[j] = this->c[k];
  381.                 this->c[k] = 0;
  382.             }
  383.  
  384.             /* if necessary, add a newline to this buf */
  385.             for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; )
  386.             {
  387.             }
  388.             if (this->c[k] != '\n')
  389.             {
  390.                 setflag(file, ADDEDNL);
  391.                 this->c[k + 1] = '\n';
  392.             }
  393.  
  394.             /* count the lines in this block */
  395.             for (k = 0; k < BLKSIZE && this->c[k]; k++)
  396.             {
  397.                 if (this->c[k] == '\n')
  398.                 {
  399.                     nlines++;
  400.                 }
  401.                 nbytes++;
  402.             }
  403.             lnum[i - 1] = nlines;
  404.         }
  405. FoundEOF:
  406.  
  407.         /* if this is a zero-length file, add 1 line */
  408.         if (nlines == 0)
  409.         {
  410.             this = blkget(1);     /* get the new text block */
  411.             strcpy(this->c, "\n");    /* put a line in it */
  412.  
  413.             lnum[1] = 1;    /* block 1 ends with line 1 */
  414.             nlines = 1;    /* there is 1 line in the file */
  415.             nbytes = 1;
  416.         }
  417.  
  418. #if MSDOS || TOS || OS2
  419.         /* each line has an extra CR that we didn't count yet */
  420.         nbytes += nlines;
  421. #endif
  422.  
  423.         /* report the number of lines in the file */
  424.         msg("\"%s\" %s %ld line%s, %ld char%s",
  425.             origname,
  426.             (tstflag(file, READONLY) ? "[READONLY]" : ""),
  427.             nlines,
  428.             nlines == 1 ? "" : "s",
  429.             nbytes,
  430.             nbytes == 1 ? "" : "s");
  431.     }
  432.  
  433.     /* initialize the cursor to start of line 1 */
  434.     cursor = MARK_FIRST;
  435.  
  436.     /* close the original file */
  437.     close(origfd);
  438.  
  439.     /* any other messages? */
  440.     if (tstflag(file, HADNUL))
  441.     {
  442.         msg("This file contained NULs.  They've been changed to \\x80 chars");
  443.     }
  444.     if (tstflag(file, ADDEDNL))
  445.     {
  446.         msg("Newline characters have been inserted to break up long lines");
  447.     }
  448. #ifndef CRUNCH
  449.     if (tstflag(file, HADBS))
  450.     {
  451.         msg("Backspace characters deleted due to ':set beautify'");
  452.     }
  453. #endif
  454.  
  455.     /* stuff the name of this file into the temp file, to support
  456.      * file preservation & recovery.
  457.      */
  458.     storename(origname);
  459.  
  460. #ifndef NO_EXFILERC
  461.     /* execute the .exfilerc file, if any */
  462.     filename = gethome((char *)0);
  463.     if (filename && *filename)
  464.     {
  465.         strcpy(tmpblk.c, filename);
  466.         filename = tmpblk.c + strlen(tmpblk.c);
  467. #if !VMS
  468. # if AMIGA    /* Don't SLASH a device. "Elvis:.exrc" */
  469.         if (filename[-1] != COLON && filename[-1] != SLASH)
  470. # else
  471.         if (filename[-1] != SLASH)
  472. # endif
  473.         {
  474.             *filename++ = SLASH;
  475.         }
  476. #endif
  477.         strcpy(filename, EXFILERC);
  478.         doexrc(tmpblk.c);
  479.         clrflag(file, MODIFIED);
  480.     }
  481. #endif
  482.  
  483. #ifndef NO_SAFER
  484.     /* don't do anything stupid */
  485.     i = *o_safer;
  486.     *o_safer = TRUE;
  487. #endif
  488.  
  489. #ifndef NO_MODELINES
  490.     /* search for & execute any "mode lines" in the text */
  491.     if (nlines > 10)
  492.     {
  493.         do_modelines(1L, 5L);
  494.         do_modelines(nlines - 4L, nlines);
  495.     }
  496.     else
  497.     {
  498.         do_modelines(1L, nlines);
  499.     }
  500. #endif
  501.  
  502. #ifndef NO_SAFER
  503.     /* okay, you can do stupid things again */
  504.     *o_safer = i;
  505. #endif
  506.  
  507.     /* force all blocks out onto the disk, to support file recovery */
  508.     blksync();
  509.  
  510.     return 0;
  511. }
  512.  
  513.  
  514.  
  515. /* This function copies the temp file back onto an original file.
  516.  * Returns TRUE if successful, or FALSE if the file could NOT be saved.
  517.  */
  518. int tmpsave(filename, bang)
  519.     char    *filename;    /* the name to save it to */
  520.     int    bang;        /* forced write? */
  521. {
  522.     int        fd;    /* fd of the file we're writing to */
  523.     REG int        len;    /* length of a text block */
  524.     REG BLK        *this;    /* a text block */
  525.     long        bytes;    /* byte counter */
  526.     REG int        i;
  527.     struct stat     statb;  /* stat buffer, used to examine inode */
  528.  
  529.     /* if no filename is given, assume the original file name */
  530.     if (!filename || !*filename)
  531.     {
  532.         filename = origname;
  533.     }
  534.  
  535.     /* if still no file name, then fail */
  536.     if (!*filename)
  537.     {
  538.         msg("Don't know a name for this file -- NOT WRITTEN");
  539.         return FALSE;
  540.     }
  541.  
  542.     /* can't rewrite a READONLY file */
  543.     if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang)
  544.     {
  545.         msg("\"%s\" [READONLY] -- NOT WRITTEN", filename);
  546.         return FALSE;
  547.     }
  548.  
  549.     /* open the file */
  550.     if (*filename == '>' && filename[1] == '>')
  551.     {
  552.         filename += 2;
  553.         while (*filename == ' ' || *filename == '\t')
  554.         {
  555.             filename++;
  556.         }
  557. #ifdef O_APPEND
  558.         fd = open(filename, O_WRONLY|O_APPEND);
  559. #else
  560.         fd = open(filename, O_WRONLY);
  561.         lseek(fd, 0L, 2);
  562. #endif
  563.     }
  564.     else
  565.     {
  566.         /* either the file must not exist, or it must be the original
  567.          * file, or we must have a bang, or "writeany" must be set.
  568.          */
  569.         if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang
  570. #ifndef CRUNCH
  571.             && !*o_writeany
  572. #endif
  573.                    )
  574.         {
  575.             msg("File already exists - Use :w! to overwrite");
  576.             return FALSE;
  577.         }
  578. #if VMS
  579.         /* On VMS we want to propogate the file protection
  580.          * of the previous version of the file, if any.
  581.          * If the stat fails, protection defaults to user default
  582.          */
  583.         statb.st_mode = 0;
  584.         stat(filename, &statb);
  585.         /* Create a new VMS version of this file. */
  586.         { 
  587.         char *strrchr(), *ptr = strrchr(filename,';');
  588.         if (ptr) *ptr = '\0';  /* Snip off any ;number in the name */
  589.         }
  590.         fd = creat(filename,(statb.st_mode & 511));
  591. #else
  592.         fd = creat(filename, FILEPERMS);
  593. #endif
  594.     }
  595.     if (fd < 0)
  596.     {
  597.         msg("Can't write to \"%s\" -- NOT WRITTEN", filename);
  598.         return FALSE;
  599.     }
  600.  
  601.     /* write each text block to the file */
  602.     bytes = 0L;
  603.     for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++)
  604.     {
  605.         for (len = 0; len < BLKSIZE && this->c[len]; len++)
  606.         {
  607.         }
  608.         if (twrite(fd, this->c, len) < len)
  609.         {
  610.             msg("Trouble writing to \"%s\"", filename);
  611.             if (!strcmp(filename, origname))
  612.             {
  613.                 setflag(file, MODIFIED);
  614.             }
  615.             close(fd);
  616.             return FALSE;
  617.         }
  618.         bytes += len;
  619.     }
  620.  
  621.     /* reset the "modified" flag, but not the "undoable" flag */
  622.     clrflag(file, MODIFIED);
  623.     significant = FALSE;
  624.     if (!strcmp(origname, filename))
  625.     {
  626.         exitcode &= ~1;
  627.         clrflag(file, NOTEDITED);
  628.     }
  629.     else /* make # refer to the file we just wrote */
  630.     {
  631.         strcpy(prevorig, filename);
  632.     }
  633.  
  634.     /* report lines & characters */
  635. #if MSDOS || TOS || OS2
  636.     bytes += nlines; /* for the inserted carriage returns */
  637. #endif
  638.     msg("Wrote \"%s\"  %ld lines, %ld characters", filename, nlines, bytes);
  639.  
  640.     /* close the file */
  641. #if MSDOS
  642.     /* Novell requires a ^Z at the end of the text? */
  643.     if (*o_controlz)
  644.     {
  645.         twrite(fd, "\032", 1);
  646.     }
  647. #endif
  648.     close(fd);
  649. #if VMS
  650.         chmod(filename,(unsigned int)(statb.st_mode & 511));
  651. #endif
  652.     return TRUE;
  653. }
  654.  
  655.  
  656. /* This function deletes the temporary file.  If the file has been modified
  657.  * and "bang" is FALSE, then it returns FALSE without doing anything; else
  658.  * it returns TRUE.
  659.  *
  660.  * If the "autowrite" option is set, then instead of returning FALSE when
  661.  * the file has been modified and "bang" is false, it will call tmpend().
  662.  */
  663. int tmpabort(bang)
  664.     int    bang;
  665. {
  666.     /* if there is no file, return successfully */
  667.     if (tmpfd < 0)
  668.     {
  669.         return TRUE;
  670.     }
  671.  
  672.     /* see if we must return FALSE -- can't quit */
  673.     if (!bang && tstflag(file, MODIFIED))
  674.     {
  675.         /* if "autowrite" is set, then act like tmpend() */
  676.         if (*o_autowrite)
  677.             return tmpend(bang);
  678.         else
  679.             return FALSE;
  680.     }
  681.  
  682.     /* delete the tmp file */
  683.     cutswitch();
  684.     strcpy(prevorig, origname);
  685.     prevline = markline(cursor);
  686.     *origname = '\0';
  687.     origtime = 0L;
  688.     blkinit();
  689.     nlines = 0;
  690.     initflags();
  691.     return TRUE;
  692. }
  693.  
  694. /* This function saves the file if it has been modified, and then deletes
  695.  * the temporary file. Returns TRUE if successful, or FALSE if the file
  696.  * needs to be saved but can't be.  When it returns FALSE, it will not have
  697.  * deleted the tmp file, either.
  698.  */
  699. int tmpend(bang)
  700.     int    bang;
  701. {
  702.     /* save the file if it has been modified */
  703.     if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang)
  704.     {
  705.         return FALSE;
  706.     }
  707.  
  708.     /* delete the tmp file */
  709.     tmpabort(TRUE);
  710.  
  711.     return TRUE;
  712. }
  713.  
  714.  
  715. /* If the tmp file has been changed, then this function will force those
  716.  * changes to be written to the disk, so that the tmp file will survive a
  717.  * system crash or power failure.
  718.  */
  719. #if AMIGA || MSDOS || TOS || OS2
  720. sync()
  721. {
  722.     /* MS-DOS and TOS don't flush their buffers until the file is closed,
  723.      * so here we close the tmp file and then immediately reopen it.
  724.      */
  725.     close(tmpfd);
  726.     tmpfd = open(tmpname, O_RDWR | O_BINARY);
  727.     return 0;
  728. }
  729. #endif
  730.  
  731.  
  732. /* This function stores the file's name in the second block of the temp file.
  733.  * SLEAZE ALERT!  SLEAZE ALERT!  The "tmpblk" buffer is probably being used
  734.  * to store the arguments to a command, so we can't use it here.  Instead,
  735.  * we'll borrow the buffer that is used for "shift-U".
  736.  */
  737. int
  738. storename(name)
  739.     char    *name;    /* the name of the file - normally origname */
  740. {
  741. #ifndef CRUNCH
  742.     int    len;
  743.     char    *ptr;
  744. #endif
  745.  
  746.     /* we're going to clobber the U_text buffer, so reset U_line */
  747.     U_line = 0L;
  748.  
  749.     if (!name)
  750.     {
  751.         strncpy(U_text, "", BLKSIZE);
  752.         U_text[1] = 127;
  753.     }
  754. #ifndef CRUNCH
  755. # if TOS || MINT || MSDOS || AMIGA || OS2
  756.     else if (*name != '/' && *name != '\\' && !(*name && name[1] == ':'))
  757. # else
  758.     else if (*name != SLASH)
  759. # endif
  760.     {
  761.         /* get the directory name */
  762.         ptr = getcwd(U_text, BLKSIZE);
  763.         if (ptr != U_text)
  764.         {
  765.             strcpy(U_text, ptr);
  766.         }
  767.  
  768.         /* append a slash to the directory name */
  769.         len = strlen(U_text);
  770.         U_text[len++] = SLASH;
  771.  
  772.         /* append the filename, padded with heaps o' NULs */
  773.         strncpy(U_text + len, *name ? name : "foo", BLKSIZE - len);
  774.     }
  775. #endif
  776.     else
  777.     {
  778.         /* copy the filename into U_text */
  779.         strncpy(U_text, *name ? name : "foo", BLKSIZE);
  780.     }
  781.  
  782.     if (tmpfd >= 0)
  783.     {
  784.         /* write the name out to second block of the temp file */
  785.         lseek(tmpfd, (long)BLKSIZE, 0);
  786.         if (write(tmpfd, U_text, (unsigned)BLKSIZE) < BLKSIZE)
  787.         {
  788.             FAIL("Error stuffing name \"%s\" into temp file", U_text);
  789.         }
  790.     }
  791.     return 0;
  792. }
  793.  
  794.  
  795.  
  796. /* This function handles deadly signals.  It restores sanity to the terminal
  797.  * preserves the current temp file, and deletes any old temp files.
  798.  */
  799. SIGTYPE deathtrap(sig)
  800.     int    sig;    /* the deadly signal that we caught */
  801. {
  802.     char    *why;
  803.  
  804.     /* restore the terminal's sanity */
  805.     endwin();
  806.  
  807. #ifdef CRUNCH
  808.     why = "-Elvis died";
  809. #else
  810.     /* give a more specific description of how Elvis died */
  811.     switch (sig)
  812.     {
  813. # ifdef SIGHUP
  814.       case SIGHUP:    why = "-the modem lost its carrier";        break;
  815. # endif
  816. # ifndef DEBUG
  817. #  ifdef SIGILL
  818.       case SIGILL:    why = "-Elvis hit an illegal instruction";    break;
  819. #  endif
  820. #  ifdef SIGBUS
  821.       case SIGBUS:    why = "-Elvis had a bus error";            break;
  822. #  endif
  823. #  ifdef SIGSEGV
  824. #   if !TOS
  825.       case SIGSEGV:    why = "-Elvis had a segmentation violation";    break;
  826. #   endif
  827. #  endif
  828. #  ifdef SIGSYS
  829.       case SIGSYS:    why = "-Elvis munged a system call";        break;
  830. #  endif
  831. # endif /* !DEBUG */
  832. # ifdef SIGPIPE
  833.       case SIGPIPE:    why = "-the pipe reader died";            break;
  834. # endif
  835. # ifdef SIGTERM
  836.       case SIGTERM:    why = "-Elvis was terminated";            break;
  837. # endif
  838. # if !MINIX
  839. #  ifdef SIGUSR1
  840.       case SIGUSR1:    why = "-Elvis was killed via SIGUSR1";        break;
  841. #  endif
  842. #  ifdef SIGUSR2
  843.       case SIGUSR2:    why = "-Elvis was killed via SIGUSR2";        break;
  844. #  endif
  845. # endif
  846.       default:    why = "-Elvis died";                break;
  847.     }
  848. #endif
  849.  
  850.     /* if we had a temp file going, then preserve it */
  851.     if (tmpnum > 0 && tmpfd >= 0)
  852.     {
  853.         close(tmpfd);
  854.         tmpfd = -1;
  855.         sprintf(tmpblk.c, "%s \"%s\" %s", PRESERVE, why, tmpname);
  856.         system(tmpblk.c);
  857.     }
  858.  
  859.     /* delete any old temp files */
  860.     cutend();
  861.  
  862.     /* exit with the proper exit status */
  863.     exit(sig);
  864. }
  865.