1 /* ========================================================================== **
5 * Copyright (C) 2012 by Christopher R. Hertel
7 * Email: crh@ubiqx.mn.org
9 * $Id: Gstr.c 2012-06-20 11:45:36 -0500 crh$
11 * -------------------------------------------------------------------------- **
14 * A string buffer that grows as you use it.
16 * -------------------------------------------------------------------------- **
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 3.0 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * -------------------------------------------------------------------------- **
37 * This module assumes that the contents of the buffers it handles are
38 * C-style NUL-terminated strings. This module *does not* handle length-
39 * delimited buffers of arbirary bytes.
41 * ========================================================================== **
44 #include <stdlib.h> /* For NULL. */
45 #include <string.h> /* For strncat(3). */
46 #include <stdio.h> /* for vs[n]printf(3). */
47 #include <stdarg.h> /* Variable argument lists. */
49 #include "Gstr.h" /* Module header. */
52 /* -------------------------------------------------------------------------- **
56 Gstr *initGstr( Gstr *gs )
57 /* ------------------------------------------------------------------------ **
58 * Initialize an unused Gstr structure.
60 * Input: gs - The Gstr to initialize.
62 * Output: A pointer to the initialized Gstr structure (same as <gs>),
63 * or NULL if buffer memory could not be allocated.
65 * ------------------------------------------------------------------------ **
68 gs->bSize = STARTbSIZE;
70 gs->bufr = (char *)calloc( STARTbSIZE, sizeof( char ) );
72 return( (gs->bufr) ? gs : NULL );
76 void clearGstr( Gstr *gs )
77 /* ------------------------------------------------------------------------ **
78 * Clear the current contents of a Gstr.
80 * Input: gs - The Gstr to clear.
84 * ------------------------------------------------------------------------ **
88 if( NULL != gs->bufr )
93 Gstr *resetGstr( Gstr *gs )
94 /* ------------------------------------------------------------------------ **
97 * Input: gs - The Gstr to be reset.
99 * Output: A pointer to the initialized Gstr structure (same as <gs>),
100 * or NULL if buffer memory could not be reallocated.
102 * Notes: This function resets the Gstr to an initial state.
103 * The buffer is reallocated to the starting size, and set to
104 * empty (at least the first byte is zeroed). The string
105 * length is set to zero and the buffer size is set correctly.
107 * ------------------------------------------------------------------------ **
110 /* If we have a buffer of the correct initial size.
111 * Just clean things up and return.
113 if( (NULL != gs->bufr) && (gs->bSize == STARTbSIZE) )
120 /* Wrong sized buffer (too big?). Free it.
122 if( NULL != gs->bufr )
125 /* We have a Gstr with no buffer.
128 return( initGstr( gs ) );
132 Gstr *freeGstr( Gstr *gs )
133 /* ------------------------------------------------------------------------ **
134 * Free the buffer associated with a Gstr.
136 * Input: gs - The Gstr to be pruned.
138 * Output: A pointer to the now bufferless Gstr.
140 * Notes: This function frees memory allocated and assigned to a Gstr.
141 * The Gstr itself is *NOT* freed.
143 * ------------------------------------------------------------------------ **
146 if( NULL != gs->bufr )
155 int growGstr( Gstr *gs, const int len )
156 /* ------------------------------------------------------------------------ **
157 * Ensure that there are at least <len> free bytes in the Gstr bufr.
159 * Input: gs - Pointer to the Gstr to grow.
160 * len - Minimum number of free bytes we require.
162 * Output: The free bytes now available in the Gstr buffer.
163 * If the buffer cannot be expanded, the function returns -1 and
164 * the buffer contents are no longer considered valid.
166 * ------------------------------------------------------------------------ **
169 int tmplen = gs->len + len + 1;
170 int newsize = gs->bSize;
172 while( newsize < tmplen )
174 newsize += STARTbSIZE;
175 if( newsize > MAXbSIZE )
179 if( newsize > gs->bSize )
181 gs->bufr = (char *)realloc( gs->bufr, newsize );
182 if( NULL == gs->bufr )
191 return( (gs->bSize - gs->len) - 1 );
195 int concatGstr( Gstr *gs, const char *src, const int len )
196 /* ------------------------------------------------------------------------ **
197 * Tack additional string bytes onto the end of a Gstr buffer.
199 * Input: gs - The Gstr to which the new string will be concatenated.
200 * src - Source string from which bytes will be copied into the
202 * len - Maximum number of bytes of <src> to copy.
204 * Output: String length of the resulting string, or -1 if the Gstr
205 * string buffer could not be extended to the required size.
207 * Notes: If -1 is returned, the contents of the Gstr are no longer
208 * valid. This is indicates a fatal error.
210 * If the return value is non-negative, then the string contained
211 * within the Gstr structure is always NUL terminated.
213 * ------------------------------------------------------------------------ **
216 if( growGstr( gs, len ) < 1 )
219 (void)strncat( gs->bufr, src, len );
220 gs->len += strlen( &(gs->bufr[gs->len]) );
225 int addcGstr( Gstr *gs, const char c )
226 /* ------------------------------------------------------------------------ **
227 * Append a character to the tail end of a Gstr.
229 * Input: gs - Pointer to the Gstr.
230 * c - The character to be appended to the string.
232 * Output: The length of the string or -1 if the character could not be
235 * ------------------------------------------------------------------------ **
238 if( ((gs->len + 1) >= gs->bSize) && (growGstr( gs, 8 ) < 1) )
241 gs->bufr[(gs->len)++] = c;
242 gs->bufr[(gs->len)] = '\0';
247 int printGstr( Gstr *gs, const char *fmt, ... )
248 /* ------------------------------------------------------------------------ **
249 * Like sprintf(3), except that we print to a Gstr.
251 * Input: gs - Pointer to the Gstr.
252 * fmt - The format string used to generate the resulting string.
253 * ... - The variable argument list.
255 * Output: The length of the string or -1 if the buffer could not be
256 * expanded sufficiently to accommodate the output.
258 * ------------------------------------------------------------------------ **
265 /* Make sure we have buffers in our Gstrs.
267 if( NULL == gs->bufr )
268 if( NULL == initGstr( gs ) )
270 if( NULL == initGstr( tmp ) )
273 /* It may take two tries to format the string.
274 * If the first try returns a length that is greater than our buffer size,
275 * we will have to grow the buffer and try again.
278 tmp->len = 1 + vsnprintf( tmp->bufr, tmp->bSize, fmt, ap );
281 /* If our buffer is too small... */
282 if( (tmp->len) > (tmp->bSize) )
284 if( growGstr( tmp, tmp->len ) < 0 )
286 (void)freeGstr( tmp );
290 tmp->len = 1 + vsprintf( tmp->bufr, fmt, ap );
294 /* If we made it this far, the formatted string is contained in <tmp>
295 * and <tmp->len> is the total length (including the NUL byte) needed
296 * to store the string. Add the string to the existing string.
298 result = concatGstr( gs, tmp->bufr, tmp->len );
299 (void)freeGstr( tmp );
304 bool isemptyGstr( Gstr *gs )
305 /* ------------------------------------------------------------------------ **
306 * Return true if the string stored in Gstr is the empty string (or NULL).
308 * Input: gs - Pointer to the Gstr.
310 * Output: True if the string is empty, else false.
312 * Notes: There are three factors to consider when determining whether
313 * the string is empty.
314 * + If the string doesn't exist (is NULL), then it's empty.
315 * + If the string exists, but the first byte is '\0', it's empty.
316 * + If the Gstr length is zero, the string is empty.
318 * ------------------------------------------------------------------------ **
321 if( (NULL != gs->bufr) && ('\0' != *(gs->bufr)) && (gs->len) )
327 int lenGstr( Gstr *gs )
328 /* ------------------------------------------------------------------------ **
329 * Return the length of the string currently stored in the Gstr.
331 * Input: gs - Pointer to the Gstr.
333 * Output: String length of the string in the Gstr buffer.
335 * ------------------------------------------------------------------------ **
342 const char *strGstr( Gstr *gs )
343 /* ------------------------------------------------------------------------ **
344 * Return a pointer to the string currently stored in the Gstr.
346 * Input: gs - Pointer to the Gstr.
348 * Output: A pointer to the string, returned as "const" to prevent
351 * ------------------------------------------------------------------------ **
354 if( NULL == gs->bufr )
359 /* ========================================================================== */