/*************************************************************************** * Copyright (C) 2009 By Duane Ellis * * openocd@duaneellis.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include "membuf.h" struct membuf { // buflen is alway "+1" bigger then // what is shown here, the +1 is for // the NULL string terminator #define DEFAULT_BUFSIZE 100 size_t maxlen; // allocated size size_t curlen; // where we are inserting at char *_strtoklast; void *buf; }; #define space_avail( pBuf ) (pBuf->maxlen - pBuf->curlen) #define dataend( pBuf ) ( ((char *)(pBuf->buf)) + pBuf->curlen ) size_t membuf_len( struct membuf *pBuf ) { return pBuf->curlen; } const void * membuf_datapointer( struct membuf *pBuf ) { return ((void *)(pBuf->buf)); } const char * membuf_strtok( struct membuf *pBuf, const char *sep, void **pLast ) { if ( pBuf ){ pBuf->_strtoklast = NULL; *pLast = pBuf; return strtok_r( ((char *)(pBuf->buf)), sep, &(pBuf->_strtoklast) ); } else { // recover our pBuf pBuf = *((struct membuf **)(pLast)); return strtok_r( NULL, sep, &(pBuf->_strtoklast) ); } } struct membuf * membuf_new(void) { // by default - parameters are zero. struct membuf *pBuf; pBuf = calloc( 1, sizeof(*pBuf) ); if ( pBuf ){ // we *ALWAYS* allocate +1 for null terminator. pBuf->buf = calloc( DEFAULT_BUFSIZE+1, sizeof(char)); if ( pBuf->buf == NULL ){ free(pBuf); pBuf = NULL; } else { pBuf->maxlen = DEFAULT_BUFSIZE; } } return pBuf; } struct membuf * membuf_grow( struct membuf *pBuf, int n ) { void *vp; signed int newsize; // this is a *SIGNED* value newsize = ((int)(pBuf->maxlen)) + n; // do not go negative, or too small if ( newsize < DEFAULT_BUFSIZE ){ newsize = DEFAULT_BUFSIZE; } // always alloc +1 for the null terminator vp = realloc( pBuf->buf, newsize+1 ); if ( vp ){ pBuf->buf = vp; pBuf->maxlen = newsize; return pBuf; } else { return NULL; } } void membuf_reset( struct membuf *pBuf ) { pBuf->curlen = 0; } void membuf_delete( struct membuf *pBuf ) { if ( pBuf ){ if ( pBuf->buf){ // wack data so it cannot be reused memset(pBuf->buf,0,pBuf->maxlen); free(pBuf->buf); } // wack dat so it cannot be reused memset(pBuf,0,sizeof(pBuf)); free(pBuf); } } int membuf_sprintf( struct membuf *pBuf , const char *fmt, ... ) { int r; va_list ap; va_start( ap, fmt ); r = membuf_vsprintf( pBuf, fmt, ap ); va_end(ap); return r; } int membuf_vsprintf( struct membuf *pBuf, const char *fmt, va_list ap ) { int r; size_t sa; int grew; grew = 0; for (;;) { sa = space_avail(pBuf); // do work r = vsnprintf( dataend( pBuf ), sa, fmt, ap ); if ( (r > 0) && (((size_t)(r)) < sa) ){ // Success! pBuf->curlen += ((size_t)(r)); // remember: We always alloc'ed +1 // so this does not overflow ((char *)(pBuf->buf))[ pBuf->curlen ] = 0; r = 0; break; } // failure if ( r < 0 ){ // Option(A) format error // Option(B) glibc2.0 bug // assume (B). r = (4 * DEFAULT_BUFSIZE); } // don't do this again if ( grew ){ r = -1; break; } grew = 1; pBuf = membuf_grow( pBuf, r ); if (pBuf == NULL){ // grow failed r = -1; break; } } return r; } struct membuf * membuf_strcat( struct membuf *pBuf, const char *pStr ) { return membuf_append( pBuf, pStr, strlen( pStr ) ); } struct membuf * membuf_append( struct membuf *pBuf, const void *pData, size_t len ) { size_t sa; int r; // how much room is there? sa = space_avail( pBuf ); // will it fit? if ( sa < len ){ // if not, how much do we need? r = ((int)(sa - len)); // do the grow. pBuf = membuf_grow( pBuf, r ); // failed? if (pBuf==NULL){ return pBuf; } } // append memcpy( dataend(pBuf), pData, len ); pBuf->curlen += len; return pBuf; }