466 lines
12 KiB
C
466 lines
12 KiB
C
/* This file is in the public domain. */
|
|
|
|
/*
|
|
* The routines in this file handle the reading and writing of disk files.
|
|
* All details about the reading and writing of the disk are in "fileio.c"
|
|
*/
|
|
|
|
#include <string.h> /* strncpy(3) */
|
|
#include "estruct.h"
|
|
#include "edef.h"
|
|
|
|
extern int mlreply(char *prompt, char *buf, int nbuf);
|
|
extern int swbuffer(BUFFER *bp);
|
|
extern void mlwrite();
|
|
extern int bclear(BUFFER *bp);
|
|
extern int ffropen(char *fn);
|
|
extern int ffgetline(char buf[], int nbuf);
|
|
extern int ffwopen(char *fn);
|
|
extern int ffclose();
|
|
extern int ffputline(char buf[], int nbuf);
|
|
extern BUFFER *bfind();
|
|
extern LINE *lalloc();
|
|
|
|
int fileread(int f, int n);
|
|
int insfile(int f, int n);
|
|
int filefind(int f, int n);
|
|
int getfile(char fname[]);
|
|
int readin(char fname[]);
|
|
void makename(char bname[], char fname[]);
|
|
int filewrite(int f, int n);
|
|
int filesave(int f, int n);
|
|
int writeout(char *fn);
|
|
int filename(int f, int n);
|
|
int ifile(char fname[]);
|
|
|
|
/*
|
|
* 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. Bound to "C-X C-R"
|
|
*/
|
|
int fileread(int f, int n)
|
|
{
|
|
int s;
|
|
char fname[NFILEN];
|
|
|
|
if ((s = mlreply("Read file: ", fname, NFILEN)) != TRUE)
|
|
return (s);
|
|
return (readin(fname));
|
|
}
|
|
|
|
/*
|
|
* 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. Bound to "C-X C-I".
|
|
*/
|
|
int insfile(int f, int n)
|
|
{
|
|
int s;
|
|
char fname[NFILEN];
|
|
|
|
if ((s = mlreply("Insert file: ", fname, NFILEN)) != TRUE)
|
|
return (s);
|
|
return (ifile(fname));
|
|
}
|
|
|
|
/*
|
|
* Select a file for editing. Look around to see if you can find the fine 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. Bound to C-X C-F.
|
|
*/
|
|
int filefind(int f, int n)
|
|
{
|
|
char fname[NFILEN]; /* file user wishes to find */
|
|
int s; /* status return */
|
|
|
|
if ((s = mlreply("Find file: ", fname, NFILEN)) != TRUE)
|
|
return (s);
|
|
return (getfile(fname));
|
|
}
|
|
|
|
int getfile(char fname[])
|
|
{
|
|
BUFFER *bp;
|
|
LINE *lp;
|
|
char bname[NBUFN]; /* buffer name to put file */
|
|
int i, s;
|
|
|
|
for (bp = bheadp; bp != (BUFFER*)0; bp = bp->b_bufp)
|
|
{
|
|
if ((bp->b_flag & BFTEMP) == 0 && strcmp(bp->b_fname, fname) == 0)
|
|
{
|
|
if (--curbp->b_nwnd == 0)
|
|
{
|
|
curbp->b_dotp = curwp->w_dotp;
|
|
curbp->b_doto = curwp->w_doto;
|
|
curbp->b_markp = curwp->w_markp;
|
|
curbp->b_marko = curwp->w_marko;
|
|
}
|
|
swbuffer(bp);
|
|
lp = curwp->w_dotp;
|
|
i = curwp->w_ntrows / 2;
|
|
while (i-- && lback(lp) != curbp->b_linep)
|
|
lp = lback(lp);
|
|
curwp->w_linep = lp;
|
|
curwp->w_flag |= WFMODE | WFHARD;
|
|
mlwrite("[Old buffer]");
|
|
return (TRUE);
|
|
}
|
|
}
|
|
makename(bname, fname); /* New buffer name */
|
|
while ((bp = bfind(bname, FALSE, 0)) != (BUFFER*)0)
|
|
{
|
|
s = mlreply("Buffer name: ", bname, NBUFN);
|
|
if (s == ABORT) /* ^G to just quit */
|
|
return (s);
|
|
if (s == FALSE)
|
|
{ /* CR to clobber it */
|
|
makename(bname, fname);
|
|
break;
|
|
}
|
|
}
|
|
if (bp == (BUFFER*)0 && (bp = bfind(bname, TRUE, 0)) == (BUFFER*)0)
|
|
{
|
|
mlwrite("Cannot create buffer");
|
|
return (FALSE);
|
|
}
|
|
if (--curbp->b_nwnd == 0)
|
|
{ /* Undisplay */
|
|
curbp->b_dotp = curwp->w_dotp;
|
|
curbp->b_doto = curwp->w_doto;
|
|
curbp->b_markp = curwp->w_markp;
|
|
curbp->b_marko = curwp->w_marko;
|
|
}
|
|
curbp = bp; /* Switch to it */
|
|
curwp->w_bufp = bp;
|
|
curbp->b_nwnd++;
|
|
return (readin(fname)); /* Read it in */
|
|
}
|
|
|
|
/*
|
|
* Read file "fname" into the current buffer, blowing away any text found
|
|
* there. Called by both the read and find commands. Return the final status
|
|
* of the read. Also called by the mainline, to read in a file specified on
|
|
* the command line as an argument.
|
|
*/
|
|
int readin(char fname[])
|
|
{
|
|
LINE *lp1, *lp2;
|
|
WINDOW *wp;
|
|
BUFFER *bp;
|
|
char line[NLINE];
|
|
int nbytes, s, i;
|
|
int nline = 0; /* initialize here to silence a gcc warning */
|
|
int lflag; /* any lines longer than allowed? */
|
|
|
|
bp = curbp; /* Cheap */
|
|
if ((s = bclear(bp)) != TRUE) /* Might be old */
|
|
return (s);
|
|
bp->b_flag &= ~(BFTEMP | BFCHG);
|
|
strncpy(bp->b_fname, fname, NFILEN);
|
|
if ((s = ffropen(fname)) == FIOERR) /* Hard file open */
|
|
goto out;
|
|
if (s == FIOFNF)
|
|
{ /* File not found */
|
|
mlwrite("[New file]");
|
|
goto out;
|
|
}
|
|
mlwrite("[Reading file]");
|
|
lflag = FALSE;
|
|
while ((s = ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG)
|
|
{
|
|
if (s == FIOLNG)
|
|
lflag = TRUE;
|
|
nbytes = strlen(line);
|
|
if ((lp1 = lalloc(nbytes)) == NULL)
|
|
{
|
|
s = FIOERR; /* Keep message on the display */
|
|
break;
|
|
}
|
|
lp2 = lback(curbp->b_linep);
|
|
lp2->l_fp = lp1;
|
|
lp1->l_fp = curbp->b_linep;
|
|
lp1->l_bp = lp2;
|
|
curbp->b_linep->l_bp = lp1;
|
|
for (i = 0; i < nbytes; ++i)
|
|
lputc(lp1, i, line[i]);
|
|
++nline;
|
|
}
|
|
ffclose(); /* Ignore errors */
|
|
if (s == FIOEOF)
|
|
{ /* Don't zap message! */
|
|
if (nline != 1)
|
|
mlwrite("[Read %d lines]", nline);
|
|
else
|
|
mlwrite("[Read 1 line]");
|
|
}
|
|
if (lflag)
|
|
{
|
|
if (nline != 1)
|
|
mlwrite("[Read %d lines: Long lines wrapped]", nline);
|
|
else
|
|
mlwrite("[Read 1 line: Long lines wrapped]");
|
|
}
|
|
curwp->w_bufp->b_lines = nline;
|
|
out:
|
|
for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
|
|
{
|
|
if (wp->w_bufp == curbp)
|
|
{
|
|
wp->w_linep = lforw(curbp->b_linep);
|
|
wp->w_dotp = lforw(curbp->b_linep);
|
|
wp->w_doto = 0;
|
|
wp->w_markp = NULL;
|
|
wp->w_marko = 0;
|
|
wp->w_flag |= WFMODE | WFHARD;
|
|
}
|
|
}
|
|
if (s == FIOERR || s == FIOFNF) /* False if error */
|
|
return (FALSE);
|
|
return (TRUE);
|
|
}
|
|
|
|
/*
|
|
* Take a 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[], char fname[])
|
|
{
|
|
char *cp1, *cp2;
|
|
|
|
cp1 = &fname[0];
|
|
while (*cp1 != 0)
|
|
++cp1;
|
|
|
|
while (cp1 != &fname[0] && cp1[-1] != '/')
|
|
--cp1;
|
|
cp2 = &bname[0];
|
|
while (cp2 != &bname[NBUFN - 1] && *cp1 != 0 && *cp1 != ';')
|
|
*cp2++ = *cp1++;
|
|
*cp2 = 0;
|
|
}
|
|
|
|
/*
|
|
* Ask for a file name, and write the contents of the current buffer to that
|
|
* file. Update the remembered file name and clear the buffer changed flag.
|
|
* This handling of file names is different from the earlier versions, and is
|
|
* more compatable with Gosling EMACS than with ITS EMACS. Bound to "C-X C-W".
|
|
*/
|
|
int filewrite(int f, int n)
|
|
{
|
|
WINDOW *wp;
|
|
char fname[NFILEN];
|
|
int s;
|
|
|
|
if ((s = mlreply("Write file: ", fname, NFILEN)) != TRUE)
|
|
return (s);
|
|
if ((s = writeout(fname)) == TRUE)
|
|
{
|
|
strncpy(curbp->b_fname, fname, NFILEN);
|
|
curbp->b_flag &= ~BFCHG;
|
|
wp = wheadp; /* Update mode lines */
|
|
while (wp != NULL)
|
|
{
|
|
if (wp->w_bufp == curbp)
|
|
wp->w_flag |= WFMODE;
|
|
wp = wp->w_wndp;
|
|
}
|
|
}
|
|
return (s);
|
|
}
|
|
|
|
/*
|
|
* Save the contents of the current buffer in its associatd file. No nothing
|
|
* if nothing has changed (this may be a bug, not a feature). Error if there
|
|
* is no remembered file name for the buffer. Bound to "C-X C-S". May get
|
|
* called by "C-Z"
|
|
*/
|
|
int filesave(int f, int n)
|
|
{
|
|
WINDOW *wp;
|
|
int s;
|
|
|
|
if ((curbp->b_flag & BFCHG) == 0) /* Return, no changes */
|
|
return (TRUE);
|
|
if (curbp->b_fname[0] == 0)
|
|
{ /* Must have a name */
|
|
mlwrite("No file name");
|
|
return (FALSE);
|
|
}
|
|
if ((s = writeout(curbp->b_fname)) == TRUE)
|
|
{
|
|
curbp->b_flag &= ~BFCHG;
|
|
wp = wheadp; /* Update mode lines */
|
|
while (wp != NULL)
|
|
{
|
|
if (wp->w_bufp == curbp)
|
|
wp->w_flag |= WFMODE;
|
|
wp = wp->w_wndp;
|
|
}
|
|
}
|
|
return (s);
|
|
}
|
|
|
|
/*
|
|
* This function performs the details of file writing. Uses the file
|
|
* management routines in the "fileio.c" package. The number of lines written
|
|
* is displayed. Sadly, it looks inside a LINE; provide a macro for this. Most
|
|
* of the grief is error checking of some sort.
|
|
*/
|
|
int writeout(char *fn)
|
|
{
|
|
LINE *lp;
|
|
int nline, s;
|
|
|
|
if ((s = ffwopen(fn)) != FIOSUC) /* Open writes message */
|
|
return (FALSE);
|
|
mlwrite("[Writing]"); /* tell us were writing */
|
|
lp = lforw(curbp->b_linep); /* First line */
|
|
nline = 0; /* Number of lines */
|
|
while (lp != curbp->b_linep)
|
|
{
|
|
if ((s = ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
|
|
break;
|
|
++nline;
|
|
lp = lforw(lp);
|
|
}
|
|
if (s == FIOSUC)
|
|
{ /* No write error */
|
|
s = ffclose();
|
|
if (s == FIOSUC)
|
|
{ /* No close error */
|
|
if (nline != 1)
|
|
mlwrite("[Wrote %d lines]", nline);
|
|
else
|
|
mlwrite("[Wrote 1 line]");
|
|
}
|
|
}
|
|
else /* ignore close error */
|
|
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.
|
|
*/
|
|
int filename(int f, int n)
|
|
{
|
|
WINDOW *wp;
|
|
char fname[NFILEN];
|
|
int s;
|
|
|
|
if ((s = mlreply("Name: ", fname, NFILEN)) == ABORT)
|
|
return (s);
|
|
if (s == FALSE)
|
|
strncpy(curbp->b_fname, "", 1);
|
|
else
|
|
strncpy(curbp->b_fname, fname, NFILEN);
|
|
wp = wheadp; /* update mode lines */
|
|
while (wp != NULL)
|
|
{
|
|
if (wp->w_bufp == curbp)
|
|
wp->w_flag |= WFMODE;
|
|
wp = wp->w_wndp;
|
|
}
|
|
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[])
|
|
{
|
|
LINE *lp0, *lp1, *lp2;
|
|
BUFFER *bp;
|
|
char line[NLINE];
|
|
int i, s, nbytes;
|
|
int nline = 0;
|
|
int lflag; /* any lines longer than allowed? */
|
|
|
|
bp = curbp; /* Cheap */
|
|
bp->b_flag |= BFCHG; /* we have changed */
|
|
bp->b_flag &= ~BFTEMP; /* and are not temporary */
|
|
if ((s = ffropen(fname)) == FIOERR) /* Hard file open */
|
|
goto out;
|
|
if (s == FIOFNF)
|
|
{ /* File not found */
|
|
mlwrite("[No such file]");
|
|
return (FALSE);
|
|
}
|
|
mlwrite("[Inserting file]");
|
|
|
|
/* back up a line and save the mark here */
|
|
curwp->w_dotp = lback(curwp->w_dotp);
|
|
curwp->w_doto = 0;
|
|
curwp->w_markp = curwp->w_dotp;
|
|
curwp->w_marko = 0;
|
|
|
|
lflag = FALSE;
|
|
while ((s = ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG)
|
|
{
|
|
if (s == FIOLNG)
|
|
lflag = TRUE;
|
|
nbytes = strlen(line);
|
|
if ((lp1 = lalloc(nbytes)) == NULL)
|
|
{
|
|
s = FIOERR; /* keep message on the */
|
|
break; /* display */
|
|
}
|
|
lp0 = curwp->w_dotp; /* line previous to insert */
|
|
lp2 = lp0->l_fp; /* line after insert */
|
|
|
|
/* re-link new line between lp0 and lp2 */
|
|
lp2->l_bp = lp1;
|
|
lp0->l_fp = lp1;
|
|
lp1->l_bp = lp0;
|
|
lp1->l_fp = lp2;
|
|
|
|
/* and advance and write out the current line */
|
|
curwp->w_dotp = lp1;
|
|
for (i = 0; i < nbytes; ++i)
|
|
lputc(lp1, i, line[i]);
|
|
++nline;
|
|
}
|
|
ffclose(); /* Ignore errors */
|
|
curwp->w_markp = lforw(curwp->w_markp);
|
|
if (s == FIOEOF)
|
|
{ /* Don't zap message! */
|
|
if (nline != 1)
|
|
mlwrite("[Inserted %d lines]", nline);
|
|
else
|
|
mlwrite("[Inserted 1 line]");
|
|
}
|
|
if (lflag)
|
|
{
|
|
if (nline != 1)
|
|
mlwrite("[Inserted %d lines: Long lines wrapped]", nline);
|
|
else
|
|
mlwrite("[Inserted 1 line: Long lines wrapped]");
|
|
}
|
|
out:
|
|
/* advance to the next line and mark the window for changes */
|
|
curwp->w_dotp = lforw(curwp->w_dotp);
|
|
curwp->w_flag |= WFHARD;
|
|
|
|
/* copy window parameters back to the buffer structure */
|
|
curbp->b_dotp = curwp->w_dotp;
|
|
curbp->b_doto = curwp->w_doto;
|
|
curbp->b_markp = curwp->w_markp;
|
|
curbp->b_marko = curwp->w_marko;
|
|
|
|
/* we need to update number of lines in the buffer */
|
|
curwp->w_bufp->b_lines += nline;
|
|
|
|
if (s == FIOERR) /* False if error */
|
|
return (FALSE);
|
|
return (TRUE);
|
|
}
|