dyn-string.c revision 218822
168765Sobrien/* An abstract string datatype. 2218822Sdim Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. 368765Sobrien Contributed by Mark Mitchell (mark@markmitchell.com). 468765Sobrien 568765SobrienThis file is part of GNU CC. 668765Sobrien 768765SobrienGNU CC is free software; you can redistribute it and/or modify 868765Sobrienit under the terms of the GNU General Public License as published by 968765Sobrienthe Free Software Foundation; either version 2, or (at your option) 1068765Sobrienany later version. 1168765Sobrien 12104834SobrienIn addition to the permissions in the GNU General Public License, the 13104834SobrienFree Software Foundation gives you unlimited permission to link the 14104834Sobriencompiled version of this file into combinations with other programs, 15104834Sobrienand to distribute those combinations without any restriction coming 16104834Sobrienfrom the use of this file. (The General Public License restrictions 17104834Sobriendo apply in other respects; for example, they cover modification of 18104834Sobrienthe file, and distribution when not linked into a combined 19104834Sobrienexecutable.) 20104834Sobrien 2168765SobrienGNU CC is distributed in the hope that it will be useful, 2268765Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 2368765SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2468765SobrienGNU General Public License for more details. 2568765Sobrien 2668765SobrienYou should have received a copy of the GNU General Public License 2768765Sobrienalong with GNU CC; see the file COPYING. If not, write to 28218822Sdimthe Free Software Foundation, 51 Franklin Street - Fifth Floor, 29218822SdimBoston, MA 02110-1301, USA. */ 3068765Sobrien 3168765Sobrien#ifdef HAVE_CONFIG_H 3268765Sobrien#include "config.h" 3368765Sobrien#endif 3468765Sobrien 3568765Sobrien#include <stdio.h> 3668765Sobrien 3768765Sobrien#ifdef HAVE_STRING_H 3868765Sobrien#include <string.h> 3968765Sobrien#endif 4068765Sobrien 4168765Sobrien#ifdef HAVE_STDLIB_H 4268765Sobrien#include <stdlib.h> 4368765Sobrien#endif 4468765Sobrien 4568765Sobrien#include "libiberty.h" 4668765Sobrien#include "dyn-string.h" 4768765Sobrien 4868765Sobrien/* Performs in-place initialization of a dyn_string struct. This 4968765Sobrien function can be used with a dyn_string struct on the stack or 5068765Sobrien embedded in another object. The contents of of the string itself 5168765Sobrien are still dynamically allocated. The string initially is capable 5268765Sobrien of holding at least SPACE characeters, including the terminating 5368765Sobrien NUL. If SPACE is 0, it will silently be increated to 1. 5468765Sobrien 5568765Sobrien If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation 5668765Sobrien fails, returns 0. Otherwise returns 1. */ 5768765Sobrien 5868765Sobrienint 59218822Sdimdyn_string_init (struct dyn_string *ds_struct_ptr, int space) 6068765Sobrien{ 6168765Sobrien /* We need at least one byte in which to store the terminating NUL. */ 6268765Sobrien if (space == 0) 6368765Sobrien space = 1; 6468765Sobrien 6568765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE 6668765Sobrien ds_struct_ptr->s = (char *) malloc (space); 6768765Sobrien if (ds_struct_ptr->s == NULL) 6868765Sobrien return 0; 6968765Sobrien#else 70218822Sdim ds_struct_ptr->s = XNEWVEC (char, space); 7168765Sobrien#endif 7268765Sobrien ds_struct_ptr->allocated = space; 7368765Sobrien ds_struct_ptr->length = 0; 7468765Sobrien ds_struct_ptr->s[0] = '\0'; 7568765Sobrien 7668765Sobrien return 1; 7768765Sobrien} 7868765Sobrien 7968765Sobrien/* Create a new dynamic string capable of holding at least SPACE 8068765Sobrien characters, including the terminating NUL. If SPACE is 0, it will 8168765Sobrien be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is 8268765Sobrien defined and memory allocation fails, returns NULL. Otherwise 8368765Sobrien returns the newly allocated string. */ 8468765Sobrien 8568765Sobriendyn_string_t 86218822Sdimdyn_string_new (int space) 8768765Sobrien{ 8868765Sobrien dyn_string_t result; 8968765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE 9068765Sobrien result = (dyn_string_t) malloc (sizeof (struct dyn_string)); 9168765Sobrien if (result == NULL) 9268765Sobrien return NULL; 9368765Sobrien if (!dyn_string_init (result, space)) 9468765Sobrien { 9568765Sobrien free (result); 9668765Sobrien return NULL; 9768765Sobrien } 9868765Sobrien#else 99218822Sdim result = XNEW (struct dyn_string); 10068765Sobrien dyn_string_init (result, space); 10168765Sobrien#endif 10268765Sobrien return result; 10368765Sobrien} 10468765Sobrien 10568765Sobrien/* Free the memory used by DS. */ 10668765Sobrien 10768765Sobrienvoid 108218822Sdimdyn_string_delete (dyn_string_t ds) 10968765Sobrien{ 11068765Sobrien free (ds->s); 11168765Sobrien free (ds); 11268765Sobrien} 11368765Sobrien 11468765Sobrien/* Returns the contents of DS in a buffer allocated with malloc. It 11568765Sobrien is the caller's responsibility to deallocate the buffer using free. 11668765Sobrien DS is then set to the empty string. Deletes DS itself. */ 11768765Sobrien 11868765Sobrienchar* 119218822Sdimdyn_string_release (dyn_string_t ds) 12068765Sobrien{ 12168765Sobrien /* Store the old buffer. */ 12268765Sobrien char* result = ds->s; 12368765Sobrien /* The buffer is no longer owned by DS. */ 12468765Sobrien ds->s = NULL; 12568765Sobrien /* Delete DS. */ 12668765Sobrien free (ds); 12768765Sobrien /* Return the old buffer. */ 12868765Sobrien return result; 12968765Sobrien} 13068765Sobrien 13168765Sobrien/* Increase the capacity of DS so it can hold at least SPACE 13268765Sobrien characters, plus the terminating NUL. This function will not (at 13368765Sobrien present) reduce the capacity of DS. Returns DS on success. 13468765Sobrien 13568765Sobrien If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation 13668765Sobrien operation fails, deletes DS and returns NULL. */ 13768765Sobrien 13868765Sobriendyn_string_t 139218822Sdimdyn_string_resize (dyn_string_t ds, int space) 14068765Sobrien{ 14168765Sobrien int new_allocated = ds->allocated; 14268765Sobrien 14368765Sobrien /* Increase SPACE to hold the NUL termination. */ 14468765Sobrien ++space; 14568765Sobrien 14668765Sobrien /* Increase allocation by factors of two. */ 14768765Sobrien while (space > new_allocated) 14868765Sobrien new_allocated *= 2; 14968765Sobrien 15068765Sobrien if (new_allocated != ds->allocated) 15168765Sobrien { 15268765Sobrien ds->allocated = new_allocated; 15368765Sobrien /* We actually need more space. */ 15468765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE 15568765Sobrien ds->s = (char *) realloc (ds->s, ds->allocated); 15668765Sobrien if (ds->s == NULL) 15768765Sobrien { 15868765Sobrien free (ds); 15968765Sobrien return NULL; 16068765Sobrien } 16168765Sobrien#else 162218822Sdim ds->s = XRESIZEVEC (char, ds->s, ds->allocated); 16368765Sobrien#endif 16468765Sobrien } 16568765Sobrien 16668765Sobrien return ds; 16768765Sobrien} 16868765Sobrien 16968765Sobrien/* Sets the contents of DS to the empty string. */ 17068765Sobrien 17168765Sobrienvoid 172218822Sdimdyn_string_clear (dyn_string_t ds) 17368765Sobrien{ 17468765Sobrien /* A dyn_string always has room for at least the NUL terminator. */ 17568765Sobrien ds->s[0] = '\0'; 17668765Sobrien ds->length = 0; 17768765Sobrien} 17868765Sobrien 17968765Sobrien/* Makes the contents of DEST the same as the contents of SRC. DEST 18068765Sobrien and SRC must be distinct. Returns 1 on success. On failure, if 18168765Sobrien RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 18268765Sobrien 18368765Sobrienint 184218822Sdimdyn_string_copy (dyn_string_t dest, dyn_string_t src) 18568765Sobrien{ 18668765Sobrien if (dest == src) 18768765Sobrien abort (); 18868765Sobrien 18968765Sobrien /* Make room in DEST. */ 19068765Sobrien if (dyn_string_resize (dest, src->length) == NULL) 19168765Sobrien return 0; 19268765Sobrien /* Copy DEST into SRC. */ 19368765Sobrien strcpy (dest->s, src->s); 19468765Sobrien /* Update the size of DEST. */ 19568765Sobrien dest->length = src->length; 19668765Sobrien return 1; 19768765Sobrien} 19868765Sobrien 19968765Sobrien/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on 20068765Sobrien success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 20168765Sobrien and returns 0. */ 20268765Sobrien 20368765Sobrienint 204218822Sdimdyn_string_copy_cstr (dyn_string_t dest, const char *src) 20568765Sobrien{ 20668765Sobrien int length = strlen (src); 20768765Sobrien /* Make room in DEST. */ 20868765Sobrien if (dyn_string_resize (dest, length) == NULL) 20968765Sobrien return 0; 21068765Sobrien /* Copy DEST into SRC. */ 21168765Sobrien strcpy (dest->s, src); 21268765Sobrien /* Update the size of DEST. */ 21368765Sobrien dest->length = length; 21468765Sobrien return 1; 21568765Sobrien} 21668765Sobrien 21768765Sobrien/* Inserts SRC at the beginning of DEST. DEST is expanded as 21868765Sobrien necessary. SRC and DEST must be distinct. Returns 1 on success. 21968765Sobrien On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 22068765Sobrien returns 0. */ 22168765Sobrien 22268765Sobrienint 223218822Sdimdyn_string_prepend (dyn_string_t dest, dyn_string_t src) 22468765Sobrien{ 22568765Sobrien return dyn_string_insert (dest, 0, src); 22668765Sobrien} 22768765Sobrien 22868765Sobrien/* Inserts SRC, a NUL-terminated string, at the beginning of DEST. 22968765Sobrien DEST is expanded as necessary. Returns 1 on success. On failure, 23068765Sobrien if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 23168765Sobrien 23268765Sobrienint 233218822Sdimdyn_string_prepend_cstr (dyn_string_t dest, const char *src) 23468765Sobrien{ 23568765Sobrien return dyn_string_insert_cstr (dest, 0, src); 23668765Sobrien} 23768765Sobrien 23868765Sobrien/* Inserts SRC into DEST starting at position POS. DEST is expanded 23968765Sobrien as necessary. SRC and DEST must be distinct. Returns 1 on 24068765Sobrien success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 24168765Sobrien and returns 0. */ 24268765Sobrien 24368765Sobrienint 244218822Sdimdyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src) 24568765Sobrien{ 24668765Sobrien int i; 24768765Sobrien 24868765Sobrien if (src == dest) 24968765Sobrien abort (); 25068765Sobrien 25168765Sobrien if (dyn_string_resize (dest, dest->length + src->length) == NULL) 25268765Sobrien return 0; 25368765Sobrien /* Make room for the insertion. Be sure to copy the NUL. */ 25468765Sobrien for (i = dest->length; i >= pos; --i) 25568765Sobrien dest->s[i + src->length] = dest->s[i]; 25668765Sobrien /* Splice in the new stuff. */ 25768765Sobrien strncpy (dest->s + pos, src->s, src->length); 25868765Sobrien /* Compute the new length. */ 25968765Sobrien dest->length += src->length; 26068765Sobrien return 1; 26168765Sobrien} 26268765Sobrien 26368765Sobrien/* Inserts SRC, a NUL-terminated string, into DEST starting at 26468765Sobrien position POS. DEST is expanded as necessary. Returns 1 on 26568765Sobrien success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST 26668765Sobrien and returns 0. */ 26768765Sobrien 26868765Sobrienint 269218822Sdimdyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) 27068765Sobrien{ 27168765Sobrien int i; 27268765Sobrien int length = strlen (src); 27368765Sobrien 27468765Sobrien if (dyn_string_resize (dest, dest->length + length) == NULL) 27568765Sobrien return 0; 27668765Sobrien /* Make room for the insertion. Be sure to copy the NUL. */ 27768765Sobrien for (i = dest->length; i >= pos; --i) 27868765Sobrien dest->s[i + length] = dest->s[i]; 27968765Sobrien /* Splice in the new stuff. */ 28068765Sobrien strncpy (dest->s + pos, src, length); 28168765Sobrien /* Compute the new length. */ 28268765Sobrien dest->length += length; 28368765Sobrien return 1; 28468765Sobrien} 28568765Sobrien 28677298Sobrien/* Inserts character C into DEST starting at position POS. DEST is 28777298Sobrien expanded as necessary. Returns 1 on success. On failure, 28877298Sobrien RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 28977298Sobrien 29077298Sobrienint 291218822Sdimdyn_string_insert_char (dyn_string_t dest, int pos, int c) 29277298Sobrien{ 29377298Sobrien int i; 29477298Sobrien 29577298Sobrien if (dyn_string_resize (dest, dest->length + 1) == NULL) 29677298Sobrien return 0; 29777298Sobrien /* Make room for the insertion. Be sure to copy the NUL. */ 29877298Sobrien for (i = dest->length; i >= pos; --i) 29977298Sobrien dest->s[i + 1] = dest->s[i]; 30077298Sobrien /* Add the new character. */ 30177298Sobrien dest->s[pos] = c; 30277298Sobrien /* Compute the new length. */ 30377298Sobrien ++dest->length; 30477298Sobrien return 1; 30577298Sobrien} 30677298Sobrien 30768765Sobrien/* Append S to DS, resizing DS if necessary. Returns 1 on success. 30868765Sobrien On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 30968765Sobrien returns 0. */ 31068765Sobrien 31168765Sobrienint 312218822Sdimdyn_string_append (dyn_string_t dest, dyn_string_t s) 31368765Sobrien{ 31468765Sobrien if (dyn_string_resize (dest, dest->length + s->length) == 0) 31568765Sobrien return 0; 31668765Sobrien strcpy (dest->s + dest->length, s->s); 31768765Sobrien dest->length += s->length; 31868765Sobrien return 1; 31968765Sobrien} 32068765Sobrien 32168765Sobrien/* Append the NUL-terminated string S to DS, resizing DS if necessary. 32268765Sobrien Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 32368765Sobrien deletes DEST and returns 0. */ 32468765Sobrien 32568765Sobrienint 326218822Sdimdyn_string_append_cstr (dyn_string_t dest, const char *s) 32768765Sobrien{ 32868765Sobrien int len = strlen (s); 32968765Sobrien 33068765Sobrien /* The new length is the old length plus the size of our string, plus 33168765Sobrien one for the null at the end. */ 33268765Sobrien if (dyn_string_resize (dest, dest->length + len) == NULL) 33368765Sobrien return 0; 33468765Sobrien strcpy (dest->s + dest->length, s); 33568765Sobrien dest->length += len; 33668765Sobrien return 1; 33768765Sobrien} 33868765Sobrien 33968765Sobrien/* Appends C to the end of DEST. Returns 1 on success. On failiure, 34068765Sobrien if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 34168765Sobrien 34268765Sobrienint 343218822Sdimdyn_string_append_char (dyn_string_t dest, int c) 34468765Sobrien{ 34568765Sobrien /* Make room for the extra character. */ 34668765Sobrien if (dyn_string_resize (dest, dest->length + 1) == NULL) 34768765Sobrien return 0; 34868765Sobrien /* Append the character; it will overwrite the old NUL. */ 34968765Sobrien dest->s[dest->length] = c; 35068765Sobrien /* Add a new NUL at the end. */ 35168765Sobrien dest->s[dest->length + 1] = '\0'; 35268765Sobrien /* Update the length. */ 35368765Sobrien ++(dest->length); 35468765Sobrien return 1; 35568765Sobrien} 35668765Sobrien 35768765Sobrien/* Sets the contents of DEST to the substring of SRC starting at START 35868765Sobrien and ending before END. START must be less than or equal to END, 35968765Sobrien and both must be between zero and the length of SRC, inclusive. 36068765Sobrien Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 36168765Sobrien deletes DEST and returns 0. */ 36268765Sobrien 36368765Sobrienint 364218822Sdimdyn_string_substring (dyn_string_t dest, dyn_string_t src, 365218822Sdim int start, int end) 36668765Sobrien{ 36768765Sobrien int i; 36868765Sobrien int length = end - start; 36968765Sobrien 37068765Sobrien if (start > end || start > src->length || end > src->length) 37168765Sobrien abort (); 37268765Sobrien 37368765Sobrien /* Make room for the substring. */ 37468765Sobrien if (dyn_string_resize (dest, length) == NULL) 37568765Sobrien return 0; 37668765Sobrien /* Copy the characters in the substring, */ 37768765Sobrien for (i = length; --i >= 0; ) 37868765Sobrien dest->s[i] = src->s[start + i]; 37968765Sobrien /* NUL-terimate the result. */ 38068765Sobrien dest->s[length] = '\0'; 38168765Sobrien /* Record the length of the substring. */ 38268765Sobrien dest->length = length; 38368765Sobrien 38468765Sobrien return 1; 38568765Sobrien} 38668765Sobrien 38768765Sobrien/* Returns non-zero if DS1 and DS2 have the same contents. */ 38868765Sobrien 38968765Sobrienint 390218822Sdimdyn_string_eq (dyn_string_t ds1, dyn_string_t ds2) 39168765Sobrien{ 39268765Sobrien /* If DS1 and DS2 have different lengths, they must not be the same. */ 39368765Sobrien if (ds1->length != ds2->length) 39468765Sobrien return 0; 39568765Sobrien else 39668765Sobrien return !strcmp (ds1->s, ds2->s); 39768765Sobrien} 398