switch 'rm' command away from using Jim
[fw/openocd] / src / helper / membuf.c
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  ***************************************************************************/
20
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "membuf.h"
27
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;
37 };
38
39
40 #define space_avail(pBuf)  (pBuf->maxlen - pBuf->curlen)
41 #define dataend(pBuf)      (((char *)(pBuf->buf)) + pBuf->curlen)
42
43 size_t
44 membuf_len(struct membuf *pBuf)
45 {
46     return pBuf->curlen;
47 }
48
49 const void *
50 membuf_datapointer(struct membuf *pBuf)
51 {
52     return ((void *)(pBuf->buf));
53 }
54
55 const char *
56 membuf_strtok(struct membuf *pBuf, const char *sep, void **pLast)
57 {
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);
68     }
69 }
70
71
72
73 struct membuf *
74 membuf_new(void)
75 {
76     // by default - parameters are zero.
77     struct membuf *pBuf;
78
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;
88         }
89     }
90     return pBuf;
91 }
92
93
94 struct membuf *
95 membuf_grow(struct membuf *pBuf, int n)
96 {
97     void *vp;
98     signed int newsize;
99
100     // this is a *SIGNED* value
101     newsize = ((int)(pBuf->maxlen)) + n;
102
103     // do not go negative, or too small
104     if (newsize < DEFAULT_BUFSIZE) {
105         newsize = DEFAULT_BUFSIZE;
106     }
107
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;
116     }
117 }
118
119
120 void membuf_reset(struct membuf *pBuf)
121 {
122     pBuf->curlen = 0;
123 }
124
125
126 void membuf_delete(struct membuf *pBuf)
127 {
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);
133         }
134         // wack dat so it cannot be reused
135         memset(pBuf,0,sizeof(pBuf));
136         free(pBuf);
137     }
138 }
139
140 int
141 membuf_sprintf(struct membuf *pBuf , const char *fmt, ...)
142 {
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;
149 }
150
151 int
152 membuf_vsprintf(struct membuf *pBuf, const char *fmt, va_list ap)
153 {
154     int r;
155     size_t sa;
156     int grew;
157
158
159     grew = 0;
160     for (;;) {
161         sa = space_avail(pBuf);
162
163         // do work
164         r = vsnprintf(dataend(pBuf),
165                        sa,
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;
176         }
177
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);
184         }
185
186         // don't do this again
187         if (grew) {
188             r = -1;
189             break;
190         }
191         grew = 1;
192         pBuf = membuf_grow(pBuf, r);
193         if (pBuf == NULL) {
194             // grow failed
195             r = -1;
196             break;
197         }
198     }
199     return r;
200 }
201
202 struct membuf *
203 membuf_strcat(struct membuf *pBuf, const char *pStr)
204 {
205     return membuf_append(pBuf, pStr, strlen(pStr));
206 }
207
208 struct membuf *
209 membuf_append(struct membuf *pBuf, const void *pData, size_t len)
210 {
211     size_t sa;
212     int r;
213
214     // how much room is there?
215     sa = space_avail(pBuf);
216
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;
226         }
227     }
228     // append
229     memcpy(dataend(pBuf),
230             pData,
231             len);
232     pBuf->curlen += len;
233     return pBuf;
234 }
235
236
237
238
239
240