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 #include <stdlib.h> 33 #include <stdio.h> 34 #include <errno.h> 35 36 #include "strngmem.h" 37 #include "freelist.h" 38 39 struct StringMem { 40 unsigned long nmalloc; /* The number of strings allocated with malloc */ 41 FreeList *fl; /* The free-list */ 42 }; 43 44 /*....................................................................... 45 * Create a string free-list container and the first block of its free-list. 46 * 47 * Input: 48 * blocking_factor int The blocking_factor argument specifies how 49 * many strings of length SM_STRLEN 50 * bytes (see stringmem.h) are allocated in each 51 * free-list block. 52 * For example if blocking_factor=64 and 53 * SM_STRLEN=16, then each new 54 * free-list block will take 1K of memory. 55 * Output: 56 * return StringMem * The new free-list container, or NULL on 57 * error. 58 */ 59 StringMem *_new_StringMem(unsigned blocking_factor) 60 { 61 StringMem *sm; /* The container to be returned. */ 62 /* 63 * Check arguments. 64 */ 65 if(blocking_factor < 1) { 66 errno = EINVAL; 67 return NULL; 68 }; 69 /* 70 * Allocate the container. 71 */ 72 sm = (StringMem *) malloc(sizeof(StringMem)); 73 if(!sm) { 74 errno = ENOMEM; 75 return NULL; 76 }; 77 /* 78 * Before attempting any operation that might fail, initialize 79 * the container at least up to the point at which it can safely 80 * be passed to _del_StringMem(). 81 */ 82 sm->nmalloc = 0; 83 sm->fl = NULL; 84 /* 85 * Allocate the free-list. 86 */ 87 sm->fl = _new_FreeList(SM_STRLEN, blocking_factor); 88 if(!sm->fl) 89 return _del_StringMem(sm, 1); 90 /* 91 * Return the free-list container. 92 */ 93 return sm; 94 } 95 96 /*....................................................................... 97 * Delete a string free-list. 98 * 99 * Input: 100 * sm StringMem * The string free-list to be deleted, or NULL. 101 * force int If force==0 then _del_StringMem() will complain 102 * and refuse to delete the free-list if any 103 * of nodes have not been returned to the free-list. 104 * If force!=0 then _del_StringMem() will not check 105 * whether any nodes are still in use and will 106 * always delete the list. 107 * Output: 108 * return StringMem * Always NULL (even if the list couldn't be 109 * deleted). 110 */ 111 StringMem *_del_StringMem(StringMem *sm, int force) 112 { 113 if(sm) { 114 /* 115 * Check whether any strings have not been returned to the free-list. 116 */ 117 if(!force && (sm->nmalloc > 0 || _busy_FreeListNodes(sm->fl) > 0)) { 118 errno = EBUSY; 119 return NULL; 120 }; 121 /* 122 * Delete the free-list. 123 */ 124 sm->fl = _del_FreeList(sm->fl, force); 125 /* 126 * Delete the container. 127 */ 128 free(sm); 129 }; 130 return NULL; 131 } 132 133 /*....................................................................... 134 * Allocate an array of 'length' chars. 135 * 136 * Input: 137 * sm StringMem * The string free-list to allocate from. 138 * length size_t The length of the new string (including '\0'). 139 * Output: 140 * return char * The new string or NULL on error. 141 */ 142 char *_new_StringMemString(StringMem *sm, size_t length) 143 { 144 char *string; /* The string to be returned */ 145 int was_malloc; /* True if malloc was used to allocate the string */ 146 /* 147 * Check arguments. 148 */ 149 if(!sm) 150 return NULL; 151 if(length < 1) 152 length = 1; 153 /* 154 * Allocate the new node from the free list if possible. 155 */ 156 if(length < SM_STRLEN) { 157 string = (char *)_new_FreeListNode(sm->fl); 158 if(!string) 159 return NULL; 160 was_malloc = 0; 161 } else { 162 string = (char *) malloc(length+1); /* Leave room for the flag byte */ 163 if(!string) 164 return NULL; 165 /* 166 * Count malloc allocations. 167 */ 168 was_malloc = 1; 169 sm->nmalloc++; 170 }; 171 /* 172 * Use the first byte of the string to record whether the string was 173 * allocated with malloc or from the free-list. Then return the rest 174 * of the string for use by the user. 175 */ 176 string[0] = (char) was_malloc; 177 return string + 1; 178 } 179 180 /*....................................................................... 181 * Free a string that was previously returned by _new_StringMemString(). 182 * 183 * Input: 184 * sm StringMem * The free-list from which the string was originally 185 * allocated. 186 * s char * The string to be returned to the free-list, or NULL. 187 * Output: 188 * return char * Always NULL. 189 */ 190 char *_del_StringMemString(StringMem *sm, char *s) 191 { 192 int was_malloc; /* True if the string originally came from malloc() */ 193 /* 194 * Is there anything to be deleted? 195 */ 196 if(s && sm) { 197 /* 198 * Retrieve the true string pointer. This is one less than the one 199 * returned by _new_StringMemString() because the first byte of the 200 * allocated memory is reserved by _new_StringMemString as a flag byte 201 * to say whether the memory was allocated from the free-list or directly 202 * from malloc(). 203 */ 204 s--; 205 /* 206 * Get the origination flag. 207 */ 208 was_malloc = s[0]; 209 if(was_malloc) { 210 free(s); 211 s = NULL; 212 sm->nmalloc--; 213 } else { 214 s = (char *) _del_FreeListNode(sm->fl, s); 215 }; 216 }; 217 return NULL; 218 } 219