1993-03-21 12:45:37 +03:00
|
|
|
/* tmp.c */
|
|
|
|
|
|
|
|
/* Author:
|
|
|
|
* Steve Kirkendall
|
|
|
|
* 14407 SW Teal Blvd. #C
|
|
|
|
* Beaverton, OR 97005
|
|
|
|
* kirkenda@cs.pdx.edu
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* This file contains functions which create & readback a TMPFILE */
|
|
|
|
|
1993-08-02 21:48:44 +04:00
|
|
|
#ifndef lint
|
|
|
|
static char rcsid[] = "$Id: tmp.c,v 1.4 1993/08/02 17:54:11 mycroft Exp $";
|
|
|
|
#endif /* not lint */
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "vi.h"
|
|
|
|
#if TOS
|
|
|
|
# include <stat.h>
|
|
|
|
#else
|
|
|
|
# if OSK
|
|
|
|
# include "osk.h"
|
|
|
|
# else
|
|
|
|
# if AMIGA
|
|
|
|
# include "amistat.h"
|
|
|
|
# else
|
|
|
|
# include <sys/stat.h>
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
#if TURBOC
|
|
|
|
# include <process.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef NO_MODELINES
|
|
|
|
static void do_modelines(l, stop)
|
|
|
|
long l; /* line number to start at */
|
|
|
|
long stop; /* line number to stop at */
|
|
|
|
{
|
|
|
|
char *str; /* used to scan through the line */
|
|
|
|
char *start; /* points to the start of the line */
|
|
|
|
char buf[80];
|
|
|
|
|
|
|
|
/* if modelines are disabled, then do nothing */
|
|
|
|
if (!*o_modelines)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for each line... */
|
|
|
|
for (; l <= stop; l++)
|
|
|
|
{
|
|
|
|
/* for each position in the line.. */
|
|
|
|
for (str = fetchline(l); *str; str++)
|
|
|
|
{
|
|
|
|
/* if it is the start of a modeline command... */
|
|
|
|
if ((str[0] == 'e' && str[1] == 'x'
|
|
|
|
|| str[0] == 'v' && str[1] == 'i')
|
|
|
|
&& str[2] == ':')
|
|
|
|
{
|
|
|
|
start = str += 3;
|
|
|
|
|
|
|
|
/* find the end */
|
|
|
|
for (str = start + strlen(start); *--str != ':'; )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if it is a well-formed modeline, execute it */
|
|
|
|
if (str > start && str - start < sizeof buf)
|
|
|
|
{
|
|
|
|
strncpy(buf, start, (int)(str - start));
|
|
|
|
exstring(buf, str - start, '\\');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* The FAIL() macro prints an error message and then exits. */
|
|
|
|
#define FAIL(why,arg) mode = MODE_EX; msg(why, arg); endwin(); exit(9)
|
|
|
|
|
|
|
|
/* This is the name of the temp file */
|
|
|
|
static char tmpname[80];
|
|
|
|
|
|
|
|
/* This function creates the temp file and copies the original file into it.
|
|
|
|
* Returns if successful, or stops execution if it fails.
|
|
|
|
*/
|
|
|
|
int tmpstart(filename)
|
|
|
|
char *filename; /* name of the original file */
|
|
|
|
{
|
|
|
|
int origfd; /* fd used for reading the original file */
|
|
|
|
struct stat statb; /* stat buffer, used to examine inode */
|
|
|
|
REG BLK *this; /* pointer to the current block buffer */
|
|
|
|
REG BLK *next; /* pointer to the next block buffer */
|
|
|
|
int inbuf; /* number of characters in a buffer */
|
|
|
|
int nread; /* number of bytes read */
|
|
|
|
REG int j, k;
|
|
|
|
int i;
|
|
|
|
long nbytes;
|
|
|
|
|
|
|
|
/* switching to a different file certainly counts as a change */
|
|
|
|
changes++;
|
|
|
|
redraw(MARK_UNSET, FALSE);
|
|
|
|
|
|
|
|
/* open the original file for reading */
|
|
|
|
*origname = '\0';
|
|
|
|
if (filename && *filename)
|
|
|
|
{
|
|
|
|
strcpy(origname, filename);
|
|
|
|
origfd = open(origname, O_RDONLY);
|
|
|
|
if (origfd < 0 && errno != ENOENT)
|
|
|
|
{
|
|
|
|
msg("Can't open \"%s\"", origname);
|
|
|
|
return tmpstart("");
|
|
|
|
}
|
|
|
|
if (origfd >= 0)
|
|
|
|
{
|
|
|
|
if (stat(origname, &statb) < 0)
|
|
|
|
{
|
|
|
|
FAIL("Can't stat \"%s\"", origname);
|
|
|
|
}
|
|
|
|
#if TOS
|
|
|
|
if (origfd >= 0 && (statb.st_mode & S_IJDIR))
|
|
|
|
#else
|
|
|
|
# if OSK
|
|
|
|
if (origfd >= 0 && (statb.st_mode & S_IFDIR))
|
|
|
|
# else
|
|
|
|
if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG)
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
msg("\"%s\" is not a regular file", origname);
|
|
|
|
return tmpstart("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stat(".", &statb);
|
|
|
|
}
|
|
|
|
if (origfd >= 0)
|
|
|
|
{
|
|
|
|
origtime = statb.st_mtime;
|
|
|
|
#if OSK
|
|
|
|
if (*o_readonly || !(statb.st_mode &
|
|
|
|
((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE :
|
|
|
|
((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE)))))
|
|
|
|
#endif
|
1993-04-08 06:22:57 +04:00
|
|
|
#if AMIGA || MSDOS
|
1993-03-21 12:45:37 +03:00
|
|
|
if (*o_readonly || !(statb.st_mode & S_IWRITE))
|
|
|
|
#endif
|
1993-04-08 06:22:57 +04:00
|
|
|
#if TOS
|
|
|
|
# ifdef __GNUC__
|
|
|
|
if (*o_readonly || !(statb.st_mode & S_IWRITE))
|
|
|
|
# else
|
1993-03-21 12:45:37 +03:00
|
|
|
if (*o_readonly || (statb.st_mode & S_IJRON))
|
1993-04-08 06:22:57 +04:00
|
|
|
# endif
|
1993-03-21 12:45:37 +03:00
|
|
|
#endif
|
|
|
|
#if ANY_UNIX
|
|
|
|
if (*o_readonly || !(statb.st_mode &
|
|
|
|
((geteuid() == 0) ? 0222 :
|
|
|
|
((statb.st_uid != geteuid() ? 0022 : 0200)))))
|
|
|
|
#endif
|
|
|
|
#if VMS
|
|
|
|
if (*o_readonly)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
setflag(file, READONLY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
origtime = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setflag(file, NOFILE);
|
|
|
|
origfd = -1;
|
|
|
|
origtime = 0L;
|
|
|
|
stat(".", &statb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make a name for the tmp file */
|
1993-04-08 06:22:57 +04:00
|
|
|
do
|
|
|
|
{
|
|
|
|
tmpnum++;
|
1993-03-21 12:45:37 +03:00
|
|
|
#if MSDOS || TOS
|
1993-04-08 06:22:57 +04:00
|
|
|
/* MS-Dos doesn't allow multiple slashes, but supports drives
|
|
|
|
* with current directories.
|
|
|
|
* This relies on TMPNAME beginning with "%s\\"!!!!
|
|
|
|
*/
|
|
|
|
strcpy(tmpname, o_directory);
|
|
|
|
if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
|
|
|
|
tmpname[i++]=SLASH;
|
|
|
|
sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum);
|
1993-03-21 12:45:37 +03:00
|
|
|
#else
|
1993-04-08 06:22:57 +04:00
|
|
|
sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
|
1993-03-21 12:45:37 +03:00
|
|
|
#endif
|
1993-04-08 06:22:57 +04:00
|
|
|
} while (access(tmpname, 0) == 0);
|
|
|
|
|
|
|
|
/* !!! RACE CONDITION HERE - some other process with the same PID could
|
|
|
|
* create the temp file between the access() call and the creat() call.
|
|
|
|
* This could happen in a couple of ways:
|
|
|
|
* - different workstation may share the same temp dir via NFS. Each
|
|
|
|
* workstation could have a process with the same number.
|
|
|
|
* - The DOS version may be running multiple times on the same physical
|
|
|
|
* machine in different virtual machines. The DOS pid number will
|
|
|
|
* be the same on all virtual machines.
|
|
|
|
*
|
|
|
|
* This race condition could be fixed by replacing access(tmpname, 0)
|
|
|
|
* with open(tmpname, O_CREAT|O_EXCL, 0600), if we could only be sure
|
|
|
|
* that open() *always* used modern UNIX semantics.
|
|
|
|
*/
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/* create the temp file */
|
|
|
|
#if ANY_UNIX
|
|
|
|
close(creat(tmpname, 0600)); /* only we can read it */
|
|
|
|
#else
|
|
|
|
close(creat(tmpname, FILEPERMS)); /* anybody body can read it, alas */
|
|
|
|
#endif
|
|
|
|
tmpfd = open(tmpname, O_RDWR | O_BINARY);
|
|
|
|
if (tmpfd < 0)
|
|
|
|
{
|
|
|
|
FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate space for the header in the file */
|
1993-04-08 06:22:57 +04:00
|
|
|
if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) < BLKSIZE
|
|
|
|
|| write(tmpfd, tmpblk.c, (unsigned)BLKSIZE) < BLKSIZE)
|
|
|
|
{
|
|
|
|
FAIL("Error writing headers to \"%s\"", tmpname);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#ifndef NO_RECYCLE
|
|
|
|
/* initialize the block allocator */
|
|
|
|
/* This must already be done here, before the first attempt
|
|
|
|
* to write to the new file! GB */
|
|
|
|
garbage();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* initialize lnum[] */
|
|
|
|
for (i = 1; i < MAXBLKS; i++)
|
|
|
|
{
|
|
|
|
lnum[i] = INFINITY;
|
|
|
|
}
|
|
|
|
lnum[0] = 0;
|
|
|
|
|
|
|
|
/* if there is no original file, then create a 1-line file */
|
|
|
|
if (origfd < 0)
|
|
|
|
{
|
|
|
|
hdr.n[0] = 0; /* invalid inode# denotes new file */
|
|
|
|
|
|
|
|
this = blkget(1); /* get the new text block */
|
|
|
|
strcpy(this->c, "\n"); /* put a line in it */
|
|
|
|
|
|
|
|
lnum[1] = 1L; /* block 1 ends with line 1 */
|
|
|
|
nlines = 1L; /* there is 1 line in the file */
|
|
|
|
nbytes = 1L;
|
|
|
|
|
|
|
|
if (*origname)
|
|
|
|
{
|
|
|
|
msg("\"%s\" [NEW FILE] 1 line, 1 char", origname);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg("\"[NO FILE]\" 1 line, 1 char");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* there is an original file -- read it in */
|
|
|
|
{
|
|
|
|
nbytes = nlines = 0;
|
|
|
|
|
|
|
|
/* preallocate 1 "next" buffer */
|
|
|
|
i = 1;
|
|
|
|
next = blkget(i);
|
|
|
|
inbuf = 0;
|
|
|
|
|
|
|
|
/* loop, moving blocks from orig to tmp */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/* "next" buffer becomes "this" buffer */
|
|
|
|
this = next;
|
|
|
|
|
|
|
|
/* read [more] text into this block */
|
|
|
|
nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
|
|
|
|
if (nread < 0)
|
|
|
|
{
|
|
|
|
close(origfd);
|
|
|
|
close(tmpfd);
|
|
|
|
tmpfd = -1;
|
|
|
|
unlink(tmpname);
|
|
|
|
FAIL("Error reading \"%s\"", origname);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert NUL characters to something else */
|
|
|
|
for (j = k = inbuf; k < inbuf + nread; k++)
|
|
|
|
{
|
|
|
|
if (!this->c[k])
|
|
|
|
{
|
|
|
|
setflag(file, HADNUL);
|
|
|
|
this->c[j++] = 0x80;
|
|
|
|
}
|
|
|
|
#ifndef CRUNCH
|
1993-04-08 06:22:57 +04:00
|
|
|
else if (*o_beautify && this->c[k] < ' ' && this->c[k] >= 1)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
if (this->c[k] == '\t'
|
|
|
|
|| this->c[k] == '\n'
|
|
|
|
|| this->c[k] == '\f')
|
|
|
|
{
|
|
|
|
this->c[j++] = this->c[k];
|
|
|
|
}
|
|
|
|
else if (this->c[k] == '\b')
|
|
|
|
{
|
|
|
|
/* delete '\b', but complain */
|
|
|
|
setflag(file, HADBS);
|
|
|
|
}
|
|
|
|
/* else silently delete control char */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->c[j++] = this->c[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inbuf = j;
|
|
|
|
|
|
|
|
/* if the buffer is empty, quit */
|
|
|
|
if (inbuf == 0)
|
|
|
|
{
|
|
|
|
goto FoundEOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if MSDOS || TOS
|
|
|
|
/* BAH! MS text mode read fills inbuf, then compresses eliminating \r
|
|
|
|
but leaving garbage at end of buf. The same is true for TURBOC. GB. */
|
|
|
|
|
|
|
|
memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* search backward for last newline */
|
|
|
|
for (k = inbuf; --k >= 0 && this->c[k] != '\n';)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
if (k++ < 0)
|
|
|
|
{
|
|
|
|
if (inbuf >= BLKSIZE - 1)
|
|
|
|
{
|
|
|
|
k = 80;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
k = inbuf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate next buffer */
|
1993-04-08 06:22:57 +04:00
|
|
|
if (i >= MAXBLKS - 2)
|
|
|
|
{
|
|
|
|
FAIL("File too big. Limit is approx %ld kbytes.", MAXBLKS * BLKSIZE / 1024L);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
next = blkget(++i);
|
|
|
|
|
|
|
|
/* move fragmentary last line to next buffer */
|
|
|
|
inbuf -= k;
|
|
|
|
for (j = 0; k < BLKSIZE; j++, k++)
|
|
|
|
{
|
|
|
|
next->c[j] = this->c[k];
|
|
|
|
this->c[k] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if necessary, add a newline to this buf */
|
|
|
|
for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
if (this->c[k] != '\n')
|
|
|
|
{
|
|
|
|
setflag(file, ADDEDNL);
|
|
|
|
this->c[k + 1] = '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* count the lines in this block */
|
|
|
|
for (k = 0; k < BLKSIZE && this->c[k]; k++)
|
|
|
|
{
|
|
|
|
if (this->c[k] == '\n')
|
|
|
|
{
|
|
|
|
nlines++;
|
|
|
|
}
|
|
|
|
nbytes++;
|
|
|
|
}
|
|
|
|
lnum[i - 1] = nlines;
|
|
|
|
}
|
|
|
|
FoundEOF:
|
|
|
|
|
|
|
|
/* if this is a zero-length file, add 1 line */
|
|
|
|
if (nlines == 0)
|
|
|
|
{
|
|
|
|
this = blkget(1); /* get the new text block */
|
|
|
|
strcpy(this->c, "\n"); /* put a line in it */
|
|
|
|
|
|
|
|
lnum[1] = 1; /* block 1 ends with line 1 */
|
|
|
|
nlines = 1; /* there is 1 line in the file */
|
|
|
|
nbytes = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if MSDOS || TOS
|
|
|
|
/* each line has an extra CR that we didn't count yet */
|
|
|
|
nbytes += nlines;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* report the number of lines in the file */
|
|
|
|
msg("\"%s\" %s %ld line%s, %ld char%s",
|
|
|
|
origname,
|
|
|
|
(tstflag(file, READONLY) ? "[READONLY]" : ""),
|
|
|
|
nlines,
|
|
|
|
nlines == 1 ? "" : "s",
|
|
|
|
nbytes,
|
|
|
|
nbytes == 1 ? "" : "s");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize the cursor to start of line 1 */
|
|
|
|
cursor = MARK_FIRST;
|
|
|
|
|
|
|
|
/* close the original file */
|
|
|
|
close(origfd);
|
|
|
|
|
|
|
|
/* any other messages? */
|
|
|
|
if (tstflag(file, HADNUL))
|
|
|
|
{
|
|
|
|
msg("This file contained NULs. They've been changed to \\x80 chars");
|
|
|
|
}
|
|
|
|
if (tstflag(file, ADDEDNL))
|
|
|
|
{
|
|
|
|
msg("Newline characters have been inserted to break up long lines");
|
|
|
|
}
|
|
|
|
#ifndef CRUNCH
|
|
|
|
if (tstflag(file, HADBS))
|
|
|
|
{
|
|
|
|
msg("Backspace characters deleted due to ':set beautify'");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
storename(origname);
|
|
|
|
|
|
|
|
#ifndef NO_MODELINES
|
|
|
|
if (nlines > 10)
|
|
|
|
{
|
|
|
|
do_modelines(1L, 5L);
|
|
|
|
do_modelines(nlines - 4L, nlines);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_modelines(1L, nlines);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* force all blocks out onto the disk, to support file recovery */
|
|
|
|
blksync();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function copies the temp file back onto an original file.
|
|
|
|
* Returns TRUE if successful, or FALSE if the file could NOT be saved.
|
|
|
|
*/
|
|
|
|
int tmpsave(filename, bang)
|
|
|
|
char *filename; /* the name to save it to */
|
|
|
|
int bang; /* forced write? */
|
|
|
|
{
|
|
|
|
int fd; /* fd of the file we're writing to */
|
|
|
|
REG int len; /* length of a text block */
|
|
|
|
REG BLK *this; /* a text block */
|
|
|
|
long bytes; /* byte counter */
|
|
|
|
REG int i;
|
|
|
|
|
|
|
|
/* if no filename is given, assume the original file name */
|
|
|
|
if (!filename || !*filename)
|
|
|
|
{
|
|
|
|
filename = origname;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if still no file name, then fail */
|
|
|
|
if (!*filename)
|
|
|
|
{
|
|
|
|
msg("Don't know a name for this file -- NOT WRITTEN");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* can't rewrite a READONLY file */
|
|
|
|
if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang)
|
|
|
|
{
|
|
|
|
msg("\"%s\" [READONLY] -- NOT WRITTEN", filename);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* open the file */
|
|
|
|
if (*filename == '>' && filename[1] == '>')
|
|
|
|
{
|
|
|
|
filename += 2;
|
|
|
|
while (*filename == ' ' || *filename == '\t')
|
|
|
|
{
|
|
|
|
filename++;
|
|
|
|
}
|
|
|
|
#ifdef O_APPEND
|
|
|
|
fd = open(filename, O_WRONLY|O_APPEND);
|
|
|
|
#else
|
|
|
|
fd = open(filename, O_WRONLY);
|
|
|
|
lseek(fd, 0L, 2);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* either the file must not exist, or it must be the original
|
|
|
|
* file, or we must have a bang, or "writeany" must be set.
|
|
|
|
*/
|
|
|
|
if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang
|
|
|
|
#ifndef CRUNCH
|
|
|
|
&& !*o_writeany
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
msg("File already exists - Use :w! to overwrite");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#if VMS
|
|
|
|
/* Create a new VMS version of this file. */
|
|
|
|
{
|
|
|
|
char *strrchr(), *ptr = strrchr(filename,';');
|
|
|
|
if (ptr) *ptr = '\0'; /* Snip off any ;number in the name */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
fd = creat(filename, FILEPERMS);
|
|
|
|
}
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
msg("Can't write to \"%s\" -- NOT WRITTEN", filename);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write each text block to the file */
|
|
|
|
bytes = 0L;
|
|
|
|
for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++)
|
|
|
|
{
|
|
|
|
for (len = 0; len < BLKSIZE && this->c[len]; len++)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
if (twrite(fd, this->c, len) < len)
|
|
|
|
{
|
|
|
|
msg("Trouble writing to \"%s\"", filename);
|
|
|
|
if (!strcmp(filename, origname))
|
|
|
|
{
|
|
|
|
setflag(file, MODIFIED);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
bytes += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset the "modified" flag, but not the "undoable" flag */
|
|
|
|
clrflag(file, MODIFIED);
|
|
|
|
significant = FALSE;
|
1993-04-08 06:22:57 +04:00
|
|
|
if (!strcmp(origname, filename))
|
|
|
|
{
|
|
|
|
exitcode &= ~1;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/* report lines & characters */
|
|
|
|
#if MSDOS || TOS
|
|
|
|
bytes += nlines; /* for the inserted carriage returns */
|
|
|
|
#endif
|
|
|
|
msg("Wrote \"%s\" %ld lines, %ld characters", filename, nlines, bytes);
|
|
|
|
|
|
|
|
/* close the file */
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function deletes the temporary file. If the file has been modified
|
|
|
|
* and "bang" is FALSE, then it returns FALSE without doing anything; else
|
|
|
|
* it returns TRUE.
|
|
|
|
*
|
|
|
|
* If the "autowrite" option is set, then instead of returning FALSE when
|
|
|
|
* the file has been modified and "bang" is false, it will call tmpend().
|
|
|
|
*/
|
|
|
|
int tmpabort(bang)
|
|
|
|
int bang;
|
|
|
|
{
|
|
|
|
/* if there is no file, return successfully */
|
|
|
|
if (tmpfd < 0)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* see if we must return FALSE -- can't quit */
|
|
|
|
if (!bang && tstflag(file, MODIFIED))
|
|
|
|
{
|
|
|
|
/* if "autowrite" is set, then act like tmpend() */
|
|
|
|
if (*o_autowrite)
|
|
|
|
return tmpend(bang);
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete the tmp file */
|
|
|
|
cutswitch();
|
|
|
|
strcpy(prevorig, origname);
|
|
|
|
prevline = markline(cursor);
|
|
|
|
*origname = '\0';
|
|
|
|
origtime = 0L;
|
|
|
|
blkinit();
|
|
|
|
nlines = 0;
|
|
|
|
initflags();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function saves the file if it has been modified, and then deletes
|
|
|
|
* the temporary file. Returns TRUE if successful, or FALSE if the file
|
|
|
|
* needs to be saved but can't be. When it returns FALSE, it will not have
|
|
|
|
* deleted the tmp file, either.
|
|
|
|
*/
|
|
|
|
int tmpend(bang)
|
|
|
|
int bang;
|
|
|
|
{
|
|
|
|
/* save the file if it has been modified */
|
|
|
|
if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete the tmp file */
|
|
|
|
tmpabort(TRUE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* If the tmp file has been changed, then this function will force those
|
|
|
|
* changes to be written to the disk, so that the tmp file will survive a
|
|
|
|
* system crash or power failure.
|
|
|
|
*/
|
|
|
|
#if AMIGA || MSDOS || TOS
|
|
|
|
sync()
|
|
|
|
{
|
|
|
|
/* MS-DOS and TOS don't flush their buffers until the file is closed,
|
|
|
|
* so here we close the tmp file and then immediately reopen it.
|
|
|
|
*/
|
|
|
|
close(tmpfd);
|
|
|
|
tmpfd = open(tmpname, O_RDWR | O_BINARY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* This function stores the file's name in the second block of the temp file.
|
|
|
|
* SLEAZE ALERT! SLEAZE ALERT! The "tmpblk" buffer is probably being used
|
|
|
|
* to store the arguments to a command, so we can't use it here. Instead,
|
|
|
|
* we'll borrow the buffer that is used for "shift-U".
|
|
|
|
*/
|
1993-04-08 06:22:57 +04:00
|
|
|
int
|
1993-03-21 12:45:37 +03:00
|
|
|
storename(name)
|
|
|
|
char *name; /* the name of the file - normally origname */
|
|
|
|
{
|
|
|
|
#ifndef CRUNCH
|
|
|
|
int len;
|
|
|
|
char *ptr;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* we're going to clobber the U_text buffer, so reset U_line */
|
|
|
|
U_line = 0L;
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
{
|
|
|
|
strncpy(U_text, "", BLKSIZE);
|
|
|
|
U_text[1] = 127;
|
|
|
|
}
|
|
|
|
#ifndef CRUNCH
|
1993-04-08 06:22:57 +04:00
|
|
|
# if TOS || MINT || MSDOS || AMIGA
|
|
|
|
else if (*name != '/' && *name != '\\' && !(*name && name[1] == ':'))
|
|
|
|
# else
|
1993-03-21 12:45:37 +03:00
|
|
|
else if (*name != SLASH)
|
1993-04-08 06:22:57 +04:00
|
|
|
# endif
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
/* get the directory name */
|
|
|
|
ptr = getcwd(U_text, BLKSIZE);
|
|
|
|
if (ptr != U_text)
|
|
|
|
{
|
|
|
|
strcpy(U_text, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* append a slash to the directory name */
|
|
|
|
len = strlen(U_text);
|
|
|
|
U_text[len++] = SLASH;
|
|
|
|
|
|
|
|
/* append the filename, padded with heaps o' NULs */
|
|
|
|
strncpy(U_text + len, *name ? name : "foo", BLKSIZE - len);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* copy the filename into U_text */
|
|
|
|
strncpy(U_text, *name ? name : "foo", BLKSIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmpfd >= 0)
|
|
|
|
{
|
|
|
|
/* write the name out to second block of the temp file */
|
|
|
|
lseek(tmpfd, (long)BLKSIZE, 0);
|
1993-04-08 06:22:57 +04:00
|
|
|
if (write(tmpfd, U_text, (unsigned)BLKSIZE) < BLKSIZE)
|
|
|
|
{
|
|
|
|
FAIL("Error stuffing name \"%s\" into temp file", U_text);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function handles deadly signals. It restores sanity to the terminal
|
|
|
|
* preserves the current temp file, and deletes any old temp files.
|
|
|
|
*/
|
1993-04-08 06:22:57 +04:00
|
|
|
SIGTYPE deathtrap(sig)
|
1993-03-21 12:45:37 +03:00
|
|
|
int sig; /* the deadly signal that we caught */
|
|
|
|
{
|
|
|
|
char *why;
|
|
|
|
|
|
|
|
/* restore the terminal's sanity */
|
|
|
|
endwin();
|
|
|
|
|
|
|
|
#ifdef CRUNCH
|
|
|
|
why = "-Elvis died";
|
|
|
|
#else
|
|
|
|
/* give a more specific description of how Elvis died */
|
|
|
|
switch (sig)
|
|
|
|
{
|
|
|
|
# ifdef SIGHUP
|
|
|
|
case SIGHUP: why = "-the modem lost its carrier"; break;
|
|
|
|
# endif
|
|
|
|
# ifndef DEBUG
|
|
|
|
# ifdef SIGILL
|
|
|
|
case SIGILL: why = "-Elvis hit an illegal instruction"; break;
|
|
|
|
# endif
|
|
|
|
# ifdef SIGBUS
|
|
|
|
case SIGBUS: why = "-Elvis had a bus error"; break;
|
|
|
|
# endif
|
1993-04-08 06:22:57 +04:00
|
|
|
# ifdef SIGSEGV
|
|
|
|
# if !TOS
|
1993-03-21 12:45:37 +03:00
|
|
|
case SIGSEGV: why = "-Elvis had a segmentation violation"; break;
|
1993-04-08 06:22:57 +04:00
|
|
|
# endif
|
1993-03-21 12:45:37 +03:00
|
|
|
# endif
|
|
|
|
# ifdef SIGSYS
|
|
|
|
case SIGSYS: why = "-Elvis munged a system call"; break;
|
|
|
|
# endif
|
|
|
|
# endif /* !DEBUG */
|
|
|
|
# ifdef SIGPIPE
|
|
|
|
case SIGPIPE: why = "-the pipe reader died"; break;
|
|
|
|
# endif
|
|
|
|
# ifdef SIGTERM
|
|
|
|
case SIGTERM: why = "-Elvis was terminated"; break;
|
|
|
|
# endif
|
|
|
|
# if !MINIX
|
|
|
|
# ifdef SIGUSR1
|
|
|
|
case SIGUSR1: why = "-Elvis was killed via SIGUSR1"; break;
|
|
|
|
# endif
|
|
|
|
# ifdef SIGUSR2
|
|
|
|
case SIGUSR2: why = "-Elvis was killed via SIGUSR2"; break;
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
default: why = "-Elvis died"; break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* if we had a temp file going, then preserve it */
|
|
|
|
if (tmpnum > 0 && tmpfd >= 0)
|
|
|
|
{
|
|
|
|
close(tmpfd);
|
|
|
|
sprintf(tmpblk.c, "%s \"%s\" %s", PRESERVE, why, tmpname);
|
|
|
|
system(tmpblk.c);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete any old temp files */
|
|
|
|
cutend();
|
|
|
|
|
|
|
|
/* exit with the proper exit status */
|
|
|
|
exit(sig);
|
|
|
|
}
|