Added to the repository.
[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-12 21:46:10 -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 a buffer in our Gstr.
266    */
267   if( NULL == gs->bufr )
268     initGstr( gs );
269
270   /* It may take two tries to format the string.
271    * If the first try returns a length that is greater than our buffer size,
272    * we will have to grow the buffer and try again.
273    */
274   va_start( ap, fmt );
275   tmp->len = 1 + vsnprintf( tmp->bufr, tmp->bSize, fmt, ap );
276   va_end( ap );
277
278   if( (tmp->len) > (tmp->bSize) )
279     {
280     if( growGstr( tmp, tmp->len ) < 0 )
281       {
282       (void)freeGstr( tmp );
283       return( -1 );
284       }
285     va_start( ap, fmt );
286     tmp->len = 1 + vsprintf( tmp->bufr, fmt, ap );
287     va_end( ap );
288     }
289
290   /* If we made it this far, the formatted string is contained in <tmp>
291    * and <tmp->len> is the total length (including the NUL byte) needed
292    * to store the string.  Add the string to the existing string.
293    */
294   result = concatGstr( gs, tmp->bufr, tmp->len );
295   (void)freeGstr( tmp );
296   return( result );
297   } /* printGstr */
298
299
300 bool isemptyGstr( Gstr *gs )
301   /* ------------------------------------------------------------------------ **
302    * Return true if the string stored in Gstr is the empty string (or NULL).
303    *
304    *  Input:  gs  - Pointer to the Gstr.
305    *
306    *  Output: True if the string is empty, else false.
307    *
308    * ------------------------------------------------------------------------ **
309    */
310   {
311   if( (NULL != gs->bufr) && ( '\0' != *(gs->bufr) ) )
312     return( false );
313   return( true );
314   } /* isemptyGstr */
315
316
317 int lenGstr( Gstr *gs )
318   /* ------------------------------------------------------------------------ **
319    * Return the length of the string currently stored in the Gstr.
320    *
321    *  Input:  gs  - Pointer to the Gstr.
322    *
323    *  Output: String length of the string in the Gstr buffer.
324    *
325    * ------------------------------------------------------------------------ **
326    */
327   {
328   return( gs->len );
329   } /* lenGstr */
330
331
332 const char *strGstr( Gstr *gs )
333   /* ------------------------------------------------------------------------ **
334    * Return a pointer to the string currently stored in the Gstr.
335    *
336    *  Input:  gs  - Pointer to the Gstr.
337    *
338    *  Output: A pointer to the string, returned as "const" to prevent
339    *          fuddlement.
340    *
341    * ------------------------------------------------------------------------ **
342    */
343   {
344   if( NULL == gs->bufr )
345     initGstr( gs );
346   return( gs->bufr );
347   } /* strGstr */
348
349 /* ========================================================================== */