4eaec1c0a9a300365ec1252a79f9944d3aef6e93
[m6w6/ext-http] / phpstr / phpstr.c
1
2 /* $Id$ */
3
4 #include "php.h"
5 #include "phpstr.h"
6
7 #define NOMEM ((size_t) -1)
8
9 PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags)
10 {
11 if (!buf) {
12 buf = pemalloc(sizeof(phpstr), flags & PHPSTR_INIT_PERSISTENT);
13 }
14
15 if (buf) {
16 buf->size = (chunk_size) ? chunk_size : PHPSTR_DEFAULT_SIZE;
17 buf->pmem = (flags & PHPSTR_INIT_PERSISTENT) ? 1 : 0;
18 buf->data = (flags & PHPSTR_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL;
19 buf->free = (flags & PHPSTR_INIT_PREALLOC) ? buf->size : 0;
20 buf->used = 0;
21 }
22
23 return buf;
24 }
25
26 PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, const char *string, size_t length)
27 {
28 if ((buf = phpstr_init(buf))) {
29 if (NOMEM == phpstr_append(buf, string, length)) {
30 pefree(buf, buf->pmem);
31 buf = NULL;
32 }
33 }
34 return buf;
35 }
36
37 PHPSTR_API size_t phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size, int allow_error)
38 {
39 #if 0
40 fprintf(stderr, "RESIZE: size=%lu, used=%lu, free=%lu\n", buf->size, buf->used, buf->free);
41 #endif
42 if (buf->free < len) {
43 size_t size = override_size ? override_size : buf->size;
44
45 while ((size + buf->free) < len) {
46 size *= 2;
47 }
48 if (buf->data) {
49 char *ptr;
50
51 if (allow_error) {
52 ptr = perealloc_recoverable(buf->data, buf->used + buf->free + size, buf->pmem);
53 } else {
54 ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem);
55 }
56
57 if (ptr) {
58 buf->data = ptr;
59 } else {
60 return NOMEM;
61 }
62 } else {
63 buf->data = pemalloc(size, buf->pmem);
64
65 if (!buf->data) {
66 return NOMEM;
67 }
68 }
69 buf->free += size;
70 return size;
71 }
72 return 0;
73 }
74
75 PHPSTR_API size_t phpstr_shrink(phpstr *buf)
76 {
77 /* avoid another realloc on fixation */
78 if (buf->free > 1) {
79 char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem);
80
81 if (ptr) {
82 buf->data = ptr;
83 } else {
84 return NOMEM;
85 }
86 buf->free = 1;
87 }
88 return buf->used;
89 }
90
91 PHPSTR_API size_t phpstr_append(phpstr *buf, const char *append, size_t append_len)
92 {
93 if (NOMEM == phpstr_resize(buf, append_len)) {
94 return NOMEM;
95 }
96 memcpy(buf->data + buf->used, append, append_len);
97 buf->used += append_len;
98 buf->free -= append_len;
99 return append_len;
100 }
101
102 PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...)
103 {
104 va_list argv;
105 char *append;
106 size_t append_len, alloc;
107
108 va_start(argv, format);
109 append_len = vspprintf(&append, 0, format, argv);
110 va_end(argv);
111
112 alloc = phpstr_append(buf, append, append_len);
113 efree(append);
114
115 if (NOMEM == alloc) {
116 return NOMEM;
117 }
118 return append_len;
119 }
120
121 PHPSTR_API size_t phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset)
122 {
123 if (NOMEM == phpstr_resize(buf, insert_len)) {
124 return NOMEM;
125 }
126 memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
127 memcpy(buf->data + offset, insert, insert_len);
128 buf->used += insert_len;
129 buf->free -= insert_len;
130 return insert_len;
131 }
132
133 PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...)
134 {
135 va_list argv;
136 char *insert;
137 size_t insert_len, alloc;
138
139 va_start(argv, format);
140 insert_len = vspprintf(&insert, 0, format, argv);
141 va_end(argv);
142
143 alloc = phpstr_insert(buf, insert, insert_len, offset);
144 efree(insert);
145
146 if (NOMEM == alloc) {
147 return NOMEM;
148 }
149 return insert_len;
150 }
151
152 PHPSTR_API size_t phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len)
153 {
154 if (NOMEM == phpstr_resize(buf, prepend_len)) {
155 return NOMEM;
156 }
157 memmove(buf->data + prepend_len, buf->data, buf->used);
158 memcpy(buf->data, prepend, prepend_len);
159 buf->used += prepend_len;
160 buf->free -= prepend_len;
161 return prepend_len;
162 }
163
164 PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...)
165 {
166 va_list argv;
167 char *prepend;
168 size_t prepend_len, alloc;
169
170 va_start(argv, format);
171 prepend_len = vspprintf(&prepend, 0, format, argv);
172 va_end(argv);
173
174 alloc = phpstr_prepend(buf, prepend, prepend_len);
175 efree(prepend);
176
177 if (NOMEM == alloc) {
178 return NOMEM;
179 }
180 return prepend_len;
181 }
182
183 PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len)
184 {
185 char *copy = ecalloc(1, buf->used + 1);
186 memcpy(copy, buf->data, buf->used);
187 if (into) {
188 *into = copy;
189 }
190 if (len) {
191 *len = buf->used;
192 }
193 return copy;
194 }
195
196 PHPSTR_API phpstr *phpstr_dup(const phpstr *buf)
197 {
198 phpstr *dup = phpstr_clone(buf);
199 if (NOMEM == phpstr_append(dup, buf->data, buf->used)) {
200 phpstr_free(&dup);
201 }
202 return dup;
203 }
204
205 PHPSTR_API size_t phpstr_cut(phpstr *buf, size_t offset, size_t length)
206 {
207 if (offset >= buf->used) {
208 return 0;
209 }
210 if (offset + length > buf->used) {
211 length = buf->used - offset;
212 }
213 memmove(buf->data + offset, buf->data + offset + length, buf->used - length);
214 buf->used -= length;
215 buf->free += length;
216 return length;
217 }
218
219 PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t length)
220 {
221 if (offset >= buf->used) {
222 return NULL;
223 } else {
224 size_t need = (length + offset) > buf->used ? (buf->used - offset) : (length - offset);
225 phpstr *sub = phpstr_init_ex(NULL, need, PHPSTR_INIT_PREALLOC | (buf->pmem ? PHPSTR_INIT_PERSISTENT:0));
226 if (sub) {
227 if (NOMEM == phpstr_append(sub, buf->data + offset, need)) {
228 phpstr_free(&sub);
229 } else {
230 sub->size = buf->size;
231 }
232 }
233 return sub;
234 }
235 }
236
237 PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length)
238 {
239 if (length < buf->used) {
240 return phpstr_sub(buf, buf->used - length, length);
241 } else {
242 return phpstr_sub(buf, 0, buf->used);
243 }
244 }
245
246
247 PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv)
248 {
249 unsigned i = 0;
250 buf = phpstr_init(buf);
251
252 if (buf) {
253 while (argc > i++) {
254 phpstr_free_t f = va_arg(argv, phpstr_free_t);
255 phpstr *current = va_arg(argv, phpstr *);
256 phpstr_append(buf, current->data, current->used);
257 FREE_PHPSTR(f, current);
258 }
259 }
260
261 return buf;
262 }
263
264 PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...)
265 {
266 va_list argv;
267 phpstr *ret;
268
269 va_start(argv, argc);
270 ret = phpstr_merge_va(buf, argc, argv);
271 va_end(argv);
272 return ret;
273 }
274
275 PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...)
276 {
277 va_list argv;
278 phpstr *ret;
279
280 va_start(argv, argc);
281 ret = phpstr_merge_va(NULL, argc, argv);
282 va_end(argv);
283 return ret;
284 }
285
286 PHPSTR_API phpstr *phpstr_fix(phpstr *buf)
287 {
288 if (NOMEM == phpstr_resize_ex(buf, 1, 1, 0)) {
289 return NULL;
290 }
291 buf->data[buf->used] = '\0';
292 return buf;
293 }
294
295 PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right)
296 {
297 if (left->used > right->used) {
298 return -1;
299 } else if (right->used > left->used) {
300 return 1;
301 } else {
302 return memcmp(left->data, right->data, left->used);
303 }
304 }
305
306 PHPSTR_API void phpstr_reset(phpstr *buf)
307 {
308 buf->free += buf->used;
309 buf->used = 0;
310 }
311
312 PHPSTR_API void phpstr_dtor(phpstr *buf)
313 {
314 if (buf->data) {
315 pefree(buf->data, buf->pmem);
316 buf->data = NULL;
317 }
318 buf->used = 0;
319 buf->free = 0;
320 }
321
322 PHPSTR_API void phpstr_free(phpstr **buf)
323 {
324 if (*buf) {
325 phpstr_dtor(*buf);
326 pefree(*buf, (*buf)->pmem);
327 *buf = NULL;
328 }
329 }
330
331 PHPSTR_API size_t phpstr_chunk_buffer(phpstr **s, const char *data, size_t data_len, char **chunk, size_t chunk_size)
332 {
333 phpstr *storage;
334
335 *chunk = NULL;
336
337 if (!*s) {
338 *s = phpstr_init_ex(NULL, chunk_size * 2, chunk_size ? PHPSTR_INIT_PREALLOC : 0);
339 }
340 storage = *s;
341
342 if (data_len) {
343 phpstr_append(storage, data, data_len);
344 }
345
346 if (!chunk_size) {
347 phpstr_data(storage, chunk, &chunk_size);
348 phpstr_free(s);
349 return chunk_size;
350 }
351
352 if (storage->used >= storage->size/2) {
353 phpstr *avail = phpstr_left(storage, storage->size/2);
354 *chunk = estrndup(PHPSTR_VAL(avail), PHPSTR_LEN(avail));
355 phpstr_free(&avail);
356 phpstr_cut(storage, 0, storage->size/2);
357 return storage->size/2;
358 }
359
360 return 0;
361 }
362
363 PHPSTR_API void phpstr_chunked_output(phpstr **s, const char *data, size_t data_len, size_t chunk_len, phpstr_passthru_func passthru, void *opaque TSRMLS_DC)
364 {
365 char *chunk = NULL;
366 size_t got = 0;
367
368 while ((got = phpstr_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
369 passthru(opaque, chunk, got TSRMLS_CC);
370 if (!chunk_len) {
371 /* we already got the last chunk,
372 and freed all resources */
373 break;
374 }
375 data = NULL;
376 data_len = 0;
377 STR_SET(chunk, NULL);
378 }
379 STR_FREE(chunk);
380 }
381
382 /*
383 * Local variables:
384 * tab-width: 4
385 * c-basic-offset: 4
386 * End:
387 * vim600: sw=4 ts=4 fdm=marker
388 * vim<600: sw=4 ts=4
389 */
390