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