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