Mercurial > libpst
comparison src/vbuf.c @ 182:b65e8d0a088a
more cleanup on external names in the shared object file
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 13 Apr 2009 11:39:33 -0700 |
parents | ac6e22c8a9cf |
children | 320cfcba8058 |
comparison
equal
deleted
inserted
replaced
181:3b04745ff76d | 182:b65e8d0a088a |
---|---|
1 | 1 |
2 #include "define.h" | 2 #include "define.h" |
3 | |
4 static int pst_skip_nl(char *s); // returns the width of the newline at s[0] | |
5 static int pst_find_nl(vstr *vs); // find newline of type type in b | |
6 | |
7 // vbuf functions | |
8 static void pst_vbfree(vbuf *vb); | |
9 static void pst_vbclear(vbuf *vb); // ditch the data, keep the buffer | |
10 static void pst_vbresize(vbuf *vb, size_t len); | |
11 static size_t pst_vbavail(vbuf *vb); | |
12 static void pst_vbdump(vbuf *vb); | |
13 static void pst_vbskipws(vbuf *vb); | |
14 static void pst_vbskip(vbuf *vb, size_t skip); | |
15 static void pst_vboverwrite(vbuf *vbdest, vbuf *vbsrc); | |
16 | |
17 // vstr functions | |
18 static vstr *pst_vsalloc(size_t len); | |
19 static char *pst_vsb(vstr *vs); | |
20 static size_t pst_vslen(vstr *vs); //strlen | |
21 static void pst_vsfree(vstr *vs); | |
22 static void pst_vsset(vstr *vs, char *s); // Store string s in vb | |
23 static void pst_vsnset(vstr *vs, char *s, size_t n); // Store string s in vb | |
24 static void pst_vsgrow(vstr *vs, size_t len); // grow buffer by len bytes, data are preserved | |
25 static size_t pst_vsavail(vstr *vs); | |
26 static void pst_vscat(vstr *vs, char *str); | |
27 static void pst_vsncat(vstr *vs, char *str, size_t len); | |
28 static void pst_vsnprepend(vstr *vs, char *str, size_t len) ; | |
29 static void pst_vsskip(vstr *vs, size_t len); | |
30 static int pst_vscmp(vstr *vs, char *str); | |
31 static void pst_vsskipws(vstr *vs); | |
32 static void pst_vs_printf(vstr *vs, char *fmt, ...); | |
33 static void pst_vs_printfa(vstr *vs, char *fmt, ...); | |
34 static void pst_vshexdump(vstr *vs, const char *b, size_t start, size_t stop, int ascii); | |
35 static int pst_vscatprintf(vstr *vs, char *fmt, ...); | |
36 static void pst_vsvprintf(vstr *vs, char *fmt, va_list ap); | |
37 static void pst_vstrunc(vstr *vs, size_t off); // Drop chars [off..dlen] | |
38 static int pst_vslast(vstr *vs); // returns the last character stored in a vstr string | |
39 static void pst_vscharcat(vstr *vs, int ch); | |
40 | |
41 static void pst_unicode_close(); | |
42 | |
43 static int pst_vb_skipline(vbuf *vb); // in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff" | |
44 | |
45 | |
46 | |
47 | |
48 #define ASSERT(x,...) { if( !(x) ) DIE(( __VA_ARGS__)); } | |
49 | |
50 | |
51 static int pst_skip_nl(char *s) | |
52 { | |
53 if (s[0] == '\n') | |
54 return 1; | |
55 if (s[0] == '\r' && s[1] == '\n') | |
56 return 2; | |
57 if (s[0] == '\0') | |
58 return 0; | |
59 return -1; | |
60 } | |
61 | |
62 | |
63 static int pst_find_nl(vstr * vs) | |
64 { | |
65 char *nextr, *nextn; | |
66 | |
67 nextr = memchr(vs->b, '\r', vs->dlen); | |
68 nextn = memchr(vs->b, '\n', vs->dlen); | |
69 | |
70 //case 1: UNIX, we find \n first | |
71 if (nextn && (!nextr || (nextr > nextn))) { | |
72 return nextn - vs->b; | |
73 } | |
74 //case 2: DOS, we find \r\n | |
75 if (nextr && nextn && (nextn-nextr == 1)) { | |
76 return nextr - vs->b; | |
77 } | |
78 //case 3: we find nothing | |
79 | |
80 return -1; | |
81 } | |
82 | |
83 | |
84 // UTF8 <-> UTF16 <-> ISO8859 Character set conversion functions and (ack) their globals | |
85 | 3 |
86 static int unicode_up = 0; | 4 static int unicode_up = 0; |
87 static iconv_t i16to8; | 5 static iconv_t i16to8; |
88 static const char *target_charset = NULL; | 6 static const char *target_charset = NULL; |
89 static int target_open_from = 0; | 7 static int target_open_from = 0; |
90 static int target_open_to = 0; | 8 static int target_open_to = 0; |
91 static iconv_t i8totarget = (iconv_t)-1; | 9 static iconv_t i8totarget = (iconv_t)-1; |
92 static iconv_t target2i8 = (iconv_t)-1; | 10 static iconv_t target2i8 = (iconv_t)-1; |
93 | 11 |
94 | 12 |
95 void pst_unicode_init() | 13 #define ASSERT(x,...) { if( !(x) ) DIE(( __VA_ARGS__)); } |
96 { | 14 |
97 if (unicode_up) pst_unicode_close(); | 15 |
98 i16to8 = iconv_open("utf-8", "utf-16le"); | 16 /** DESTRUCTIVELY grow or shrink buffer |
99 if (i16to8 == (iconv_t)-1) { | 17 */ |
100 WARN(("Couldn't open iconv descriptor for utf-16le to utf-8.\n")); | 18 static void pst_vbresize(pst_vbuf *vb, size_t len); |
101 exit(1); | 19 static void pst_vbresize(pst_vbuf *vb, size_t len) |
102 } | 20 { |
103 unicode_up = 1; | 21 vb->dlen = 0; |
104 } | 22 |
105 | 23 if (vb->blen >= len) { |
106 | 24 vb->b = vb->buf; |
107 static void pst_unicode_close() | 25 return; |
108 { | 26 } |
109 iconv_close(i16to8); | 27 |
110 if (target_open_from) iconv_close(i8totarget); | 28 vb->buf = realloc(vb->buf, len); |
111 if (target_open_to) iconv_close(target2i8); | 29 vb->b = vb->buf; |
112 if (target_charset) free((char *)target_charset); | 30 vb->blen = len; |
113 target_charset = NULL; | 31 } |
114 target_open_from = 0; | 32 |
115 target_open_to = 0; | 33 |
116 unicode_up = 0; | 34 static size_t pst_vbavail(pst_vbuf * vb); |
117 } | 35 static size_t pst_vbavail(pst_vbuf * vb) |
118 | 36 { |
119 | 37 return vb->blen - vb->dlen - (size_t)(vb->b - vb->buf); |
120 static int utf16_is_terminated(const char *str, int length); | |
121 static int utf16_is_terminated(const char *str, int length) | |
122 { | |
123 VSTR_STATIC(errbuf, 100); | |
124 int len = -1; | |
125 int i; | |
126 for (i = 0; i < length; i += 2) { | |
127 if (str[i] == 0 && str[i + 1] == 0) { | |
128 len = i; | |
129 } | |
130 } | |
131 | |
132 if (-1 == len) { | |
133 pst_vshexdump(errbuf, str, 0, length, 1); | |
134 DEBUG_WARN(("String is not zero terminated (probably broken data from registry) %s.\n", errbuf->b)); | |
135 } | |
136 | |
137 return (-1 == len) ? 0 : 1; | |
138 } | |
139 | |
140 | |
141 size_t pst_vb_utf16to8(vbuf *dest, const char *inbuf, int iblen) | |
142 { | |
143 size_t inbytesleft = iblen; | |
144 size_t icresult = (size_t)-1; | |
145 size_t outbytesleft = 0; | |
146 char *outbuf = NULL; | |
147 int myerrno; | |
148 | |
149 ASSERT(unicode_up, "vb_utf16to8() called before unicode started."); | |
150 pst_vbresize(dest, iblen); | |
151 | |
152 //Bad Things can happen if a non-zero-terminated utf16 string comes through here | |
153 if (!utf16_is_terminated(inbuf, iblen)) | |
154 return (size_t)-1; | |
155 | |
156 do { | |
157 outbytesleft = dest->blen - dest->dlen; | |
158 outbuf = dest->b + dest->dlen; | |
159 icresult = iconv(i16to8, (ICONV_CONST char**)&inbuf, &inbytesleft, &outbuf, &outbytesleft); | |
160 myerrno = errno; | |
161 dest->dlen = outbuf - dest->b; | |
162 if (inbytesleft) pst_vbgrow(dest, inbytesleft); | |
163 } while ((size_t)-1 == icresult && E2BIG == myerrno); | |
164 | |
165 if (icresult == (size_t)-1) { | |
166 DEBUG_WARN(("iconv failure: %s\n", strerror(myerrno))); | |
167 pst_unicode_init(); | |
168 return (size_t)-1; | |
169 } | |
170 return (icresult) ? (size_t)-1 : 0; | |
171 } | 38 } |
172 | 39 |
173 | 40 |
174 static void open_targets(const char* charset); | 41 static void open_targets(const char* charset); |
175 static void open_targets(const char* charset) | 42 static void open_targets(const char* charset) |
193 } | 60 } |
194 } | 61 } |
195 } | 62 } |
196 | 63 |
197 | 64 |
198 static size_t sbcs_conversion(vbuf *dest, const char *inbuf, int iblen, iconv_t conversion); | 65 static size_t sbcs_conversion(pst_vbuf *dest, const char *inbuf, int iblen, iconv_t conversion); |
199 static size_t sbcs_conversion(vbuf *dest, const char *inbuf, int iblen, iconv_t conversion) | 66 static size_t sbcs_conversion(pst_vbuf *dest, const char *inbuf, int iblen, iconv_t conversion) |
200 { | 67 { |
201 size_t inbytesleft = iblen; | 68 size_t inbytesleft = iblen; |
202 size_t icresult = (size_t)-1; | 69 size_t icresult = (size_t)-1; |
203 size_t outbytesleft = 0; | 70 size_t outbytesleft = 0; |
204 char *outbuf = NULL; | 71 char *outbuf = NULL; |
222 } | 89 } |
223 return (icresult) ? (size_t)-1 : 0; | 90 return (icresult) ? (size_t)-1 : 0; |
224 } | 91 } |
225 | 92 |
226 | 93 |
227 size_t pst_vb_utf8to8bit(vbuf *dest, const char *inbuf, int iblen, const char* charset) | 94 static void pst_unicode_close(); |
228 { | 95 static void pst_unicode_close() |
229 open_targets(charset); | 96 { |
230 if (!target_open_from) return (size_t)-1; // failure to open the target | 97 iconv_close(i16to8); |
231 return sbcs_conversion(dest, inbuf, iblen, i8totarget); | 98 if (target_open_from) iconv_close(i8totarget); |
232 } | 99 if (target_open_to) iconv_close(target2i8); |
233 | 100 if (target_charset) free((char *)target_charset); |
234 | 101 target_charset = NULL; |
235 size_t pst_vb_8bit2utf8(vbuf *dest, const char *inbuf, int iblen, const char* charset) | 102 target_open_from = 0; |
236 { | 103 target_open_to = 0; |
237 open_targets(charset); | 104 unicode_up = 0; |
238 if (!target_open_to) return (size_t)-1; // failure to open the target | 105 } |
239 return sbcs_conversion(dest, inbuf, iblen, target2i8); | 106 |
240 } | 107 |
241 | 108 static int utf16_is_terminated(const char *str, int length); |
242 | 109 static int utf16_is_terminated(const char *str, int length) |
243 vbuf *pst_vballoc(size_t len) | 110 { |
244 { | 111 int len = -1; |
245 vbuf *result = malloc(sizeof(vbuf)); | 112 int i; |
113 for (i = 0; i < length; i += 2) { | |
114 if (str[i] == 0 && str[i + 1] == 0) { | |
115 len = i; | |
116 } | |
117 } | |
118 | |
119 if (len == -1) { | |
120 DEBUG_WARN(("utf16 string is not zero terminated\n")); | |
121 } | |
122 | |
123 return (len == -1) ? 0 : 1; | |
124 } | |
125 | |
126 | |
127 pst_vbuf *pst_vballoc(size_t len) | |
128 { | |
129 pst_vbuf *result = pst_malloc(sizeof(pst_vbuf)); | |
246 if (result) { | 130 if (result) { |
247 result->dlen = 0; | 131 result->dlen = 0; |
248 result->blen = 0; | 132 result->blen = 0; |
249 result->buf = NULL; | 133 result->buf = NULL; |
250 pst_vbresize(result, len); | 134 pst_vbresize(result, len); |
252 else DIE(("malloc() failure")); | 136 else DIE(("malloc() failure")); |
253 return result; | 137 return result; |
254 } | 138 } |
255 | 139 |
256 | 140 |
257 static void pst_vbcheck(vbuf * vb) | 141 /** out: vbavail(vb) >= len, data are preserved |
258 { | 142 */ |
259 ASSERT(vb->b >= vb->buf, "vbcheck(): data not inside buffer"); | 143 void pst_vbgrow(pst_vbuf *vb, size_t len) |
260 ASSERT((size_t)(vb->b - vb->buf) <= vb->blen, "vbcheck(): vb->b outside of buffer range."); | |
261 ASSERT(vb->dlen <= vb->blen, "vbcheck(): data length > buffer length."); | |
262 ASSERT(vb->blen < 1024 * 1024, "vbcheck(): blen is a bit large...hmmm."); | |
263 } | |
264 | |
265 | |
266 static void pst_vbfree(vbuf * vb) | |
267 { | |
268 free(vb->buf); | |
269 free(vb); | |
270 } | |
271 | |
272 | |
273 static void pst_vbclear(vbuf *vb) // ditch the data, keep the buffer | |
274 { | |
275 pst_vbresize(vb, 0); | |
276 } | |
277 | |
278 | |
279 static void pst_vbresize(vbuf *vb, size_t len) // DESTRUCTIVELY grow or shrink buffer | |
280 { | |
281 vb->dlen = 0; | |
282 | |
283 if (vb->blen >= len) { | |
284 vb->b = vb->buf; | |
285 return; | |
286 } | |
287 | |
288 vb->buf = realloc(vb->buf, len); | |
289 vb->b = vb->buf; | |
290 vb->blen = len; | |
291 } | |
292 | |
293 | |
294 static size_t pst_vbavail(vbuf * vb) | |
295 { | |
296 return vb->blen - vb->dlen - (size_t)(vb->b - vb->buf); | |
297 } | |
298 | |
299 | |
300 void pst_vbgrow(vbuf *vb, size_t len) // out: vbavail(vb) >= len, data are preserved | |
301 { | 144 { |
302 if (0 == len) | 145 if (0 == len) |
303 return; | 146 return; |
304 | 147 |
305 if (0 == vb->blen) { | 148 if (0 == vb->blen) { |
327 | 170 |
328 ASSERT(pst_vbavail(vb) >= len, "vbgrow(): I have failed in my mission."); | 171 ASSERT(pst_vbavail(vb) >= len, "vbgrow(): I have failed in my mission."); |
329 } | 172 } |
330 | 173 |
331 | 174 |
332 void pst_vbset(vbuf * vb, void *b, size_t len) // set vbuf b size=len, resize if necessary, relen = how much to over-allocate | 175 /** set vbuf b size=len, resize if necessary, relen = how much to over-allocate |
176 */ | |
177 void pst_vbset(pst_vbuf * vb, void *b, size_t len) | |
333 { | 178 { |
334 pst_vbresize(vb, len); | 179 pst_vbresize(vb, len); |
335 memcpy(vb->b, b, len); | 180 memcpy(vb->b, b, len); |
336 vb->dlen = len; | 181 vb->dlen = len; |
337 } | 182 } |
338 | 183 |
339 | 184 |
340 static void pst_vsskipws(vstr * vs) | 185 /** append len bytes of b to vb, resize if necessary |
341 { | 186 */ |
342 char *p = vs->b; | 187 void pst_vbappend(pst_vbuf *vb, void *b, size_t len) |
343 while ((size_t)(p - vs->b) < vs->dlen && isspace(p[0])) | |
344 p++; | |
345 | |
346 pst_vbskip((vbuf *) vs, p - vs->b); | |
347 } | |
348 | |
349 | |
350 // append len bytes of b to vbuf, resize if necessary | |
351 void pst_vbappend(vbuf *vb, void *b, size_t len) | |
352 { | 188 { |
353 if (0 == vb->dlen) { | 189 if (0 == vb->dlen) { |
354 pst_vbset(vb, b, len); | 190 pst_vbset(vb, b, len); |
355 return; | 191 return; |
356 } | 192 } |
358 memcpy(vb->b + vb->dlen, b, len); | 194 memcpy(vb->b + vb->dlen, b, len); |
359 vb->dlen += len; | 195 vb->dlen += len; |
360 } | 196 } |
361 | 197 |
362 | 198 |
363 // dumps the first skip bytes from vbuf | 199 void pst_unicode_init() |
364 static void pst_vbskip(vbuf *vb, size_t skip) | 200 { |
365 { | 201 if (unicode_up) pst_unicode_close(); |
366 ASSERT(skip <= vb->dlen, "vbskip(): Attempt to seek past end of buffer."); | 202 i16to8 = iconv_open("utf-8", "utf-16le"); |
367 vb->b += skip; | 203 if (i16to8 == (iconv_t)-1) { |
368 vb->dlen -= skip; | 204 WARN(("Couldn't open iconv descriptor for utf-16le to utf-8.\n")); |
369 } | 205 exit(1); |
370 | 206 } |
371 | 207 unicode_up = 1; |
372 // overwrite vbdest with vbsrc | 208 } |
373 static void pst_vboverwrite(vbuf *vbdest, vbuf *vbsrc) | 209 |
374 { | 210 |
375 pst_vbresize(vbdest, vbsrc->blen); | 211 size_t pst_vb_utf16to8(pst_vbuf *dest, const char *inbuf, int iblen) |
376 memcpy(vbdest->b, vbsrc->b, vbsrc->dlen); | 212 { |
377 vbdest->blen = vbsrc->blen; | 213 size_t inbytesleft = iblen; |
378 vbdest->dlen = vbsrc->dlen; | 214 size_t icresult = (size_t)-1; |
379 } | 215 size_t outbytesleft = 0; |
380 | 216 char *outbuf = NULL; |
381 | 217 int myerrno; |
382 static vstr *pst_vsalloc(size_t len) | 218 |
383 { | 219 ASSERT(unicode_up, "vb_utf16to8() called before unicode started."); |
384 vstr *result = (vstr *) pst_vballoc(len + 1); | 220 pst_vbresize(dest, iblen); |
385 pst_vsset(result, ""); | 221 |
386 return result; | 222 //Bad Things can happen if a non-zero-terminated utf16 string comes through here |
387 } | 223 if (!utf16_is_terminated(inbuf, iblen)) |
388 | 224 return (size_t)-1; |
389 | 225 |
390 static char *pst_vsstr(vstr * vs); | 226 do { |
391 static char *pst_vsstr(vstr * vs) | 227 outbytesleft = dest->blen - dest->dlen; |
392 { | 228 outbuf = dest->b + dest->dlen; |
393 return vs->b; | 229 icresult = iconv(i16to8, (ICONV_CONST char**)&inbuf, &inbytesleft, &outbuf, &outbytesleft); |
394 } | 230 myerrno = errno; |
395 | 231 dest->dlen = outbuf - dest->b; |
396 | 232 if (inbytesleft) pst_vbgrow(dest, inbytesleft); |
397 static size_t pst_vslen(vstr * vs) | 233 } while ((size_t)-1 == icresult && E2BIG == myerrno); |
398 { | 234 |
399 return strlen(pst_vsstr(vs)); | 235 if (icresult == (size_t)-1) { |
400 } | 236 DEBUG_WARN(("iconv failure: %s\n", strerror(myerrno))); |
401 | 237 pst_unicode_init(); |
402 | 238 return (size_t)-1; |
403 static void pst_vsfree(vstr * vs) | 239 } |
404 { | 240 return (icresult) ? (size_t)-1 : 0; |
405 pst_vbfree((vbuf *) vs); | 241 } |
406 } | 242 |
407 | 243 |
408 | 244 size_t pst_vb_utf8to8bit(pst_vbuf *dest, const char *inbuf, int iblen, const char* charset) |
409 static void pst_vscharcat(vstr * vb, int ch) | 245 { |
410 { | 246 open_targets(charset); |
411 pst_vbgrow((vbuf *) vb, 1); | 247 if (!target_open_from) return (size_t)-1; // failure to open the target |
412 vb->b[vb->dlen - 1] = ch; | 248 return sbcs_conversion(dest, inbuf, iblen, i8totarget); |
413 vb->b[vb->dlen] = '\0'; | 249 } |
414 vb->dlen++; | 250 |
415 } | 251 |
416 | 252 size_t pst_vb_8bit2utf8(pst_vbuf *dest, const char *inbuf, int iblen, const char* charset) |
417 | 253 { |
418 // prependappend string str to vbuf, vbuf must already contain a valid string | 254 open_targets(charset); |
419 static void pst_vsnprepend(vstr * vb, char *str, size_t len) | 255 if (!target_open_to) return (size_t)-1; // failure to open the target |
420 { | 256 return sbcs_conversion(dest, inbuf, iblen, target2i8); |
421 ASSERT(vb->b[vb->dlen - 1] == '\0', "vsncat(): attempt to append string to non-string."); | 257 } |
422 size_t sl = strlen(str); | 258 |
423 size_t n = (sl < len) ? sl : len; | |
424 pst_vbgrow((vbuf *) vb, n + 1); | |
425 memmove(vb->b + n, vb->b, vb->dlen - 1); | |
426 memcpy(vb->b, str, n); | |
427 vb->dlen += n; | |
428 vb->b[vb->dlen - 1] = '\0'; | |
429 } | |
430 | |
431 | |
432 // len < dlen-1 -> skip len chars, else DIE | |
433 static void pst_vsskip(vstr * vs, size_t len) | |
434 { | |
435 ASSERT(len < vs->dlen - 1, "Attempt to skip past end of string"); | |
436 pst_vbskip((vbuf *) vs, len); | |
437 } | |
438 | |
439 | |
440 // in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff" | |
441 static int pst_vsskipline(vstr * vs) | |
442 { | |
443 int nloff = pst_find_nl(vs); | |
444 int nll = pst_skip_nl(vs->b + nloff); | |
445 | |
446 if (nloff < 0) { | |
447 //TODO: error | |
448 printf("vb_skipline(): there seems to be no newline here.\n"); | |
449 return -1; | |
450 } | |
451 if (nll < 0) { | |
452 //TODO: error | |
453 printf("vb_skipline(): there seems to be no newline here...except there should be. :P\n"); | |
454 return -1; | |
455 } | |
456 | |
457 memmove(vs->b, vs->b + nloff + nll, vs->dlen - nloff - nll); | |
458 | |
459 vs->dlen -= nloff + nll; | |
460 | |
461 return 0; | |
462 } | |
463 | |
464 | |
465 static int pst_vscatprintf(vstr * vs, char *fmt, ...) | |
466 { | |
467 int size; | |
468 va_list ap; | |
469 | |
470 /* Guess we need no more than 100 bytes. */ | |
471 //vsresize( vb, 100 ); | |
472 if (!vs->b || vs->dlen == 0) { | |
473 pst_vsset(vs, ""); | |
474 } | |
475 | |
476 while (1) { | |
477 /* Try to print in the allocated space. */ | |
478 va_start(ap, fmt); | |
479 size = vsnprintf(vs->b + vs->dlen - 1, vs->blen - vs->dlen, fmt, ap); | |
480 va_end(ap); | |
481 | |
482 /* If that worked, return the string. */ | |
483 if ((size > -1) && ((size_t)size < vs->blen - vs->dlen)) { | |
484 vs->dlen += size; | |
485 return size; | |
486 } | |
487 /* Else try again with more space. */ | |
488 if (size >= 0) /* glibc 2.1 */ | |
489 pst_vbgrow((vbuf *) vs, size + 1); /* precisely what is needed */ | |
490 else /* glibc 2.0 */ | |
491 pst_vbgrow((vbuf *) vs, vs->blen); | |
492 } | |
493 } | |
494 | |
495 | |
496 // returns the last character stored in a vstr | |
497 static int pst_vslast(vstr * vs) | |
498 { | |
499 if (vs->dlen < 1) | |
500 return -1; | |
501 if (vs->b[vs->dlen - 1] != '\0') | |
502 return -1; | |
503 if (vs->dlen == 1) | |
504 return '\0'; | |
505 return vs->b[vs->dlen - 2]; | |
506 } | |
507 | |
508 | |
509 // print over vb | |
510 static void pst_vs_printf(vstr * vs, char *fmt, ...) | |
511 { | |
512 int size; | |
513 va_list ap; | |
514 | |
515 /* Guess we need no more than 100 bytes. */ | |
516 pst_vbresize((vbuf *) vs, 100); | |
517 | |
518 while (1) { | |
519 /* Try to print in the allocated space. */ | |
520 va_start(ap, fmt); | |
521 size = vsnprintf(vs->b, vs->blen, fmt, ap); | |
522 va_end(ap); | |
523 | |
524 /* If that worked, return the string. */ | |
525 if ((size > -1) && ((size_t)size < vs->blen)) { | |
526 vs->dlen = size + 1; | |
527 return; | |
528 } | |
529 /* Else try again with more space. */ | |
530 if (size >= 0) /* glibc 2.1 */ | |
531 pst_vbresize((vbuf *) vs, size + 1); /* precisely what is needed */ | |
532 else /* glibc 2.0 */ | |
533 pst_vbresize((vbuf *) vs, vs->blen * 2); | |
534 } | |
535 } | |
536 | |
537 | |
538 // printf append to vs | |
539 static void pst_vs_printfa(vstr * vs, char *fmt, ...) | |
540 { | |
541 int size; | |
542 va_list ap; | |
543 | |
544 if (vs->blen - vs->dlen < 50) | |
545 pst_vbgrow((vbuf *) vs, 100); | |
546 | |
547 while (1) { | |
548 /* Try to print in the allocated space. */ | |
549 va_start(ap, fmt); | |
550 size = vsnprintf(vs->b + vs->dlen - 1, vs->blen - vs->dlen + 1, fmt, ap); | |
551 va_end(ap); | |
552 | |
553 /* If that worked, return the string. */ | |
554 if ((size > -1) && ((size_t)size < vs->blen)) { | |
555 vs->dlen += size; | |
556 return; | |
557 } | |
558 /* Else try again with more space. */ | |
559 if (size >= 0) /* glibc 2.1 */ | |
560 pst_vbgrow((vbuf *) vs, size + 1 - vs->dlen); /* precisely what is needed */ | |
561 else /* glibc 2.0 */ | |
562 pst_vbgrow((vbuf *) vs, size); | |
563 } | |
564 } | |
565 | |
566 | |
567 static void pst_vshexdump(vstr * vs, const char *b, size_t start, size_t stop, int ascii) | |
568 { | |
569 char c; | |
570 int diff, i; | |
571 | |
572 while (start < stop) { | |
573 diff = stop - start; | |
574 if (diff > 16) | |
575 diff = 16; | |
576 | |
577 pst_vs_printfa(vs, ":%08X ", start); | |
578 | |
579 for (i = 0; i < diff; i++) { | |
580 if (8 == i) | |
581 pst_vs_printfa(vs, " "); | |
582 pst_vs_printfa(vs, "%02X ", (unsigned char) *(b + start + i)); | |
583 } | |
584 if (ascii) { | |
585 for (i = diff; i < 16; i++) | |
586 pst_vs_printfa(vs, " "); | |
587 for (i = 0; i < diff; i++) { | |
588 c = *(b + start + i); | |
589 pst_vs_printfa(vs, "%c", isprint(c) ? c : '.'); | |
590 } | |
591 } | |
592 pst_vs_printfa(vs, "\n"); | |
593 start += 16; | |
594 } | |
595 } | |
596 | |
597 | |
598 static void pst_vsset(vstr * vs, char *s) // Store string s in vs | |
599 { | |
600 pst_vsnset(vs, s, strlen(s)); | |
601 } | |
602 | |
603 | |
604 static void pst_vsnset(vstr * vs, char *s, size_t n) // Store string s in vs | |
605 { | |
606 pst_vbresize((vbuf *) vs, n + 1); | |
607 memcpy(vs->b, s, n); | |
608 vs->b[n] = '\0'; | |
609 vs->dlen = n + 1; | |
610 } | |
611 | |
612 | |
613 static void pst_vsgrow(vstr * vs, size_t len) // grow buffer by len bytes, data are preserved | |
614 { | |
615 pst_vbgrow((vbuf *) vs, len); | |
616 } | |
617 | |
618 | |
619 static size_t pst_vsavail(vstr * vs) | |
620 { | |
621 return pst_vbavail((vbuf *) vs); | |
622 } | |
623 | |
624 | |
625 static void pst_vsnset16(vstr * vs, char *s, size_t len) // Like vbstrnset, but for UTF16 | |
626 { | |
627 pst_vbresize((vbuf *) vs, len + 1); | |
628 memcpy(vs->b, s, len); | |
629 | |
630 vs->b[len] = '\0'; | |
631 vs->dlen = len + 1; | |
632 vs->b[len] = '\0'; | |
633 } | |
634 | |
635 | |
636 static void pst_vscat(vstr * vs, char *str) | |
637 { | |
638 pst_vsncat(vs, str, strlen(str)); | |
639 } | |
640 | |
641 | |
642 static int pst_vscmp(vstr * vs, char *str) | |
643 { | |
644 return strcmp(vs->b, str); | |
645 } | |
646 | |
647 | |
648 static void pst_vsncat(vstr * vs, char *str, size_t len) // append string str to vstr, vstr must already contain a valid string | |
649 { | |
650 ASSERT(vs->b[vs->dlen - 1] == '\0', "vsncat(): attempt to append string to non-string."); | |
651 size_t sl = strlen(str); | |
652 size_t n = (sl < len) ? sl : len; | |
653 //string append | |
654 pst_vbgrow((vbuf *) vs, n + 1); | |
655 memcpy(vs->b + vs->dlen - 1, str, n); | |
656 vs->dlen += n; | |
657 vs->b[vs->dlen - 1] = '\0'; | |
658 } | |
659 | |
660 | |
661 static void pst_vstrunc(vstr * v, size_t off) // Drop chars [off..dlen] | |
662 { | |
663 if (off >= v->dlen - 1) | |
664 return; //nothing to do | |
665 v->b[off] = '\0'; | |
666 v->dlen = off + 1; | |
667 } | |
668 | |
669 |