Bugfixes and additional comments.
[jarrpa/prequel.git] / src / daemon / Gstr.c
1 /* ========================================================================== **
2  *                                   Gstr.c
3  *
4  * Copyright:
5  *  Copyright (C) 2012 by Christopher R. Hertel
6  *
7  * Email: crh@ubiqx.mn.org
8  *
9  * $Id: Gstr.c 2012-06-20 11:45:36 -0500 crh$
10  *
11  * -------------------------------------------------------------------------- **
12  *
13  * Description:
14  *  A string buffer that grows as you use it.
15  *
16  * -------------------------------------------------------------------------- **
17  *
18  * License:
19  *
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.
24  *
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.
29  *
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
33  *
34  * -------------------------------------------------------------------------- **
35  *
36  * Notes:
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.
40  *
41  * ========================================================================== **
42  */
43
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. */
48
49 #include "Gstr.h"     /* Module header.           */
50
51
52 /* -------------------------------------------------------------------------- **
53  * Functions:
54  */
55
56 Gstr *initGstr( Gstr *gs )
57   /* ------------------------------------------------------------------------ **
58    * Initialize an unused Gstr structure.
59    *
60    *  Input:  gs  - The Gstr to initialize.
61    *
62    *  Output: A pointer to the initialized Gstr structure (same as <gs>),
63    *          or NULL if buffer memory could not be allocated.
64    *
65    * ------------------------------------------------------------------------ **
66    */
67   {
68   gs->bSize = STARTbSIZE;
69   gs->len   = 0;
70   gs->bufr  = (char *)calloc( STARTbSIZE, sizeof( char ) );
71
72   return( (gs->bufr) ? gs : NULL );
73   } /* initGstr */
74
75
76 void clearGstr( Gstr *gs )
77   /* ------------------------------------------------------------------------ **
78    * Clear the current contents of a Gstr.
79    *
80    *  Input:  gs  - The Gstr to clear.
81    *
82    *  Output: <none>
83    *
84    * ------------------------------------------------------------------------ **
85    */
86   {
87   gs->len = 0;
88   if( NULL != gs->bufr )
89     gs->bufr[0] = '\0';
90   } /* clearGsr */
91
92
93 Gstr *resetGstr( Gstr *gs )
94   /* ------------------------------------------------------------------------ **
95    * Reset a used Gstr.
96    *
97    *  Input:  gs  - The Gstr to be reset.
98    *
99    *  Output: A pointer to the initialized Gstr structure (same as <gs>),
100    *          or NULL if buffer memory could not be reallocated.
101    *
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.
106    *
107    * ------------------------------------------------------------------------ **
108    */
109   {
110   /* If we have a buffer of the correct initial size.
111    * Just clean things up and return.
112    */
113   if( (NULL != gs->bufr) && (gs->bSize == STARTbSIZE) )
114     {
115     gs->len     = 0;
116     gs->bufr[0] = '\0';
117     return( gs );
118     }
119
120   /* Wrong sized buffer (too big?).  Free it.
121    */
122   if( NULL != gs->bufr )
123     free( gs->bufr );
124
125   /* We have a Gstr with no buffer.
126    * Initialize it.
127    */
128   return( initGstr( gs ) );
129   } /* resetGstr */
130
131
132 Gstr *freeGstr( Gstr *gs )
133   /* ------------------------------------------------------------------------ **
134    * Free the buffer associated with a Gstr.
135    *
136    *  Input:  gs  - The Gstr to be pruned.
137    *
138    *  Output: A pointer to the now bufferless Gstr.
139    *
140    *  Notes:  This function frees memory allocated and assigned to a Gstr.
141    *          The Gstr itself is *NOT* freed.
142    *
143    * ------------------------------------------------------------------------ **
144    */
145   {
146   if( NULL != gs->bufr )
147     free( gs->bufr );
148   gs->len   = 0;
149   gs->bSize = 0;
150
151   return( gs );
152   } /* freeGstr */
153
154
155 int growGstr( Gstr *gs, const int len )
156   /* ------------------------------------------------------------------------ **
157    * Ensure that there are at least <len> free bytes in the Gstr bufr.
158    *
159    *  Input:  gs  - Pointer to the Gstr to grow.
160    *          len - Minimum number of free bytes we require.
161    *
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.
165    *
166    * ------------------------------------------------------------------------ **
167    */
168   {
169   int tmplen  = gs->len + len + 1;
170   int newsize = gs->bSize;
171
172   while( newsize < tmplen )
173     {
174     newsize += STARTbSIZE;
175     if( newsize > MAXbSIZE )
176       return( -1 );
177     }
178
179   if( newsize > gs->bSize )
180     {
181     gs->bufr = (char *)realloc( gs->bufr, newsize );
182     if( NULL == gs->bufr )
183       {
184       gs->len   = 0;
185       gs->bSize = 0;
186       return( -1 );
187       }
188     gs->bSize = newsize;
189     }
190
191   return( (gs->bSize - gs->len) - 1 );
192   } /* growGstr */
193
194
195 int concatGstr( Gstr *gs, const char *src, const int len )
196   /* ------------------------------------------------------------------------ **
197    * Tack additional string bytes onto the end of a Gstr buffer.
198    *
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
201    *                Gstr.
202    *          len - Maximum number of bytes of <src> to copy.
203    *
204    *  Output: String length of the resulting string, or -1 if the Gstr
205    *          string buffer could not be extended to the required size.
206    *
207    *  Notes:  If -1 is returned, the contents of the Gstr are no longer
208    *          valid.  This is indicates a fatal error.
209    *
210    *          If the return value is non-negative, then the string contained
211    *          within the Gstr structure is always NUL terminated.
212    *
213    * ------------------------------------------------------------------------ **
214    */
215   {
216   if( growGstr( gs, len ) < 1 )
217     return( -1 );
218
219   (void)strncat( gs->bufr, src, len );
220   gs->len += strlen( &(gs->bufr[gs->len]) );
221   return( gs->len );
222   } /* concatGstr */
223
224
225 int addcGstr( Gstr *gs, const char c )
226   /* ------------------------------------------------------------------------ **
227    * Append a character to the tail end of a Gstr.
228    *
229    *  Input:  gs  - Pointer to the Gstr.
230    *          c   - The character to be appended to the string.
231    *
232    *  Output: The length of the string or -1 if the character could not be
233    *          added.
234    *
235    * ------------------------------------------------------------------------ **
236    */
237   {
238   if( ((gs->len + 1) >= gs->bSize) && (growGstr( gs, 8 ) < 1) )
239     return( -1 );
240
241   gs->bufr[(gs->len)++] = c;
242   gs->bufr[(gs->len)]   = '\0';
243   return( gs->len );
244   } /* addcGstr */
245
246
247 int printGstr( Gstr *gs, const char *fmt, ... )
248   /* ------------------------------------------------------------------------ **
249    * Like sprintf(3), except that we print to a Gstr.
250    *
251    *  Input:  gs  - Pointer to the Gstr.
252    *          fmt - The format string used to generate the resulting string.
253    *          ... - The variable argument list.
254    *
255    *  Output: The length of the string or -1 if the buffer could not be
256    *          expanded sufficiently to accommodate the output.
257    *
258    * ------------------------------------------------------------------------ **
259    */
260   {
261   int     result;
262   Gstr    tmp[1];
263   va_list ap;
264
265   /* Make sure we have buffers in our Gstrs.
266    */
267   if( NULL == gs->bufr )
268     if( NULL == initGstr( gs ) )
269       return( -1 );
270   if( NULL == initGstr( tmp ) )
271     return( -1 );
272
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.
276    */
277   va_start( ap, fmt );
278   tmp->len = 1 + vsnprintf( tmp->bufr, tmp->bSize, fmt, ap );
279   va_end( ap );
280
281   /* If our buffer is too small...  */
282   if( (tmp->len) > (tmp->bSize) )
283     {
284     if( growGstr( tmp, tmp->len ) < 0 )
285       {
286       (void)freeGstr( tmp );
287       return( -1 );
288       }
289     va_start( ap, fmt );
290     tmp->len = 1 + vsprintf( tmp->bufr, fmt, ap );
291     va_end( ap );
292     }
293
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.
297    */
298   result = concatGstr( gs, tmp->bufr, tmp->len );
299   (void)freeGstr( tmp );
300   return( result );
301   } /* printGstr */
302
303
304 bool isemptyGstr( Gstr *gs )
305   /* ------------------------------------------------------------------------ **
306    * Return true if the string stored in Gstr is the empty string (or NULL).
307    *
308    *  Input:  gs  - Pointer to the Gstr.
309    *
310    *  Output: True if the string is empty, else false.
311    *
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.
317    *
318    * ------------------------------------------------------------------------ **
319    */
320   {
321   if( (NULL != gs->bufr) && ('\0' != *(gs->bufr)) && (gs->len) )
322     return( false );
323   return( true );
324   } /* isemptyGstr */
325
326
327 int lenGstr( Gstr *gs )
328   /* ------------------------------------------------------------------------ **
329    * Return the length of the string currently stored in the Gstr.
330    *
331    *  Input:  gs  - Pointer to the Gstr.
332    *
333    *  Output: String length of the string in the Gstr buffer.
334    *
335    * ------------------------------------------------------------------------ **
336    */
337   {
338   return( gs->len );
339   } /* lenGstr */
340
341
342 const char *strGstr( Gstr *gs )
343   /* ------------------------------------------------------------------------ **
344    * Return a pointer to the string currently stored in the Gstr.
345    *
346    *  Input:  gs  - Pointer to the Gstr.
347    *
348    *  Output: A pointer to the string, returned as "const" to prevent
349    *          fuddlement.
350    *
351    * ------------------------------------------------------------------------ **
352    */
353   {
354   if( NULL == gs->bufr )
355     initGstr( gs );
356   return( gs->bufr );
357   } /* strGstr */
358
359 /* ========================================================================== */