home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
x
/
xvisrc.zoo
/
alloc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
6KB
|
296 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)alloc.c 2.1 (Chris & John Downey) 7/29/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
alloc.c
* module function:
Various routines dealing with allocation
and deallocation of data structures.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
/*
* We use a special strategy for the allocation & freeing of Change
* structures to make these operations as fast as possible (since we
* have to allocate one for each input character in INSERT & REPLACE
* states).
*
* So we have a linked list of reusable Change structures; freeing a
* Change means just adding it to this list.
*/
static Change *chlist = NULL;
/*
* Free a Change structure. This just means adding it to our list of
* reusable structures, so a later request for an allocation of a
* Change can be satisfied very quickly from the front of the list.
*/
void
chfree(ch)
Change *ch;
{
ch->c_next = chlist;
chlist = ch;
}
Change *
challoc()
{
if (chlist) {
Change *ch;
ch = chlist;
chlist = chlist->c_next;
return ch;
}
return (Change *) alloc(sizeof (Change));
}
/*
* We also use a similar strategy for Line structures.
*/
static Line *lnlist = NULL;
char *
alloc(size)
unsigned size;
{
char *p; /* pointer to new storage space */
while ((p = malloc(size)) == NULL) {
/*
* No more memory in the heap, but we may be able to
* satisfy the request by recycling entries in one of
* our lists of reusable structures.
*/
if (lnlist) {
p = (char *) lnlist;
lnlist = lnlist->l_next;
free(p);
} else if (chlist) {
p = (char *) chlist;
chlist = chlist->c_next;
free(p);
} else {
/*
* No: we're out.
*/
show_error(curwin, "Not enough memory!");
break;
}
}
return(p);
}
char *
strsave(string)
const char *string;
{
char *space;
space = alloc((unsigned) strlen(string) + 1);
if (space != NULL)
(void) strcpy(space, string);
return(space);
}
/*
* Allocate and initialize a new line structure with room for
* 'nchars' characters.
*/
Line *
newline(nchars)
int nchars;
{
register Line *l;
char *ltp;
if (lnlist == NULL) {
register unsigned n;
/*
* To avoid memory fragmentation, we try to allocate a
* contiguous block of 100 Line structures if we
* haven't already got any.
*
* This means that, for every 100 lines of a file we
* read in, there should be a block of Line
* structures, which may never be freed, followed by
* a large arena for the lines' text and other sundry
* dynamically allocated objects, which generally will
* be.
*
* If we can't even get one structure, alloc() should
* print an error message. For subsequent ones, we use
* malloc() instead because it isn't necessarily a
* serious error if we can't get any more space than
* we've actually been asked for.
*/
if ((lnlist = (Line *) alloc(sizeof(Line))) == NULL) {
return(NULL);
}
lnlist->l_next = NULL;
for (n = 99; n != 0; n--) {
if ((l = (Line *) malloc(sizeof(Line))) == NULL) {
break;
}
l->l_next = lnlist;
lnlist = l;
}
}
/*
* Assertion: lnlist != NULL.
*/
l = lnlist;
lnlist = l->l_next;
/*
* It is okay for newline() to be called with a 0
* parameter - but we must never call malloc(0) as
* this will break on many systems.
*/
if (nchars == 0)
nchars = 1;
ltp = alloc((unsigned) nchars);
if (ltp == NULL) {
free((char *) l);
return(NULL);
}
ltp[0] = '\0';
l->l_text = ltp;
l->l_size = nchars;
l->l_prev = NULL;
l->l_next = NULL;
return(l);
}
/*
* bufempty() - return TRUE if the buffer is empty
*/
bool_t
bufempty(b)
Buffer *b;
{
return(buf1line(b) && b->b_file->l_text[0] == '\0');
}
/*
* buf1line() - return TRUE if there is only one line
*/
bool_t
buf1line(b)
Buffer *b;
{
return(b->b_file->l_next == b->b_lastline);
}
/*
* endofline() - return TRUE if the given position is at end of line
*
* This routine will probably never be called with a position resting
* on the zero byte, but handle it correctly in case it happens.
*/
bool_t
endofline(p)
Posn *p;
{
register char *endtext = p->p_line->l_text + p->p_index;
return(*endtext == '\0' || *(endtext + 1) == '\0');
}
/*
* grow_line(lp, n)
* - increase the size of the space allocated for the line by n bytes.
*
* This routine returns TRUE immediately if the requested space is available.
* If not, it attempts to allocate the space and adjust the data structures
* accordingly, and returns TRUE if this worked.
* If everything fails it returns FALSE.
*/
bool_t
grow_line(lp, n)
Line *lp;
register int n;
{
register int nsize;
register char *s; /* pointer to new space */
nsize = strlen(lp->l_text) + 1 + n; /* size required */
if (nsize <= lp->l_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) {
return(FALSE);
}
lp->l_size = nsize + SLOP;
(void) strcpy(s, lp->l_text);
free(lp->l_text);
lp->l_text = s;
return(TRUE);
}
/*
* Free up space used by the given list of lines.
*
* Note that the Line structures themselves are just added to the list
* of reusable ones.
*/
void
throw(lineptr)
Line *lineptr;
{
if (lineptr != NULL) {
Line *newlist;
newlist = lineptr;
for (;;) {
Line *nextline;
if (lineptr->l_text != NULL)
free(lineptr->l_text);
if ((nextline = lineptr->l_next) == NULL) {
/*
* We've reached the end of this list;
* join it on to lnlist ...
*/
lineptr->l_next = lnlist;
/*
* ... & point lnlist at the beginning
* of this list.
*/
lnlist = newlist;
return;
} else {
lineptr = nextline;
}
}
}
}