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 /* 33*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 34*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 40*7c478bd9Sstevel@tonic-gate #include <stdio.h> 41*7c478bd9Sstevel@tonic-gate #include <string.h> 42*7c478bd9Sstevel@tonic-gate #include <errno.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include "freelist.h" 45*7c478bd9Sstevel@tonic-gate #include "stringrp.h" 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* 48*7c478bd9Sstevel@tonic-gate * StringSegment objects store lots of small strings in larger 49*7c478bd9Sstevel@tonic-gate * character arrays. Since the total length of all of the strings can't 50*7c478bd9Sstevel@tonic-gate * be known in advance, an extensible list of large character arrays, 51*7c478bd9Sstevel@tonic-gate * called string-segments are used. 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate typedef struct StringSegment StringSegment; 54*7c478bd9Sstevel@tonic-gate struct StringSegment { 55*7c478bd9Sstevel@tonic-gate StringSegment *next; /* A pointer to the next segment in the list */ 56*7c478bd9Sstevel@tonic-gate char *block; /* An array of characters to be shared between strings */ 57*7c478bd9Sstevel@tonic-gate int unused; /* The amount of unused space at the end of block[] */ 58*7c478bd9Sstevel@tonic-gate }; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* 61*7c478bd9Sstevel@tonic-gate * StringGroup is typedef'd in stringrp.h. 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate struct StringGroup { 64*7c478bd9Sstevel@tonic-gate FreeList *node_mem; /* The StringSegment free-list */ 65*7c478bd9Sstevel@tonic-gate int block_size; /* The dimension of each character array block */ 66*7c478bd9Sstevel@tonic-gate StringSegment *head; /* The list of character arrays */ 67*7c478bd9Sstevel@tonic-gate }; 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate * Specify how many StringSegment's to allocate at a time. 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate #define STR_SEG_BLK 20 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /*....................................................................... 75*7c478bd9Sstevel@tonic-gate * Create a new StringGroup object. 76*7c478bd9Sstevel@tonic-gate * 77*7c478bd9Sstevel@tonic-gate * Input: 78*7c478bd9Sstevel@tonic-gate * segment_size int The length of each of the large character 79*7c478bd9Sstevel@tonic-gate * arrays in which multiple strings will be 80*7c478bd9Sstevel@tonic-gate * stored. This sets the length of longest 81*7c478bd9Sstevel@tonic-gate * string that can be stored, and for efficiency 82*7c478bd9Sstevel@tonic-gate * should be at least 10 times as large as 83*7c478bd9Sstevel@tonic-gate * the average string that will be stored. 84*7c478bd9Sstevel@tonic-gate * Output: 85*7c478bd9Sstevel@tonic-gate * return StringGroup * The new object, or NULL on error. 86*7c478bd9Sstevel@tonic-gate */ 87*7c478bd9Sstevel@tonic-gate StringGroup *_new_StringGroup(int segment_size) 88*7c478bd9Sstevel@tonic-gate { 89*7c478bd9Sstevel@tonic-gate StringGroup *sg; /* The object to be returned */ 90*7c478bd9Sstevel@tonic-gate /* 91*7c478bd9Sstevel@tonic-gate * Check the arguments. 92*7c478bd9Sstevel@tonic-gate */ 93*7c478bd9Sstevel@tonic-gate if(segment_size < 1) { 94*7c478bd9Sstevel@tonic-gate errno = EINVAL; 95*7c478bd9Sstevel@tonic-gate return NULL; 96*7c478bd9Sstevel@tonic-gate }; 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * Allocate the container. 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate sg = (StringGroup *) malloc(sizeof(StringGroup)); 101*7c478bd9Sstevel@tonic-gate if(!sg) { 102*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 103*7c478bd9Sstevel@tonic-gate return NULL; 104*7c478bd9Sstevel@tonic-gate }; 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * Before attempting any operation that might fail, initialize the 107*7c478bd9Sstevel@tonic-gate * container at least up to the point at which it can safely be passed 108*7c478bd9Sstevel@tonic-gate * to _del_StringGroup(). 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate sg->node_mem = NULL; 111*7c478bd9Sstevel@tonic-gate sg->head = NULL; 112*7c478bd9Sstevel@tonic-gate sg->block_size = segment_size; 113*7c478bd9Sstevel@tonic-gate /* 114*7c478bd9Sstevel@tonic-gate * Allocate the free list that is used to allocate list nodes. 115*7c478bd9Sstevel@tonic-gate */ 116*7c478bd9Sstevel@tonic-gate sg->node_mem = _new_FreeList(sizeof(StringSegment), STR_SEG_BLK); 117*7c478bd9Sstevel@tonic-gate if(!sg->node_mem) 118*7c478bd9Sstevel@tonic-gate return _del_StringGroup(sg); 119*7c478bd9Sstevel@tonic-gate return sg; 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate /*....................................................................... 123*7c478bd9Sstevel@tonic-gate * Delete a StringGroup object. 124*7c478bd9Sstevel@tonic-gate * 125*7c478bd9Sstevel@tonic-gate * Input: 126*7c478bd9Sstevel@tonic-gate * sg StringGroup * The object to be deleted. 127*7c478bd9Sstevel@tonic-gate * Output: 128*7c478bd9Sstevel@tonic-gate * return StringGroup * The deleted object (always NULL). 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate StringGroup *_del_StringGroup(StringGroup *sg) 131*7c478bd9Sstevel@tonic-gate { 132*7c478bd9Sstevel@tonic-gate if(sg) { 133*7c478bd9Sstevel@tonic-gate StringSegment *node; 134*7c478bd9Sstevel@tonic-gate /* 135*7c478bd9Sstevel@tonic-gate * Delete the character arrays. 136*7c478bd9Sstevel@tonic-gate */ 137*7c478bd9Sstevel@tonic-gate for(node=sg->head; node; node=node->next) { 138*7c478bd9Sstevel@tonic-gate if(node->block) 139*7c478bd9Sstevel@tonic-gate free(node->block); 140*7c478bd9Sstevel@tonic-gate node->block = NULL; 141*7c478bd9Sstevel@tonic-gate }; 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Delete the list nodes that contained the string segments. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate sg->node_mem = _del_FreeList(sg->node_mem, 1); 146*7c478bd9Sstevel@tonic-gate sg->head = NULL; /* Already deleted by deleting sg->node_mem */ 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * Delete the container. 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate free(sg); 151*7c478bd9Sstevel@tonic-gate }; 152*7c478bd9Sstevel@tonic-gate return NULL; 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /*....................................................................... 156*7c478bd9Sstevel@tonic-gate * Make a copy of a string in the specified string group, and return 157*7c478bd9Sstevel@tonic-gate * a pointer to the copy. 158*7c478bd9Sstevel@tonic-gate * 159*7c478bd9Sstevel@tonic-gate * Input: 160*7c478bd9Sstevel@tonic-gate * sg StringGroup * The group to store the string in. 161*7c478bd9Sstevel@tonic-gate * string const char * The string to be recorded. 162*7c478bd9Sstevel@tonic-gate * remove_escapes int If true, omit backslashes which escape 163*7c478bd9Sstevel@tonic-gate * other characters when making the copy. 164*7c478bd9Sstevel@tonic-gate * Output: 165*7c478bd9Sstevel@tonic-gate * return char * The pointer to the copy of the string, 166*7c478bd9Sstevel@tonic-gate * or NULL if there was insufficient memory. 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate char *_sg_store_string(StringGroup *sg, const char *string, int remove_escapes) 169*7c478bd9Sstevel@tonic-gate { 170*7c478bd9Sstevel@tonic-gate char *copy; /* The recorded copy of string[] */ 171*7c478bd9Sstevel@tonic-gate size_t len; 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Check the arguments. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate if(!sg || !string) 176*7c478bd9Sstevel@tonic-gate return NULL; 177*7c478bd9Sstevel@tonic-gate /* 178*7c478bd9Sstevel@tonic-gate * Get memory for the string. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate len = strlen(string); 181*7c478bd9Sstevel@tonic-gate copy = _sg_alloc_string(sg, len); 182*7c478bd9Sstevel@tonic-gate if(copy) { 183*7c478bd9Sstevel@tonic-gate /* 184*7c478bd9Sstevel@tonic-gate * If needed, remove backslash escapes while copying the input string 185*7c478bd9Sstevel@tonic-gate * into the cache string. 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate if(remove_escapes) { 188*7c478bd9Sstevel@tonic-gate int escaped = 0; /* True if the next character should be */ 189*7c478bd9Sstevel@tonic-gate /* escaped. */ 190*7c478bd9Sstevel@tonic-gate const char *src = string; /* A pointer into the input string */ 191*7c478bd9Sstevel@tonic-gate char *dst = copy; /* A pointer into the cached copy of the */ 192*7c478bd9Sstevel@tonic-gate /* string. */ 193*7c478bd9Sstevel@tonic-gate while(*src) { 194*7c478bd9Sstevel@tonic-gate if(!escaped && *src == '\\') { 195*7c478bd9Sstevel@tonic-gate escaped = 1; 196*7c478bd9Sstevel@tonic-gate src++; 197*7c478bd9Sstevel@tonic-gate } else { 198*7c478bd9Sstevel@tonic-gate escaped = 0; 199*7c478bd9Sstevel@tonic-gate *dst++ = *src++; 200*7c478bd9Sstevel@tonic-gate }; 201*7c478bd9Sstevel@tonic-gate }; 202*7c478bd9Sstevel@tonic-gate *dst = '\0'; 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * If escapes have already been removed, copy the input string directly 205*7c478bd9Sstevel@tonic-gate * into the cache. 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate } else { 208*7c478bd9Sstevel@tonic-gate strlcpy(copy, string, len + 1); 209*7c478bd9Sstevel@tonic-gate }; 210*7c478bd9Sstevel@tonic-gate }; 211*7c478bd9Sstevel@tonic-gate /* 212*7c478bd9Sstevel@tonic-gate * Return a pointer to the copy of the string (or NULL if the allocation 213*7c478bd9Sstevel@tonic-gate * failed). 214*7c478bd9Sstevel@tonic-gate */ 215*7c478bd9Sstevel@tonic-gate return copy; 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate /*....................................................................... 219*7c478bd9Sstevel@tonic-gate * Allocate memory for a string of a given length. 220*7c478bd9Sstevel@tonic-gate * 221*7c478bd9Sstevel@tonic-gate * Input: 222*7c478bd9Sstevel@tonic-gate * sg StringGroup * The group to store the string in. 223*7c478bd9Sstevel@tonic-gate * length int The required length of the string. 224*7c478bd9Sstevel@tonic-gate * Output: 225*7c478bd9Sstevel@tonic-gate * return char * The pointer to the copy of the string, 226*7c478bd9Sstevel@tonic-gate * or NULL if there was insufficient memory. 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate char *_sg_alloc_string(StringGroup *sg, int length) 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate StringSegment *node; /* A node of the list of string segments */ 231*7c478bd9Sstevel@tonic-gate char *copy; /* The allocated string */ 232*7c478bd9Sstevel@tonic-gate /* 233*7c478bd9Sstevel@tonic-gate * If the string is longer than block_size, then we can't record it. 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate if(length > sg->block_size || length < 0) 236*7c478bd9Sstevel@tonic-gate return NULL; 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * See if there is room to record the string in one of the existing 239*7c478bd9Sstevel@tonic-gate * string segments. Do this by advancing the node pointer until we find 240*7c478bd9Sstevel@tonic-gate * a node with length+1 bytes unused, or we get to the end of the list. 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate for(node=sg->head; node && node->unused <= length; node=node->next) 243*7c478bd9Sstevel@tonic-gate ; 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * If there wasn't room, allocate a new string segment. 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate if(!node) { 248*7c478bd9Sstevel@tonic-gate node = (StringSegment *) _new_FreeListNode(sg->node_mem); 249*7c478bd9Sstevel@tonic-gate if(!node) 250*7c478bd9Sstevel@tonic-gate return NULL; 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * Initialize the segment. 253*7c478bd9Sstevel@tonic-gate */ 254*7c478bd9Sstevel@tonic-gate node->next = NULL; 255*7c478bd9Sstevel@tonic-gate node->block = NULL; 256*7c478bd9Sstevel@tonic-gate node->unused = sg->block_size; 257*7c478bd9Sstevel@tonic-gate /* 258*7c478bd9Sstevel@tonic-gate * Attempt to allocate the string segment character array. 259*7c478bd9Sstevel@tonic-gate */ 260*7c478bd9Sstevel@tonic-gate node->block = (char *) malloc(sg->block_size); 261*7c478bd9Sstevel@tonic-gate if(!node->block) 262*7c478bd9Sstevel@tonic-gate return NULL; 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * Prepend the node to the list. 265*7c478bd9Sstevel@tonic-gate */ 266*7c478bd9Sstevel@tonic-gate node->next = sg->head; 267*7c478bd9Sstevel@tonic-gate sg->head = node; 268*7c478bd9Sstevel@tonic-gate }; 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * Get memory for the string. 271*7c478bd9Sstevel@tonic-gate */ 272*7c478bd9Sstevel@tonic-gate copy = node->block + sg->block_size - node->unused; 273*7c478bd9Sstevel@tonic-gate node->unused -= length + 1; 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * Return a pointer to the string memory. 276*7c478bd9Sstevel@tonic-gate */ 277*7c478bd9Sstevel@tonic-gate return copy; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate /*....................................................................... 281*7c478bd9Sstevel@tonic-gate * Delete all of the strings that are currently stored by a specified 282*7c478bd9Sstevel@tonic-gate * StringGroup object. 283*7c478bd9Sstevel@tonic-gate * 284*7c478bd9Sstevel@tonic-gate * Input: 285*7c478bd9Sstevel@tonic-gate * sg StringGroup * The group of strings to clear. 286*7c478bd9Sstevel@tonic-gate */ 287*7c478bd9Sstevel@tonic-gate void _clr_StringGroup(StringGroup *sg) 288*7c478bd9Sstevel@tonic-gate { 289*7c478bd9Sstevel@tonic-gate StringSegment *node; /* A node in the list of string segments */ 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * Mark all of the string segments as unoccupied. 292*7c478bd9Sstevel@tonic-gate */ 293*7c478bd9Sstevel@tonic-gate for(node=sg->head; node; node=node->next) 294*7c478bd9Sstevel@tonic-gate node->unused = sg->block_size; 295*7c478bd9Sstevel@tonic-gate return; 296*7c478bd9Sstevel@tonic-gate } 297