/* dstring.c dynamic string buffer functions Copyright (C) 2002 Brian Koropoff. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif static __attribute__ ((used)) const char rcsid[] = "$Id$"; #include #include #include "QF/sys.h" #include "QF/dstring.h" #include "compat.h" static void * dstring_alloc (void *data, size_t size) { return calloc (1, size); } static void dstring_free (void *data, void *ptr) { free (ptr); } static void * dstring_realloc (void *data, void *ptr, size_t size) { return realloc (ptr, size); } dstring_mem_t dstring_default_mem = { dstring_alloc, dstring_free, dstring_realloc, 0 }; inline dstring_t * _dstring_new (dstring_mem_t *mem) { dstring_t *new; new = mem->alloc (mem->data, sizeof (dstring_t)); if (!new) Sys_Error ("dstring_new: Failed to allocate memory."); new->mem = mem; return new; } dstring_t * dstring_new (void) { return _dstring_new (&dstring_default_mem); } void dstring_delete (dstring_t *dstr) { if (dstr->str) dstr->mem->free (dstr->mem->data, dstr->str); dstr->mem->free (dstr->mem->data, dstr); } inline void dstring_adjust (dstring_t *dstr) { if (dstr->size > dstr->truesize) { dstr->truesize = (dstr->size + 1023) & ~1023; dstr->str = dstr->mem->realloc (dstr->mem->data, dstr->str, dstr->truesize); if (!dstr->str) Sys_Error ("dstring_adjust: Failed to reallocate memory."); } } void dstring_copy (dstring_t *dstr, const char *data, unsigned int len) { dstr->size = len; dstring_adjust (dstr); memcpy (dstr->str, data, len); } void dstring_append (dstring_t *dstr, const char *data, unsigned int len) { unsigned int ins = dstr->size; // Save insertion point dstr->size += len; dstring_adjust (dstr); memcpy (dstr->str + ins, data, len); } void dstring_insert (dstring_t *dstr, unsigned int pos, const char *data, unsigned int len) { unsigned int oldsize = dstr->size; if (pos > dstr->size) pos = dstr->size; dstr->size += len; dstring_adjust (dstr); memmove (dstr->str + pos + len, dstr->str + pos, oldsize - pos); memcpy (dstr->str + pos, data, len); } void dstring_snip (dstring_t *dstr, unsigned int pos, unsigned int len) { if (pos > dstr->size) pos = dstr->size; if (pos + len > dstr->size) len = dstr->size - pos; if (!len) return; memmove (dstr->str + pos, dstr->str + pos + len, dstr->size - pos - len); dstr->size -= len; dstring_adjust (dstr); } void dstring_clear (dstring_t *dstr) { dstr->size = 0; dstring_adjust (dstr); } void dstring_replace (dstring_t *dstr, unsigned int pos, unsigned int rlen, const char *data, unsigned int len) { unsigned int oldsize = dstr->size; if (pos > dstr->size) pos = dstr->size; if (pos + rlen > dstr->size) rlen = dstr->size - pos; if (rlen < len) { dstr->size += len - rlen; dstring_adjust (dstr); memmove (dstr->str + pos + len, dstr->str + pos + rlen, oldsize - (pos + rlen)); } else if (rlen > len) { memmove (dstr->str + pos + len, dstr->str + pos + rlen, oldsize - (pos + rlen)); dstr->size -= rlen - len; dstring_adjust (dstr); } memcpy (dstr->str + pos, data, len); } char * dstring_freeze (dstring_t *dstr) { char *str = dstr->mem->realloc (dstr->mem->data, dstr->str, dstr->size); dstr->mem->free (dstr->mem->data, dstr); return str; } inline dstring_t * _dstring_newstr (dstring_mem_t *mem) { dstring_t *new; new = mem->alloc (mem->data, sizeof (dstring_t)); if (!new) Sys_Error ("dstring_newstr: Failed to allocate memory."); new->mem = mem; new->size = 1; dstring_adjust (new); new->str[0] = 0; return new; } dstring_t * dstring_newstr (void) { return _dstring_newstr (&dstring_default_mem); } void dstring_copystr (dstring_t *dstr, const char *str) { dstr->size = strlen (str) + 1; dstring_adjust (dstr); strcpy (dstr->str, str); } void dstring_copysubstr (dstring_t *dstr, const char *str, unsigned int len) { len = strnlen (str, len); dstr->size = len + 1; dstring_adjust (dstr); strncpy (dstr->str, str, len); dstr->str[len] = 0; } void dstring_appendstr (dstring_t *dstr, const char *str) { unsigned int pos = strnlen (dstr->str, dstr->size); unsigned int len = strlen (str); dstr->size = pos + len + 1; dstring_adjust (dstr); strcpy (dstr->str + pos, str); } void dstring_appendsubstr (dstring_t *dstr, const char *str, unsigned int len) { unsigned int pos = strnlen (dstr->str, dstr->size); len = strnlen (str, len); dstr->size = pos + len + 1; dstring_adjust (dstr); strncpy (dstr->str + pos, str, len); dstr->str[pos + len] = 0; } void dstring_insertstr (dstring_t *dstr, unsigned int pos, const char *str) { // Don't insert strlen + 1 to achieve concatenation dstring_insert (dstr, pos, str, strlen (str)); } void dstring_insertsubstr (dstring_t *dstr, unsigned int pos, const char *str, unsigned int len) { len = strnlen (str, len); dstring_insert (dstr, pos, str, len); } void dstring_clearstr (dstring_t *dstr) { dstr->size = 1; dstring_adjust (dstr); dstr->str[0] = 0; } #if defined (HAVE_VA_COPY) # define VA_COPY(a,b) va_copy (a, b) #elif defined (HAVE__VA_COPY) # define VA_COPY(a,b) __va_copy (a, b) #else # define VA_COPY(a,b) memcpy (a, b, sizeof (a)) #endif static int _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) { int size; #ifdef VA_LIST_IS_ARRAY va_list tmp_args; VA_COPY (tmp_args, args); #endif if (!dstr->truesize) dstring_clearstr (dstr); // Make it a string // Some vsnprintf implementations return -1 on truncation while ((size = vsnprintf (dstr->str + offs, dstr->truesize - offs, fmt, args)) == -1) { dstr->size = (dstr->truesize & ~1023) + 1024; dstring_adjust (dstr); #ifdef VA_LIST_IS_ARRAY VA_COPY (args, tmp_args); #endif } dstr->size = size + offs + 1; // "Proper" implementations return the required size if (dstr->size > dstr->truesize) { dstring_adjust (dstr); #ifdef VA_LIST_IS_ARRAY VA_COPY (args, tmp_args); #endif vsnprintf (dstr->str + offs, dstr->truesize - offs, fmt, args); } return size; } int dvsprintf (dstring_t *dstr, const char *fmt, va_list args) { return _dvsprintf (dstr, 0, fmt, args); } int dsprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; int ret; va_start (args, fmt); ret = _dvsprintf (dstr, 0, fmt, args); va_end (args); return ret; } int davsprintf (dstring_t *dstr, const char *fmt, va_list args) { int offs = 0; if (dstr->size) offs = dstr->size - 1; return _dvsprintf (dstr, offs, fmt, args); } int dasprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; int ret; int offs = 0; if (dstr->size) offs = dstr->size - 1; va_start (args, fmt); ret = _dvsprintf (dstr, offs, fmt, args); va_end (args); return ret; }