dyn-string.c revision 77298
168765Sobrien/* An abstract string datatype. 268765Sobrien Copyright (C) 1998, 1999, 2000 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 1268765SobrienGNU CC is distributed in the hope that it will be useful, 1368765Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1468765SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1568765SobrienGNU General Public License for more details. 1668765Sobrien 1768765SobrienYou should have received a copy of the GNU General Public License 1868765Sobrienalong with GNU CC; see the file COPYING. If not, write to 1968765Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330, 2068765SobrienBoston, MA 02111-1307, USA. */ 2168765Sobrien 2268765Sobrien#ifdef HAVE_CONFIG_H 2368765Sobrien#include "config.h" 2468765Sobrien#endif 2568765Sobrien 2668765Sobrien#include <stdio.h> 2768765Sobrien 2868765Sobrien#ifdef HAVE_STRING_H 2968765Sobrien#include <string.h> 3068765Sobrien#endif 3168765Sobrien 3268765Sobrien#ifdef HAVE_STDLIB_H 3368765Sobrien#include <stdlib.h> 3468765Sobrien#endif 3568765Sobrien 3668765Sobrien#include "libiberty.h" 3768765Sobrien#include "dyn-string.h" 3868765Sobrien 3968765Sobrien/* If this file is being compiled for inclusion in the C++ runtime 4068765Sobrien library, as part of the demangler implementation, we don't want to 4168765Sobrien abort if an allocation fails. Instead, percolate an error code up 4268765Sobrien through the call chain. */ 4368765Sobrien 4468765Sobrien#ifdef IN_LIBGCC2 4568765Sobrien#define RETURN_ON_ALLOCATION_FAILURE 4668765Sobrien#endif 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 5968765Sobriendyn_string_init (ds_struct_ptr, space) 6068765Sobrien struct dyn_string *ds_struct_ptr; 6168765Sobrien int space; 6268765Sobrien{ 6368765Sobrien /* We need at least one byte in which to store the terminating NUL. */ 6468765Sobrien if (space == 0) 6568765Sobrien space = 1; 6668765Sobrien 6768765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE 6868765Sobrien ds_struct_ptr->s = (char *) malloc (space); 6968765Sobrien if (ds_struct_ptr->s == NULL) 7068765Sobrien return 0; 7168765Sobrien#else 7268765Sobrien ds_struct_ptr->s = (char *) xmalloc (space); 7368765Sobrien#endif 7468765Sobrien ds_struct_ptr->allocated = space; 7568765Sobrien ds_struct_ptr->length = 0; 7668765Sobrien ds_struct_ptr->s[0] = '\0'; 7768765Sobrien 7868765Sobrien return 1; 7968765Sobrien} 8068765Sobrien 8168765Sobrien/* Create a new dynamic string capable of holding at least SPACE 8268765Sobrien characters, including the terminating NUL. If SPACE is 0, it will 8368765Sobrien be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is 8468765Sobrien defined and memory allocation fails, returns NULL. Otherwise 8568765Sobrien returns the newly allocated string. */ 8668765Sobrien 8768765Sobriendyn_string_t 8868765Sobriendyn_string_new (space) 8968765Sobrien int space; 9068765Sobrien{ 9168765Sobrien dyn_string_t result; 9268765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE 9368765Sobrien result = (dyn_string_t) malloc (sizeof (struct dyn_string)); 9468765Sobrien if (result == NULL) 9568765Sobrien return NULL; 9668765Sobrien if (!dyn_string_init (result, space)) 9768765Sobrien { 9868765Sobrien free (result); 9968765Sobrien return NULL; 10068765Sobrien } 10168765Sobrien#else 10268765Sobrien result = (dyn_string_t) xmalloc (sizeof (struct dyn_string)); 10368765Sobrien dyn_string_init (result, space); 10468765Sobrien#endif 10568765Sobrien return result; 10668765Sobrien} 10768765Sobrien 10868765Sobrien/* Free the memory used by DS. */ 10968765Sobrien 11068765Sobrienvoid 11168765Sobriendyn_string_delete (ds) 11268765Sobrien dyn_string_t ds; 11368765Sobrien{ 11468765Sobrien free (ds->s); 11568765Sobrien free (ds); 11668765Sobrien} 11768765Sobrien 11868765Sobrien/* Returns the contents of DS in a buffer allocated with malloc. It 11968765Sobrien is the caller's responsibility to deallocate the buffer using free. 12068765Sobrien DS is then set to the empty string. Deletes DS itself. */ 12168765Sobrien 12268765Sobrienchar* 12368765Sobriendyn_string_release (ds) 12468765Sobrien dyn_string_t ds; 12568765Sobrien{ 12668765Sobrien /* Store the old buffer. */ 12768765Sobrien char* result = ds->s; 12868765Sobrien /* The buffer is no longer owned by DS. */ 12968765Sobrien ds->s = NULL; 13068765Sobrien /* Delete DS. */ 13168765Sobrien free (ds); 13268765Sobrien /* Return the old buffer. */ 13368765Sobrien return result; 13468765Sobrien} 13568765Sobrien 13668765Sobrien/* Increase the capacity of DS so it can hold at least SPACE 13768765Sobrien characters, plus the terminating NUL. This function will not (at 13868765Sobrien present) reduce the capacity of DS. Returns DS on success. 13968765Sobrien 14068765Sobrien If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation 14168765Sobrien operation fails, deletes DS and returns NULL. */ 14268765Sobrien 14368765Sobriendyn_string_t 14468765Sobriendyn_string_resize (ds, space) 14568765Sobrien dyn_string_t ds; 14668765Sobrien int space; 14768765Sobrien{ 14868765Sobrien int new_allocated = ds->allocated; 14968765Sobrien 15068765Sobrien /* Increase SPACE to hold the NUL termination. */ 15168765Sobrien ++space; 15268765Sobrien 15368765Sobrien /* Increase allocation by factors of two. */ 15468765Sobrien while (space > new_allocated) 15568765Sobrien new_allocated *= 2; 15668765Sobrien 15768765Sobrien if (new_allocated != ds->allocated) 15868765Sobrien { 15968765Sobrien ds->allocated = new_allocated; 16068765Sobrien /* We actually need more space. */ 16168765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE 16268765Sobrien ds->s = (char *) realloc (ds->s, ds->allocated); 16368765Sobrien if (ds->s == NULL) 16468765Sobrien { 16568765Sobrien free (ds); 16668765Sobrien return NULL; 16768765Sobrien } 16868765Sobrien#else 16968765Sobrien ds->s = (char *) xrealloc (ds->s, ds->allocated); 17068765Sobrien#endif 17168765Sobrien } 17268765Sobrien 17368765Sobrien return ds; 17468765Sobrien} 17568765Sobrien 17668765Sobrien/* Sets the contents of DS to the empty string. */ 17768765Sobrien 17868765Sobrienvoid 17968765Sobriendyn_string_clear (ds) 18068765Sobrien dyn_string_t ds; 18168765Sobrien{ 18268765Sobrien /* A dyn_string always has room for at least the NUL terminator. */ 18368765Sobrien ds->s[0] = '\0'; 18468765Sobrien ds->length = 0; 18568765Sobrien} 18668765Sobrien 18768765Sobrien/* Makes the contents of DEST the same as the contents of SRC. DEST 18868765Sobrien and SRC must be distinct. Returns 1 on success. On failure, if 18968765Sobrien RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 19068765Sobrien 19168765Sobrienint 19268765Sobriendyn_string_copy (dest, src) 19368765Sobrien dyn_string_t dest; 19468765Sobrien dyn_string_t src; 19568765Sobrien{ 19668765Sobrien if (dest == src) 19768765Sobrien abort (); 19868765Sobrien 19968765Sobrien /* Make room in DEST. */ 20068765Sobrien if (dyn_string_resize (dest, src->length) == NULL) 20168765Sobrien return 0; 20268765Sobrien /* Copy DEST into SRC. */ 20368765Sobrien strcpy (dest->s, src->s); 20468765Sobrien /* Update the size of DEST. */ 20568765Sobrien dest->length = src->length; 20668765Sobrien return 1; 20768765Sobrien} 20868765Sobrien 20968765Sobrien/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on 21068765Sobrien success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 21168765Sobrien and returns 0. */ 21268765Sobrien 21368765Sobrienint 21468765Sobriendyn_string_copy_cstr (dest, src) 21568765Sobrien dyn_string_t dest; 21668765Sobrien const char *src; 21768765Sobrien{ 21868765Sobrien int length = strlen (src); 21968765Sobrien /* Make room in DEST. */ 22068765Sobrien if (dyn_string_resize (dest, length) == NULL) 22168765Sobrien return 0; 22268765Sobrien /* Copy DEST into SRC. */ 22368765Sobrien strcpy (dest->s, src); 22468765Sobrien /* Update the size of DEST. */ 22568765Sobrien dest->length = length; 22668765Sobrien return 1; 22768765Sobrien} 22868765Sobrien 22968765Sobrien/* Inserts SRC at the beginning of DEST. DEST is expanded as 23068765Sobrien necessary. SRC and DEST must be distinct. Returns 1 on success. 23168765Sobrien On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 23268765Sobrien returns 0. */ 23368765Sobrien 23468765Sobrienint 23568765Sobriendyn_string_prepend (dest, src) 23668765Sobrien dyn_string_t dest; 23768765Sobrien dyn_string_t src; 23868765Sobrien{ 23968765Sobrien return dyn_string_insert (dest, 0, src); 24068765Sobrien} 24168765Sobrien 24268765Sobrien/* Inserts SRC, a NUL-terminated string, at the beginning of DEST. 24368765Sobrien DEST is expanded as necessary. Returns 1 on success. On failure, 24468765Sobrien if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 24568765Sobrien 24668765Sobrienint 24768765Sobriendyn_string_prepend_cstr (dest, src) 24868765Sobrien dyn_string_t dest; 24968765Sobrien const char *src; 25068765Sobrien{ 25168765Sobrien return dyn_string_insert_cstr (dest, 0, src); 25268765Sobrien} 25368765Sobrien 25468765Sobrien/* Inserts SRC into DEST starting at position POS. DEST is expanded 25568765Sobrien as necessary. SRC and DEST must be distinct. Returns 1 on 25668765Sobrien success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 25768765Sobrien and returns 0. */ 25868765Sobrien 25968765Sobrienint 26068765Sobriendyn_string_insert (dest, pos, src) 26168765Sobrien dyn_string_t dest; 26268765Sobrien int pos; 26368765Sobrien dyn_string_t src; 26468765Sobrien{ 26568765Sobrien int i; 26668765Sobrien 26768765Sobrien if (src == dest) 26868765Sobrien abort (); 26968765Sobrien 27068765Sobrien if (dyn_string_resize (dest, dest->length + src->length) == NULL) 27168765Sobrien return 0; 27268765Sobrien /* Make room for the insertion. Be sure to copy the NUL. */ 27368765Sobrien for (i = dest->length; i >= pos; --i) 27468765Sobrien dest->s[i + src->length] = dest->s[i]; 27568765Sobrien /* Splice in the new stuff. */ 27668765Sobrien strncpy (dest->s + pos, src->s, src->length); 27768765Sobrien /* Compute the new length. */ 27868765Sobrien dest->length += src->length; 27968765Sobrien return 1; 28068765Sobrien} 28168765Sobrien 28268765Sobrien/* Inserts SRC, a NUL-terminated string, into DEST starting at 28368765Sobrien position POS. DEST is expanded as necessary. Returns 1 on 28468765Sobrien success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST 28568765Sobrien and returns 0. */ 28668765Sobrien 28768765Sobrienint 28868765Sobriendyn_string_insert_cstr (dest, pos, src) 28968765Sobrien dyn_string_t dest; 29068765Sobrien int pos; 29168765Sobrien const char *src; 29268765Sobrien{ 29368765Sobrien int i; 29468765Sobrien int length = strlen (src); 29568765Sobrien 29668765Sobrien if (dyn_string_resize (dest, dest->length + length) == NULL) 29768765Sobrien return 0; 29868765Sobrien /* Make room for the insertion. Be sure to copy the NUL. */ 29968765Sobrien for (i = dest->length; i >= pos; --i) 30068765Sobrien dest->s[i + length] = dest->s[i]; 30168765Sobrien /* Splice in the new stuff. */ 30268765Sobrien strncpy (dest->s + pos, src, length); 30368765Sobrien /* Compute the new length. */ 30468765Sobrien dest->length += length; 30568765Sobrien return 1; 30668765Sobrien} 30768765Sobrien 30877298Sobrien/* Inserts character C into DEST starting at position POS. DEST is 30977298Sobrien expanded as necessary. Returns 1 on success. On failure, 31077298Sobrien RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 31177298Sobrien 31277298Sobrienint 31377298Sobriendyn_string_insert_char (dest, pos, c) 31477298Sobrien dyn_string_t dest; 31577298Sobrien int pos; 31677298Sobrien int c; 31777298Sobrien{ 31877298Sobrien int i; 31977298Sobrien 32077298Sobrien if (dyn_string_resize (dest, dest->length + 1) == NULL) 32177298Sobrien return 0; 32277298Sobrien /* Make room for the insertion. Be sure to copy the NUL. */ 32377298Sobrien for (i = dest->length; i >= pos; --i) 32477298Sobrien dest->s[i + 1] = dest->s[i]; 32577298Sobrien /* Add the new character. */ 32677298Sobrien dest->s[pos] = c; 32777298Sobrien /* Compute the new length. */ 32877298Sobrien ++dest->length; 32977298Sobrien return 1; 33077298Sobrien} 33177298Sobrien 33268765Sobrien/* Append S to DS, resizing DS if necessary. Returns 1 on success. 33368765Sobrien On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 33468765Sobrien returns 0. */ 33568765Sobrien 33668765Sobrienint 33768765Sobriendyn_string_append (dest, s) 33868765Sobrien dyn_string_t dest; 33968765Sobrien dyn_string_t s; 34068765Sobrien{ 34168765Sobrien if (dyn_string_resize (dest, dest->length + s->length) == 0) 34268765Sobrien return 0; 34368765Sobrien strcpy (dest->s + dest->length, s->s); 34468765Sobrien dest->length += s->length; 34568765Sobrien return 1; 34668765Sobrien} 34768765Sobrien 34868765Sobrien/* Append the NUL-terminated string S to DS, resizing DS if necessary. 34968765Sobrien Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 35068765Sobrien deletes DEST and returns 0. */ 35168765Sobrien 35268765Sobrienint 35368765Sobriendyn_string_append_cstr (dest, s) 35468765Sobrien dyn_string_t dest; 35568765Sobrien const char *s; 35668765Sobrien{ 35768765Sobrien int len = strlen (s); 35868765Sobrien 35968765Sobrien /* The new length is the old length plus the size of our string, plus 36068765Sobrien one for the null at the end. */ 36168765Sobrien if (dyn_string_resize (dest, dest->length + len) == NULL) 36268765Sobrien return 0; 36368765Sobrien strcpy (dest->s + dest->length, s); 36468765Sobrien dest->length += len; 36568765Sobrien return 1; 36668765Sobrien} 36768765Sobrien 36868765Sobrien/* Appends C to the end of DEST. Returns 1 on success. On failiure, 36968765Sobrien if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 37068765Sobrien 37168765Sobrienint 37268765Sobriendyn_string_append_char (dest, c) 37368765Sobrien dyn_string_t dest; 37468765Sobrien int c; 37568765Sobrien{ 37668765Sobrien /* Make room for the extra character. */ 37768765Sobrien if (dyn_string_resize (dest, dest->length + 1) == NULL) 37868765Sobrien return 0; 37968765Sobrien /* Append the character; it will overwrite the old NUL. */ 38068765Sobrien dest->s[dest->length] = c; 38168765Sobrien /* Add a new NUL at the end. */ 38268765Sobrien dest->s[dest->length + 1] = '\0'; 38368765Sobrien /* Update the length. */ 38468765Sobrien ++(dest->length); 38568765Sobrien return 1; 38668765Sobrien} 38768765Sobrien 38868765Sobrien/* Sets the contents of DEST to the substring of SRC starting at START 38968765Sobrien and ending before END. START must be less than or equal to END, 39068765Sobrien and both must be between zero and the length of SRC, inclusive. 39168765Sobrien Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 39268765Sobrien deletes DEST and returns 0. */ 39368765Sobrien 39468765Sobrienint 39568765Sobriendyn_string_substring (dest, src, start, end) 39668765Sobrien dyn_string_t dest; 39768765Sobrien dyn_string_t src; 39868765Sobrien int start; 39968765Sobrien int end; 40068765Sobrien{ 40168765Sobrien int i; 40268765Sobrien int length = end - start; 40368765Sobrien 40468765Sobrien if (start > end || start > src->length || end > src->length) 40568765Sobrien abort (); 40668765Sobrien 40768765Sobrien /* Make room for the substring. */ 40868765Sobrien if (dyn_string_resize (dest, length) == NULL) 40968765Sobrien return 0; 41068765Sobrien /* Copy the characters in the substring, */ 41168765Sobrien for (i = length; --i >= 0; ) 41268765Sobrien dest->s[i] = src->s[start + i]; 41368765Sobrien /* NUL-terimate the result. */ 41468765Sobrien dest->s[length] = '\0'; 41568765Sobrien /* Record the length of the substring. */ 41668765Sobrien dest->length = length; 41768765Sobrien 41868765Sobrien return 1; 41968765Sobrien} 42068765Sobrien 42168765Sobrien/* Returns non-zero if DS1 and DS2 have the same contents. */ 42268765Sobrien 42368765Sobrienint 42468765Sobriendyn_string_eq (ds1, ds2) 42568765Sobrien dyn_string_t ds1; 42668765Sobrien dyn_string_t ds2; 42768765Sobrien{ 42868765Sobrien /* If DS1 and DS2 have different lengths, they must not be the same. */ 42968765Sobrien if (ds1->length != ds2->length) 43068765Sobrien return 0; 43168765Sobrien else 43268765Sobrien return !strcmp (ds1->s, ds2->s); 43368765Sobrien} 434