- Fixes '==' whitespace
[openocd.git] / src / helper / membuf.c
blob5b24034dd1d6c17dd49f2fe6b18ffe78c65babf7
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 <malloc.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 return strtok_r( ((char *)(pBuf->buf)), sep, &(pBuf->_strtoklast) );
62 } else {
63 // recover our pBuf
64 pBuf = *((struct membuf **)(pLast));
65 return strtok_r( NULL, sep, &(pBuf->_strtoklast) );
71 struct membuf *
72 membuf_new(void)
74 // by default - parameters are zero.
75 struct membuf *pBuf;
77 pBuf = calloc( 1, sizeof(*pBuf) );
78 if ( pBuf ){
79 // we *ALWAYS* allocate +1 for null terminator.
80 pBuf->buf = calloc( DEFAULT_BUFSIZE+1, sizeof(char));
81 if ( pBuf->buf == NULL ){
82 free(pBuf);
83 pBuf = NULL;
84 } else {
85 pBuf->maxlen = DEFAULT_BUFSIZE;
88 return pBuf;
92 struct membuf *
93 membuf_grow( struct membuf *pBuf, int n )
95 void *vp;
96 signed int newsize;
98 // this is a *SIGNED* value
99 newsize = ((int)(pBuf->maxlen)) + n;
101 // do not go negative, or too small
102 if ( newsize < DEFAULT_BUFSIZE ){
103 newsize = DEFAULT_BUFSIZE;
106 // always alloc +1 for the null terminator
107 vp = realloc( pBuf->buf, newsize+1 );
108 if ( vp ){
109 pBuf->buf = vp;
110 pBuf->maxlen = newsize;
111 return pBuf;
112 } else {
113 return NULL;
118 void membuf_reset( struct membuf *pBuf )
120 pBuf->curlen = 0;
124 void membuf_delete( struct membuf *pBuf )
126 if ( pBuf ){
127 if ( pBuf->buf){
128 // wack data so it cannot be reused
129 memset(pBuf->buf,0,pBuf->maxlen);
130 free(pBuf->buf);
132 // wack dat so it cannot be reused
133 memset(pBuf,0,sizeof(pBuf));
134 free(pBuf);
139 membuf_sprintf( struct membuf *pBuf , const char *fmt, ... )
141 int r;
142 va_list ap;
143 va_start( ap, fmt );
144 r = membuf_vsprintf( pBuf, fmt, ap );
145 va_end(ap);
146 return r;
150 membuf_vsprintf( struct membuf *pBuf, const char *fmt, va_list ap )
152 int r;
153 size_t sa;
154 int grew;
157 grew = 0;
158 for (;;) {
159 sa = space_avail(pBuf);
161 // do work
162 r = vsnprintf( dataend( pBuf ),
164 fmt,
165 ap );
166 if ( (r > 0) && (((size_t)(r)) < sa) ){
167 // Success!
168 pBuf->curlen += ((size_t)(r));
169 // remember: We always alloc'ed +1
170 // so this does not overflow
171 ((char *)(pBuf->buf))[ pBuf->curlen ] = 0;
172 r = 0;
173 break;
176 // failure
177 if ( r < 0 ){
178 // Option(A) format error
179 // Option(B) glibc2.0 bug
180 // assume (B).
181 r = (4 * DEFAULT_BUFSIZE);
184 // don't do this again
185 if ( grew ){
186 r = -1;
187 break;
189 grew = 1;
190 pBuf = membuf_grow( pBuf, r );
191 if (pBuf == NULL){
192 // grow failed
193 r = -1;
194 break;
197 return r;
200 struct membuf *
201 membuf_strcat( struct membuf *pBuf, const char *pStr )
203 return membuf_append( pBuf, pStr, strlen( pStr ) );
206 struct membuf *
207 membuf_append( struct membuf *pBuf, const void *pData, size_t len )
209 size_t sa;
210 int r;
212 // how much room is there?
213 sa = space_avail( pBuf );
215 // will it fit?
216 if ( sa < len ){
217 // if not, how much do we need?
218 r = ((int)(sa - len));
219 // do the grow.
220 pBuf = membuf_grow( pBuf, r );
221 // failed?
222 if (pBuf == NULL){
223 return pBuf;
226 // append
227 memcpy( dataend(pBuf),
228 pData,
229 len );
230 pBuf->curlen += len;
231 return pBuf;