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