home *** CD-ROM | disk | FTP | other *** search
- /*
- varray.c 1/10/88
-
- % 'virtual smart' array functions
-
- thought of by Joe DeSantis.
- fleshed out by Ted Peck.
-
- OWL 1.1
- Copyright (c) 1986, 1987, 1988, by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
-
- Revision History:
- -----------------
- 4/05/88 Ted Added VOID *'s, prototype arg names, initialization
- 4/18/88 Ted Added free element/next element handling
- */
-
- /* -------------------------------------------------------------------------- */
- #include "oakhead.h"
- #include "vadecl.h"
-
- OSTATIC void OWLPRIV va_clearout(_arg3(varray, va_index, unsigned));
- /* -------------------------------------------------------------------------- */
-
- varray va_make(nelem, elemsize, clearelem, inuse, tag)
- unsigned nelem; /* Starting guess for varray size */
- unsigned elemsize; /* Size of individual varray element */
- VOID *clearelem; /* Pointer to sample clear element; may be NULL */
- boolean inuse; /* Flag to initialize elements as in use */
- va_tag tag; /* Tag to tag initial elements with */
- /*
- Creates a virtual array. Each element is elemsize bytes.
- Creates a local copy of clearelem if it is given, so its contents are frozen
- at the time of the call here.
- */
- {
- varray va;
-
- /* Each element gets this little structure tacked on */
- elemsize += sizeof(vae_struct);
-
- if (nelem > UINT_MAX / elemsize) {
- oak_SetErrno(OA_VARRAY);
- return(NULL);
- }
-
- /* Allocate 'va' structure */
- if ((va = (varray) omalloc(OA_VARRAY, sizeof(struct varray_struct))) == NULL) {
- return(NULL);
- }
- /* Allocate the array */
- if ((va->array = (byte *) omalloc(OA_VARRAY, nelem * elemsize)) == NULL) {
- ofree(OA_VARRAY, va);
- return(NULL);
- }
-
- /* Set the element info */
- va->nelem = nelem;
- va->elemsize = elemsize;
-
- /* If elements initialized to non-free value set hint to end of list */
- if (inuse) va->hint = va_nelem(va);
- else va->hint = 0;
-
- if (clearelem == NULL && inuse == 0 && tag == 0) {
- va->clearelem = NULL;
- }
- else {
- /* Allocate private copy of the sample clear element */
- if ((va->clearelem = omalloc(OA_VARRAY, va_inesize(va))) == NULL) {
- ofree(OA_VARRAY, va->array);
- ofree(OA_VARRAY, va);
- return NULL;
- }
- /* If no sample clear element is given, just clear to 0's */
- if (clearelem == NULL) {
- memset(va_clearelem(va), 0, va_elemsize(va));
- }
- else {
- memcpy(va_clearelem(va), clearelem, va_elemsize(va));
- }
- /* Set up sample free flag and tag */
- va_seteleminuse(va, va_clearelem(va), inuse);
- va_setelemtag(va, va_clearelem(va), tag);
- }
- va_clearout(va, 0, va_nelem(va));
-
- /* If no sample element was passed, free our temporary one */
- if (clearelem == NULL && tag == 0 && inuse == 0 && va_clearelem(va) != NULL) {
- ofree(OA_VARRAY, va_clearelem(va));
- va->clearelem = NULL;
- }
- return(va);
- }
- /* -------------------------------------------------------------------------- */
- void va_free(va)
- varray va;
- /*
- Destroy a virtual array.
- */
- {
- if (va != NULL) {
- if (va_clearelem(va) != NULL) {
- ofree(OA_VARRAY, va_clearelem(va));
- }
- if (va_array(va) != NULL) {
- ofree(OA_VARRAY, va_array(va));
- }
- ofree(OA_VARRAY, va);
- }
- }
- /* -------------------------------------------------------------------------- */
- VOID *va_put(va, index, elem)
- varray va;
- va_index index;
- VOID *elem;
- /*
- Copies elem into array. Resizes array if not large enough.
- Returns location of elem or NULL if failed.
- */
- {
- byte *eptr;
-
- if (index >= va_nelem(va)) {
- va_expand(va, index);
- }
- /* Put data into array */
- eptr = va_elem(va, index);
- if (elem) {
- memmove(eptr, elem, va_elemsize(va));
- }
- return((VOID *)eptr);
- }
- /* -------------------------------------------------------------------------- */
- unsigned va_clear(va, index, nelem)
- varray va;
- va_index index;
- unsigned nelem;
- /*
- Clear out nelem elements of the varray, starting at index.
- If the varray must be extended to include all the elements that
- are to be cleared, so be it.
- Returns the number of elements in the varray when all is done.
- */
- {
- /* If trying to clear past end of array, expand array */
- if (index + nelem > va_nelem(va)) {
- va_clearout(va, index, va_nelem(va) - index);
- va_expand(va, index + nelem);
- }
- else va_clearout(va, index, nelem);
-
- return(va_nelem(va));
- }
- /* -------------------------------------------------------------------------- */
- void va_freeelem(va, index)
- varray va;
- va_index index;
- /*
- Set a varray element's free flag.
- */
- {
- va_setfree(va, index, TRUE);
- if (index < va_hint(va)) {
- va->hint = index;
- }
- }
- /* -------------------------------------------------------------------------- */
- va_index va_findfree(va)
- varray va;
- /*
- Return first found free varray element.
- */
- {
- va_index index;
- unsigned maxelem;
-
- maxelem = va_nelem(va);
-
- /* Search from current hint ptr towards end of varray */
- for (index = va_hint(va); index < maxelem; index++) {
- if (va_isfree(va, index)) {
- goto FOUNDELEM;
- }
- }
- /* If we got to the end of the array, expand the array */
- if (va_put(va, index, va_clearelem(va)) == NULL) {
- return(NOID);
- }
- FOUNDELEM:
- /* Set flag for element in use */
- va_setfree(va, index, FALSE);
-
- va->hint = index+1;
- return(index);
- }
- /* -------------------------------------------------------------------------- */
- va_index va_getnext(va, tagspec, indexp, key)
- varray va;
- va_tag tagspec;
- va_index *indexp;
- va_key key;
- /*
- Return the index of the next nonfree element in the varray to *indexp.
- Only returns elements whose tag matches 'tagspec'. 0 tagspec matches any.
- Return value is key to be passed to next request.
- */
- {
- va_index lastelem;
-
- for (key++, lastelem = va_nelem(va); key < lastelem; key++) {
- if (!va_isfree (va, key)){
- if (tagspec == 0 || va_gettag(va, key) == tagspec) {
- *indexp = key;
- return(key);
- }
- }
- }
- *indexp = NOID;
- return(0);
- }
- /* -------------------------------------------------------------------------- */
- unsigned va_expand(va, index)
- varray va;
- va_index index;
- /*
- Resize the varray big enough to hold index.
- Returns the number of elements added.
- */
- {
- unsigned nelem, max_size;
- byte *narray;
-
- max_size = UINT_MAX / va_elemsize(va);
-
- if (index >= max_size) {
- return(0);
- }
- nelem = (va_nelem(va) + index < max_size) ?
- va_nelem(va) + index : max_size;
-
- narray = (byte *)orealloc(OA_VARRAY, va_array(va), nelem * va_inesize(va));
- if (narray == NULL) {
- return(0);
- }
- else va->array = narray;
-
- index = va_nelem(va);
- va->nelem = nelem;
-
- nelem -= index;
- va_clearout(va, index, nelem);
-
- return(nelem);
- }
- /* -------------------------------------------------------------------------- */
-
- static void OWLPRIV va_clearout(va, index, nelem)
- varray va;
- va_index index;
- unsigned nelem;
- /*
- Clear out nelem elements of the varray, starting at index.
- If any elements that are to be cleared are not in the array at its current
- size, they are ignored.
- */
- {
- byte *eptr;
-
- if (index > va_nelem(va)) {
- return;
- }
- if (index + nelem > va_nelem(va)) {
- nelem = va_nelem(va) - index;
- }
-
- eptr = va_elem(va, index);
-
- if (va_clearelem(va) == NULL) {
- /* If no sample clear element is given, just clear to 0's */
- /* (set inuse to FALSE and tag to 0 for all new elements) */
- memset(eptr, 0, nelem * va_inesize(va));
- }
- else {
- for ( ; nelem > 0; nelem--, eptr += va_inesize(va)) {
- memcpy(eptr, va_clearelem(va), va_inesize(va));
- }
- }
- if (va_isfree(va, index)) {
- if (index < va_hint(va)) {
- va->hint = index;
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
-