--- /dev/null
+/***************************************************************************\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
--- /dev/null
+#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