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