7 #define NOMEM ((size_t) -1)
9 PHPSTR_API phpstr
*phpstr_init_ex(phpstr
*buf
, size_t chunk_size
, int flags
)
12 buf
= pemalloc(sizeof(phpstr
), flags
& PHPSTR_INIT_PERSISTENT
);
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;
26 PHPSTR_API phpstr
*phpstr_from_string_ex(phpstr
*buf
, const char *string
, size_t length
)
28 if ((buf
= phpstr_init(buf
))) {
29 if (NOMEM
== phpstr_append(buf
, string
, length
)) {
30 pefree(buf
, buf
->pmem
);
37 PHPSTR_API
size_t phpstr_resize_ex(phpstr
*buf
, size_t len
, size_t override_size
)
40 fprintf(stderr
, "RESIZE: size=%lu, used=%lu, free=%lu\n", buf
->size
, buf
->used
, buf
->free
);
42 if (buf
->free
< len
) {
43 size_t size
= override_size
? override_size
: buf
->size
;
45 while ((size
+ buf
->free
) < len
) {
49 char *ptr
= perealloc(buf
->data
, buf
->used
+ buf
->free
+ size
, buf
->pmem
);
57 buf
->data
= pemalloc(size
, buf
->pmem
);
69 PHPSTR_API
size_t phpstr_shrink(phpstr
*buf
)
71 /* avoid another realloc on fixation */
73 char *ptr
= perealloc(buf
->data
, buf
->used
+ 1, buf
->pmem
);
85 PHPSTR_API
size_t phpstr_append(phpstr
*buf
, const char *append
, size_t append_len
)
87 if (NOMEM
== phpstr_resize(buf
, append_len
)) {
90 memcpy(buf
->data
+ buf
->used
, append
, append_len
);
91 buf
->used
+= append_len
;
92 buf
->free
-= append_len
;
96 PHPSTR_API
size_t phpstr_appendf(phpstr
*buf
, const char *format
, ...)
100 size_t append_len
, alloc
;
102 va_start(argv
, format
);
103 append_len
= vspprintf(&append
, 0, format
, argv
);
106 alloc
= phpstr_append(buf
, append
, append_len
);
109 if (NOMEM
== alloc
) {
115 PHPSTR_API
size_t phpstr_insert(phpstr
*buf
, const char *insert
, size_t insert_len
, size_t offset
)
117 if (NOMEM
== phpstr_resize(buf
, insert_len
)) {
120 memmove(buf
->data
+ offset
+ insert_len
, buf
->data
+ offset
, insert_len
);
121 memcpy(buf
->data
+ offset
, insert
, insert_len
);
122 buf
->used
+= insert_len
;
123 buf
->free
-= insert_len
;
127 PHPSTR_API
size_t phpstr_insertf(phpstr
*buf
, size_t offset
, const char *format
, ...)
131 size_t insert_len
, alloc
;
133 va_start(argv
, format
);
134 insert_len
= vspprintf(&insert
, 0, format
, argv
);
137 alloc
= phpstr_insert(buf
, insert
, insert_len
, offset
);
140 if (NOMEM
== alloc
) {
146 PHPSTR_API
size_t phpstr_prepend(phpstr
*buf
, const char *prepend
, size_t prepend_len
)
148 if (NOMEM
== phpstr_resize(buf
, prepend_len
)) {
151 memmove(buf
->data
+ prepend_len
, buf
->data
, buf
->used
);
152 memcpy(buf
->data
, prepend
, prepend_len
);
153 buf
->used
+= prepend_len
;
154 buf
->free
-= prepend_len
;
158 PHPSTR_API
size_t phpstr_prependf(phpstr
*buf
, const char *format
, ...)
162 size_t prepend_len
, alloc
;
164 va_start(argv
, format
);
165 prepend_len
= vspprintf(&prepend
, 0, format
, argv
);
168 alloc
= phpstr_prepend(buf
, prepend
, prepend_len
);
171 if (NOMEM
== alloc
) {
177 PHPSTR_API
char *phpstr_data(const phpstr
*buf
, char **into
, size_t *len
)
179 char *copy
= ecalloc(1, buf
->used
+ 1);
180 memcpy(copy
, buf
->data
, buf
->used
);
190 PHPSTR_API phpstr
*phpstr_dup(const phpstr
*buf
)
192 phpstr
*dup
= phpstr_clone(buf
);
193 if (NOMEM
== phpstr_append(dup
, buf
->data
, buf
->used
)) {
199 PHPSTR_API
size_t phpstr_cut(phpstr
*buf
, size_t offset
, size_t length
)
201 if (offset
>= buf
->used
) {
204 if (offset
+ length
> buf
->used
) {
205 length
= buf
->used
- offset
;
207 memmove(buf
->data
+ offset
, buf
->data
+ offset
+ length
, buf
->used
- length
);
213 PHPSTR_API phpstr
*phpstr_sub(const phpstr
*buf
, size_t offset
, size_t length
)
215 if (offset
>= buf
->used
) {
218 size_t need
= (length
+ offset
) > buf
->used
? (buf
->used
- offset
) : (length
- offset
);
219 phpstr
*sub
= phpstr_init_ex(NULL
, need
, PHPSTR_INIT_PREALLOC
| (buf
->pmem
? PHPSTR_INIT_PERSISTENT
:0));
221 if (NOMEM
== phpstr_append(sub
, buf
->data
+ offset
, need
)) {
224 sub
->size
= buf
->size
;
231 PHPSTR_API phpstr
*phpstr_right(const phpstr
*buf
, size_t length
)
233 if (length
< buf
->used
) {
234 return phpstr_sub(buf
, buf
->used
- length
, length
);
236 return phpstr_sub(buf
, 0, buf
->used
);
241 PHPSTR_API phpstr
*phpstr_merge_va(phpstr
*buf
, unsigned argc
, va_list argv
)
243 unsigned f
= 0, i
= 0;
244 buf
= phpstr_init(buf
);
248 phpstr_free_t f
= va_arg(argv
, phpstr_free_t
);
249 phpstr
*current
= va_arg(argv
, phpstr
*);
250 if (NOMEM
== phpstr_append(buf
, current
->data
, current
->used
)) {
253 FREE_PHPSTR(f
, current
);
264 PHPSTR_API phpstr
*phpstr_merge_ex(phpstr
*buf
, unsigned argc
, ...)
269 va_start(argv
, argc
);
270 ret
= phpstr_merge_va(buf
, argc
, argv
);
275 PHPSTR_API phpstr
*phpstr_merge(unsigned argc
, ...)
280 va_start(argv
, argc
);
281 ret
= phpstr_merge_va(NULL
, argc
, argv
);
286 PHPSTR_API phpstr
*phpstr_fix(phpstr
*buf
)
288 if (NOMEM
== phpstr_resize_ex(buf
, 1, 1)) {
291 buf
->data
[buf
->used
] = '\0';
295 PHPSTR_API
int phpstr_cmp(phpstr
*left
, phpstr
*right
)
297 if (left
->used
> right
->used
) {
299 } else if (right
->used
> left
->used
) {
302 return memcmp(left
->data
, right
->data
, left
->used
);
306 PHPSTR_API
void phpstr_reset(phpstr
*buf
)
308 buf
->free
+= buf
->used
;
312 PHPSTR_API
void phpstr_dtor(phpstr
*buf
)
315 pefree(buf
->data
, buf
->pmem
);
322 PHPSTR_API
void phpstr_free(phpstr
**buf
)
326 pefree(*buf
, (*buf
)->pmem
);
331 PHPSTR_API
size_t phpstr_chunk_buffer(phpstr
**s
, const char *data
, size_t data_len
, char **chunk
, size_t chunk_size
)
338 *s
= phpstr_init_ex(NULL
, chunk_size
* 2, chunk_size
? PHPSTR_INIT_PREALLOC
: 0);
343 phpstr_append(storage
, data
, data_len
);
347 phpstr_data(storage
, chunk
, &chunk_size
);
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
));
356 phpstr_cut(storage
, 0, storage
->size
/2);
357 return storage
->size
/2;
363 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
)
368 while ((got
= phpstr_chunk_buffer(s
, data
, data_len
, &chunk
, chunk_len
))) {
369 passthru(chunk
, got TSRMLS_CC
);
371 /* we already got the last chunk,
372 and freed all resources */
377 STR_SET(chunk
, NULL
);
387 * vim600: sw=4 ts=4 fdm=marker