/*
 * 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"

/*
 * This file contains various routines dealing with allocation and
 * deallocation of data structures. 
 */

char           *
alloc(size)
    unsigned        size;
{
    char           *p;		/* pointer to new storage space */

    p = malloc(size);
    if (p == (char *) NULL) {	/* if there is no more room... */
	emsg("alloc() is unable to find memory!");
    }
    return (p);
}

char           *
strsave(string)
    char           *string;
{
    return (strcpy(alloc((unsigned) (strlen(string) + 1)), string));
}

void
screenalloc()
{
    /*
     * If we're changing the size of the screen, free the old arrays 
     */
    if (Realscreen != NULL)
	free(Realscreen);
    if (Nextscreen != NULL)
	free(Nextscreen);

    Realscreen = malloc((unsigned) (Rows * Columns));
    Nextscreen = malloc((unsigned) (Rows * Columns));
}

/*
 * Allocate and initialize a new line structure with room for 'nchars'
 * characters. 
 */
LINE           *
newline(nchars)
    int             nchars;
{
    LINE           *l;

    l = (LINE *) alloc((unsigned) sizeof(LINE));
    if (l == NULL)
	return (LINE *) NULL;

    l->s = alloc((unsigned) nchars);	/* the line is empty */
    l->s[0] = NUL;
    l->size = nchars;

    l->prev = (LINE *) NULL;	/* should be initialized by caller */
    l->next = (LINE *) NULL;

    return l;
}

/*
 * filealloc() - construct an initial empty file buffer 
 */
void
filealloc()
{
    if ((Filemem->linep = newline(1)) == NULL) {
	fprintf(stderr, "Unable to allocate file memory!\n");
	getout(1);
    }
    if ((Fileend->linep = newline(1)) == NULL) {
	fprintf(stderr, "Unable to allocate file memory!\n");
	getout(1);
    }
    Filemem->index = 0;
    Fileend->index = 0;

    Filemem->linep->next = Fileend->linep;
    Fileend->linep->prev = Filemem->linep;

    *Curschar = *Filemem;
    *Topchar = *Filemem;

    Filemem->linep->num = 0;
    Fileend->linep->num = 0xffff;

    clrall();			/* clear all marks */
}

/*
 * freeall() - free the current buffer 
 *
 * Free all lines in the current buffer. 
 */
void
freeall()
{
    LINE           *lp, *xlp;

    for (lp = Filemem->linep; lp != NULL; lp = xlp) {
	if (lp->s != NULL)
	    free(lp->s);
	xlp = lp->next;
	free((char *) lp);
    }

    Curschar->linep = NULL;	/* clear pointers */
    Filemem->linep = NULL;
    Fileend->linep = NULL;
}

/*
 * canincrease(n) - returns TRUE if the current line can be increased 'n'
 * bytes 
 *
 * This routine returns immediately if the requested space is available. If not,
 * it attempts to allocate the space and adjust the data structures
 * accordingly. If everything fails it returns FALSE. 
 */
bool_t
canincrease(n)
    int             n;
{
    int             nsize;
    char           *s;		/* pointer to new space */

    nsize = strlen(Curschar->linep->s) + 1 + n;	/* size required */

    if (nsize <= Curschar->linep->size)
	return TRUE;

    /*
     * Need to allocate more space for the string. Allow some extra space on
     * the assumption that we may need it soon. This avoids excessive numbers
     * of calls to malloc while entering new text. 
     */
    s = alloc((unsigned) (nsize + SLOP));
    if (s == NULL) {
	emsg("Can't add anything, file is too big!");
	State = NORMAL;
	return FALSE;
    }
    Curschar->linep->size = nsize + SLOP;
    strcpy(s, Curschar->linep->s);
    free(Curschar->linep->s);
    Curschar->linep->s = s;

    return TRUE;
}
