2 * strbuf.c: A simple string buffer
4 * Copyright (c) 2006-2009 Dennis Stosberg <dennis@stosberg.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License,
8 * version 2 as published by the Free Software Foundation
13 static const size_t strbuf_start_sz
= 128;
14 static const size_t strbuf_grow_sz
= 128;
16 static void strbuf_grow(STRBUF
*buf
); /* enlarge a buffer by strbuf_grow_sz */
19 static void die(const char *format
, ...) {
21 va_start(argp
, format
);
22 vfprintf(stderr
, format
, argp
);
24 fprintf(stderr
, "\n");
28 static void strbuf_check(STRBUF
*buf
)
34 die("buf->data is null");
36 if (!(buf
->opt
& STRBUF_NULLOK
) && strlen(buf
->data
) != buf
->len
)
37 die("length mismatch. strlen says %u, len says %u",
38 (unsigned int)strlen(buf
->data
), buf
->len
);
40 if (buf
->len
+ 1 > buf
->buf_sz
)
44 #define strbuf_check(a)
47 STRBUF
*strbuf_new(void)
49 STRBUF
*buf
= ymalloc(sizeof(STRBUF
));
51 buf
->buf_sz
= strbuf_start_sz
;
52 buf
->data
= ymalloc(strbuf_start_sz
);
63 void strbuf_free(STRBUF
*buf
)
71 void strbuf_shrink(STRBUF
*buf
)
75 buf
->buf_sz
= buf
->len
+ 1;
76 buf
->data
= yrealloc(buf
->data
, buf
->buf_sz
);
81 size_t strbuf_append_n(STRBUF
*buf
, const char *str
, size_t n
)
88 while (buf
->len
+ n
+ 1 > buf
->buf_sz
)
91 memcpy(buf
->data
+ buf
->len
, str
, n
);
93 *(buf
->data
+ buf
->len
) = 0;
99 size_t strbuf_append(STRBUF
*buf
, const char *str
)
101 return strbuf_append_n(buf
, str
, strlen(str
));
104 const char *strbuf_get(STRBUF
*buf
)
110 size_t strbuf_len(STRBUF
*buf
)
116 int strbuf_subst(STRBUF
*buf
,
117 size_t start
, size_t stop
,
133 subst_len
= strlen(subst
);
134 diff
= subst_len
- len
;
137 memcpy(buf
->data
+ start
, subst
, subst_len
);
138 memmove(buf
->data
+ start
+ subst_len
, buf
->data
+ stop
,
139 buf
->len
- stop
+ 1);
141 } else if (0 == diff
) {
142 memcpy(buf
->data
+ start
, subst
, subst_len
);
144 } else { /* 0 < diff */
145 while (buf
->len
+ diff
+ 1 > buf
->buf_sz
)
148 memmove(buf
->data
+ start
+ subst_len
, buf
->data
+ stop
,
149 buf
->len
- stop
+ 1);
150 memcpy(buf
->data
+ start
, subst
, subst_len
);
159 size_t strbuf_append_file(STRBUF
*buf
, FILE *in
)
163 /* save NULLOK flag */
164 int nullok
= (buf
->opt
& STRBUF_NULLOK
) ? 1 : 0;
165 strbuf_setopt(buf
, STRBUF_NULLOK
);
172 read_len
= fread(readbuf
, 1, sizeof(readbuf
), in
);
176 while (buf
->buf_sz
< buf
->len
+ sizeof(readbuf
))
179 memcpy(buf
->data
+ buf
->len
, readbuf
, read_len
);
180 buf
->len
+= read_len
;
183 } while (read_len
== sizeof(readbuf
));
185 /* terminate buffer */
186 if (buf
->len
+ 1 > buf
->buf_sz
)
188 *(buf
->data
+ buf
->len
) = '\0';
190 /* restore NULLOK option */
192 strbuf_unsetopt(buf
, STRBUF_NULLOK
);
199 size_t strbuf_append_inflate(STRBUF
*buf
, FILE *in
)
209 /* save NULLOK flag */
210 nullok
= (buf
->opt
& STRBUF_NULLOK
) ? 1 : 0;
211 strbuf_setopt(buf
, STRBUF_NULLOK
);
214 strm
.zalloc
= Z_NULL
;
216 strm
.opaque
= Z_NULL
;
217 strm
.next_in
= Z_NULL
;
220 z_ret
= inflateInit2(&strm
, -15);
222 fprintf(stderr
, "A: zlib returned error: %d\n", z_ret
);
229 strm
.avail_in
= (uInt
)fread(readbuf
, 1, sizeof(readbuf
), in
);
233 (void)inflateEnd(&strm
);
234 fprintf(stderr
, "stdio error: %d\n", f_err
);
235 exit(EXIT_FAILURE
); /* TODO: errmsg? continue? */
238 if (strm
.avail_in
== 0)
241 strm
.next_in
= readbuf
;
243 size_t bytes_inflated
;
245 while (buf
->buf_sz
< buf
->len
+ sizeof(readbuf
) * 2)
248 strm
.next_out
= (Bytef
*)(buf
->data
+ buf
->len
);
249 strm
.avail_out
= (uInt
)(buf
->buf_sz
- buf
->len
);
251 z_ret
= inflate(&strm
, Z_SYNC_FLUSH
);
256 (void)inflateEnd(&strm
);
257 fprintf(stderr
, "B: zlib returned error: %d\n", z_ret
);
261 bytes_inflated
= (buf
->buf_sz
- buf
->len
) - strm
.avail_out
;
262 buf
->len
+= bytes_inflated
;
264 } while (strm
.avail_out
== 0);
266 } while (z_ret
!= Z_STREAM_END
);
268 /* terminate buffer */
269 if (buf
->len
+ 1 > buf
->buf_sz
)
271 *(buf
->data
+ buf
->len
) = '\0';
273 /* restore NULLOK option */
275 strbuf_unsetopt(buf
, STRBUF_NULLOK
);
279 len
= (size_t)strm
.total_out
;
280 (void)inflateEnd(&strm
);
282 if (z_ret
!= Z_STREAM_END
) {
283 fprintf(stderr
, "ERR\n");
290 static void strbuf_grow(STRBUF
*buf
)
292 buf
->buf_sz
+= strbuf_grow_sz
;
293 buf
->data
= yrealloc(buf
->data
, buf
->buf_sz
);
298 STRBUF
*strbuf_slurp(char *str
)
300 return strbuf_slurp_n(str
, strlen(str
));
303 STRBUF
*strbuf_slurp_n(char *str
, size_t len
)
305 STRBUF
*buf
= ymalloc(sizeof(STRBUF
));
307 buf
->buf_sz
= len
+ 1;
308 buf
->data
= yrealloc(str
, buf
->buf_sz
);
309 *(buf
->data
+ len
) = '\0';
316 char *strbuf_spit(STRBUF
*buf
)
329 unsigned int strbuf_crc32(STRBUF
*buf
)
331 uLong crc
= crc32(0L, Z_NULL
, 0);
332 crc
= crc32(crc
, (Bytef
*)buf
->data
, buf
->len
);
334 return (unsigned int)crc
;
337 void strbuf_setopt(STRBUF
*buf
, enum strbuf_opt opt
)
342 void strbuf_unsetopt(STRBUF
*buf
, enum strbuf_opt opt
)