Add a growable sprintf memory buffer library
authorduane <duane@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 24 Jun 2009 01:54:25 +0000 (01:54 +0000)
committerduane <duane@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 24 Jun 2009 01:54:25 +0000 (01:54 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@2381 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/helper/Makefile.am
src/helper/membuf.c [new file with mode: 0644]
src/helper/membuf.h [new file with mode: 0644]

index 93df605..757eb2e 100644 (file)
@@ -23,6 +23,7 @@ libhelper_la_SOURCES = \
        time_support.c \
        replacements.c \
        fileio.c \
+       membuf.c \
        startup_tcl.c
 
 if IOUTIL
@@ -41,6 +42,7 @@ noinst_HEADERS = \
        types.h \
        log.h \
        command.h \
+       membuf.h \
        time_support.h \
        replacements.h \
        fileio.h \
diff --git a/src/helper/membuf.c b/src/helper/membuf.c
new file mode 100644 (file)
index 0000000..af396ca
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************\r
+ *   Copyright (C) 2009 By Duane Ellis                                     *\r
+ *   openocd@duaneellis.com                                                *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   This program is distributed in the hope that it will be useful,       *\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
+ *   GNU General Public License for more details.                          *\r
+ *                                                                         *\r
+ *   You should have received a copy of the GNU General Public License     *\r
+ *   along with this program; if not, write to the                         *\r
+ *   Free Software Foundation, Inc.,                                       *\r
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
+ ***************************************************************************/\r
+\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include <malloc.h>\r
+#include <string.h>\r
+\r
+#include "membuf.h"\r
+\r
+struct membuf {\r
+    // buflen is alway "+1" bigger then\r
+    // what is shown here, the +1 is for\r
+    // the NULL string terminator\r
+#define DEFAULT_BUFSIZE 100    \r
+    size_t maxlen; // allocated size\r
+    size_t curlen; // where we are inserting at\r
+    char *_strtoklast;\r
+    void *buf;\r
+};\r
+\r
+\r
+#define space_avail( pBuf )  (pBuf->maxlen - pBuf->curlen)\r
+#define dataend( pBuf )      ( ((char *)(pBuf->buf)) + pBuf->curlen )\r
+\r
+size_t \r
+membuf_len( struct membuf *pBuf )\r
+{\r
+    return pBuf->curlen;\r
+}\r
+\r
+const void *\r
+membuf_datapointer( struct membuf *pBuf )\r
+{\r
+    return ((void *)(pBuf->buf));\r
+}\r
+\r
+const char *\r
+membuf_strtok( struct membuf *pBuf, const char *sep, void **pLast )\r
+{\r
+    if( pBuf ){\r
+       pBuf->_strtoklast = NULL;\r
+       *pLast = pBuf;\r
+       return strtok_r( ((char *)(pBuf->buf)), sep, &(pBuf->_strtoklast) );\r
+    } else {\r
+       // recover our pBuf\r
+       pBuf = *((struct membuf **)(pLast));\r
+       return strtok_r( NULL, sep, &(pBuf->_strtoklast) );\r
+    }\r
+}\r
+       \r
+\r
+\r
+struct membuf *\r
+membuf_new(void)\r
+{\r
+    // by default - parameters are zero.\r
+    struct membuf *pBuf;\r
+\r
+    pBuf = calloc( 1, sizeof(*pBuf) );\r
+    if( pBuf ){\r
+       // we *ALWAYS* allocate +1 for null terminator.\r
+       pBuf->buf = calloc( DEFAULT_BUFSIZE+1, sizeof(char));\r
+       if( pBuf->buf == NULL ){\r
+           free(pBuf);\r
+           pBuf = NULL;\r
+       } else {\r
+           pBuf->maxlen = DEFAULT_BUFSIZE;\r
+       }\r
+    }\r
+    return pBuf;\r
+}\r
+\r
+\r
+struct membuf *\r
+membuf_grow( struct membuf *pBuf, int n )\r
+{\r
+    void *vp;\r
+    signed int newsize;\r
+\r
+    // this is a *SIGNED* value\r
+    newsize = ((int)(pBuf->maxlen)) + n;\r
+\r
+    // do not go negative, or too small\r
+    if( newsize < DEFAULT_BUFSIZE ){\r
+       newsize = DEFAULT_BUFSIZE;\r
+    }\r
+\r
+    // always alloc +1 for the null terminator\r
+    vp = realloc( pBuf->buf, newsize+1 );\r
+    if( vp ){\r
+       pBuf->buf    = vp;\r
+       pBuf->maxlen = newsize;\r
+       return pBuf;\r
+    } else {\r
+       return NULL;\r
+    }\r
+}\r
+\r
+\r
+void membuf_reset( struct membuf *pBuf )\r
+{\r
+    pBuf->curlen = 0;\r
+}\r
+\r
+\r
+void membuf_delete( struct membuf *pBuf )\r
+{\r
+    if( pBuf ){\r
+       if( pBuf->buf){\r
+           // wack data so it cannot be reused\r
+           memset(pBuf->buf,0,pBuf->maxlen);\r
+           free(pBuf->buf);\r
+       }\r
+       // wack dat so it cannot be reused\r
+       memset(pBuf,0,sizeof(pBuf));\r
+       free(pBuf);\r
+    }\r
+}\r
+\r
+int\r
+membuf_sprintf( struct membuf *pBuf , const char *fmt, ... )\r
+{\r
+    int r;\r
+    va_list ap;\r
+    va_start( ap, fmt );\r
+    r = membuf_vsprintf( pBuf, fmt, ap );\r
+    va_end(ap);\r
+    return r;\r
+}\r
+\r
+int\r
+membuf_vsprintf( struct membuf *pBuf, const char *fmt, va_list ap )\r
+{\r
+    int r;\r
+    size_t sa;\r
+    int grew;\r
+\r
+\r
+    grew = 0;\r
+    for(;;) {\r
+       sa = space_avail(pBuf);\r
+\r
+       // do work\r
+       r = vsnprintf( dataend( pBuf ),\r
+                      sa,\r
+                      fmt, \r
+                      ap );\r
+       if( (r > 0) && (((size_t)(r)) < sa) ){\r
+           // Success!\r
+           pBuf->curlen += ((size_t)(r));\r
+           // remember: We always alloc'ed +1\r
+           // so this does not overflow\r
+           ((char *)(pBuf->buf))[ pBuf->curlen ] = 0;\r
+           r = 0;\r
+           break;\r
+       }\r
+\r
+       // failure\r
+       if( r < 0 ){\r
+           // Option(A) format error\r
+           // Option(B) glibc2.0 bug\r
+           // assume (B).\r
+           r = (4 * DEFAULT_BUFSIZE);\r
+       }\r
+\r
+       // don't do this again\r
+       if( grew ){\r
+           r = -1;\r
+           break;\r
+       }\r
+       grew = 1;\r
+       pBuf = membuf_grow( pBuf, r );\r
+       if(pBuf == NULL){\r
+           // grow failed\r
+           r = -1;\r
+           break;\r
+       }\r
+    }\r
+    return r;\r
+}\r
+\r
+struct membuf *\r
+membuf_strcat( struct membuf *pBuf, const char *pStr )\r
+{\r
+    return membuf_append( pBuf, pStr, strlen( pStr ) );\r
+}\r
+\r
+struct membuf *\r
+membuf_append( struct membuf *pBuf, const void *pData, size_t len )\r
+{\r
+    size_t sa;\r
+    int r;\r
+\r
+    // how much room is there?\r
+    sa = space_avail( pBuf );\r
+\r
+    // will it fit?\r
+    if( sa < len ){\r
+       // if not, how much do we need?\r
+       r = ((int)(sa - len));\r
+       // do the grow.\r
+       pBuf = membuf_grow( pBuf, r );\r
+       // failed?\r
+       if(pBuf==NULL){\r
+           return pBuf;\r
+       }\r
+    }\r
+    // append\r
+    memcpy( dataend(pBuf),\r
+           pData,\r
+           len );\r
+    pBuf->curlen += len;\r
+    return pBuf;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/src/helper/membuf.h b/src/helper/membuf.h
new file mode 100644 (file)
index 0000000..6b291ff
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef HELPER_MEMBUF_H\r
+#define HELPER_MEMBUF_H\r
+\r
+/** @file */\r
+\r
+/** @page MEMBUF - an auto-growing string buffer\r
+ *\r
+ * With OpenOCD often, one must write code that sends text to\r
+ * different places.. the historical command_ctx, or JIM output,\r
+ * and/or other places.\r
+ *\r
+ * This is a simple 'string buffer' that auto-grows.\r
+ *\r
+ * More correctly put, this is a "memory buffer"\r
+ * it may contain binary data \r
+ * \r
+ * Note: Internally the buffer always has a 'null terminator'\r
+ */\r
+\r
+/* contents of this structure are 'opaque' */\r
+struct membuf;\r
+  \r
+\r
+/** Create a new membuf\r
+ * By default the memory buffer has "some non-zero-size"\r
+ * (couple hundred bytes, exact amount is opaque)\r
+ */\r
+struct membuf *membuf_new(void);\r
+\r
+/** delete (destroy) the mem buffer\r
+ * @param pBuf - buffer to release\r
+ */\r
+void membuf_delete( struct membuf *pBuf );\r
+\r
+\r
+/** grow/shrink a membuf by specified amount.\r
+ * @param pBuf   - the buffer \r
+ * @param amount - the amount to grow or shrink by.\r
+ *\r
+ * Symantics of 'realloc()' return NULL on failure\r
+ */\r
+struct membuf *membuf_grow( struct membuf *pBuf, int amount );\r
+\r
+/** how long is this buffer (memlen(), strlen())\r
+ * @param pBuf - the buffer\r
+ * \r
+ * @returns: length of current buffer.\r
+ */\r
+size_t membuf_len( struct membuf *pBuf );\r
+\r
+\r
+/** reset an membuf to zero length.\r
+ * @param pBuf - buffer to reset\r
+ *\r
+ * Note this does not 'release' the memory buffer\r
+ */\r
+void membuf_reset( struct membuf *pBuf );\r
+\r
+\r
+/** sprintf() to the string buffer\r
+ * @param pBuf - buffer to capture sprintf() data into\r
+ * @param fmt  - printf format\r
+ *\r
+ * Returns 0 on success\r
+ * Returns non-zero on failure\r
+ */\r
+int membuf_sprintf( struct membuf *pBuf , const char *fmt, ... );\r
+\r
+/** vsprintf() to the string buffer\r
+ * @param pBuf - buffer to capture sprintf() data into\r
+ * @param fmt  - printf format\r
+ * @param ap   - va_list for fmt\r
+ *\r
+ * Returns 0 on success\r
+ * Returns non-zero on failure\r
+ */\r
+int membuf_vsprintf( struct membuf *pBuf , const char *fmt, va_list ap);\r
+\r
+/** Tokenize lines using strtok() \r
+ * @param pBuf - buffer to tokenize\r
+ * @param delim - delimiter parameter for strtok_r()\r
+ * \r
+ * Identical to "strtok()" - pass "pBuff=NULL" on second call\r
+ *\r
+ * NOTE: This call is <b>destructive</b> to the buffer.\r
+ */\r
+const char *membuf_strtok( struct membuf *pBuf, const char *delim, void **pSave );\r
+\r
+/** Return pointer to the memory in the buffer\r
+ * @param pBuf - buffer\r
+ *\r
+ * NOTE: Thou shall not modify this pointer, it is <b>CONST</b>\r
+ */\r
+const void *membuf_datapointer( struct membuf *pBuf );\r
+\r
+\r
+/** Append data to the buffer\r
+ * @param pBuf  - buffer to append\r
+ * @param pData - pointer to data to append\r
+ * @param len   - length of data to append\r
+ *\r
+ * Modified symantics of "memcpy()".  On memory allocation failure\r
+ * returns NULL.  On success, returns pointer to orginal membuf.\r
+ */\r
+struct membuf *membuf_append( struct membuf *pBuf, const void *pData, size_t len );\r
+\r
+\r
+/** Append string to the buffer\r
+ * @param pBuf  - buffer to append\r
+ * @param str   - string to append\r
+ *\r
+ * Modified symantics of "strcat()".  On memory allocation failure\r
+ * returns NULL.  On success, returns pointer to orginal membuf.\r
+ */\r
+struct membuf *membuf_strcat( struct membuf *pBuf, const char *s );\r
+\r
+\r
+#endif\r