Convert xml-protected spaces to real spaces
[odt2txt.git] / strbuf.c
blob64985f981777132a356093f30394dc16c844cbbc
1 /*
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
9 */
11 #include "strbuf.h"
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 */
18 #ifdef STRBUF_CHECK
19 static void die(const char *format, ...) {
20 va_list argp;
21 va_start(argp, format);
22 vfprintf(stderr, format, argp);
23 va_end(argp);
24 fprintf(stderr, "\n");
25 exit(EXIT_FAILURE);
28 static void strbuf_check(STRBUF *buf)
30 if (!buf)
31 die("buf is null");
33 if (!buf->data)
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)
41 die("overlap");
43 #else
44 #define strbuf_check(a)
45 #endif
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);
54 buf->len = 0;
55 buf->data[0] = '\0';
57 buf->opt = 0;
59 strbuf_check(buf);
60 return buf;
63 void strbuf_free(STRBUF *buf)
65 strbuf_check(buf);
67 yfree(buf->data);
68 yfree(buf);
71 void strbuf_shrink(STRBUF *buf)
73 strbuf_check(buf);
75 buf->buf_sz = buf->len + 1;
76 buf->data = yrealloc(buf->data, buf->buf_sz);
78 strbuf_check(buf);
81 size_t strbuf_append_n(STRBUF *buf, const char *str, size_t n)
83 strbuf_check(buf);
85 if (n == 0)
86 return buf->len;
88 while (buf->len + n + 1 > buf->buf_sz)
89 strbuf_grow(buf);
91 memcpy(buf->data + buf->len, str, n);
92 buf->len += n;
93 *(buf->data + buf->len) = 0;
95 strbuf_check(buf);
96 return buf->len;
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)
106 strbuf_check(buf);
107 return buf->data;
110 size_t strbuf_len(STRBUF *buf)
112 strbuf_check(buf);
113 return buf->len;
116 int strbuf_subst(STRBUF *buf,
117 size_t start, size_t stop,
118 const char *subst)
120 size_t len;
121 size_t subst_len;
122 int diff;
124 strbuf_check(buf);
126 if (start > stop) {
127 size_t tmp = start;
128 start = stop;
129 stop = tmp;
132 len = stop - start;
133 subst_len = strlen(subst);
134 diff = subst_len - len;
136 if (0 > diff) {
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)
146 strbuf_grow(buf);
148 memmove(buf->data + start + subst_len, buf->data + stop,
149 buf->len - stop + 1);
150 memcpy(buf->data + start, subst, subst_len);
153 buf->len += diff;
155 strbuf_check(buf);
156 return diff;
159 size_t strbuf_append_file(STRBUF *buf, FILE *in)
161 strbuf_check(buf);
163 /* save NULLOK flag */
164 int nullok = (buf->opt & STRBUF_NULLOK) ? 1 : 0;
165 strbuf_setopt(buf, STRBUF_NULLOK);
168 size_t len = 0;
169 size_t read_len = 0;
170 char readbuf[1024];
171 do {
172 read_len = fread(readbuf, 1, sizeof(readbuf), in);
173 len += read_len;
175 if (read_len > 0) {
176 while (buf->buf_sz < buf->len + sizeof(readbuf))
177 strbuf_grow(buf);
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)
187 strbuf_grow(buf);
188 *(buf->data + buf->len) = '\0';
190 /* restore NULLOK option */
191 if (!nullok)
192 strbuf_unsetopt(buf, STRBUF_NULLOK);
194 strbuf_check(buf);
196 return len;
199 size_t strbuf_append_inflate(STRBUF *buf, FILE *in)
201 size_t len;
202 z_stream strm;
203 Bytef readbuf[1024];
204 int z_ret;
205 int nullok;
207 strbuf_check(buf);
209 /* save NULLOK flag */
210 nullok = (buf->opt & STRBUF_NULLOK) ? 1 : 0;
211 strbuf_setopt(buf, STRBUF_NULLOK);
213 /* zlib init */
214 strm.zalloc = Z_NULL;
215 strm.zfree = Z_NULL;
216 strm.opaque = Z_NULL;
217 strm.next_in = Z_NULL;
218 strm.avail_in = 0;
220 z_ret = inflateInit2(&strm, -15);
221 if (z_ret != Z_OK) {
222 fprintf(stderr, "A: zlib returned error: %d\n", z_ret);
223 exit(EXIT_FAILURE);
226 do {
227 int f_err;
229 strm.avail_in = (uInt)fread(readbuf, 1, sizeof(readbuf), in);
231 f_err = ferror(in);
232 if (f_err) {
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)
239 break;
241 strm.next_in = readbuf;
242 do {
243 size_t bytes_inflated;
245 while (buf->buf_sz < buf->len + sizeof(readbuf) * 2)
246 strbuf_grow(buf);
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);
252 switch (z_ret) {
253 case Z_NEED_DICT:
254 case Z_DATA_ERROR:
255 case Z_MEM_ERROR:
256 (void)inflateEnd(&strm);
257 fprintf(stderr, "B: zlib returned error: %d\n", z_ret);
258 exit(EXIT_FAILURE);
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)
270 strbuf_grow(buf);
271 *(buf->data + buf->len) = '\0';
273 /* restore NULLOK option */
274 if (!nullok)
275 strbuf_unsetopt(buf, STRBUF_NULLOK);
277 strbuf_check(buf);
279 len = (size_t)strm.total_out;
280 (void)inflateEnd(&strm);
282 if (z_ret != Z_STREAM_END) {
283 fprintf(stderr, "ERR\n");
284 exit(EXIT_FAILURE);
287 return len;
290 static void strbuf_grow(STRBUF *buf)
292 buf->buf_sz += strbuf_grow_sz;
293 buf->data = yrealloc(buf->data, buf->buf_sz);
295 strbuf_check(buf);
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));
306 buf->len = len;
307 buf->buf_sz = len + 1;
308 buf->data = yrealloc(str, buf->buf_sz);
309 *(buf->data + len) = '\0';
311 buf->opt = 0;
313 return buf;
316 char *strbuf_spit(STRBUF *buf)
318 char *data;
320 strbuf_check(buf);
322 strbuf_shrink(buf);
323 data = buf->data;
324 yfree(buf);
326 return data;
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)
339 buf->opt |= opt;
342 void strbuf_unsetopt(STRBUF *buf, enum strbuf_opt opt)
344 buf->opt &= ~opt;