/*
 *				v s t r i n g . c
 */

/*)LIBRARY
*/

#ifdef	DOCUMENTATION

title	vstring	Functions to Manipulate Vstrings
index		Create a new vstring
index		Add a character to a vstring
index		Add a string to a vstring
index		Free a vstring

synopsis

	 #ifdef vms
	 #include "c:vstrin.h"
	 #else
	 #include <vstrin.h>
	 #endif

	 VSTRING *
	 vstring(dim,ext)
	 unsigned dim;
	 unsigned ext;

	 VSTRING *
	 vsaddc(pv,c)
	 VSTRING *pv;
	 char c;

	 VSTRING *
	 vsadds(pv,s)
	 VSTRING *pv;
	 char *s;

	 vsfree(pv)
	 VSTRING *pv;

description

	Vstrings are dynamically expandable strings.  They have room for some
	fixed number of characters, but can grow, obtaining memory through
	malloc(), if necessary.

	vstring(dim,ext) returns a pointer to a new vstring, or NULL if there
	is no space for one.  The vstring initially has room for dim bytes,
	and will grow by ext bytes if it fills.

	vsaddc() adds a character to a vstring.

	vsadds() adds a string to a vstring.  It merely calls vsaddc() in a
	loop. The trailing EOS is NOT added.	

	Both vsaddc() and vsadds() return NULL if the vstring would have had
	to grow but couldn't due to lack of memory or a zero growth quantum.
	In this case, the data in the vstring is lost and the vstring itself
	is marked damaged and cannot be used again; further attempts always
	return NULL.

	If all went well, the vstring's address as passed is returned.

	It is occassionally necessary to recover the information in a damaged
	vstring (in most cases, there is no reasonable way to continue once
	the program runs out of memory).  This can be done by making use of
	realloc()'s ability to reallocate the most recently freed block of
	core.  Before making the potentially damaging call, save the current
	values of the vsdata and vsused elements of the vstring.  Should the
	vstring become damaged, the vsdata value can be passed to realloc()
	safely.  Note that this recovers the data, but not the vstring's
	header; you still cannot apply any of the vstring-handling functions
	to it.

	vsfree() frees a vstring.  Attempting to free something that was not
	created with vstring() will cause trouble.  However, NULL or a vstring
	that was filled and marked damaged may be safely passed.

bugs

	A vstring is a special case of a flex which always has an item size
	of 1 byte.  It is convenient to maintain it as a separate data type
	because the kinds of operations done on the two differ.  For example,
	fxadd() takes the address of the item to add; vsaddc() takes the
	character itself, which is often more convenient.  The basic set of
	functions provided for vstrings is more limited; perhaps more purely
	string-oriented functions that work on vstrings will be defined later.

author

	Jerry Leichter

#endif

/*
 *)EDITLEVEL=10
 * Edit history
 * 0.0 28-Apr-81 JSL	Invention
 * 0.1  4-May-81 JSL	Better error handling
 * 0.2 12-May-81 JSL	Decided to keep blocks around after all; changed the
 *			name of balloc() to block() to match flex().
 * 0.3 23-Jun-81 JSL	Conversion to the new documentation conventions.
 * 1.0 26-Jun-81 JSL	Changed block to vstring, which makes more sense.
 * 1.1 29-Jun-81 JSL	More name changes; get consistent with flexes.
 */

#ifdef	vms
#include "c:vstrin.h"
#else
#include <vstrin.h>
#endif
#define NULL 0

extern char *malloc(), *realloc();

VSTRING *
vstring(dim,ext)
unsigned dim;		/* initial size for this vstring */
unsigned ext;		/* growth quantum */
{	register VSTRING *pv;
	if ((pv = (VSTRING *)malloc(sizeof(VSTRING))) == NULL)
		return(NULL);
	if ((pv->vsdata = malloc(dim)) == NULL)
	{	free(pv);
		return(NULL);
	}
	pv->vsdim = dim;
	pv->vsext = ext;
	pv->vslen = 0;
	return(pv);
}	

VSTRING *
vsaddc(pv,c)
register VSTRING *pv;
char c;
{
	if (pv != NULL)
	{	if (pv->vsdim <= pv->vslen)
		{	pv->vsdim += pv->vsext;
			if (pv->vsdim <= pv->vslen
			|| pv->vsdata == NULL
			|| (pv->vsdata = realloc(pv->vsdata,pv->vsdim))
				== NULL)
			{	pv->vsdim = 0;
				return(pv->vsdata = NULL);
			}
		}
		(pv->vsdata)[pv->vslen++] = c;
	}
	return(pv);
}

VSTRING *
vsadds(pv,s)
register VSTRING *pv;
register char *s;
{	while (*s)
		pv = vsaddc(pv,*s++);
	return(pv);
}

vsfree(pv)
register VSTRING *pv;
{	if (pv != NULL)
	{	if (pv->vsdata != NULL)
			free(pv->vsdata);
		free(pv);
	}
}
