diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am
index 93df6058147ccc47af0e5c2239647cb503b626e1..757eb2e1b4b0ffa5acab6c2aeb122775aeeb7aeb 100644
--- a/src/helper/Makefile.am
+++ b/src/helper/Makefile.am
@@ -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
index 0000000000000000000000000000000000000000..af396ca0c7637c7c79951ebea7c7f60a17d92f5e
--- /dev/null
+++ b/src/helper/membuf.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <string.h>
+
+#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;
+}
+
+
+
+
+
+
diff --git a/src/helper/membuf.h b/src/helper/membuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b291ff212cb1754c5bafd29475481aa8f9652d0
--- /dev/null
+++ b/src/helper/membuf.h
@@ -0,0 +1,118 @@
+#ifndef HELPER_MEMBUF_H
+#define HELPER_MEMBUF_H
+
+/** @file */
+
+/** @page MEMBUF - an auto-growing string buffer
+ *
+ * With OpenOCD often, one must write code that sends text to
+ * different places.. the historical command_ctx, or JIM output,
+ * and/or other places.
+ *
+ * This is a simple 'string buffer' that auto-grows.
+ *
+ * More correctly put, this is a "memory buffer"
+ * it may contain binary data 
+ * 
+ * Note: Internally the buffer always has a 'null terminator'
+ */
+
+/* contents of this structure are 'opaque' */
+struct membuf;
+  
+
+/** Create a new membuf
+ * By default the memory buffer has "some non-zero-size"
+ * (couple hundred bytes, exact amount is opaque)
+ */
+struct membuf *membuf_new(void);
+
+/** delete (destroy) the mem buffer
+ * @param pBuf - buffer to release
+ */
+void membuf_delete( struct membuf *pBuf );
+
+
+/** grow/shrink a membuf by specified amount.
+ * @param pBuf   - the buffer 
+ * @param amount - the amount to grow or shrink by.
+ *
+ * Symantics of 'realloc()' return NULL on failure
+ */
+struct membuf *membuf_grow( struct membuf *pBuf, int amount );
+
+/** how long is this buffer (memlen(), strlen())
+ * @param pBuf - the buffer
+ * 
+ * @returns: length of current buffer.
+ */
+size_t membuf_len( struct membuf *pBuf );
+
+
+/** reset an membuf to zero length.
+ * @param pBuf - buffer to reset
+ *
+ * Note this does not 'release' the memory buffer
+ */
+void membuf_reset( struct membuf *pBuf );
+
+
+/** sprintf() to the string buffer
+ * @param pBuf - buffer to capture sprintf() data into
+ * @param fmt  - printf format
+ *
+ * Returns 0 on success
+ * Returns non-zero on failure
+ */
+int membuf_sprintf( struct membuf *pBuf , const char *fmt, ... );
+
+/** vsprintf() to the string buffer
+ * @param pBuf - buffer to capture sprintf() data into
+ * @param fmt  - printf format
+ * @param ap   - va_list for fmt
+ *
+ * Returns 0 on success
+ * Returns non-zero on failure
+ */
+int membuf_vsprintf( struct membuf *pBuf , const char *fmt, va_list ap);
+
+/** Tokenize lines using strtok() 
+ * @param pBuf - buffer to tokenize
+ * @param delim - delimiter parameter for strtok_r()
+ * 
+ * Identical to "strtok()" - pass "pBuff=NULL" on second call
+ *
+ * NOTE: This call is <b>destructive</b> to the buffer.
+ */
+const char *membuf_strtok( struct membuf *pBuf, const char *delim, void **pSave );
+
+/** Return pointer to the memory in the buffer
+ * @param pBuf - buffer
+ *
+ * NOTE: Thou shall not modify this pointer, it is <b>CONST</b>
+ */
+const void *membuf_datapointer( struct membuf *pBuf );
+
+
+/** Append data to the buffer
+ * @param pBuf  - buffer to append
+ * @param pData - pointer to data to append
+ * @param len   - length of data to append
+ *
+ * Modified symantics of "memcpy()".  On memory allocation failure
+ * returns NULL.  On success, returns pointer to orginal membuf.
+ */
+struct membuf *membuf_append( struct membuf *pBuf, const void *pData, size_t len );
+
+
+/** Append string to the buffer
+ * @param pBuf  - buffer to append
+ * @param str   - string to append
+ *
+ * Modified symantics of "strcat()".  On memory allocation failure
+ * returns NULL.  On success, returns pointer to orginal membuf.
+ */
+struct membuf *membuf_strcat( struct membuf *pBuf, const char *s );
+
+
+#endif