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 >
Wrap
C/C++ Source or Header
|
1998-09-28
|
48KB
|
2,085 lines
/* FILE.C: for MicroEMACS
*
* The routines in this file handle the reading, writing
* and lookup of disk files. All of details about the
* reading and writing of the disk are in "fileio.c".
*
*
* $Header: /usr/build/vile/vile/RCS/file.c,v 1.234 1998/09/29 02:22:01 tom Exp $
*
*/
#include "estruct.h"
#include "edef.h"
#if SYS_WINNT
#include <io.h> /* for mktemp */
#endif
static int bp2swbuffer(BUFFER *bp, int ask_rerun, int lockfl);
static int kifile(char *fname);
static int writereg(REGION *rp, const char *fn, int msgf, BUFFER *bp, int forced);
static void readlinesmsg(int n, int s, const char *f, int rdo);
#if OPT_DOSFILES
/* give DOS the benefit of the doubt on ambiguous files */
# if CRLF_LINES
# define MORETHAN >=
# else
# define MORETHAN >
# endif
#endif
#if !(SYS_MSDOS || SYS_WIN31)
static int quickreadf(BUFFER *bp, int *nlinep);
#endif
/*--------------------------------------------------------------------------*/
/* Returns the modification time iff the path corresponds to an existing file,
* otherwise it returns zero.
*/
#if defined(MDCHK_MODTIME) || SYS_VMS || SYS_UNIX
time_t
file_modified(char *path)
{
struct stat statbuf;
time_t the_time = 0;
if (stat(SL_TO_BSL(path), &statbuf) >= 0
#if CC_CSETPP
&& (statbuf.st_mode & S_IFREG) == S_IFREG)
#else
&& (statbuf.st_mode & S_IFMT) == S_IFREG)
#endif
{
#if SYS_VMS
the_time = statbuf.st_ctime; /* e.g., creation-time */
#else
the_time = statbuf.st_mtime;
#endif
}
return the_time;
}
#endif
#ifdef MDCHK_MODTIME
static int
PromptModtime (
BUFFER *bp,
char *fname,
const char *question,
int iswrite)
{
int status = SORTOFTRUE;
time_t current;
char prompt[NLINE];
if (!isInternalName(bp->b_fname)
&& b_val(bp, MDCHK_MODTIME)
&& bp->b_active /* only buffers that are loaded */
&& same_fname(fname, bp, FALSE)
&& get_modtime(bp, ¤t)) {
time_t check_against;
const char *remind, *again;
if (iswrite) {
check_against = bp->b_modtime;
remind = "Reminder: ";
again = "";
} else {
remind = "";
if (bp->b_modtime_at_warn) {
check_against = bp->b_modtime_at_warn;
again = "again ";
} else {
check_against = bp->b_modtime;
again = "";
}
}
if (check_against != current) {
(void)lsprintf(prompt,
"%sFile for buffer \"%s\" has changed %son disk. %s",
remind, bp->b_bname, again, question);
if ((status = mlyesno( prompt )) != TRUE)
mlerase();
/* avoid reprompts */
bp->b_modtime_at_warn = current;
}
}
return status;
}
int
ask_shouldchange(BUFFER *bp)
{
int status;
status = PromptModtime(bp, bp->b_fname, "Continue", FALSE);
return (status == TRUE || status == SORTOFTRUE);
}
int
get_modtime (BUFFER *bp, time_t *the_time)
{
if (isInternalName(bp->b_fname))
*the_time = 0;
else
*the_time = file_modified(bp->b_fname);
return (*the_time != 0);
}
void
set_modtime(BUFFER *bp, char *fn)
{
time_t current;
if (same_fname(fn, bp, FALSE) && get_modtime(bp, ¤t)) {
bp->b_modtime = current;
bp->b_modtime_at_warn = 0;
}
}
int
check_modtime(BUFFER *bp, char *fn)
{
int status = TRUE;
if (PromptModtime(bp, fn, "Read from disk", FALSE) == TRUE) {
#if OPT_LCKFILES
/* release own lock before read the file again */
if ( global_g_val(GMDUSEFILELOCK) ) {
if (!b_val(curbp,MDLOCKED) && !b_val(curbp,MDVIEW))
release_lock(fn);
}
#endif
status = readin(fn, TRUE, bp, TRUE);
}
return status;
}
static int
inquire_modtime(BUFFER *bp, char *fn)
{
register int status;
if ((status = PromptModtime(bp, fn, "Continue write", TRUE)) != TRUE
&& (status != SORTOFTRUE)) {
mlforce("[Write aborted]");
return FALSE;
}
return TRUE;
}
int
check_visible_modtimes (void)
{
register WINDOW *wp;
for_each_visible_window(wp)
(void)check_modtime(wp->w_bufp, wp->w_bufp->b_fname);
return TRUE;
}
#endif /* MDCHK_MODTIME */
#if SYS_UNIX || SYS_MSDOS
#define CleanToPipe() if (fileispipe) ttclean(TRUE)
static void
CleanAfterPipe (int Wrote)
{
if (fileispipe == TRUE) {
ttunclean(); /* may clear the screen as a side-effect */
TTflush();
if (Wrote) pressreturn();
sgarbf = TRUE;
}
}
#else /* !SYS_UNIX */
#ifdef GMDW32PIPES
static void
CleanToPipe(void)
{
if (fileispipe)
{
kbd_erase_to_end(0);
kbd_flush();
TTkclose();
}
}
static void
CleanAfterPipe(int Wrote)
{
if (fileispipe)
{
TTkopen();
if (global_g_val(GMDW32PIPES))
{
if (Wrote) pressreturn();
sgarbf = TRUE;
}
}
}
#else /* !GMDW32PIPES */
#define CleanToPipe() TTkclose()
#define CleanAfterPipe(f) TTkopen()
#endif
#endif /* SYS_UNIX */
/*
* On faster machines, a pipe-writer will tend to keep the pipe full. This
* function is used by 'slowreadf()' to test if we've not done an update
* recently even if this is the case.
*/
#if SYS_UNIX && OPT_SHELL
static int
slowtime (time_t *refp)
{
int status = FALSE;
if (fileispipe) {
time_t temp = time((time_t *)0);
status = (!ffhasdata() || (temp != *refp));
if (status)
*refp = temp;
}
return status;
}
#else
# if SYS_WINNT
# define slowtime(refp) (fileispipe && !nowait_pipe_cmd && !ffhasdata())
# else
# define slowtime(refp) (fileispipe && !ffhasdata())
# endif
#endif
int
no_such_file(const char * fname)
{
mlwarn("[No such file \"%s\"]", fname);
return FALSE;
}
#if OPT_VMS_PATH
static char *
version_of(char *fname)
{
register char *s = strchr(fname, ';');
if (s == 0)
s = skip_string(fname);
return s;
}
static int
explicit_version(char *ver)
{
if (*ver++ == ';') {
if (isDigit(*ver))
return TRUE;
}
return FALSE;
}
#endif /* OPT_VMS_PATH */
#if SYS_VMS
static char *
resolve_filename(BUFFER *bp)
{
char temp[NFILEN];
ch_fname(bp, fgetname(ffp, temp));
markWFMODE(bp);
return bp->b_fname;
}
#endif
/*
* Returns true if the given filename is the same as that of the referenced
* buffer. The 'lengthen' parameter controls whether we assume the filename is
* already in canonical form, since that may be an expensive operation to do in
* a loop.
*/
int
same_fname(char *fname, BUFFER *bp, int lengthen)
{
char temp[NFILEN];
if (fname == 0
|| bp->b_fname == 0
|| isInternalName(fname)
|| isInternalName(bp->b_fname))
return FALSE;
if (lengthen)
fname = lengthen_path(strcpy(temp, fname));
#if OPT_VMS_PATH
/* ignore version numbers in this comparison unless both are given */
if (is_vms_pathname(fname, FALSE)) {
char *bname = bp->b_fname,
*s = version_of(bname),
*t = version_of(fname);
if (!explicit_version(s)
|| !explicit_version(t))
if ((s-bname) == (t-fname))
return !strncmp(fname, bname, (SIZE_T)(s-bname));
}
#endif
return !strcmp(fname, bp->b_fname);
}
/*
* Set the buffer-name based on the filename
*/
static void
set_buffer_name(BUFFER *bp)
{
char bname[NBUFN];
bp->b_bname[0] = EOS; /* ...so 'unqname()' doesn't find me */
makename(bname, bp->b_fname);
unqname(bname);
set_bname(bp, bname);
updatelistbuffers();
markWFMODE(bp);
}
/*
* Read a file into the current
* buffer. This is really easy; all you do it
* find the name of the file, and call the standard
* "read a file into the current buffer" code.
*/
/* ARGSUSED */
int
fileread(int f GCC_UNUSED, int n GCC_UNUSED)
{
register int s;
char fname[NFILEN];
if (more_named_cmd()) {
if ((s = mlreply_file("Replace with file: ", (TBUFF **)0,
FILEC_REREAD, fname)) != TRUE)
return s;
}
else if (!global_g_val(GMDWARNREREAD)
|| ((s = mlyesno("Reread current buffer")) == TRUE)) {
(void)strcpy(fname, curbp->b_fname);
/* Check if we are rereading the unnamed-buffer if it is not
* associated with a file.
*/
if (curbp->b_fname[0] == EOS
&& eql_bname(curbp, UNNAMED_BufName)) {
s = bclear(curbp);
if (s == TRUE)
mlerase();
return s;
}
} else {
return FALSE;
}
#if OPT_LCKFILES
/* release own lock before read the replaced file */
if ( global_g_val(GMDUSEFILELOCK) ) {
if (!b_val(curbp,MDLOCKED) && !b_val(curbp,MDVIEW))
release_lock(curbp->b_fname);
}
#endif
/* we want no errors or complaints, so mark it unchanged */
b_clr_changed(curbp);
s = readin(fname, TRUE, curbp, TRUE);
set_buffer_name(curbp);
return s;
}
/*
* Select a file for editing.
* Look around to see if you can find the
* file in another buffer; if you can find it
* just switch to the buffer. If you cannot find
* the file, create a new buffer, read in the
* text, and switch to the new buffer.
* This is ": e"
*/
TBUFF *lastfileedited;
void
set_last_file_edited(const char *f)
{
tb_scopy(&lastfileedited, f);
}
/* ARGSUSED */
int
filefind(int f GCC_UNUSED, int n GCC_UNUSED)
{
register int s;
register BUFFER *bp;
char fname[NFILEN];
char *actual;
BUFFER *firstbp = 0;
if ((s = mlreply_file("Find file: ", &lastfileedited,
FILEC_READ|FILEC_EXPAND,
fname)) == TRUE) {
while ((actual = filec_expand()) != 0) {
if ((bp = getfile2bp(actual, !clexec,FALSE)) == 0)
break;
bp->b_flag |= BFARGS; /* treat this as an argument */
if (firstbp == 0)
firstbp = bp;
}
if (firstbp != 0)
s = bp2swbuffer(firstbp, FALSE, TRUE);
}
return s;
}
/* ARGSUSED */
int
viewfile(int f GCC_UNUSED, int n GCC_UNUSED) /* visit a file in VIEW mode */
{
char fname[NFILEN]; /* file user wishes to find */
register int s; /* status return */
char *actual;
static TBUFF *last;
if ((s = mlreply_file("View file: ", &last, FILEC_READ|FILEC_EXPAND,
fname)) == TRUE) {
while ((actual = filec_expand()) != 0) {
if ((s = getfile(actual, FALSE)) != TRUE)
break;
/* if we succeed, put it in view mode */
make_local_b_val(curwp->w_bufp,MDVIEW);
set_b_val(curwp->w_bufp,MDVIEW,TRUE);
markWFMODE(curwp->w_bufp);
}
}
return s;
}
/*
* Insert a file into the current
* buffer. This is really easy; all you do it
* find the name of the file, and call the standard
* "insert a file into the current buffer" code.
*/
/* ARGSUSED */
int
insfile(int f GCC_UNUSED, int n GCC_UNUSED)
{
register int s;
char fname[NFILEN];
static TBUFF *last;
if (!calledbefore) {
if ((s= mlreply_file("Insert file: ", &last,
FILEC_READ|FILEC_PROMPT, fname)) != TRUE)
return s;
}
if (ukb == 0)
return ifile(fname, TRUE, (FILE *)0);
else
return kifile(fname);
}
BUFFER *
getfile2bp(
const char *fname, /* file name to find */
int ok_to_ask,
int cmdline)
{
register BUFFER *bp = 0;
register int s;
char bname[NBUFN]; /* buffer name to put file */
char nfname[NFILEN]; /* canonical form of 'fname' */
/* user may have renamed buffer to look like filename */
if (cmdline
|| (bp = find_b_name(fname)) == NULL
|| (strlen(fname) > (SIZE_T)NBUFN-1)) {
/* It's not already here by that buffer name.
* Try to find it assuming we're given the file name.
*/
(void)lengthen_path(strcpy(nfname, fname));
if (is_internalname(nfname)) {
mlforce("[Buffer not found]");
return 0;
}
for_each_buffer(bp) {
/* is it here by that filename? */
if (same_fname(nfname, bp, FALSE)) {
return bp;
}
}
/* it's not here */
makename(bname, nfname); /* New buffer name. */
/* make sure the buffer name doesn't exist */
while ((bp = find_b_name(bname)) != NULL) {
if ( !b_is_changed(bp) && is_empty_buf(bp) &&
!ffexists(bp->b_fname)) {
/* empty and unmodified -- then it's okay
to re-use this buffer */
bp->b_active = FALSE;
ch_fname(bp, nfname);
return bp;
}
/* old buffer name conflict code */
unqname(bname);
if (!ok_to_ask || !global_g_val(GMDWARNRENAME))
continue;
hst_glue(' ');
s = mlreply("Will use buffer name: ", bname, sizeof(bname));
if (s == ABORT)
return 0;
if (s == FALSE || bname[0] == EOS)
makename(bname, fname);
}
/* okay, we've got a unique name -- create it */
if (bp==NULL && (bp=bfind(bname, 0))==NULL) {
mlwarn("[Cannot create buffer]");
return 0;
}
/* switch and read it in. */
ch_fname(bp, nfname);
}
return bp;
}
static int
bp2swbuffer(BUFFER *bp, int ask_rerun, int lockfl)
{
register int s;
if ((s = (bp != 0)) != FALSE) {
if (bp->b_active) {
if (ask_rerun) {
switch (mlyesno(
"Old command output -- rerun")) {
case TRUE:
bp->b_active = FALSE;
break;
case ABORT:
s = FALSE;
default:
mlerase();
break;
}
} else {
mlwrite("[Old buffer]");
}
}
#if BEFORE
/*
* The 'swbuffer()' function will invoke 'readin()', but it
* doesn't accept the 'lockfl' parameter, so we call it here.
*/
/* added swbuffer_lfl() to take lockfl arg to get around this problem. the
* readin() was happening before a lot of the buffer info was set up, so a
* user readhook couldn't use that info successfully.
* if this change appears successful, the bp2readin routine (4 lines) can
* be folded into swbuffer_lfl(), which is the only caller. --pgf */
if (!(bp->b_active))
s = bp2readin(bp, lockfl);
#endif
if (s == TRUE)
s = swbuffer_lfl(bp, lockfl);
if (s == TRUE)
curwp->w_flag |= WFMODE|WFHARD;
}
return s;
}
int
getfile(
char *fname, /* file name to find */
int lockfl) /* check the file for locks? */
{
register BUFFER *bp = 0;
/* if there are no path delimiters in the name, then the user
is likely asking for an existing buffer -- try for that
first */
if ((strlen(fname) > (SIZE_T)NBUFN-1) /* too big to be a bname */
|| maybe_pathname(fname) /* looks a lot like a filename */
|| (bp = find_b_name(fname)) == NULL) {
/* oh well. canonicalize the name, and try again */
bp = getfile2bp(fname,!clexec,FALSE);
if (!bp)
return FALSE;
}
return bp2swbuffer(bp, isShellOrPipe(bp->b_fname), lockfl);
}
/*
* Scan a buffer to see if it contains more lines terminated by CR-LF than by
* LF alone. If so, set the DOS-mode to true, otherwise false.
*/
#if OPT_DOSFILES
/*
* If the given buffer is one that we're sourcing (e.g., with ":so"), or
* specified in initialization, we require that _all_ of the lines end with
* ^M's before deciding that it is DOS-style. That is to protect us from
* accidentally trimming the ^M's from a :map command.
*/
static void
apply_dosmode(BUFFER *bp, int doslines, int unixlines)
{
int result;
if (bp->b_flag & BFEXEC) {
if (doslines && !unixlines) {
result = TRUE;
} else {
result = FALSE;
}
} else {
result = (doslines MORETHAN unixlines);
}
set_b_val(bp, MDDOS, result);
}
static void
strip_if_dosmode(BUFFER *bp, int doslines, int unixlines)
{
apply_dosmode(bp, doslines, unixlines);
if (b_val(bp, MDDOS)) { /* if it _is_ a dos file, strip 'em */
register LINE *lp;
for_each_line(lp,bp) {
if (llength(lp) > 0 &&
lgetc(lp, llength(lp)-1) == '\r') {
llength(lp)--;
bp->b_bytecount--;
}
}
}
}
static void
guess_dosmode(BUFFER *bp)
{
int doslines = 0,
unixlines = 0;
register LINE *lp;
make_local_b_val(bp, MDDOS); /* keep it local, if not */
/* first count 'em */
for_each_line(lp,bp) {
if (llength(lp) > 0 &&
lgetc(lp, llength(lp)-1) == '\r') {
doslines++;
} else {
unixlines++;
}
}
strip_if_dosmode(bp, doslines, unixlines);
TRACE(("guess_dosmode %d\n", b_val(bp, MDDOS)))
}
/*
* Forces the current buffer to be in DOS-mode, stripping any trailing CR's.
* ( any argument forces non-DOS mode, trailing CR's still stripped )
*/
/*ARGSUSED*/
int
set_dosmode(int f, int n GCC_UNUSED)
{
guess_dosmode(curbp);
/* force dos mode on the buffer, based on the user argument */
set_b_val(curbp, MDDOS, !f);
curwp->w_flag |= WFMODE;
return TRUE;
}
/* as above, but forces unix-mode instead */
/*ARGSUSED*/
int
set_unixmode(int f, int n)
{
return set_dosmode(!f, n);
}
#endif
#if OPT_LCKFILES
static void
grab_lck_file(BUFFER *bp, char *fname)
{
/* Write the lock */
if (global_g_val(GMDUSEFILELOCK) &&
! isShellOrPipe(fname) &&
! b_val(bp,MDVIEW) )
{
char locker[100];
if ( ! set_lock(fname,locker,sizeof(locker)) ) {
/* we didn't get it */
make_local_b_val(bp,MDVIEW);
set_b_val(bp,MDVIEW,TRUE);
make_local_b_val(bp,MDLOCKED);
set_b_val(bp,MDLOCKED,TRUE);
make_local_b_val(bp,VAL_LOCKER);
set_b_val_ptr(bp,VAL_LOCKER, strmalloc(locker));
markWFMODE(bp);
}
}
}
#endif
/*
* Read file "fname" into a buffer, blowing away any text
* found there. Returns the final status of the read.
*/
/* ARGSUSED */
int
readin(
char *fname, /* name of file to read */
int lockfl, /* check for file locks? */
register BUFFER *bp, /* read into this buffer */
int mflg) /* print messages? */
{
register WINDOW *wp;
register int s;
int nline;
if (bp == 0) /* doesn't hurt to check */
return FALSE;
if (*fname == EOS) {
mlwrite("BUG: readin called with NULL fname");
return FALSE;
}
#if OPT_ENCRYPT
if ((s = resetkey(bp, fname)) != TRUE)
return s;
#endif
if ((s=bclear(bp)) != TRUE) /* Might be old. */
return s;
#if OPT_ENCRYPT
/* bclear() gets rid of local flags */
if (bp->b_key[0] != EOS) {
make_local_b_val(bp, MDCRYPT);
set_b_val(bp, MDCRYPT, TRUE);
}
#endif
b_clr_flags(bp, BFINVS|BFCHG);
ch_fname(bp,fname);
fname = bp->b_fname; /* this may have been b_fname! */
#if OPT_DOSFILES
make_local_b_val(bp, MDDOS);
/* assume that if our OS wants it, that the buffer will have CRLF
* lines. this may change when the file is read, based on actual
* line counts, below. otherwise, if there's an error, or the
* file doesn't exist, we will keep this default.
*/
set_b_val(bp, MDDOS, CRLF_LINES);
#endif
make_local_b_val(bp,MDNEWLINE);
set_b_val(bp, MDNEWLINE, TRUE); /* assume we've got it */
if ((s = ffropen(fname)) == FIOERR) { /* Hard file error. */
/* do nothing -- error has been reported,
and it will appear as empty buffer */
/*EMPTY*/;
} else if (s == FIOFNF) { /* File not found. */
if (mflg)
mlwrite("[New file]");
} else {
if (mflg)
mlforce("[Reading %s ]", fname);
#if SYS_VMS
if (!isInternalName(bp->b_fname))
fname = resolve_filename(bp);
#endif
/* read the file in */
nline = 0;
#if OPT_WORKING
max_working = cur_working = old_working = 0;
#endif
#if ! (SYS_MSDOS||SYS_WIN31)
if (fileispipe || (s = quickreadf(bp, &nline)) == FIOMEM)
#endif
s = slowreadf(bp, &nline);
#if OPT_WORKING
cur_working = 0;
#endif
if (s == FIOERR) {
/*EMPTY*/;
} else {
if (s == FIOFUN) /* last line is incomplete */
set_b_val(bp, MDNEWLINE, FALSE);
b_clr_changed(bp);
#if OPT_FINDERR
if (fileispipe == TRUE)
set_febuff(bp->b_bname);
#endif
(void)ffclose(); /* Ignore errors. */
if (mflg)
readlinesmsg(nline, s, fname, ffronly(fname));
/* set view mode for read-only files */
if ((global_g_val(GMDRONLYVIEW) && ffronly(fname) )) {
make_local_b_val(bp, MDVIEW);
set_b_val(bp, MDVIEW, TRUE);
}
/* set read-only mode for read-only files */
if (isShellOrPipe(fname) ||
(global_g_val(GMDRONLYRONLY) &&
ffronly(fname) )) {
make_local_b_val(bp, MDREADONLY);
set_b_val(bp, MDREADONLY, TRUE);
}
bp->b_active = TRUE;
bp->b_lines_on_disk = bp->b_linecount;
}
}
/*
* Set the majormode if the file's suffix matches.
*/
setm_by_suffix(bp);
setm_by_preamble(bp);
for_each_window(wp) {
if (wp->w_bufp == bp) {
wp->w_line.l = lforw(buf_head(bp));
wp->w_dot.l = lforw(buf_head(bp));
wp->w_dot.o = 0;
#if WINMARK
wp->w_mark = nullmark;
#endif
wp->w_lastdot = nullmark;
wp->w_flag |= WFMODE|WFHARD;
}
}
imply_alt(fname, FALSE, lockfl);
updatelistbuffers();
#if OPT_LCKFILES
if (lockfl && s != FIOERR)
grab_lck_file(bp,fname);
#endif
#if OPT_PROCEDURES
if (s <= FIOEOF) {
static int readhooking;
if (!readhooking && *readhook && !b_is_temporary(bp)) {
readhooking = TRUE;
run_procedure(readhook);
readhooking = FALSE;
}
}
#endif
b_match_attrs_dirty(bp);
return (s != FIOERR);
}
/*
* Read the file into a given buffer, setting dot to the first line.
*/
int
bp2readin(BUFFER *bp, int lockfl)
{
register int s = readin(bp->b_fname, lockfl, bp, TRUE);
bp->b_dot.l = lforw(buf_head(bp));
bp->b_dot.o = 0;
bp->b_active = TRUE;
return s;
}
#if ! (SYS_MSDOS || SYS_WIN31)
static int
quickreadf(register BUFFER *bp, int *nlinep)
{
register UCHAR *textp;
UCHAR *countp;
L_NUM nlines;
int incomplete = FALSE;
B_COUNT len, nbytes;
if ((len = ffsize()) < 0) {
mlwarn("[Can't size file]");
return FIOERR;
}
/* avoid malloc(0) problems down below; let slowreadf() do the work */
if (len == 0)
return FIOMEM;
#if OPT_WORKING
max_working = len;
#endif
/* leave an extra byte at the front, for the length of the first
line. after that, lengths go in place of the newline at
the end of the previous line */
bp->b_ltext = castalloc(UCHAR, (ALLOC_T)(len + 2));
if (bp->b_ltext == NULL)
return FIOMEM;
if ((len = ffread((char *)&bp->b_ltext[1], len)) < 0) {
FreeAndNull(bp->b_ltext);
mlerror("reading");
return FIOERR;
}
#if OPT_ENCRYPT
if (b_val(bp, MDCRYPT)
&& bp->b_key[0]) { /* decrypt the file */
char temp[NPAT];
(void)strcpy(temp, bp->b_key);
ue_crypt((char *)0, 0);
ue_crypt(temp, strlen(temp));
ue_crypt((char *)&bp->b_ltext[1], (UINT)len);
}
#endif
/* loop through the buffer, replacing all newlines with the
length of the _following_ line */
bp->b_ltext_end = bp->b_ltext + len + 1;
countp = bp->b_ltext;
textp = countp + 1;
nbytes = len;
nlines = 0;
if (textp[len-1] != '\n') {
textp[len++] = '\n';
set_b_val(bp, MDNEWLINE, FALSE);
}
while (len--) {
if (*textp == '\n') {
if (textp - countp >= 255) {
UCHAR *np;
#if OPT_WORKING
max_working = bp->b_ltext_end - countp;
#endif
len = (B_COUNT)(countp - bp->b_ltext);
incomplete = TRUE;
/* we'll re-read the rest later */
if (len) {
ffseek(len);
np = castrealloc(UCHAR, bp->b_ltext, (ALLOC_T)len);
} else {
np = NULL;
}
if (np == NULL) {
ffrewind();
FreeAndNull(bp->b_ltext);
return FIOMEM;
}
bp->b_ltext = np;
bp->b_ltext_end = np + len + 1;
nbytes = len;
break;
}
*countp = textp - countp - 1;
countp = textp;
nlines++;
}
++textp;
}
if (nlines == 0) {
ffrewind();
FreeAndNull(bp->b_ltext);
incomplete = TRUE;
} else {
/* allocate all of the line structs we'll need */
bp->b_LINEs = typeallocn(LINE,nlines);
if (bp->b_LINEs == NULL) {
FreeAndNull(bp->b_ltext);
ffrewind();
return FIOMEM;
}
bp->b_LINEs_end = bp->b_LINEs + nlines;
bp->b_bytecount = nbytes;
bp->b_linecount = nlines;
b_set_counted(bp);
/* loop through the buffer again, creating
line data structure for each line */
{
register LINE *lp;
#if !SMALLER
L_NUM lineno = 0;
#endif
lp = bp->b_LINEs;
textp = bp->b_ltext;
while (lp != bp->b_LINEs_end) {
#if !SMALLER
lp->l_number = ++lineno;
#endif
lp->l_used = *textp;
lp->l_size = *textp + 1;
lp->l_text = (char *)textp + 1;
set_lforw(lp, lp + 1);
if (lp != bp->b_LINEs)
set_lback(lp, lp - 1);
lsetclear(lp);
lp->l_nxtundo = null_ptr;
lp++;
textp += *textp + 1;
}
/*
if (textp != bp->b_ltext_end - 1)
mlwrite("BUG: textp not equal to end %d %d",
textp,bp->b_ltext_end);
*/
lp--; /* point at last line again */
/* connect the end of the list */
set_lforw(lp, buf_head(bp));
set_lback(buf_head(bp), lp);
/* connect the front of the list */
set_lback(bp->b_LINEs, buf_head(bp));
set_lforw(buf_head(bp), bp->b_LINEs);
}
}
*nlinep = nlines;
if (incomplete)
return FIOMEM;
#if OPT_DOSFILES
if (global_b_val(MDDOS))
guess_dosmode(bp);
#endif
return b_val(bp, MDNEWLINE) ? FIOSUC : FIOFUN;
}
#endif /* ! SYS_MSDOS */
int
slowreadf(register BUFFER *bp, int *nlinep)
{
int s;
int len;
#if OPT_DOSFILES
int doslines = 0,
unixlines = 0;
#endif
#if SYS_UNIX || SYS_MSDOS || SYS_WIN31 || SYS_OS2 || SYS_WINNT /* i.e., we can read from a pipe */
USHORT flag = 0;
int done_update = FALSE;
#endif
#if SYS_UNIX && OPT_SHELL
time_t last_updated = time((time_t *)0);
#endif
b_set_counted(bp); /* make 'addline()' do the counting */
#if OPT_DOSFILES
/*
* There might be some pre-existing lines if quickreadf
* read part of the file and then left the rest up to us.
*/
make_local_b_val(bp, MDDOS); /* keep it local, if not */
if (global_b_val(MDDOS)) {
register LINE *lp;
for_each_line(lp,bp) {
if (llength(lp) > 0 &&
lgetc(lp, llength(lp)-1) == '\r') {
doslines++;
} else {
unixlines++;
}
}
}
#endif
bp->b_lines_on_disk = 0;
while ((s = ffgetline(&len)) <= FIOSUC) {
bp->b_lines_on_disk += 1;
#if OPT_DOSFILES
/*
* Strip CR's if we are reading in DOS-mode. Otherwise,
* keep any CR's that we read.
*/
if (global_b_val(MDDOS)) {
if (len > 0 && fline[len-1] == '\r') {
doslines++;
} else {
unixlines++;
}
}
#endif
if (addline(bp,fline,len) != TRUE) {
s = FIOMEM; /* Keep message on the */
break; /* display. */
}
#if SYS_UNIX || SYS_MSDOS || SYS_WIN31 || SYS_OS2 || SYS_WINNT
else {
/* reading from a pipe, and internal? */
if (slowtime(&last_updated)) {
register WINDOW *wp;
flag |= (WFEDIT|WFFORCE);
if (!done_update || bp->b_nwnd > 1)
flag |= WFHARD;
for_each_window(wp) {
if (wp->w_bufp == bp) {
wp->w_line.l=
lforw(buf_head(bp));
wp->w_dot.l =
lback(buf_head(bp));
wp->w_dot.o = 0;
wp->w_flag |= flag;
wp->w_force = -1;
}
}
/* track changes in dosfile as lines arrive */
#if OPT_DOSFILES
if (global_b_val(MDDOS))
apply_dosmode(bp, doslines, unixlines);
#endif
curwp->w_flag |= WFMODE|WFKILLS;
if (!update(TRUE)) {
s = FIOERR;
break;
}
#if DISP_X11
/* to pick up intrc if it's been hit */
x_move_events();
#endif
done_update = TRUE;
flag = 0;
} else {
flag |= WFHARD;
}
}
#endif
++(*nlinep);
if (s == FIOFUN) {
set_b_val(bp, MDNEWLINE, FALSE);
break;
}
}
#if OPT_DOSFILES
if (global_b_val(MDDOS)) {
strip_if_dosmode(bp, doslines, unixlines);
}
#endif
return s;
}
/* utility routine for no. of lines read */
static void
readlinesmsg(int n, int s, const char *f, int rdo)
{
char fname[NFILEN];
const char *m;
char *short_f = shorten_path(strcpy(fname,f),TRUE);
switch(s) {
case FIOFUN: m = "INCOMPLETE LINE, ";break;
case FIOERR: m = "I/O ERROR, "; break;
case FIOMEM: m = "OUT OF MEMORY, "; break;
case FIOABRT: m = "ABORTED, "; break;
default: m = ""; break;
}
if (!global_b_val(MDTERSE))
mlwrite("[%sRead %d line%s from \"%s\"%s]", m,
n, PLURAL(n), short_f, rdo ? " (read-only)":"" );
else
mlforce("[%s%d lines]",m,n);
}
/*
* Take a (null-terminated) file name, and from it
* fabricate a buffer name. This routine knows
* about the syntax of file names on the target system.
* I suppose that this information could be put in
* a better place than a line of code.
*/
void
makename(char *bname, const char *fname)
{
register char *fcp;
register char *bcp;
register int j;
char temp[NFILEN];
fcp = skip_string(strcpy(temp, fname));
#if OPT_VMS_PATH
if (is_vms_pathname(temp, TRUE)) {
(void)strcpy(bname, "NoName");
return;
}
if (is_vms_pathname(temp, FALSE)) {
for (;
fcp > temp && !strchr(":]", fcp[-1]);
fcp--)
;
(void)strncpy0(bname, fcp, NBUFN);
strip_version (bname);
(void)mklower(bname);
return;
}
#endif
/* trim trailing whitespace */
while (fcp != temp && (isBlank(fcp[-1])
#if SYS_UNIX || OPT_MSDOS_PATH /* trim trailing slashes as well */
|| is_slashc(fcp[-1])
#endif
) )
*(--fcp) = EOS;
fcp = temp;
/* trim leading whitespace */
while (isBlank(*fcp))
fcp++;
#if SYS_UNIX || SYS_MSDOS || SYS_WIN31 || SYS_VMS || SYS_OS2 || SYS_WINNT
bcp = bname;
if (isShellOrPipe(fcp)) {
/* ...it's a shell command; bname is first word */
*bcp++ = SCRTCH_LEFT[0];
*bcp++ = SHPIPE_LEFT[0];
do {
++fcp;
} while (isSpace(*fcp));
(void)strncpy0(bcp, fcp, (SIZE_T)(NBUFN - (bcp - bname)));
for (j = 4; (j < NBUFN) && isPrint(*bcp); j++) {
bcp++;
}
(void) strcpy(bcp, SCRTCH_RIGHT);
return;
}
(void)strncpy0(bcp, pathleaf(fcp), (SIZE_T)(NBUFN - (bcp - bname)));
#if SYS_UNIX
/* UNIX filenames can have any characters (other than EOS!). Refuse
* (rightly) to deal with leading/trailing blanks, but allow embedded
* blanks. For this special case, ensure that the buffer name has no
* blanks, otherwise it is difficult to reference from commands.
*/
for (j = 0; j < NBUFN; j++) {
if (*bcp == EOS)
break;
if (isSpace(*bcp))
*bcp = '-';
bcp++;
}
#endif
#else /* !(SYS_UNIX||SYS_VMS||SYS_MSDOS) */
bcp = skip_string(fcp);
{
register char *cp2 = bname;
strcpy0(bname, bcp, NBUFN);
cp2 = strchr(bname, ':');
if (cp2) *cp2 = EOS;
}
#endif
}
void
unqname( /* make sure a buffer name is unique */
char *name) /* name to check on */
{
register SIZE_T j;
char newname[NBUFN * 2];
char suffixbuf[NBUFN];
int suffixlen;
int adjust;
int i = 0;
SIZE_T k;
j = strlen(name);
if (j == 0)
j = strlen(strcpy(name, "NoName"));
/* check to see if it is in the buffer list */
strcpy(newname, name);
adjust = is_scratchname(newname);
while (find_b_name(newname) != NULL) {
/* from "foo" create "foo-1" or "foo-a1b5" */
/* from "thisisamuchlongernam" create
"thisisamuchlongern-1" or
"thisisamuchlong-a1b5" */
/* that is, put suffix at end if it fits, or else
overwrite some of the name to make it fit */
/* the suffix is in "base 36" */
suffixlen = (int)(lsprintf(suffixbuf,"-%r", 36, ++i) - suffixbuf);
k = NBUFN - 1 - suffixlen;
if (j < k)
k = j;
if (adjust) {
strcpy(&newname[k-1], suffixbuf);
strcat(newname, SCRTCH_RIGHT);
} else
strcpy(&newname[k], suffixbuf);
}
strncpy0(name, newname, NBUFN);
}
/*
* Ask for a file name, and write the
* contents of the current buffer to that file.
*/
int
filewrite(int f, int n)
{
register int s;
char fname[NFILEN];
int forced = (f && n == SPECIAL_BANG_ARG);
if (more_named_cmd()) {
if ((s= mlreply_file("Write to file: ", (TBUFF **)0,
FILEC_WRITE, fname)) != TRUE)
return s;
} else
(void) strcpy(fname, curbp->b_fname);
if ((s=writeout(fname,curbp,forced,TRUE)) == TRUE)
unchg_buff(curbp, 0);
return s;
}
/*
* Save the contents of the current
* buffer in its associatd file.
* Error if there is no remembered file
* name for the buffer.
*/
/* ARGSUSED */
int
filesave(int f, int n)
{
register int s;
int forced = (f && n == SPECIAL_BANG_ARG); /* then it was :w! */
if (curbp->b_fname[0] == EOS) { /* Must have a name. */
mlwarn("[No file name]");
return FALSE;
}
if ((s=writeout(curbp->b_fname,curbp,forced,TRUE)) == TRUE)
unchg_buff(curbp, 0);
return s;
}
static void
setup_file_region(BUFFER *bp, REGION *rp)
{
(void)bsizes(bp); /* make sure we have current count */
/* starting at the beginning of the buffer */
rp->r_orig.l = lforw(buf_head(bp));
rp->r_orig.o = 0;
rp->r_size = bp->b_bytecount;
rp->r_end = bp->b_line;
}
/*
* Write a whole file
*/
int
writeout(const char *fn, BUFFER *bp, int forced, int msgf)
{
REGION region;
setup_file_region(bp, ®ion);
return writereg(®ion, fn, msgf, bp, forced);
}
/*
* Write the currently-selected region (i.e., the range of lines from DOT to
* MK, inclusive).
*/
int
writeregion(void)
{
REGION region;
int status;
char fname[NFILEN];
if (end_named_cmd()) {
if (mlyesno("Okay to write [possible] partial range") != TRUE) {
mlwrite("Range not written");
return FALSE;
}
(void)strcpy(fname, curbp->b_fname);
} else {
if ((status = mlreply_file("Write region to file: ",
(TBUFF **)0, FILEC_WRITE|FILEC_PROMPT, fname)) != TRUE)
return status;
}
if ((status=getregion(®ion)) == TRUE)
status = writereg(®ion, fname, TRUE, curbp, FALSE);
return status;
}
static int
writereg(
REGION *rp,
const char *given_fn,
int msgf,
BUFFER *bp,
int forced)
{
register int s;
register LINE *lp;
register int nline;
register int i;
char fname[NFILEN], *fn;
B_COUNT nchar;
const char * ending =
#if OPT_DOSFILES
b_val(bp, MDDOS) ? "\r\n" : "\n"
#else
"\n"
#endif /* OPT_DOSFILES */
;
C_NUM offset = rp->r_orig.o;
/* this is adequate as long as we cannot write parts of lines */
int whole_file = (rp->r_orig.l == lforw(buf_head(bp)))
&& (rp->r_end.l == buf_head(bp));
if (is_internalname(given_fn)) {
mlwarn("[No filename]");
return FALSE;
}
if (!forced && b_val(bp,MDREADONLY)) {
mlwarn("[Buffer mode is \"readonly\"]");
return FALSE;
}
if (isShellOrPipe(given_fn)
&& bp->b_fname != 0
&& !strcmp(given_fn, bp->b_fname)
&& mlyesno("Are you sure (this was a pipe-read)") != TRUE) {
mlwrite("File not written");
return FALSE;
}
#if OPT_PROCEDURES
{
static int writehooking;
if (!writehooking && *writehook) {
writehooking = TRUE;
run_procedure(writehook);
writehooking = FALSE;
/*
* The write-hook may have modified the buffer. Assume
* the worst, and reconstruct the region.
*/
(void)bsizes(bp);
if (whole_file
|| line_no(bp, rp->r_orig.l) > bp->b_linecount
|| line_no(bp, rp->r_end.l) > bp->b_linecount) {
setup_file_region(bp, rp);
} else {
DOT = rp->r_orig;
MK = rp->r_end;
(void)getregion(rp);
}
offset = rp->r_orig.o;
}
}
#endif
fn = lengthen_path(strcpy(fname, given_fn));
if (same_fname(fn, bp, FALSE) && b_val(bp,MDVIEW)) {
mlwarn("[Can't write-back from view mode]");
return FALSE;
}
#if OPT_ENCRYPT
if ((s = resetkey(curbp, fn)) != TRUE)
return s;
#endif
#ifdef MDCHK_MODTIME
if ( ! inquire_modtime( bp, fn ) )
return FALSE;
#endif
if ((s=ffwopen(fn,forced)) != FIOSUC) /* Open writes message. */
return FALSE;
/* tell us we're writing */
if (msgf == TRUE)
mlwrite("[Writing...]");
if (isShellOrPipe(given_fn)) {
beginDisplay();
CleanToPipe();
}
lp = rp->r_orig.l;
nline = 0; /* Number of lines */
nchar = 0; /* Number of chars */
/* first (maybe partial) line and succeeding whole lines */
while ((rp->r_size+offset) >= llength(lp)+1) {
register C_NUM len = llength(lp) - offset;
register char *text = lp->l_text + offset;
/* If this is the last line (and no fragment will be written
* after the line), allow 'newline' mode to suppress the
* trailing newline.
*/
if ((rp->r_size -= (len + 1)) <= 0
&& !b_val(bp,MDNEWLINE))
ending = "";
if ((s = ffputline(text, len, ending)) != FIOSUC)
goto out;
++nline;
nchar += len + 1;
offset = 0;
lp = lforw(lp);
}
/* last line (fragment) */
if (rp->r_size > 0) {
for (i = 0; i < rp->r_size; i++)
if ((s = ffputc(lgetc(lp,i))) != FIOSUC)
goto out;
nchar += rp->r_size;
++nline; /* it _looks_ like a line */
}
out:
if (s == FIOSUC) { /* No write error. */
#if SYS_VMS
if (same_fname(fn, bp, FALSE))
fn = resolve_filename(bp);
#endif
s = ffclose();
if (s == FIOSUC && msgf) { /* No close error. */
if (!global_b_val(MDTERSE)) {
char *aname;
const char *action;
if ((aname = is_appendname(fn)) != 0) {
fn = aname;
action = "Appended";
} else {
action = "Wrote";
}
mlforce("[%s %d line%s %ld char%s to \"%s\"]",
action, nline, PLURAL(nline),
nchar, PLURAL(nchar), fn);
} else {
mlforce("[%d lines]", nline);
}
}
} else { /* Ignore close error */
(void)ffclose(); /* if a write error. */
}
if (whole_file) {
bp->b_linecount =
bp->b_lines_on_disk = nline;
}
if (isShellOrPipe(given_fn)) {
CleanAfterPipe(TRUE);
endofDisplay();
}
if (s != FIOSUC) /* Some sort of error. */
return FALSE;
#ifdef MDCHK_MODTIME
set_modtime(bp, fn);
#endif
/*
* If we've written the unnamed-buffer, rename it according to the file.
* FIXME: maybe we should do this to all internal-names?
*/
if (whole_file
&& eql_bname(bp, UNNAMED_BufName)
&& find_b_file(fname) == 0) {
ch_fname(bp, fname);
set_buffer_name(bp);
}
imply_alt(fn, whole_file, FALSE);
return TRUE;
}
/*
* This function writes the kill register to a file
* Uses the file management routines in the
* "fileio.c" package. The number of lines written is
* displayed.
*/
int
kwrite(char *fn, int msgf)
{
register KILL *kp; /* pointer into kill register */
register int nline;
register int s;
register int c;
register int i;
register char *sp; /* pointer into string to insert */
/* make sure there is something to put */
if (kbs[ukb].kbufh == NULL) {
if (msgf) mlforce("Nothing to write");
return FALSE; /* not an error, just nothing */
}
#if OPT_ENCRYPT
if ((s = resetkey(curbp, fn)) != TRUE)
return s;
#endif
if ((s=ffwopen(fn,FALSE)) != FIOSUC) { /* Open writes message. */
return FALSE;
}
/* tell us we're writing */
if (msgf == TRUE)
mlwrite("[Writing...]");
nline = 0; /* Number of lines. */
kp = kbs[ukb].kbufh;
while (kp != NULL) {
i = KbSize(ukb,kp);
sp = (char *)kp->d_chunk;
while (i--) {
if ((c = *sp++) == '\n')
nline++;
if ((s = ffputc(c)) != FIOSUC)
break;
}
kp = kp->d_next;
}
if (s == FIOSUC) { /* No write error. */
s = ffclose();
if (s == FIOSUC && msgf) { /* No close error. */
if (!global_b_val(MDTERSE))
mlwrite("[Wrote %d line%s to %s ]",
nline, PLURAL(nline), fn);
else
mlforce("[%d lines]", nline);
}
} else { /* Ignore close error */
(void)ffclose(); /* if a write error. */
}
if (s != FIOSUC) /* Some sort of error. */
return FALSE;
return TRUE;
}
/*
* The command allows the user
* to modify the file name associated with
* the current buffer. It is like the "f" command
* in UNIX "ed". The operation is simple; just zap
* the name in the BUFFER structure, and mark the windows
* as needing an update. You can type a blank line at the
* prompt if you wish.
*/
/* ARGSUSED */
int
filename(int f GCC_UNUSED, int n GCC_UNUSED)
{
register int s;
char fname[NFILEN];
if (end_named_cmd()) {
return showcpos(FALSE,1);
}
if ((s = mlreply_file("Name: ", (TBUFF **)0, FILEC_UNKNOWN, fname))
== ABORT)
return s;
if (s == FALSE)
return s;
make_global_b_val(curbp,MDVIEW); /* no longer read only mode */
#if OPT_LCKFILES
if ( global_g_val(GMDUSEFILELOCK) ) {
if (!b_val(curbp,MDLOCKED) && !b_val(curbp,MDVIEW))
release_lock(curbp->b_fname);
ch_fname(curbp, fname);
make_global_b_val(curbp,MDLOCKED);
make_global_b_val(curbp,VAL_LOCKER);
grab_lck_file(curbp, fname);
} else
#endif
ch_fname(curbp, fname);
curwp->w_flag |= WFMODE;
updatelistbuffers();
return TRUE;
}
/*
* Insert file "fname" into the current
* buffer, Called by insert file command. Return the final
* status of the read.
*/
int
ifile(char *fname, int belowthisline, FILE *haveffp)
{
register LINEPTR prevp;
register LINEPTR newlp;
register LINEPTR nextp;
register BUFFER *bp;
register int s;
int nbytes;
register int nline;
bp = curbp; /* Cheap. */
b_clr_flags(bp, BFINVS); /* we are not temporary*/
if (!haveffp) {
if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
goto out;
if (s == FIOFNF) /* File not found. */
return no_such_file(fname);
#if OPT_ENCRYPT
if ((s = resetkey(curbp, fname)) != TRUE)
return s;
#endif
mlwrite("[Inserting...]");
CleanToPipe();
} else { /* we already have the file pointer */
ffp = haveffp;
}
prevp = DOT.l;
DOT.o = 0;
MK = DOT;
nline = 0;
nextp = null_ptr;
while ((s=ffgetline(&nbytes)) <= FIOSUC) {
#if OPT_DOSFILES
if (b_val(curbp,MDDOS)
&& (nbytes > 0)
&& fline[nbytes-1] == '\r')
nbytes--;
#endif
if (!belowthisline) {
nextp = prevp;
prevp = lback(prevp);
}
if (add_line_at(curbp, prevp, fline, nbytes) != TRUE) {
s = FIOMEM; /* Keep message on the */
break; /* display. */
}
newlp = lforw(prevp);
tag_for_undo(newlp);
prevp = belowthisline ? newlp : nextp;
++nline;
if (s < FIOSUC)
break;
}
if (!haveffp) {
CleanAfterPipe(FALSE);
(void)ffclose(); /* Ignore errors. */
readlinesmsg(nline,s,fname,FALSE);
}
out:
/* advance to the next line and mark the window for changes */
DOT.l = lforw(DOT.l);
/* copy window parameters back to the buffer structure */
copy_traits(&(curbp->b_wtraits), &(curwp->w_traits));
imply_alt(fname, FALSE, FALSE);
chg_buff (curbp, WFHARD);
return (s != FIOERR);
}
/*
* Insert file "fname" into the kill register
* Called by insert file command. Return the final
* status of the read.
*/
static int
kifile(char *fname)
{
register int i;
register int s;
register int nline;
int nbytes;
ksetup();
if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
goto out;
if (s == FIOFNF) /* File not found. */
return no_such_file(fname);
nline = 0;
#if OPT_ENCRYPT
if ((s = resetkey(curbp, fname)) == TRUE)
#endif
{
mlwrite("[Reading...]");
CleanToPipe();
while ((s=ffgetline(&nbytes)) <= FIOSUC) {
for (i=0; i<nbytes; ++i)
if (!kinsert(fline[i]))
return FIOMEM;
if ((s == FIOSUC) && !kinsert('\n'))
return FIOMEM;
++nline;
if (s < FIOSUC)
break;
}
CleanAfterPipe(FALSE);
}
kdone();
(void)ffclose(); /* Ignore errors. */
readlinesmsg(nline,s,fname,FALSE);
out:
return (s != FIOERR);
}
#if SYS_UNIX
static const char *mailcmds[] = {
"/usr/lib/sendmail",
"/sbin/sendmail",
"/usr/sbin/sendmail",
"/bin/mail",
0
};
#endif
/* called on hangups, interrupts, and quits */
/* This code is definitely not production quality, or probably very
robust, or probably very secure. I whipped it up to save
myself while debugging... pgf */
/* on the other hand, it has limped along for well over six years now :-/ */
SIGT
imdying(int ACTUAL_SIG_ARGS)
{
static char dirnam[NSTRING] = "";
#if SYS_UNIX
static const char *tbl[] = {
"/var/tmp",
"/usr/tmp",
"/tmp"
"."
};
#endif
char filnam[NFILEN];
BUFFER *bp;
#if SYS_UNIX
char cmd[NFILEN+250];
char *np;
#endif
static int wrote = 0;
#if HAVE_MKDIR && !SYS_MSDOS && !SYS_OS2
static int created = FALSE;
#else
char temp[NFILEN];
#endif
static int i_am_dead;
#if SYS_APOLLO
extern char *getlogin(void);
#endif /* SYS_APOLLO */
#if OPT_WORKING && defined(SIGALRM)
setup_handler(SIGALRM, SIG_IGN);
#endif
if (i_am_dead++) /* prevent recursive faults */
_exit(signo);
#if SYS_APOLLO
(void)lsprintf(cmd,
"(echo signal %d killed vile;/com/tb %d)| /bin/mail %s",
signo, getpid(), getlogin());
(void)system(cmd);
#endif /* SYS_APOLLO */
/* write all modified buffers to the temp directory */
set_global_g_val(GMDIMPLYBUFF,FALSE); /* avoid side-effects! */
for_each_buffer(bp) {
if (!b_is_temporary(bp) &&
bp->b_active == TRUE &&
b_is_changed(bp)) {
#if HAVE_MKDIR && !SYS_MSDOS && !SYS_OS2
if (!created) {
#if SYS_UNIX
if ((np = getenv("TMPDIR")) != 0
&& strlen(np) < 32
&& is_directory(np)) {
strcpy(dirnam, np);
} else {
unsigned n;
for (n = 0; n < TABLESIZE(tbl); n++) {
strcpy(dirnam, tbl[n]);
if (is_directory(dirnam)) {
break;
}
}
}
#else
strcpy(dirnam, "");
#endif
(void)pathcat(dirnam, dirnam, "vileDXXXXXX");
(void)mktemp(dirnam);
if(mkdir(dirnam,0700) != 0) {
tidy_exit(BADEXIT);
}
created = TRUE;
}
(void)pathcat(filnam, dirnam, bp->b_bname);
#else
(void)pathcat(filnam, dirnam,
strcat(strcpy(temp, "V"), bp->b_bname));
#endif
set_b_val(bp,MDVIEW,FALSE);
if (writeout(filnam,bp,TRUE,FALSE) != TRUE) {
tidy_exit(BADEXIT);
}
wrote++;
}
}
#if SYS_UNIX
if (wrote) {
const char **mailcmdp;
struct stat sb;
/* choose the first mail sender we can find.
it used to be you could rely on /bin/mail being
a simple mailer, but no more. and sendmail has
been moving around too. */
for (mailcmdp = mailcmds; *mailcmdp != 0; mailcmdp++) {
if (stat(*mailcmdp, &sb) == 0)
break;
}
if (*mailcmdp &&
((np = getenv("LOGNAME")) != 0 ||
(np = getenv("USER")) != 0)) {
#if HAVE_GETHOSTNAME
char hostname[128];
if (gethostname(hostname, sizeof(hostname)) < 0)
(void)strcpy(hostname, "unknown");
hostname[sizeof(hostname)-1] = EOS;
#endif
(void)lsprintf(cmd,
"( %s%s; %s; %s; %s%d; %s%s; %s%s; %s%s%s ) | %s %s",
"echo To: ", np,
"echo Subject: vile died, files saved",
"echo ",
"echo vile died due to signal ", signo,
#if HAVE_GETHOSTNAME
"echo on host ", hostname,
#else
"echo ", "",
#endif
"echo the following files were saved in directory ",
dirnam,
#if HAVE_MKDIR
/* reverse sort so '.' comes last, in case it
* terminates the mail message early */
"ls -a ", dirnam, " | sort -r",
#else
"ls ", dirnam, "/V*",
#endif
*mailcmdp, np);
(void)system(cmd);
}
}
if (signo > 2) {
ttclean(FALSE);
abort();
}
#else
if (wrote) {
fprintf(stderr, "vile died: Files saved in directory %s\n",
dirnam);
}
#endif
tidy_exit(wrote ? BADEXIT : GOODEXIT);
/* NOTREACHED */
SIGRET;
}
void
markWFMODE(BUFFER *bp)
{
register WINDOW *wp; /* scan for windows that need updating */
for_each_visible_window(wp) {
if (wp->w_bufp == bp)
wp->w_flag |= WFMODE;
}
}
#if OPT_ENCRYPT
int
resetkey( /* reset the encryption key if needed */
BUFFER *bp,
const char *fname)
{
register int s; /* return status */
/* turn off the encryption flag */
cryptflag = FALSE;
/* if we are in crypt mode */
if (b_val(bp, MDCRYPT)) {
char temp[NFILEN];
/* don't automatically inherit key from other buffers */
if (bp->b_key[0] != EOS
&& strcmp(lengthen_path(strcpy(temp, fname)), bp->b_fname)) {
char prompt[80];
(void)lsprintf(prompt,
"Use crypt-key from %s", bp->b_bname);
s = mlyesno(prompt);
if (s != TRUE)
return (s == FALSE);
}
/* make a key if we don't have one */
if (bp->b_key[0] == EOS) {
s = ue_makekey(bp->b_key, sizeof(bp->b_key));
if (s != TRUE)
return (s == FALSE);
}
/* let others know... */
cryptflag = TRUE;
/* and set up the key to be used! */
/* de-encrypt it */
ue_crypt((char *)0, 0);
ue_crypt(bp->b_key, strlen(bp->b_key));
/* re-encrypt it...seeding it to start */
ue_crypt((char *)0, 0);
ue_crypt(bp->b_key, strlen(bp->b_key));
}
return TRUE;
}
#endif