2009-06-24 02:43:18 -05:00
|
|
|
/***************************************************************************
|
|
|
|
* 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>
|
2009-06-24 19:12:40 -05:00
|
|
|
#include <stdlib.h>
|
2009-06-24 02:43:18 -05:00
|
|
|
#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
|
2009-06-24 04:38:21 -05:00
|
|
|
#define DEFAULT_BUFSIZE 100
|
2009-06-24 02:43:18 -05:00
|
|
|
size_t maxlen; // allocated size
|
|
|
|
size_t curlen; // where we are inserting at
|
|
|
|
char *_strtoklast;
|
|
|
|
void *buf;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-06-24 04:38:08 -05:00
|
|
|
#define space_avail(pBuf) (pBuf->maxlen - pBuf->curlen)
|
|
|
|
#define dataend(pBuf) (((char *)(pBuf->buf)) + pBuf->curlen)
|
2009-06-24 02:43:18 -05:00
|
|
|
|
2009-06-24 04:38:21 -05:00
|
|
|
size_t
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_len(struct membuf *pBuf)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
return pBuf->curlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
const void *
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_datapointer(struct membuf *pBuf)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
return ((void *)(pBuf->buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_strtok(struct membuf *pBuf, const char *sep, void **pLast)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
2009-06-24 04:38:15 -05:00
|
|
|
if (pBuf) {
|
2009-06-24 02:43:18 -05:00
|
|
|
pBuf->_strtoklast = NULL;
|
|
|
|
*pLast = pBuf;
|
2009-06-27 11:44:35 -05:00
|
|
|
// this should be "strtok_r()" but windows lacks */
|
|
|
|
return strtok(((char *)(pBuf->buf)), sep);
|
2009-06-24 02:43:18 -05:00
|
|
|
} else {
|
|
|
|
// recover our pBuf
|
|
|
|
pBuf = *((struct membuf **)(pLast));
|
2009-06-27 11:44:35 -05:00
|
|
|
// this should be "strtok_r()" but windows lacks */
|
|
|
|
return strtok( NULL, sep);
|
2009-06-24 02:43:18 -05:00
|
|
|
}
|
|
|
|
}
|
2009-06-24 04:38:21 -05:00
|
|
|
|
2009-06-24 02:43:18 -05:00
|
|
|
|
|
|
|
|
|
|
|
struct membuf *
|
|
|
|
membuf_new(void)
|
|
|
|
{
|
|
|
|
// by default - parameters are zero.
|
|
|
|
struct membuf *pBuf;
|
|
|
|
|
2009-06-24 04:38:08 -05:00
|
|
|
pBuf = calloc(1, sizeof(*pBuf));
|
2009-06-24 04:38:15 -05:00
|
|
|
if (pBuf) {
|
2009-06-24 02:43:18 -05:00
|
|
|
// we *ALWAYS* allocate +1 for null terminator.
|
2009-06-24 04:38:01 -05:00
|
|
|
pBuf->buf = calloc(DEFAULT_BUFSIZE + 1, sizeof(char));
|
2009-06-24 04:38:15 -05:00
|
|
|
if (pBuf->buf == NULL) {
|
2009-06-24 02:43:18 -05:00
|
|
|
free(pBuf);
|
|
|
|
pBuf = NULL;
|
|
|
|
} else {
|
|
|
|
pBuf->maxlen = DEFAULT_BUFSIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct membuf *
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_grow(struct membuf *pBuf, int n)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
void *vp;
|
|
|
|
signed int newsize;
|
|
|
|
|
|
|
|
// this is a *SIGNED* value
|
|
|
|
newsize = ((int)(pBuf->maxlen)) + n;
|
|
|
|
|
|
|
|
// do not go negative, or too small
|
2009-06-24 04:38:15 -05:00
|
|
|
if (newsize < DEFAULT_BUFSIZE) {
|
2009-06-24 02:43:18 -05:00
|
|
|
newsize = DEFAULT_BUFSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// always alloc +1 for the null terminator
|
2009-06-24 04:38:08 -05:00
|
|
|
vp = realloc(pBuf->buf, newsize + 1);
|
2009-06-24 04:38:15 -05:00
|
|
|
if (vp) {
|
2009-06-24 02:43:18 -05:00
|
|
|
pBuf->buf = vp;
|
|
|
|
pBuf->maxlen = newsize;
|
|
|
|
return pBuf;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-24 04:38:08 -05:00
|
|
|
void membuf_reset(struct membuf *pBuf)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
pBuf->curlen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-24 04:38:08 -05:00
|
|
|
void membuf_delete(struct membuf *pBuf)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
2009-06-24 04:38:15 -05:00
|
|
|
if (pBuf) {
|
|
|
|
if (pBuf->buf) {
|
2009-06-24 02:43:18 -05:00
|
|
|
// 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
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_sprintf(struct membuf *pBuf , const char *fmt, ...)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
va_list ap;
|
2009-06-24 04:38:08 -05:00
|
|
|
va_start(ap, fmt);
|
|
|
|
r = membuf_vsprintf(pBuf, fmt, ap);
|
2009-06-24 02:43:18 -05:00
|
|
|
va_end(ap);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_vsprintf(struct membuf *pBuf, const char *fmt, va_list ap)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
size_t sa;
|
|
|
|
int grew;
|
|
|
|
|
|
|
|
|
|
|
|
grew = 0;
|
2009-06-24 04:37:23 -05:00
|
|
|
for (;;) {
|
2009-06-24 02:43:18 -05:00
|
|
|
sa = space_avail(pBuf);
|
|
|
|
|
|
|
|
// do work
|
2009-06-24 04:38:08 -05:00
|
|
|
r = vsnprintf(dataend(pBuf),
|
2009-06-24 02:43:18 -05:00
|
|
|
sa,
|
2009-06-24 04:38:21 -05:00
|
|
|
fmt,
|
2009-06-24 04:38:08 -05:00
|
|
|
ap);
|
2009-06-24 04:38:15 -05:00
|
|
|
if ((r > 0) && (((size_t)(r)) < sa)) {
|
2009-06-24 02:43:18 -05:00
|
|
|
// 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
|
2009-06-24 04:38:15 -05:00
|
|
|
if (r < 0) {
|
2009-06-24 02:43:18 -05:00
|
|
|
// Option(A) format error
|
|
|
|
// Option(B) glibc2.0 bug
|
|
|
|
// assume (B).
|
|
|
|
r = (4 * DEFAULT_BUFSIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// don't do this again
|
2009-06-24 04:38:15 -05:00
|
|
|
if (grew) {
|
2009-06-24 02:43:18 -05:00
|
|
|
r = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
grew = 1;
|
2009-06-24 04:38:08 -05:00
|
|
|
pBuf = membuf_grow(pBuf, r);
|
2009-06-24 04:38:15 -05:00
|
|
|
if (pBuf == NULL) {
|
2009-06-24 02:43:18 -05:00
|
|
|
// grow failed
|
|
|
|
r = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct membuf *
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_strcat(struct membuf *pBuf, const char *pStr)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
2009-06-24 04:38:08 -05:00
|
|
|
return membuf_append(pBuf, pStr, strlen(pStr));
|
2009-06-24 02:43:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct membuf *
|
2009-06-24 04:38:08 -05:00
|
|
|
membuf_append(struct membuf *pBuf, const void *pData, size_t len)
|
2009-06-24 02:43:18 -05:00
|
|
|
{
|
|
|
|
size_t sa;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
// how much room is there?
|
2009-06-24 04:38:08 -05:00
|
|
|
sa = space_avail(pBuf);
|
2009-06-24 02:43:18 -05:00
|
|
|
|
|
|
|
// will it fit?
|
2009-06-24 04:38:15 -05:00
|
|
|
if (sa < len) {
|
2009-06-24 02:43:18 -05:00
|
|
|
// if not, how much do we need?
|
|
|
|
r = ((int)(sa - len));
|
|
|
|
// do the grow.
|
2009-06-24 04:38:08 -05:00
|
|
|
pBuf = membuf_grow(pBuf, r);
|
2009-06-24 02:43:18 -05:00
|
|
|
// failed?
|
2009-06-24 04:38:15 -05:00
|
|
|
if (pBuf == NULL) {
|
2009-06-24 02:43:18 -05:00
|
|
|
return pBuf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// append
|
2009-06-24 04:38:01 -05:00
|
|
|
memcpy(dataend(pBuf),
|
2009-06-24 02:43:18 -05:00
|
|
|
pData,
|
2009-06-24 04:38:08 -05:00
|
|
|
len);
|
2009-06-24 02:43:18 -05:00
|
|
|
pBuf->curlen += len;
|
|
|
|
return pBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|