763 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			763 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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 */
 | |
| 
 | |
| 
 | |
| #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
 | |
| #if AMIGA || MSDOS || (TOS && defined(__GNUC__))
 | |
| 			if (*o_readonly || !(statb.st_mode & S_IWRITE))
 | |
| #endif
 | |
| #if TOS && !defined(__GNUC__)
 | |
| 			if (*o_readonly || (statb.st_mode & S_IJRON))
 | |
| #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 */
 | |
| 	tmpnum++;
 | |
| #if MSDOS || TOS
 | |
| 	/* 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);
 | |
| #else
 | |
| 	sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
 | |
| #endif
 | |
| 
 | |
| 	/* make sure nobody else is editing the same file */
 | |
| 	if (access(tmpname, 0) == 0)
 | |
| 	{
 | |
| 		FAIL("Temp file \"%s\" already exists?", tmpname);
 | |
| 	}
 | |
| 
 | |
| 	/* 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 */
 | |
| 	write(tmpfd, hdr.c, (unsigned)BLKSIZE);
 | |
| 	write(tmpfd, tmpblk.c, (unsigned)BLKSIZE);
 | |
| 
 | |
| #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
 | |
| 				else if (*o_beautify && this->c[k] < ' ' && this->c[k] > 0)
 | |
| 				{
 | |
| 					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 */
 | |
| 			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++;
 | |
| 			}
 | |
| 			if(i >= MAXBLKS) {
 | |
| 				FAIL("Too many blocks: %d.", i);
 | |
| 			}
 | |
| 			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 AMIGA
 | |
| 	if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang)
 | |
| #else
 | |
| 	if (!strcmp(filename, origname) && *o_readonly && !bang)
 | |
| #endif
 | |
| 	{
 | |
| 		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;
 | |
| 
 | |
| 	/* 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".
 | |
|  */
 | |
| 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
 | |
| 	else if (*name != SLASH)
 | |
| 	{
 | |
| 		/* 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);
 | |
| 		write(tmpfd, U_text, (unsigned)BLKSIZE);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /* This function handles deadly signals.  It restores sanity to the terminal
 | |
|  * preserves the current temp file, and deletes any old temp files.
 | |
|  */
 | |
| int deathtrap(sig)
 | |
| 	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
 | |
| #  if defined(SIGSEGV) && !defined(TOS)
 | |
| 	  case SIGSEGV:	why = "-Elvis had a segmentation violation";	break;
 | |
| #  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);
 | |
| }
 | 
