/* ========================================================================== ** * Gbfr.c * * Copyright: * Copyright (C) 2011 by ubiqx Consulting, Inc. * * Email: ubiqx@ubiqx.com * * $Id: Gbfr.c 53 2011-04-25 20:39:01Z crh $ * * -------------------------------------------------------------------------- ** * * Description: * A byte buffer that grows as you use it. * * -------------------------------------------------------------------------- ** * * License: * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * -------------------------------------------------------------------------- ** * * Notes: * * ========================================================================== ** */ #include /* For NULL. */ #include /* For strncat(3). */ #include /* for vs[n]printf(3). */ #include /* Variable argument lists. */ #include "Gbfr.h" /* Module header. */ /* -------------------------------------------------------------------------- ** * Functions: */ Gbfr *initGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Initialize an unused Gbfr structure. * * Input: gb - The Gbfr to initialize. * * Output: A pointer to the initialized Gbfr structure (same as ), * or NULL if buffer memory could not be allocated. * * ------------------------------------------------------------------------ ** */ { gb->bSize = STARTbSIZE; gb->len = 0; gb->bufr = (char *)malloc( STARTbSIZE ); return( (gb->bufr) ? gb : NULL ); } /* initGbfr */ void clearGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Clear the current contents of a Gbfr. * * Input: gb - The Gbfr to clear. * * Output: * * Notes: This function simply resets the field of the Gbfr to 0 * (zero). This indicates that the buffer is "empty" and ready * for use. * * ------------------------------------------------------------------------ ** */ { gb->len = 0; } /* clearGbfr */ Gbfr *resetGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Reset a used Gbfr. * * Input: gb - The Gbfr to be reset. * * Output: A pointer to the initialized Gbfr structure (same as ), * or NULL if buffer memory could not be reallocated. * * Notes: This function is a bit more brutal than . It * resets the Gbfr to an initial state. * + The field is reallocated to the starting size, and * the buffer size field, , is set correctly. * + The used length field, , is set to zero. * * ------------------------------------------------------------------------ ** */ { /* If we have a buffer of the correct initial size. * Just clean things up and return. */ if( (NULL != gb->bufr) && (gb->bSize == STARTbSIZE) ) { gb->len = 0; gb->bufr[0] = '\0'; return( gb ); } /* Wrong sized buffer (too big?). * Free it, then re-initialize the Gbfr. */ if( NULL != gb->bufr ) free( gb->bufr ); return( initGbfr( gb ) ); } /* resetGbfr */ int growGbfr( Gbfr *gb, const int len ) /* ------------------------------------------------------------------------ ** * Ensure that there are at least free bytes in the Gbfr bufr. * * Input: gb - Pointer to the Gbfr to grow. * len - Minimum number of free bytes we require. * * Output: The free bytes now available in the Gbfr buffer. * If the buffer cannot be expanded, the function returns -1 and * the buffer contents are no longer considered valid. * * ------------------------------------------------------------------------ ** */ { int tmp = gb->len + len; int newsize = gb->bSize; if( len > MAXbSIZE ) return( -1 ); while( newsize < tmp ) newsize += STARTbSIZE; if( newsize > MAXbSIZE ) return( -1 ); if( newsize > gb->bSize ) { gb->bufr = (char *)realloc( gb->bufr, newsize ); if( NULL == gb->bufr ) { gb->len = 0; gb->bSize = 0; return( -1 ); } gb->bSize = newsize; } return( (gb->bSize - gb->len) ); } /* growGbfr */ int concatGbfr( Gbfr *gb, const char *src, const int len ) /* ------------------------------------------------------------------------ ** * Concatenate a chunk of bytes to the end of a Gbfr. * * Input: gb - The Gbfr to which the new bytes will be concatenated. * src - Byte array from which bytes will be copied into the * Gbfr. * len - Number of bytes of to copy. * * Output: The number of bytes in use in , or -1 if the * buffer could not be extended to the required size. * * Notes: If -1 is returned, the contents of the Gbfr are no longer * valid. * * These are not handled as string buffers; No NUL terminator * is added. Gbfrs are length-delimited arrays of bytes. * * ------------------------------------------------------------------------ ** */ { int tmp = (gb->len + len); int i; if( growGbfr( gb, tmp ) < 1 ) return( -1 ); for( i = 0; i < len; i++ ) { gb->bufr[(gb->len)++] = src[i]; } return( gb->len ); } /* concatGbfr */ int addcGbfr( Gbfr *gb, const unsigned char b ) /* ------------------------------------------------------------------------ ** * Append a byte to the tail end of a Gbfr. * * Input: gb - Pointer to the Gbfr. * b - The byte to be appended to the string. * * Output: The number of bytes of the Gbfr now in use, or -1 if the byte * could not be added. * * ------------------------------------------------------------------------ ** */ { if( ((gb->len + 1) >= gb->bSize) && (growGbfr( gb, 8 ) < 1) ) return( -1 ); gb->bufr[(gb->len)++] = b; gb->bufr[(gb->len)] = '\0'; return( gb->len ); } /* addcGbfr */ bool isemptyGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Return true if the buffer in Gbfr is empty (or NULL). * * Input: gb - Pointer to the Gbfr. * * Output: True if the buffer is empty, else false. * * ------------------------------------------------------------------------ ** */ { if( (NULL != gb->bufr) && (0 != gb->len) ) return( false ); return( true ); } /* isemptyGbfr */ int lenGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Return the number of bytes currently stored in the Gbfr. * * Input: gb - Pointer to the Gbfr. * * Output: Length of the byte array stored in the Gbfr buffer. * * ------------------------------------------------------------------------ ** */ { return( gb->len ); } /* lenGbfr */ const char *bfrGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Return a pointer to the byte array currently stored in the Gbfr. * * Input: gb - Pointer to the Gbfr. * * Output: A pointer to the byte array, returned as "const" to prevent * fuddlement. NULL is returned if the Gbfr was not correctly * initialized. Note, however, that an uninitialized Gbfr may * point to random garbage. * * ------------------------------------------------------------------------ ** */ { if( NULL == gb->bufr ) initGbfr( gb ); return( gb->bufr ); } /* bfrGbfr */ Gbfr *allocGbfr( unsigned int min ) /* ------------------------------------------------------------------------ ** * Allocate an expandable memory buffer. * * Input: min - Minimum initial size of the buffer. * * Output: On failure, NULL. Otherwise, a pointer to a structure that * contains a memory buffer at least as large as bytes. * * Notes: The value passed in to this function can be though of as * a sort of hint. The actual buffer allocated will be at least * bytes in size, but probably larger. Since the buffers * will grow if needed (up to a pre-set maximum), the goal when * calling this function is to find the sweet spot at which the * initial buffer size is just big enough, most of the time. * * See Also: * * ------------------------------------------------------------------------ ** */ { Gbfr *gb; gb = (Gbfr *)calloc( 1, sizeof( Gbfr ) ); if( NULL != gb ) { gb->len = 0; gb->bSize = 0; gb->bufr = NULL; if( growGbfr( gb, min ) < 0 ) { free( gb ); return( NULL ); } } return( gb ); } /* allocGbfr */ Gbfr *freebfrGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Free only the buffer associated with a Gbfr. * * Input: gb - The Gbfr to be pruned. * * Output: A pointer to the now bufferless Gbfr. * * Notes: This function frees memory allocated and assigned to a Gbfr. * The Gbfr itself is *NOT* freed. * * See Also: * * ------------------------------------------------------------------------ ** */ { if( NULL != gb->bufr ) free( gb->bufr ); gb->len = 0; gb->bSize = 0; return( gb ); } /* freebfrGbfr */ void freeGbfr( Gbfr *gb ) /* ------------------------------------------------------------------------ ** * Free the buffer associated with a Gbfr and the Gbfr structure as well. * * Input: gb - A pointer to the Gbfr to be freed. * * Output: * * Notes: This function frees both the buffer managed by the Gbfr * structure and the Gbfr structure itself. Both must have been * allocated from the heap. * * See Also: , * * ------------------------------------------------------------------------ ** */ { if( NULL != gb ) { if( NULL != gb->bufr ) free( gb->bufr ); free( gb ); } } /* freebfrGbfr */ /* ========================================================================== */