Houston, we have Mirror!
[openocd.git] / src / helper / membuf.c
blob766364a88e7066dbdba5281927012c1f1c9fbe49
1 /***************************************************************************
2 * Copyright (C) 2009 By Duane Ellis *
3 * openocd@duaneellis.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "membuf.h"
28 struct membuf {
29 // buflen is alway "+1" bigger then
30 // what is shown here, the +1 is for
31 // the NULL string terminator
32 #define DEFAULT_BUFSIZE 100
33 size_t maxlen; // allocated size
34 size_t curlen; // where we are inserting at
35 char *_strtoklast;
36 void *buf;
40 #define space_avail(pBuf) (pBuf->maxlen - pBuf->curlen)
41 #define dataend(pBuf) (((char *)(pBuf->buf)) + pBuf->curlen)
43 size_t
44 membuf_len(struct membuf *pBuf)
46 return pBuf->curlen;
49 const void *
50 membuf_datapointer(struct membuf *pBuf)
52 return ((void *)(pBuf->buf));
55 const char *
56 membuf_strtok(struct membuf *pBuf, const char *sep, void **pLast)
58 if (pBuf) {
59 pBuf->_strtoklast = NULL;
60 *pLast = pBuf;
61 // this should be "strtok_r()" but windows lacks */
62 return strtok(((char *)(pBuf->buf)), sep);
63 } else {
64 // recover our pBuf
65 pBuf = *((struct membuf **)(pLast));
66 // this should be "strtok_r()" but windows lacks */
67 return strtok( NULL, sep);
73 struct membuf *
74 membuf_new(void)
76 // by default - parameters are zero.
77 struct membuf *pBuf;
79 pBuf = calloc(1, sizeof(*pBuf));
80 if (pBuf) {
81 // we *ALWAYS* allocate +1 for null terminator.
82 pBuf->buf = calloc(DEFAULT_BUFSIZE + 1, sizeof(char));
83 if (pBuf->buf == NULL) {
84 free(pBuf);
85 pBuf = NULL;
86 } else {
87 pBuf->maxlen = DEFAULT_BUFSIZE;
90 return pBuf;
94 struct membuf *
95 membuf_grow(struct membuf *pBuf, int n)
97 void *vp;
98 signed int newsize;
100 // this is a *SIGNED* value
101 newsize = ((int)(pBuf->maxlen)) + n;
103 // do not go negative, or too small
104 if (newsize < DEFAULT_BUFSIZE) {
105 newsize = DEFAULT_BUFSIZE;
108 // always alloc +1 for the null terminator
109 vp = realloc(pBuf->buf, newsize + 1);
110 if (vp) {
111 pBuf->buf = vp;
112 pBuf->maxlen = newsize;
113 return pBuf;
114 } else {
115 return NULL;
120 void membuf_reset(struct membuf *pBuf)
122 pBuf->curlen = 0;
126 void membuf_delete(struct membuf *pBuf)
128 if (pBuf) {
129 if (pBuf->buf) {
130 // wack data so it cannot be reused
131 memset(pBuf->buf,0,pBuf->maxlen);
132 free(pBuf->buf);
134 // wack dat so it cannot be reused
135 memset(pBuf,0,sizeof(pBuf));
136 free(pBuf);
141 membuf_sprintf(struct membuf *pBuf , const char *fmt, ...)
143 int r;
144 va_list ap;
145 va_start(ap, fmt);
146 r = membuf_vsprintf(pBuf, fmt, ap);
147 va_end(ap);
148 return r;
152 membuf_vsprintf(struct membuf *pBuf, const char *fmt, va_list ap)
154 int r;
155 size_t sa;
156 int grew;
159 grew = 0;
160 for (;;) {
161 sa = space_avail(pBuf);
163 // do work
164 r = vsnprintf(dataend(pBuf),
166 fmt,
167 ap);
168 if ((r > 0) && (((size_t)(r)) < sa)) {
169 // Success!
170 pBuf->curlen += ((size_t)(r));
171 // remember: We always alloc'ed +1
172 // so this does not overflow
173 ((char *)(pBuf->buf))[ pBuf->curlen ] = 0;
174 r = 0;
175 break;
178 // failure
179 if (r < 0) {
180 // Option(A) format error
181 // Option(B) glibc2.0 bug
182 // assume (B).
183 r = (4 * DEFAULT_BUFSIZE);
186 // don't do this again
187 if (grew) {
188 r = -1;
189 break;
191 grew = 1;
192 pBuf = membuf_grow(pBuf, r);
193 if (pBuf == NULL) {
194 // grow failed
195 r = -1;
196 break;
199 return r;
202 struct membuf *
203 membuf_strcat(struct membuf *pBuf, const char *pStr)
205 return membuf_append(pBuf, pStr, strlen(pStr));
208 struct membuf *
209 membuf_append(struct membuf *pBuf, const void *pData, size_t len)
211 size_t sa;
212 int r;
214 // how much room is there?
215 sa = space_avail(pBuf);
217 // will it fit?
218 if (sa < len) {
219 // if not, how much do we need?
220 r = ((int)(sa - len));
221 // do the grow.
222 pBuf = membuf_grow(pBuf, r);
223 // failed?
224 if (pBuf == NULL) {
225 return pBuf;
228 // append
229 memcpy(dataend(pBuf),
230 pData,
231 len);
232 pBuf->curlen += len;
233 return pBuf;