/**************************************************************************\ * * This file is part of the Coin 3D visualization library. * Copyright (C) 1998-2007 by Systems in Motion. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * ("GPL") version 2 as published by the Free Software Foundation. * See the file LICENSE.GPL at the root directory of this source * distribution for additional information about the GNU GPL. * * For using Coin with software that can not be combined with the GNU * GPL, and for taking advantage of the additional benefits of our * support services, please contact Systems in Motion about acquiring * a Coin Professional Edition License. * * See http://www.coin3d.org/ for more information. * * Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY. * http://www.sim.no/ sales@sim.no coin-support@coin3d.org * \**************************************************************************/ #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ /* ********************************************************************** */ /* FIXME: - get rid of strlen() invocations - use the cc_memalloc interface? 20020513 mortene. */ /*! \struct cc_string string.h Inventor/C/base/string.h \brief The cc_string type is a C ADT for ASCII string management. \ingroup base This is a Coin extension. */ /* ********************************************************************** */ /*! \relates cc_string */ void cc_string_remove_substring(cc_string * me, int start, int end) { const int len = (int)strlen(me->pointer); if ( end == -1 ) end = len - 1; #if COIN_DEBUG if ( start < 0 || start >= len || end < 0 || end >= len || start > end ) { cc_debugerror_postwarning("cc_string_remove_substring", "invalid arguments [%d, %d] for string ``%s''", start, end, cc_string_get_text(me)); return; } #endif /* COIN_DEBUG */ (void) memmove(me->pointer + start, me->pointer + end + 1, len - end); } static void cc_string_grow_buffer(cc_string * me, size_t newsize) { char * newbuf; static int debug = -1; if (debug == -1) { const char * env = coin_getenv("COIN_DEBUG_STRING_GROW"); debug = (env && (atoi(env) > 0)) ? 1 : 0; } /* Can not use cc_debugerror_* interface(), as that could cause an infinite recursion. */ if (debug) { printf("cc_string_grow_buffer: " "me->bufsize==%d, me->pointer==%p, me->buffer==%p => " "newsize==%d\n", me->bufsize, me->pointer, me->buffer, newsize); } if (newsize <= (size_t)me->bufsize) { return; } /* FIXME: should first try the vastly more efficient realloc() (if the current memory buffer is not the default static, of course). 20050425 mortene. */ newbuf = (char *) malloc(newsize); if (debug) { printf("cc_string_grow_buffer: newbuf==%p\n", newbuf); } assert(newbuf != NULL); (void) strcpy(newbuf, me->pointer); if (me->pointer != me->buffer) { free(me->pointer); } me->pointer = newbuf; me->bufsize = (int)newsize; } static void cc_string_expand(cc_string * me, size_t additional) { const size_t newsize = strlen(me->pointer) + additional + 1; cc_string_grow_buffer(me, newsize); } /* ********************************************************************** */ /*! \relates cc_string */ void cc_string_construct(cc_string * me) { me->pointer = me->buffer; me->bufsize = CC_STRING_MIN_SIZE; me->buffer[0] = '\0'; } /* cc_string_construct() */ /*! \relates cc_string */ cc_string * cc_string_construct_new(void) { cc_string * me; me = (cc_string *) malloc(sizeof(cc_string)); assert(me != NULL); cc_string_construct(me); return me; } /* cc_string_construct_new() */ /*! \relates cc_string */ cc_string * cc_string_clone(cc_string * string) { cc_string * me; me = cc_string_construct_new(); cc_string_set_text(me, string->pointer); return me; } /* cc_string_clone() */ /*! \relates cc_string */ void cc_string_clean(cc_string * string_struct) { if ( string_struct->pointer != string_struct->buffer ) free(string_struct->pointer); } /* cc_string_clean() */ /*! \relates cc_string */ void cc_string_destruct(cc_string * me) { assert(me != NULL); cc_string_clean(me); free(me); } /* cc_string_destruct() */ /* ********************************************************************** */ /*! \relates cc_string */ void cc_string_set_text(cc_string * me, const char * text) { static char emptystring[] = ""; size_t size; if ( text == NULL ) text = emptystring; if ( text >= me->pointer && text < (me->pointer + me->bufsize) ) { /* text is within own buffer */ const ptrdiff_t range = text - me->pointer; cc_string_remove_substring(me, 0, (int)range); return; } size = strlen(text) + 1; if (size > (size_t)me->bufsize) { cc_string_grow_buffer(me, size); } (void) strcpy(me->pointer, text); } /* cc_string_set_text() */ /*! \relates cc_string */ void cc_string_set_subtext(cc_string * me, const char * text, int start, int end) { static const char * emptystring = ""; int len, size; if ( text == NULL ) text = emptystring; len = (int)strlen(text); if ( end == -1 ) end = len - 1; #if COIN_DEBUG if (start<0) { cc_debugerror_postwarning("cc_string_set_subtext", "start index (%d) should be >= 0. Clamped to 0.", start); start=0; } else if (start>len) { cc_debugerror_postwarning("cc_string_set_subtext", "start index (%d) is out of bounds [0, %d>. " "Clamped to %d.", start, len, len-1); start=len; } if (end<0) { cc_debugerror_postwarning("cc_string_set_subtext", "end index (%d) should be >= 0. Clamped to 0.", end); end=0; } else if (end>len) { cc_debugerror_postwarning("cc_string_set_subtext", "end index (%d) is out of bounds [0, %d>. " "Clamped to %d.", end, len, len-1); end=len; } if (start>end+1) { cc_debugerror_postwarning("cc_string_set_subtext", "start index (%d) is greater than end index " "(%d). Empty string created.", start, end); start=0; end=-1; } #endif /* COIN_DEBUG */ /* if new substring fits in internal buffer, freeing allocated buffer will not happen - should this be changed? */ size = end - start + 1; if ( size >= me->bufsize ) { if ( me->pointer != me->buffer ) free(me->pointer); me->pointer = (char *) malloc(size + 1); me->bufsize = size + 1; } (void) strncpy(me->pointer, text + start, size); me->pointer[size] = '\0'; } /* cc_string_set_subtext() */ /*! \relates cc_string */ void cc_string_set_integer(cc_string * me, int integer) { me->pointer[0] = '\0'; cc_string_append_integer(me, integer); } /* cc_string_set_integer() */ /*! \relates cc_string */ void cc_string_set_string(cc_string * me, const cc_string * string) { cc_string_set_text(me, string->pointer); } /* cc_string_set_string() */ /* ********************************************************************** */ /*! \relates cc_string */ void cc_string_append_string(cc_string * me, const cc_string * string) { cc_string_append_text(me, string->pointer); } /* cc_string_append_string() */ /*! \relates cc_string */ void cc_string_append_text(cc_string * me, const char * text) { if ( text ) { cc_string_expand(me, strlen(text)); (void) strcat(me->pointer, text); } } /* cc_string_append_text() */ /*! \relates cc_string */ void cc_string_append_integer(cc_string * me, const int digits) { cc_string s; cc_string_construct(&s); (void)cc_string_sprintf(&s, "%d", digits); cc_string_append_string(me, &s); cc_string_clean(&s); } /* cc_string_append_integer() */ /*! \relates cc_string */ void cc_string_append_char(cc_string * me, const char c) { size_t pos; cc_string_expand(me, 1); pos = strlen(me->pointer); me->pointer[pos] = c; me->pointer[pos+1] = '\0'; } /* cc_string_append_char() */ /* ********************************************************************** */ /*! \relates cc_string */ unsigned int cc_string_length(const cc_string * me) { /* FIXME: should cache the length of the string. 20020513 mortene. */ return (unsigned int)strlen(me->pointer); } /*! \relates cc_string */ void cc_string_clear(cc_string * me) { if ( me->pointer != me->buffer ) { free(me->pointer); me->pointer = me->buffer; me->bufsize = CC_STRING_MIN_SIZE; } me->pointer[0] = '\0'; } /* cc_string_clear() */ /*! \relates cc_string */ void cc_string_clear_no_free(cc_string * me) { me->pointer[0] = '\0'; } /* cc_string_clear_no_free() */ /*! \relates cc_string */ uint32_t cc_string_hash_text(const char * text) { uint32_t total, shift; total = shift = 0; while ( *text ) { total = total ^ ((*text) << shift); shift += 5; if ( shift > 24 ) shift -= 24; text++; } return total; } /*! \relates cc_string */ uint32_t cc_string_hash(const cc_string * me) { return cc_string_hash_text(me->pointer); } /* cc_string_hash() */ /*! \relates cc_string */ const char * cc_string_get_text(const cc_string * me) { return me->pointer; } /* cc_string_get_text() */ /* ********************************************************************** */ /*! \relates cc_string */ int cc_string_is(const cc_string * me) { return (me->pointer[0] != '\0'); } /* cc_string_is() */ /*! \relates cc_string */ int cc_string_compare(const cc_string * lhs, const cc_string * rhs) { return cc_string_compare_text(lhs->pointer, rhs->pointer); } /* cc_string_compare() */ /*! \relates cc_string */ int cc_string_compare_text(const char * lhs, const char * rhs) { return lhs && rhs && strcmp(lhs, rhs); } /* cc_string_compare_text() */ /*! \relates cc_string */ int cc_string_compare_subtext(const cc_string * me, const char * text, int offset) { /* FIXME: assert on invalid offset */ return strncmp(me->pointer + offset, text, strlen(text)); } /* cc_string_compare_prefix() */ /* ********************************************************************** */ /*! \relates cc_string */ void cc_string_apply(cc_string * string, cc_apply_f function) { int len, i; assert(function != NULL); len = cc_string_length(string); for ( i = 0; i < len; i++ ) string->pointer[i] = function(string->pointer[i]); } /* ********************************************************************** */ /*! \relates cc_string */ void cc_string_sprintf(cc_string * me, const char * formatstr, ...) { va_list args; va_start(args, formatstr); cc_string_vsprintf(me, formatstr, args); va_end(args); } /* cc_string_sprintf() */ /*! \relates cc_string */ void cc_string_vsprintf(cc_string * me, const char * formatstr, va_list args) { int length; SbBool expand; do { length = coin_vsnprintf(me->pointer, me->bufsize, formatstr, args); expand = (length == -1); if ( expand ) { /* increase linearly in 1Kb intervals */ cc_string_grow_buffer(me, me->bufsize + 1024); } } while ( expand ); } /* cc_string_vsprintf() */ /* ********************************************************************** */