/* 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__ ((unused)) const char rcsid[] = "$Id$"; #include #include #include "QF/sys.h" #include "QF/dstring.h" #include "compat.h" dstring_t * dstring_new (void) { dstring_t *new; new = calloc (1, sizeof (dstring_t)); if (!new) Sys_Error ("dstring_new: Failed to allocate memory."); return new; } void dstring_delete (dstring_t *dstr) { if (dstr->str) free (dstr->str); free (dstr); } inline void dstring_adjust (dstring_t *dstr) { if (dstr->size > dstr->truesize) { dstr->truesize = (dstr->size + 1023) & ~1023; dstr->str = realloc (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; 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) { 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 (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 = realloc (dstr->str, dstr->size); free (dstr); return str; } dstring_t * dstring_newstr (void) { dstring_t *new; new = calloc (1, sizeof (dstring_t)); if (!new) Sys_Error ("dstring_newstr: Failed to allocate memory."); new->size = 1; dstring_adjust (new); new->str[0] = 0; return new; } void dstring_copystr (dstring_t *dstr, const char *str) { dstr->size = strlen (str) + 1; dstring_adjust (dstr); strcpy (dstr->str, str); } void dstring_appendstr (dstring_t *dstr, const char *str) { dstr->size += strlen (str); dstring_adjust (dstr); strcat (dstr->str, str); } void dstring_appendsubstr (dstring_t *dstr, const char *str, unsigned int len) { unsigned int l = strlen (str); if (len > l) len = l; dstr->size += len; dstring_adjust (dstr); strncat (dstr->str, str, len); } 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) { unsigned int l = strlen (str); if (len > l) len = l; 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 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 + 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; }