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