1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * All rights reserved. 5*7c478bd9Sstevel@tonic-gate * 6*7c478bd9Sstevel@tonic-gate * Permission is hereby granted, free of charge, to any person obtaining a 7*7c478bd9Sstevel@tonic-gate * copy of this software and associated documentation files (the 8*7c478bd9Sstevel@tonic-gate * "Software"), to deal in the Software without restriction, including 9*7c478bd9Sstevel@tonic-gate * without limitation the rights to use, copy, modify, merge, publish, 10*7c478bd9Sstevel@tonic-gate * distribute, and/or sell copies of the Software, and to permit persons 11*7c478bd9Sstevel@tonic-gate * to whom the Software is furnished to do so, provided that the above 12*7c478bd9Sstevel@tonic-gate * copyright notice(s) and this permission notice appear in all copies of 13*7c478bd9Sstevel@tonic-gate * the Software and that both the above copyright notice(s) and this 14*7c478bd9Sstevel@tonic-gate * permission notice appear in supporting documentation. 15*7c478bd9Sstevel@tonic-gate * 16*7c478bd9Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17*7c478bd9Sstevel@tonic-gate * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18*7c478bd9Sstevel@tonic-gate * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 19*7c478bd9Sstevel@tonic-gate * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20*7c478bd9Sstevel@tonic-gate * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 21*7c478bd9Sstevel@tonic-gate * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 22*7c478bd9Sstevel@tonic-gate * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 23*7c478bd9Sstevel@tonic-gate * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 24*7c478bd9Sstevel@tonic-gate * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Except as contained in this notice, the name of a copyright holder 27*7c478bd9Sstevel@tonic-gate * shall not be used in advertising or otherwise to promote the sale, use 28*7c478bd9Sstevel@tonic-gate * or other dealings in this Software without prior written authorization 29*7c478bd9Sstevel@tonic-gate * of the copyright holder. 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <stdio.h> 36*7c478bd9Sstevel@tonic-gate #include <errno.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "strngmem.h" 39*7c478bd9Sstevel@tonic-gate #include "freelist.h" 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate struct StringMem { 42*7c478bd9Sstevel@tonic-gate unsigned long nmalloc; /* The number of strings allocated with malloc */ 43*7c478bd9Sstevel@tonic-gate FreeList *fl; /* The free-list */ 44*7c478bd9Sstevel@tonic-gate }; 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /*....................................................................... 47*7c478bd9Sstevel@tonic-gate * Create a string free-list container and the first block of its free-list. 48*7c478bd9Sstevel@tonic-gate * 49*7c478bd9Sstevel@tonic-gate * Input: 50*7c478bd9Sstevel@tonic-gate * blocking_factor int The blocking_factor argument specifies how 51*7c478bd9Sstevel@tonic-gate * many strings of length SM_STRLEN 52*7c478bd9Sstevel@tonic-gate * bytes (see stringmem.h) are allocated in each 53*7c478bd9Sstevel@tonic-gate * free-list block. 54*7c478bd9Sstevel@tonic-gate * For example if blocking_factor=64 and 55*7c478bd9Sstevel@tonic-gate * SM_STRLEN=16, then each new 56*7c478bd9Sstevel@tonic-gate * free-list block will take 1K of memory. 57*7c478bd9Sstevel@tonic-gate * Output: 58*7c478bd9Sstevel@tonic-gate * return StringMem * The new free-list container, or NULL on 59*7c478bd9Sstevel@tonic-gate * error. 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate StringMem *_new_StringMem(unsigned blocking_factor) 62*7c478bd9Sstevel@tonic-gate { 63*7c478bd9Sstevel@tonic-gate StringMem *sm; /* The container to be returned. */ 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Check arguments. 66*7c478bd9Sstevel@tonic-gate */ 67*7c478bd9Sstevel@tonic-gate if(blocking_factor < 1) { 68*7c478bd9Sstevel@tonic-gate errno = EINVAL; 69*7c478bd9Sstevel@tonic-gate return NULL; 70*7c478bd9Sstevel@tonic-gate }; 71*7c478bd9Sstevel@tonic-gate /* 72*7c478bd9Sstevel@tonic-gate * Allocate the container. 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate sm = (StringMem *) malloc(sizeof(StringMem)); 75*7c478bd9Sstevel@tonic-gate if(!sm) { 76*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 77*7c478bd9Sstevel@tonic-gate return NULL; 78*7c478bd9Sstevel@tonic-gate }; 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * Before attempting any operation that might fail, initialize 81*7c478bd9Sstevel@tonic-gate * the container at least up to the point at which it can safely 82*7c478bd9Sstevel@tonic-gate * be passed to _del_StringMem(). 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate sm->nmalloc = 0; 85*7c478bd9Sstevel@tonic-gate sm->fl = NULL; 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * Allocate the free-list. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate sm->fl = _new_FreeList(SM_STRLEN, blocking_factor); 90*7c478bd9Sstevel@tonic-gate if(!sm->fl) 91*7c478bd9Sstevel@tonic-gate return _del_StringMem(sm, 1); 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * Return the free-list container. 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate return sm; 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate /*....................................................................... 99*7c478bd9Sstevel@tonic-gate * Delete a string free-list. 100*7c478bd9Sstevel@tonic-gate * 101*7c478bd9Sstevel@tonic-gate * Input: 102*7c478bd9Sstevel@tonic-gate * sm StringMem * The string free-list to be deleted, or NULL. 103*7c478bd9Sstevel@tonic-gate * force int If force==0 then _del_StringMem() will complain 104*7c478bd9Sstevel@tonic-gate * and refuse to delete the free-list if any 105*7c478bd9Sstevel@tonic-gate * of nodes have not been returned to the free-list. 106*7c478bd9Sstevel@tonic-gate * If force!=0 then _del_StringMem() will not check 107*7c478bd9Sstevel@tonic-gate * whether any nodes are still in use and will 108*7c478bd9Sstevel@tonic-gate * always delete the list. 109*7c478bd9Sstevel@tonic-gate * Output: 110*7c478bd9Sstevel@tonic-gate * return StringMem * Always NULL (even if the list couldn't be 111*7c478bd9Sstevel@tonic-gate * deleted). 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate StringMem *_del_StringMem(StringMem *sm, int force) 114*7c478bd9Sstevel@tonic-gate { 115*7c478bd9Sstevel@tonic-gate if(sm) { 116*7c478bd9Sstevel@tonic-gate /* 117*7c478bd9Sstevel@tonic-gate * Check whether any strings have not been returned to the free-list. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate if(!force && (sm->nmalloc > 0 || _busy_FreeListNodes(sm->fl) > 0)) { 120*7c478bd9Sstevel@tonic-gate errno = EBUSY; 121*7c478bd9Sstevel@tonic-gate return NULL; 122*7c478bd9Sstevel@tonic-gate }; 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * Delete the free-list. 125*7c478bd9Sstevel@tonic-gate */ 126*7c478bd9Sstevel@tonic-gate sm->fl = _del_FreeList(sm->fl, force); 127*7c478bd9Sstevel@tonic-gate /* 128*7c478bd9Sstevel@tonic-gate * Delete the container. 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate free(sm); 131*7c478bd9Sstevel@tonic-gate }; 132*7c478bd9Sstevel@tonic-gate return NULL; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /*....................................................................... 136*7c478bd9Sstevel@tonic-gate * Allocate an array of 'length' chars. 137*7c478bd9Sstevel@tonic-gate * 138*7c478bd9Sstevel@tonic-gate * Input: 139*7c478bd9Sstevel@tonic-gate * sm StringMem * The string free-list to allocate from. 140*7c478bd9Sstevel@tonic-gate * length size_t The length of the new string (including '\0'). 141*7c478bd9Sstevel@tonic-gate * Output: 142*7c478bd9Sstevel@tonic-gate * return char * The new string or NULL on error. 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate char *_new_StringMemString(StringMem *sm, size_t length) 145*7c478bd9Sstevel@tonic-gate { 146*7c478bd9Sstevel@tonic-gate char *string; /* The string to be returned */ 147*7c478bd9Sstevel@tonic-gate int was_malloc; /* True if malloc was used to allocate the string */ 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * Check arguments. 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate if(!sm) 152*7c478bd9Sstevel@tonic-gate return NULL; 153*7c478bd9Sstevel@tonic-gate if(length < 1) 154*7c478bd9Sstevel@tonic-gate length = 1; 155*7c478bd9Sstevel@tonic-gate /* 156*7c478bd9Sstevel@tonic-gate * Allocate the new node from the free list if possible. 157*7c478bd9Sstevel@tonic-gate */ 158*7c478bd9Sstevel@tonic-gate if(length < SM_STRLEN) { 159*7c478bd9Sstevel@tonic-gate string = (char *)_new_FreeListNode(sm->fl); 160*7c478bd9Sstevel@tonic-gate if(!string) 161*7c478bd9Sstevel@tonic-gate return NULL; 162*7c478bd9Sstevel@tonic-gate was_malloc = 0; 163*7c478bd9Sstevel@tonic-gate } else { 164*7c478bd9Sstevel@tonic-gate string = (char *) malloc(length+1); /* Leave room for the flag byte */ 165*7c478bd9Sstevel@tonic-gate if(!string) 166*7c478bd9Sstevel@tonic-gate return NULL; 167*7c478bd9Sstevel@tonic-gate /* 168*7c478bd9Sstevel@tonic-gate * Count malloc allocations. 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate was_malloc = 1; 171*7c478bd9Sstevel@tonic-gate sm->nmalloc++; 172*7c478bd9Sstevel@tonic-gate }; 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate * Use the first byte of the string to record whether the string was 175*7c478bd9Sstevel@tonic-gate * allocated with malloc or from the free-list. Then return the rest 176*7c478bd9Sstevel@tonic-gate * of the string for use by the user. 177*7c478bd9Sstevel@tonic-gate */ 178*7c478bd9Sstevel@tonic-gate string[0] = (char) was_malloc; 179*7c478bd9Sstevel@tonic-gate return string + 1; 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /*....................................................................... 183*7c478bd9Sstevel@tonic-gate * Free a string that was previously returned by _new_StringMemString(). 184*7c478bd9Sstevel@tonic-gate * 185*7c478bd9Sstevel@tonic-gate * Input: 186*7c478bd9Sstevel@tonic-gate * sm StringMem * The free-list from which the string was originally 187*7c478bd9Sstevel@tonic-gate * allocated. 188*7c478bd9Sstevel@tonic-gate * s char * The string to be returned to the free-list, or NULL. 189*7c478bd9Sstevel@tonic-gate * Output: 190*7c478bd9Sstevel@tonic-gate * return char * Always NULL. 191*7c478bd9Sstevel@tonic-gate */ 192*7c478bd9Sstevel@tonic-gate char *_del_StringMemString(StringMem *sm, char *s) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate int was_malloc; /* True if the string originally came from malloc() */ 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * Is there anything to be deleted? 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate if(s && sm) { 199*7c478bd9Sstevel@tonic-gate /* 200*7c478bd9Sstevel@tonic-gate * Retrieve the true string pointer. This is one less than the one 201*7c478bd9Sstevel@tonic-gate * returned by _new_StringMemString() because the first byte of the 202*7c478bd9Sstevel@tonic-gate * allocated memory is reserved by _new_StringMemString as a flag byte 203*7c478bd9Sstevel@tonic-gate * to say whether the memory was allocated from the free-list or directly 204*7c478bd9Sstevel@tonic-gate * from malloc(). 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate s--; 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * Get the origination flag. 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate was_malloc = s[0]; 211*7c478bd9Sstevel@tonic-gate if(was_malloc) { 212*7c478bd9Sstevel@tonic-gate free(s); 213*7c478bd9Sstevel@tonic-gate s = NULL; 214*7c478bd9Sstevel@tonic-gate sm->nmalloc--; 215*7c478bd9Sstevel@tonic-gate } else { 216*7c478bd9Sstevel@tonic-gate s = (char *) _del_FreeListNode(sm->fl, s); 217*7c478bd9Sstevel@tonic-gate }; 218*7c478bd9Sstevel@tonic-gate }; 219*7c478bd9Sstevel@tonic-gate return NULL; 220*7c478bd9Sstevel@tonic-gate } 221