/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

void
filemess(s)
    char           *s;
{
    sprintf(IObuff, "\"%s\" %s", ((Filename == NULL) ? "" : Filename), s);
    msg(IObuff);
}

void
renum()
{
    LPtr           *p;
    unsigned long   l = 0;

    for (p = Filemem; p != NULL; p = nextline(p), l += LINEINC)
	p->linep->num = l;

    Fileend->linep->num = 0xffffffffL;
}

#ifdef	MEGAMAX
overlay "fileio"
#endif

bool_t
readfile(fname, fromp, nochangename)
    char           *fname;
    LPtr           *fromp;
    bool_t          nochangename;	/* if TRUE, don't change the Filename */
{
    FILE           *f, *fopen();
    LINE           *curr;
    char            buf2[80];
    int             c;
    int             IObuffsize = 0;
    long            nchars = 0;
    int             linecnt = 0;
    bool_t          wasempty = bufempty();
    int             nonascii = 0;	/* count garbage characters */
    int             nulls = 0;	/* count nulls */
    bool_t          incomplete = FALSE;	/* was the last line incomplete? */
    bool_t          toolong = FALSE;	/* a line was too long */

    curr = fromp->linep;

    if (!nochangename)
	Filename = strsave(fname);

    f = fopen(fname, "r");
    if (f == NULL)
	return TRUE;

    filemess("");

    do {
	c = getc(f);

	if (c == EOF) {
	    if (IObuffsize == 0)/* normal loop termination */
		break;

	    /*
	     * If we get EOF in the middle of a line, note the fact and
	     * complete the line ourselves. 
	     */
	    incomplete = TRUE;
	    c = NL;
	}
	if (c >= 0x80) {
	    c -= 0x80;
	    nonascii++;
	}
	/*
	 * If we reached the end of the line, OR we ran out of space for it,
	 * then process the complete line. 
	 */
	if (c == NL || IObuffsize == (IOSIZE - 1)) {
	    LINE           *lp;

	    if (c != NL)
		toolong = TRUE;

	    IObuff[IObuffsize++] = NUL;
	    if ((lp = newline(IObuffsize)) == NULL) {
		fprintf(stderr, "not enough memory - should never happen");
		getout(1);
	    }
	    strcpy(lp->s, IObuff);

	    curr->next->prev = lp;	/* new line to next one */
	    lp->next = curr->next;

	    curr->next = lp;	/* new line to prior one */
	    lp->prev = curr;

	    curr = lp;		/* new line becomes current */
	    IObuffsize = 0;
	    linecnt++;
	} else if (c == NUL) {
	    nulls++;		/* count and ignore nulls */
	} else {
	    IObuff[IObuffsize++] = (char) c;	/* normal character */
	}

	nchars++;
    } while (!incomplete && !toolong);

    fclose(f);

    /*
     * If the buffer was empty when we started, we have to go back and remove
     * the "dummy" line at Filemem and patch up the ptrs. 
     */
    if (wasempty && linecnt != 0) {
	LINE           *dummy = Filemem->linep;	/* dummy line ptr */

	free(dummy->s);		/* free string space */
	Filemem->linep = Filemem->linep->next;
	free((char *) dummy);	/* free LINE struct */
	Filemem->linep->prev = Filetop->linep;
	Filetop->linep->next = Filemem->linep;

	Curschar->linep = Filemem->linep;
	Topchar->linep = Filemem->linep;
    }
    renum();

    if (toolong) {
	sprintf(IObuff, "\"%s\" Line too long", fname);
	msg(IObuff);
	return FALSE;
    }
    sprintf(IObuff, "\"%s\" %s%d line%s, %ld character%s",
	    fname,
	    incomplete ? "[Incomplete last line] " : "",
	    linecnt, (linecnt > 1) ? "s" : "",
	    nchars, (nchars > 1) ? "s" : "");

    buf2[0] = NUL;

    if (nonascii || nulls) {
	if (nonascii) {
	    if (nulls)
		sprintf(buf2, " (%d null, %d non-ASCII)",
			nulls, nonascii);
	    else
		sprintf(buf2, " (%d non-ASCII)", nonascii);
	} else
	    sprintf(buf2, " (%d null)", nulls);
    }
    strcat(IObuff, buf2);
    msg(IObuff);

    return FALSE;
}

/*
 * writeit - write to file 'fname' lines 'start' through 'end' 
 *
 * If either 'start' or 'end' contain null line pointers, the default is to use
 * the start or end of the file respectively. 
 */
bool_t
writeit(fname, start, end)
    char           *fname;
    LPtr           *start, *end;
{
    FILE           *f, *fopen();
    FILE           *fopenb();	/* open in binary mode, where needed */
    char           *backup, *s;
    long            nchars;
    int             lines;
    LPtr           *p;

    sprintf(IObuff, "\"%s\"", fname);
    msg(IObuff);

    /*
     * Form the backup file name - change foo.* to foo.bak 
     */
    backup = alloc((unsigned) (strlen(fname) + 5));
    strcpy(backup, fname);
    for (s = backup; *s && *s != '.'; s++);
    *s = NUL;
    strcat(backup, ".bak");

    /*
     * Delete any existing backup and move the current version to the backup.
     * For safety, we don't remove the backup until the write has finished
     * successfully. And if the 'backup' option is set, leave it around. 
     */
    rename(fname, backup);

    f = P(P_CR) ? fopen(fname, "w") : fopenb(fname, "w");

    if (f == NULL) {
	emsg("Can't open file for writing!");
	free((char *) backup);
	return FALSE;
    }
    /*
     * If we were given a bound, start there. Otherwise just start at the
     * beginning of the file. 
     */
    if (start == NULL || start->linep == NULL)
	p = Filemem;
    else
	p = start;

    lines = 0;
    nchars = 0;
    do {
	fprintf(f, "%s\n", p->linep->s);
	nchars += strlen(p->linep->s) + 1;
	lines++;

	/*
	 * If we were given an upper bound, and we just did that line, then
	 * bag it now. 
	 */
	if (end != NULL && end->linep != NULL) {
	    if (end->linep == p->linep)
		break;
	}
    } while ((p = nextline(p)) != NULL);

    fclose(f);
    sprintf(IObuff, "\"%s\" %d line%s, %ld character%s", fname,
	    lines, (lines > 1) ? "s" : "",
	    nchars, (nchars > 1) ? "s" : "");
    msg(IObuff);
    UNCHANGED;

    /*
     * Remove the backup unless they want it left around 
     */
    if (!P(P_BK))
	remove(backup);

    free((char *) backup);

    return TRUE;
}
