dyn-string.c revision 169695
1239310Sdim/* An abstract string datatype. 2239310Sdim Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. 3239310Sdim Contributed by Mark Mitchell (mark@markmitchell.com). 4239310Sdim 5239310SdimThis file is part of GNU CC. 6239310Sdim 7239310SdimGNU CC is free software; you can redistribute it and/or modify 8239310Sdimit under the terms of the GNU General Public License as published by 9239310Sdimthe Free Software Foundation; either version 2, or (at your option) 10239310Sdimany later version. 11239310Sdim 12239310SdimIn addition to the permissions in the GNU General Public License, the 13239310SdimFree Software Foundation gives you unlimited permission to link the 14239310Sdimcompiled version of this file into combinations with other programs, 15239310Sdimand to distribute those combinations without any restriction coming 16239310Sdimfrom the use of this file. (The General Public License restrictions 17239310Sdimdo apply in other respects; for example, they cover modification of 18239310Sdimthe file, and distribution when not linked into a combined 19239310Sdimexecutable.) 20239310Sdim 21239310SdimGNU CC is distributed in the hope that it will be useful, 22239310Sdimbut WITHOUT ANY WARRANTY; without even the implied warranty of 23239310SdimMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24239310SdimGNU General Public License for more details. 25239310Sdim 26239310SdimYou should have received a copy of the GNU General Public License 27239310Sdimalong with GNU CC; see the file COPYING. If not, write to 28239310Sdimthe Free Software Foundation, 51 Franklin Street - Fifth Floor, 29239310SdimBoston, MA 02110-1301, USA. */ 30239310Sdim 31239310Sdim#ifdef HAVE_CONFIG_H 32249423Sdim#include "config.h" 33239310Sdim#endif 34249423Sdim 35249423Sdim#include <stdio.h> 36249423Sdim 37239310Sdim#ifdef HAVE_STRING_H 38239310Sdim#include <string.h> 39243830Sdim#endif 40239310Sdim 41239310Sdim#ifdef HAVE_STDLIB_H 42239310Sdim#include <stdlib.h> 43239310Sdim#endif 44239310Sdim 45239310Sdim#include "libiberty.h" 46239310Sdim#include "dyn-string.h" 47239310Sdim 48239310Sdim/* Performs in-place initialization of a dyn_string struct. This 49239310Sdim function can be used with a dyn_string struct on the stack or 50239310Sdim embedded in another object. The contents of of the string itself 51239310Sdim are still dynamically allocated. The string initially is capable 52239310Sdim of holding at least SPACE characeters, including the terminating 53239310Sdim NUL. If SPACE is 0, it will silently be increated to 1. 54239310Sdim 55239310Sdim If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation 56239310Sdim fails, returns 0. Otherwise returns 1. */ 57239310Sdim 58239310Sdimint 59239310Sdimdyn_string_init (struct dyn_string *ds_struct_ptr, int space) 60239310Sdim{ 61239310Sdim /* We need at least one byte in which to store the terminating NUL. */ 62239310Sdim if (space == 0) 63239310Sdim space = 1; 64239310Sdim 65239310Sdim#ifdef RETURN_ON_ALLOCATION_FAILURE 66239310Sdim ds_struct_ptr->s = (char *) malloc (space); 67239310Sdim if (ds_struct_ptr->s == NULL) 68239310Sdim return 0; 69239310Sdim#else 70239310Sdim ds_struct_ptr->s = XNEWVEC (char, space); 71239310Sdim#endif 72239310Sdim ds_struct_ptr->allocated = space; 73239310Sdim ds_struct_ptr->length = 0; 74239310Sdim ds_struct_ptr->s[0] = '\0'; 75239310Sdim 76239310Sdim return 1; 77239310Sdim} 78239310Sdim 79239310Sdim/* Create a new dynamic string capable of holding at least SPACE 80239310Sdim characters, including the terminating NUL. If SPACE is 0, it will 81239310Sdim be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is 82239310Sdim defined and memory allocation fails, returns NULL. Otherwise 83239310Sdim returns the newly allocated string. */ 84239310Sdim 85239310Sdimdyn_string_t 86239310Sdimdyn_string_new (int space) 87239310Sdim{ 88239310Sdim dyn_string_t result; 89239310Sdim#ifdef RETURN_ON_ALLOCATION_FAILURE 90239310Sdim result = (dyn_string_t) malloc (sizeof (struct dyn_string)); 91239310Sdim if (result == NULL) 92239310Sdim return NULL; 93239310Sdim if (!dyn_string_init (result, space)) 94239310Sdim { 95239310Sdim free (result); 96239310Sdim return NULL; 97239310Sdim } 98239310Sdim#else 99239310Sdim result = XNEW (struct dyn_string); 100239310Sdim dyn_string_init (result, space); 101239310Sdim#endif 102239310Sdim return result; 103239310Sdim} 104239310Sdim 105239310Sdim/* Free the memory used by DS. */ 106239310Sdim 107239310Sdimvoid 108239310Sdimdyn_string_delete (dyn_string_t ds) 109239310Sdim{ 110239310Sdim free (ds->s); 111239310Sdim free (ds); 112239310Sdim} 113239310Sdim 114239310Sdim/* Returns the contents of DS in a buffer allocated with malloc. It 115239310Sdim is the caller's responsibility to deallocate the buffer using free. 116239310Sdim DS is then set to the empty string. Deletes DS itself. */ 117239310Sdim 118239310Sdimchar* 119239310Sdimdyn_string_release (dyn_string_t ds) 120239310Sdim{ 121239310Sdim /* Store the old buffer. */ 122239310Sdim char* result = ds->s; 123239310Sdim /* The buffer is no longer owned by DS. */ 124239310Sdim ds->s = NULL; 125239310Sdim /* Delete DS. */ 126239310Sdim free (ds); 127239310Sdim /* Return the old buffer. */ 128239310Sdim return result; 129239310Sdim} 130239310Sdim 131239310Sdim/* Increase the capacity of DS so it can hold at least SPACE 132239310Sdim characters, plus the terminating NUL. This function will not (at 133239310Sdim present) reduce the capacity of DS. Returns DS on success. 134239310Sdim 135239310Sdim If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation 136239310Sdim operation fails, deletes DS and returns NULL. */ 137239310Sdim 138239310Sdimdyn_string_t 139239310Sdimdyn_string_resize (dyn_string_t ds, int space) 140239310Sdim{ 141239310Sdim int new_allocated = ds->allocated; 142239310Sdim 143239310Sdim /* Increase SPACE to hold the NUL termination. */ 144239310Sdim ++space; 145239310Sdim 146239310Sdim /* Increase allocation by factors of two. */ 147239310Sdim while (space > new_allocated) 148239310Sdim new_allocated *= 2; 149239310Sdim 150239310Sdim if (new_allocated != ds->allocated) 151239310Sdim { 152239310Sdim ds->allocated = new_allocated; 153239310Sdim /* We actually need more space. */ 154239310Sdim#ifdef RETURN_ON_ALLOCATION_FAILURE 155239310Sdim ds->s = (char *) realloc (ds->s, ds->allocated); 156239310Sdim if (ds->s == NULL) 157239310Sdim { 158239310Sdim free (ds); 159239310Sdim return NULL; 160239310Sdim } 161239310Sdim#else 162239310Sdim ds->s = XRESIZEVEC (char, ds->s, ds->allocated); 163239310Sdim#endif 164239310Sdim } 165239310Sdim 166239310Sdim return ds; 167239310Sdim} 168239310Sdim 169239310Sdim/* Sets the contents of DS to the empty string. */ 170239310Sdim 171239310Sdimvoid 172239310Sdimdyn_string_clear (dyn_string_t ds) 173239310Sdim{ 174239310Sdim /* A dyn_string always has room for at least the NUL terminator. */ 175239310Sdim ds->s[0] = '\0'; 176239310Sdim ds->length = 0; 177239310Sdim} 178239310Sdim 179239310Sdim/* Makes the contents of DEST the same as the contents of SRC. DEST 180239310Sdim and SRC must be distinct. Returns 1 on success. On failure, if 181239310Sdim RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 182239310Sdim 183239310Sdimint 184239310Sdimdyn_string_copy (dyn_string_t dest, dyn_string_t src) 185239310Sdim{ 186239310Sdim if (dest == src) 187239310Sdim abort (); 188239310Sdim 189239310Sdim /* Make room in DEST. */ 190239310Sdim if (dyn_string_resize (dest, src->length) == NULL) 191239310Sdim return 0; 192239310Sdim /* Copy DEST into SRC. */ 193239310Sdim strcpy (dest->s, src->s); 194239310Sdim /* Update the size of DEST. */ 195239310Sdim dest->length = src->length; 196239310Sdim return 1; 197239310Sdim} 198239310Sdim 199239310Sdim/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on 200239310Sdim success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 201239310Sdim and returns 0. */ 202239310Sdim 203239310Sdimint 204239310Sdimdyn_string_copy_cstr (dyn_string_t dest, const char *src) 205239310Sdim{ 206239310Sdim int length = strlen (src); 207239310Sdim /* Make room in DEST. */ 208239310Sdim if (dyn_string_resize (dest, length) == NULL) 209239310Sdim return 0; 210239310Sdim /* Copy DEST into SRC. */ 211239310Sdim strcpy (dest->s, src); 212239310Sdim /* Update the size of DEST. */ 213239310Sdim dest->length = length; 214239310Sdim return 1; 215239310Sdim} 216239310Sdim 217239310Sdim/* Inserts SRC at the beginning of DEST. DEST is expanded as 218239310Sdim necessary. SRC and DEST must be distinct. Returns 1 on success. 219239310Sdim On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 220239310Sdim returns 0. */ 221239310Sdim 222239310Sdimint 223239310Sdimdyn_string_prepend (dyn_string_t dest, dyn_string_t src) 224239310Sdim{ 225239310Sdim return dyn_string_insert (dest, 0, src); 226239310Sdim} 227239310Sdim 228239310Sdim/* Inserts SRC, a NUL-terminated string, at the beginning of DEST. 229239310Sdim DEST is expanded as necessary. Returns 1 on success. On failure, 230239310Sdim if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 231239310Sdim 232239310Sdimint 233239310Sdimdyn_string_prepend_cstr (dyn_string_t dest, const char *src) 234239310Sdim{ 235239310Sdim return dyn_string_insert_cstr (dest, 0, src); 236239310Sdim} 237239310Sdim 238239310Sdim/* Inserts SRC into DEST starting at position POS. DEST is expanded 239239310Sdim as necessary. SRC and DEST must be distinct. Returns 1 on 240239310Sdim success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 241239310Sdim and returns 0. */ 242239310Sdim 243239310Sdimint 244239310Sdimdyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src) 245239310Sdim{ 246239310Sdim int i; 247239310Sdim 248239310Sdim if (src == dest) 249239310Sdim abort (); 250239310Sdim 251239310Sdim if (dyn_string_resize (dest, dest->length + src->length) == NULL) 252239310Sdim return 0; 253239310Sdim /* Make room for the insertion. Be sure to copy the NUL. */ 254239310Sdim for (i = dest->length; i >= pos; --i) 255239310Sdim dest->s[i + src->length] = dest->s[i]; 256239310Sdim /* Splice in the new stuff. */ 257239310Sdim strncpy (dest->s + pos, src->s, src->length); 258239310Sdim /* Compute the new length. */ 259239310Sdim dest->length += src->length; 260239310Sdim return 1; 261239310Sdim} 262239310Sdim 263239310Sdim/* Inserts SRC, a NUL-terminated string, into DEST starting at 264239310Sdim position POS. DEST is expanded as necessary. Returns 1 on 265239310Sdim success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST 266239310Sdim and returns 0. */ 267239310Sdim 268239310Sdimint 269239310Sdimdyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) 270239310Sdim{ 271239310Sdim int i; 272239310Sdim int length = strlen (src); 273239310Sdim 274239310Sdim if (dyn_string_resize (dest, dest->length + length) == NULL) 275239310Sdim return 0; 276239310Sdim /* Make room for the insertion. Be sure to copy the NUL. */ 277239310Sdim for (i = dest->length; i >= pos; --i) 278239310Sdim dest->s[i + length] = dest->s[i]; 279239310Sdim /* Splice in the new stuff. */ 280239310Sdim strncpy (dest->s + pos, src, length); 281239310Sdim /* Compute the new length. */ 282239310Sdim dest->length += length; 283239310Sdim return 1; 284239310Sdim} 285239310Sdim 286239310Sdim/* Inserts character C into DEST starting at position POS. DEST is 287239310Sdim expanded as necessary. Returns 1 on success. On failure, 288239310Sdim RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 289239310Sdim 290239310Sdimint 291239310Sdimdyn_string_insert_char (dyn_string_t dest, int pos, int c) 292239310Sdim{ 293239310Sdim int i; 294239310Sdim 295239310Sdim if (dyn_string_resize (dest, dest->length + 1) == NULL) 296239310Sdim return 0; 297239310Sdim /* Make room for the insertion. Be sure to copy the NUL. */ 298239310Sdim for (i = dest->length; i >= pos; --i) 299239310Sdim dest->s[i + 1] = dest->s[i]; 300239310Sdim /* Add the new character. */ 301239310Sdim dest->s[pos] = c; 302239310Sdim /* Compute the new length. */ 303239310Sdim ++dest->length; 304239310Sdim return 1; 305239310Sdim} 306239310Sdim 307239310Sdim/* Append S to DS, resizing DS if necessary. Returns 1 on success. 308239310Sdim On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 309239310Sdim returns 0. */ 310239310Sdim 311239310Sdimint 312239310Sdimdyn_string_append (dyn_string_t dest, dyn_string_t s) 313239310Sdim{ 314239310Sdim if (dyn_string_resize (dest, dest->length + s->length) == 0) 315239310Sdim return 0; 316239310Sdim strcpy (dest->s + dest->length, s->s); 317239310Sdim dest->length += s->length; 318239310Sdim return 1; 319239310Sdim} 320239310Sdim 321239310Sdim/* Append the NUL-terminated string S to DS, resizing DS if necessary. 322239310Sdim Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 323239310Sdim deletes DEST and returns 0. */ 324239310Sdim 325239310Sdimint 326239310Sdimdyn_string_append_cstr (dyn_string_t dest, const char *s) 327239310Sdim{ 328239310Sdim int len = strlen (s); 329239310Sdim 330239310Sdim /* The new length is the old length plus the size of our string, plus 331239310Sdim one for the null at the end. */ 332239310Sdim if (dyn_string_resize (dest, dest->length + len) == NULL) 333239310Sdim return 0; 334239310Sdim strcpy (dest->s + dest->length, s); 335239310Sdim dest->length += len; 336239310Sdim return 1; 337239310Sdim} 338239310Sdim 339239310Sdim/* Appends C to the end of DEST. Returns 1 on success. On failiure, 340239310Sdim if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 341239310Sdim 342239310Sdimint 343239310Sdimdyn_string_append_char (dyn_string_t dest, int c) 344239310Sdim{ 345239310Sdim /* Make room for the extra character. */ 346239310Sdim if (dyn_string_resize (dest, dest->length + 1) == NULL) 347239310Sdim return 0; 348239310Sdim /* Append the character; it will overwrite the old NUL. */ 349239310Sdim dest->s[dest->length] = c; 350239310Sdim /* Add a new NUL at the end. */ 351239310Sdim dest->s[dest->length + 1] = '\0'; 352239310Sdim /* Update the length. */ 353239310Sdim ++(dest->length); 354239310Sdim return 1; 355239310Sdim} 356239310Sdim 357239310Sdim/* Sets the contents of DEST to the substring of SRC starting at START 358239310Sdim and ending before END. START must be less than or equal to END, 359239310Sdim and both must be between zero and the length of SRC, inclusive. 360239310Sdim Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 361239310Sdim deletes DEST and returns 0. */ 362239310Sdim 363239310Sdimint 364239310Sdimdyn_string_substring (dyn_string_t dest, dyn_string_t src, 365239310Sdim int start, int end) 366239310Sdim{ 367239310Sdim int i; 368239310Sdim int length = end - start; 369239310Sdim 370239310Sdim if (start > end || start > src->length || end > src->length) 371239310Sdim abort (); 372239310Sdim 373239310Sdim /* Make room for the substring. */ 374239310Sdim if (dyn_string_resize (dest, length) == NULL) 375239310Sdim return 0; 376239310Sdim /* Copy the characters in the substring, */ 377239310Sdim for (i = length; --i >= 0; ) 378239310Sdim dest->s[i] = src->s[start + i]; 379239310Sdim /* NUL-terimate the result. */ 380239310Sdim dest->s[length] = '\0'; 381239310Sdim /* Record the length of the substring. */ 382239310Sdim dest->length = length; 383239310Sdim 384239310Sdim return 1; 385239310Sdim} 386239310Sdim 387239310Sdim/* Returns non-zero if DS1 and DS2 have the same contents. */ 388239310Sdim 389239310Sdimint 390239310Sdimdyn_string_eq (dyn_string_t ds1, dyn_string_t ds2) 391239310Sdim{ 392239310Sdim /* If DS1 and DS2 have different lengths, they must not be the same. */ 393239310Sdim if (ds1->length != ds2->length) 394239310Sdim return 0; 395239310Sdim else 396239310Sdim return !strcmp (ds1->s, ds2->s); 397239310Sdim} 398239310Sdim