dynstring.c000644 000423 000000 00000012131 11020636600 013471 0ustar00luigiwheel000000 000000 /* * $Id: dynstring.c 357 2008-06-02 00:29:40Z luigi $ * * An implementation of dynamic strings (and in general, extensible * data structures) inherited from the one i wrote myself for asterisk. */ #include "dynstring.h" #include /* vsnprintf */ #include /* varargs */ #include #include /* bcopy */ #include #define START_SIZE 48 // initial size struct __dynstr { size_t len; /* The current size of the buffer */ size_t used; /* Amount of space used */ char str[0]; /* The string buffer */ }; const char *ds_data(dynstr s) { return s ? s->str : ""; } void ds_free(dynstr s) { if (s) free(s); } int ds_len(dynstr s) { return s ? s->used : 0; } static dynstr dynstr_create(size_t init_len) { dynstr buf; buf = (dynstr)calloc(1, sizeof(*buf) + init_len); if (buf == NULL) return NULL; buf->len = init_len; buf->used = 0; return buf; } void ds_reset(dynstr buf) { if (buf) { buf->used = 0; if (buf->len) buf->str[0] = '\0'; } } static int dynstr_make_space(dynstr *buf, size_t new_len) { if (buf == NULL) return 0; if (new_len <= (*buf)->len) return 0; /* success */ /* make it slightly larger than requested */ if (new_len < 1000) new_len += new_len; else new_len += 1000; *buf = (dynstr)realloc(*buf, new_len + sizeof(struct __dynstr)); if (*buf == NULL) /* XXX watch out, we leak memory here */ return -1; (*buf)->len = new_len; return 0; } static int __dynstr_helper(dynstr *buf, size_t max_len, int append, const char *fmt, va_list ap); #define DYNSTR_BUILD_RETRY -2 #define DYNSTR_BUILD_FAILED -3 /* * Append to a dynamic string using a va_list */ #define vadsprintf(buf, max_len, fmt, ap) \ ({ \ int __res; \ while ((__res = __dynstr_helper(buf, max_len, \ 1, fmt, ap)) == DYNSTR_BUILD_RETRY) { \ va_end(ap); \ va_start(ap, fmt); \ } \ (__res); \ }) /*! * Append to a dynamic string - same as sprintf(). */ int __attribute__ ((format (printf, 2, 3))) dsprintf(dynstr *buf, const char *fmt, ...) { int res; va_list ap; if (buf == NULL) return 0; va_start(ap, fmt); res = vadsprintf(buf, 0 /* max_len */, fmt, ap); va_end(ap); return res; } /* * Append a buffer to a dynamic string (and also a '\0' to ease printing). */ int ds_append(dynstr *buf, const void *d, int len) { int need; if (buf == NULL) return 0; if (*buf == NULL) *buf = dynstr_create(START_SIZE); if (*buf == NULL) return DYNSTR_BUILD_FAILED; need = (*buf)->used + len + 1; if (need > (*buf)->len) { if (dynstr_make_space(buf, need)) return DYNSTR_BUILD_FAILED; } bcopy(d, (*buf)->str + (*buf)->used, len); (*buf)->used += len; (*buf)->str[(*buf)->used] = '\0'; return 0; } __attribute__((format (printf, 4, 0))) static int __dynstr_helper(dynstr *buf, size_t max_len, int append, const char *fmt, va_list ap) { int res, need; int offset; if (buf == NULL) return 0; if (*buf == NULL) *buf = dynstr_create(START_SIZE); if (*buf == NULL) return DYNSTR_BUILD_FAILED; offset = (append && (*buf)->len) ? (*buf)->used : 0; if (max_len < 0) max_len = (*buf)->len; /* don't exceed the allocated space */ /* * Ask vsnprintf how much space we need. Remember that vsnprintf * does not count the final '\0' so we must add 1. */ res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap); need = res + offset + 1; /* * If there is not enough space and we are below the max length, * reallocate the buffer and return a message telling to retry. */ if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) { if (max_len && max_len < need) /* truncate as needed */ need = max_len; else if (max_len == 0) /* if unbounded, give more room for next time */ need += 16 + need/4; if (dynstr_make_space(buf, need)) return DYNSTR_BUILD_FAILED; (*buf)->str[offset] = '\0'; /* Truncate the partial write. */ /* va_end() and va_start() must be done before calling * vsnprintf() again. */ return DYNSTR_BUILD_RETRY; } /* update space used, keep in mind the truncation */ (*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset; return res; } dynstring.h000644 000423 000000 00000002157 11020530037 013502 0ustar00luigiwheel000000 000000 /* * $Id: dynstring.h 339 2008-06-01 14:26:27Z luigi $ * * An implementation of dynamic strings (and in general, extensible * data structures) inherited from the one i wrote myself for asterisk. * * USE: declare the dynamic string: dynstr s = NULL; * then use as asprintf(), e.g. dsprintf(&s, fmt, ...); * or, to append a chunk of bytes: ds_append(&s, ptr, len) * * Use ds_len(s), ds_data(s), ds_reset(s), ds_free(s) to get the * length, data pointer, reset the content, and free the memory. * * This code has been originally designed for strings, however * ds_append() supports appending arbitrary chunks of bytes to * the structure. */ #ifndef __DYNSTRING_H #define __DYNSTRING_H typedef struct __dynstr * dynstr; /* sprintf and append bytes to a dynamic string */ int dsprintf(dynstr *s, const char *fmt, ...); int ds_append(dynstr *s, const void *d, int len); const char *ds_data(dynstr s); // returns a pointer to the content int ds_len(dynstr s); // returns the string lenght void ds_reset(dynstr s); // resets the buffer to empty string void ds_free(dynstr s); // frees the space #endif /* __DYNSTRING_H */