2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
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.
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.
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.
33 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
46 * StringSegment objects store lots of small strings in larger
47 * character arrays. Since the total length of all of the strings can't
48 * be known in advance, an extensible list of large character arrays,
49 * called string-segments are used.
51 typedef struct StringSegment StringSegment
;
52 struct StringSegment
{
53 StringSegment
*next
; /* A pointer to the next segment in the list */
54 char *block
; /* An array of characters to be shared between strings */
55 int unused
; /* The amount of unused space at the end of block[] */
59 * StringGroup is typedef'd in stringrp.h.
62 FreeList
*node_mem
; /* The StringSegment free-list */
63 int block_size
; /* The dimension of each character array block */
64 StringSegment
*head
; /* The list of character arrays */
68 * Specify how many StringSegment's to allocate at a time.
70 #define STR_SEG_BLK 20
72 /*.......................................................................
73 * Create a new StringGroup object.
76 * segment_size int The length of each of the large character
77 * arrays in which multiple strings will be
78 * stored. This sets the length of longest
79 * string that can be stored, and for efficiency
80 * should be at least 10 times as large as
81 * the average string that will be stored.
83 * return StringGroup * The new object, or NULL on error.
85 StringGroup
*_new_StringGroup(int segment_size
)
87 StringGroup
*sg
; /* The object to be returned */
89 * Check the arguments.
91 if(segment_size
< 1) {
96 * Allocate the container.
98 sg
= (StringGroup
*) malloc(sizeof(StringGroup
));
104 * Before attempting any operation that might fail, initialize the
105 * container at least up to the point at which it can safely be passed
106 * to _del_StringGroup().
110 sg
->block_size
= segment_size
;
112 * Allocate the free list that is used to allocate list nodes.
114 sg
->node_mem
= _new_FreeList(sizeof(StringSegment
), STR_SEG_BLK
);
116 return _del_StringGroup(sg
);
120 /*.......................................................................
121 * Delete a StringGroup object.
124 * sg StringGroup * The object to be deleted.
126 * return StringGroup * The deleted object (always NULL).
128 StringGroup
*_del_StringGroup(StringGroup
*sg
)
133 * Delete the character arrays.
135 for(node
=sg
->head
; node
; node
=node
->next
) {
140 * Delete the list nodes that contained the string segments.
142 sg
->node_mem
= _del_FreeList(sg
->node_mem
, 1);
143 sg
->head
= NULL
; /* Already deleted by deleting sg->node_mem */
145 * Delete the container.
152 /*.......................................................................
153 * Make a copy of a string in the specified string group, and return
154 * a pointer to the copy.
157 * sg StringGroup * The group to store the string in.
158 * string const char * The string to be recorded.
159 * remove_escapes int If true, omit backslashes which escape
160 * other characters when making the copy.
162 * return char * The pointer to the copy of the string,
163 * or NULL if there was insufficient memory.
165 char *_sg_store_string(StringGroup
*sg
, const char *string
, int remove_escapes
)
167 char *copy
; /* The recorded copy of string[] */
170 * Check the arguments.
175 * Get memory for the string.
177 len
= strlen(string
);
178 copy
= _sg_alloc_string(sg
, len
);
181 * If needed, remove backslash escapes while copying the input string
182 * into the cache string.
185 int escaped
= 0; /* True if the next character should be */
187 const char *src
= string
; /* A pointer into the input string */
188 char *dst
= copy
; /* A pointer into the cached copy of the */
191 if(!escaped
&& *src
== '\\') {
201 * If escapes have already been removed, copy the input string directly
205 strlcpy(copy
, string
, len
+ 1);
209 * Return a pointer to the copy of the string (or NULL if the allocation
215 /*.......................................................................
216 * Allocate memory for a string of a given length.
219 * sg StringGroup * The group to store the string in.
220 * length int The required length of the string.
222 * return char * The pointer to the copy of the string,
223 * or NULL if there was insufficient memory.
225 char *_sg_alloc_string(StringGroup
*sg
, int length
)
227 StringSegment
*node
; /* A node of the list of string segments */
228 char *copy
; /* The allocated string */
230 * If the string is longer than block_size, then we can't record it.
232 if(length
> sg
->block_size
|| length
< 0)
235 * See if there is room to record the string in one of the existing
236 * string segments. Do this by advancing the node pointer until we find
237 * a node with length+1 bytes unused, or we get to the end of the list.
239 for(node
=sg
->head
; node
&& node
->unused
<= length
; node
=node
->next
)
242 * If there wasn't room, allocate a new string segment.
245 node
= (StringSegment
*) _new_FreeListNode(sg
->node_mem
);
249 * Initialize the segment.
253 node
->unused
= sg
->block_size
;
255 * Attempt to allocate the string segment character array.
257 node
->block
= (char *) malloc(sg
->block_size
);
261 * Prepend the node to the list.
263 node
->next
= sg
->head
;
267 * Get memory for the string.
269 copy
= node
->block
+ sg
->block_size
- node
->unused
;
270 node
->unused
-= length
+ 1;
272 * Return a pointer to the string memory.
277 /*.......................................................................
278 * Delete all of the strings that are currently stored by a specified
279 * StringGroup object.
282 * sg StringGroup * The group of strings to clear.
284 void _clr_StringGroup(StringGroup
*sg
)
286 StringSegment
*node
; /* A node in the list of string segments */
288 * Mark all of the string segments as unoccupied.
290 for(node
=sg
->head
; node
; node
=node
->next
)
291 node
->unused
= sg
->block_size
;