/* * Copyright (c) 1993-1995 Vectaport Inc. * Copyright (c) 1989 Triple Vision, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the names of the copyright holders not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. The copyright holders make no * representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* MBLOCK.C Allocate a memory block and return a unique identifier. Externals: Summary: Functions to support memory allocation and return unique integer identifiers to be used to point to the block. The identifier allows the memory block to be moved but still have the same identifier. A pointer to the start of the block would not be guaranteed to point always to the same place. History: Written by Robert C. Fitch, 26 Aug 1989 */ #include #include "comutil.ci" /* comutil.ci includes stdlib.h and malloc.h */ #ifndef DMM_OFF /* This contains all information for an open mblock */ typedef struct { unsigned nel; /* number of elements in the block */ unsigned size; /* size of the element in bytes */ /* 0 size means this id cell is available */ char *head; /* pointer to the start of the block */ } mblock; /* some pointers for the different open mblocks */ static mblock *mblock_head,*mblock_curr; /* updatable pointers */ static int nmblocks=0; /* number of lists in mblock id array */ /* this makes sure an id is valid and the entry has an allocated mem block */ #define CHECKID {\ if(id < 0 || id >= nmblocks) goto error_return;\ mblock_curr=mblock_head+id;\ if(mblock_curr->size == 0) goto error_return; } /*! mblock_open Open a memory block of specified size. Summary: #include */ int mblock_open (unsigned nel,unsigned size) /*! Return Value: != -1 identifier for this mblock structure, -1 if insufficient memory. Parameters: Type Name IO Description ------------ ----------- -- ----------- */ #ifdef DOC unsigned nel ;/* I number of elements to allocate */ unsigned size ;/* I number of bytes per element */ #endif #ifdef DOC /*! Description: Allocates an area of memory (using the dmm_calloc() function) and returns a unique integer identifier that can be used to reference the starting address of the memory block. NOTE: it is ok to specify a memory block with `nel` of zero and increase its size later using mblock_resize(), but the `size` must always be greater than zero. See Also: mblock_close(), mblock_pntr(), mblock_resize(). Example: main() { int id1, id2 char *pntr1; int *pntr2; unsigned nel; unsigned long nbytes1,nbytes2; extern void *mblock_pntr(); /* open a memory block with 2000 bytes in it */ if ( (id1 = mblock_open(2000,sizeof(char))) == -1) { fprintf(stderr,"Couldn't open memory block #1\n"); return(-1); } /* open a 2nd memory block with 1000 integers */ if ( (id1 = mblock_open(1000,sizeof(int))) == -1) { fprintf(stderr,"Couldn't open memory block #2\n"); return(-1); } /* get the starting address of the memory blocks */ pntr1 = (char *) mblock_pntr(id1); pntr2 = (int *) mblock_pntr(id2); /* get the size of the memory blocks in bytes and print out */ /* get the number of elements in the mblock and the total */ /* number of bytes used for block 1 but do not get size of element */ /* get just the total bytes for block 2 */ mblock_sizes(id1,&nel1,NULL,&nbytes1); /* NULL says don't return it */ mblock_sizes(id2,NULL,NULL,&nbytes2); printf("Mblock 1 id# %d has %u records and %lu bytes\n", id1,nel,nbytes1); printf("Mblock 2 id# %d has %lu bytes\n",id2,nbytes2); /* increase the size of the second mem block to 3000 integers */ if ( mblock_resize(id2,3000)) != 0) { fprintf(stderr,"Couldn't increase size of memory block #2\n"); return(-1); } /* close both memory blocks */ mblock_close(id1); mblock_close(id2); } !*/ #endif /* DOC */ { int id,found; int retval = -1; #define ALLOC_NUM 4 /* alloc 4 id blocks at a time */ if (nmblocks <= 0) /* see if no callocing has been done yet */ { /* calloc ALLOC_NUM entires in mblock structure array */ if ( dmm_calloc((void **)&mblock_head,(long)ALLOC_NUM,sizeof(mblock)) != 0) goto error_return; /* goto error return; no message */ /* declare pointers */ if ( dmm_pntr_alloc(&mblock_head->head) != 0 || dmm_pntr_scalar(&mblock_curr) != 0 ) { dmm_free((void **)&mblock_head);/* free mblock and all alloc pointers */ goto error_return; } mblock_curr = mblock_head; /* set to be the same */ id = 0; /* set id to top of this list */ /* zeroes automatically null out everything */ nmblocks = ALLOC_NUM; /* One mblock so far */ } else /* nmblocks > 0 */ { /* first search current list for any empty ones and use them first */ for (id=found=0, mblock_curr=mblock_head; id < nmblocks; id++,mblock_curr++) { if (mblock_curr->size == 0) /* is it empty ?? */ { found = 1; /* set this flag true;OS9 didn't like it in 'if ()' */ break; /* found one, break for loop and use it */ } } if (!found) /* true if no empty ones found */ { /* which means you have to alloc some more space */ /* dmm_realloc() also clears new memory locations, so don't worry */ /* about them being zero; they are */ if ( dmm_realloc((void **)&mblock_head,(long)nmblocks+ALLOC_NUM) != 0) goto error_return; /* just return an error; no message */ /* can't have any more mblocks */ mblock_curr = mblock_head + nmblocks; /* position of newest entry */ mblock_curr->size = 0; /* make it empty */ id = nmblocks; /* use this as id, then incr number of mblocks by 1 */ nmblocks += ALLOC_NUM; /* update the total */ } } /* at this point id is the identifying index and mblock_curr points to */ /* an available mblock entry. Now calloc the mblock memory */ /* both structure arrays are cleared by calloc's which will automatically */ /* make all of their entries empty */ if ( dmm_calloc((void **)&mblock_curr->head,(long)nel,size) != 0) goto error_return; /* goto error return; no message */ /* set the sizes into the list and all done */ mblock_curr->nel = nel; mblock_curr->size = size; retval = id; error_return: /* return an error code */ return (retval); } /*! mblock_close Close the specified or all mblocks. Summary: #include */ int mblock_close (int id) /*! Return Value: 0 if close OK, -1 if error. Parameters: Type Name IO Description ------------ ----------- -- ----------- */ #ifdef DOC int id ;/* I id returned by mblock_open() to close or -1 if all mblocks are to be closed */ #endif /*! Description: Close the specified mblock. If id is -1,then close all open mblocks. See also: mblock_open() Example: See end of example in mblock_open (). !*/ { int i; int retval = -1; if (id != -1) /* just close one */ { if (id >= nmblocks) /* error if out of range */ goto error_return; i = id; } else i = 0; for (mblock_curr=mblock_head+i; isize > 0 ) /* see if opened */ { mblock_curr->size = 0; /* free this entry */ /* it is open, free internal pointers */ dmm_free ((void **)&mblock_curr->head); } if (id != -1) /* if only closing 1, exit */ break; } retval = 0; error_return: return (retval); /* error return */ } /*! mblock_resize Change the size of an already open'd mblock Summary: #include */ int mblock_resize (int id,unsigned nel) /*! Return Value: != -1 identifier for this mblock structure, -1 if insufficient memory. Parameters: Type Name IO Description ------------ ----------- -- ----------- */ #ifdef DOC int id ;/* I mblock identifier from mblock_open() */ unsigned nel ;/* I number of elements to change to */ #endif /*! Description: Changes the size of a memory block already allocated. The number of elements to change to is specified by `nel`. The size of each element stays the same as specified in mblock_open(). See Also: mblock_open() Example: !*/ { int retval = -1; CHECKID; /* make sure id is valid */ if ( dmm_realloc((void **)&mblock_curr->head,(long)nel) != 0) goto error_return; /* just return an error; no message */ mblock_curr->nel = nel; /* set new size in id structure */ retval = 0; error_return: /* return an error code */ return (retval); } /*! mblock_pntr Return pointer in specified mblock. Summary: #include */ void *mblock_pntr(int id) /*! Return Value: pntr to mblock position if OK, NULL if error. Parameters: Type Name IO Description ------------ ----------- -- ----------- */ #ifdef DOC int id ;/* I mblock identifier from mblock_open() */ #endif /*! Description: Returns a pointer to the position in the mblock specified by the `id`. A NULL is returned if the block is not in use. See also: Example: See end of example in mblock_open (). !*/ { void *retval = NULL; CHECKID; retval = (void *) (mblock_curr->head); error_return: return (retval); /* error return */ } /*! mblock_sizes Returns memory block size information. Summary: #include */ int mblock_sizes(int id,unsigned * nel,unsigned * size,unsigned long * nbytes) /*! Return Value: 0 if OK, -1 if error. Parameters: Type Name IO Description ------------ ----------- -- ----------- */ #ifdef DOC int id ;/* I mblock identifier from mblock_open() */ unsigned *nel ;/* O returns number of elements if NULL, do not return this value. */ unsigned *size ;/* O returns size of element in bytes if NULL, do not return this value. */ unsigned long *nbytes ;/* O returns total number of bytes in the block, if NULL, do not return this value. */ #endif /*! Description: Returns size information in the parameters `nel`,`size` and `nbytes'. If any of these pointers are NULL, no value is returned. The value returned for `nbytes` is just the product of `nel` and `size`, but is a long instead of just an unsigned. DON'T FORGET THOSE & symbols in your calling routine!!! See also: Example: See end of example in mblock_open (). !*/ { int retval=-1; CHECKID; if (nel != NULL) *nel = mblock_curr->nel; if (size != NULL) *size = mblock_curr->size; if (nbytes != NULL) *nbytes = ((unsigned long) mblock_curr->nel) * mblock_curr->size; retval = 0; error_return: return (retval); /* error return */ } #endif /* ifndef DMM_OFF */