198b9484cSchristos /* An abstract string datatype. 2*5173eb0aSchristos Copyright (C) 1998-2024 Free Software Foundation, Inc. 398b9484cSchristos Contributed by Mark Mitchell (mark@markmitchell.com). 498b9484cSchristos 598b9484cSchristos This file is part of GNU CC. 698b9484cSchristos 798b9484cSchristos GNU CC is free software; you can redistribute it and/or modify 898b9484cSchristos it under the terms of the GNU General Public License as published by 998b9484cSchristos the Free Software Foundation; either version 2, or (at your option) 1098b9484cSchristos any later version. 1198b9484cSchristos 1298b9484cSchristos In addition to the permissions in the GNU General Public License, the 1398b9484cSchristos Free Software Foundation gives you unlimited permission to link the 1498b9484cSchristos compiled version of this file into combinations with other programs, 1598b9484cSchristos and to distribute those combinations without any restriction coming 1698b9484cSchristos from the use of this file. (The General Public License restrictions 1798b9484cSchristos do apply in other respects; for example, they cover modification of 1898b9484cSchristos the file, and distribution when not linked into a combined 1998b9484cSchristos executable.) 2098b9484cSchristos 2198b9484cSchristos GNU CC is distributed in the hope that it will be useful, 2298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 2398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2498b9484cSchristos GNU General Public License for more details. 2598b9484cSchristos 2698b9484cSchristos You should have received a copy of the GNU General Public License 2798b9484cSchristos along with GNU CC; see the file COPYING. If not, write to 2898b9484cSchristos the Free Software Foundation, 51 Franklin Street - Fifth Floor, 2998b9484cSchristos Boston, MA 02110-1301, USA. */ 3098b9484cSchristos 3198b9484cSchristos #ifdef HAVE_CONFIG_H 3298b9484cSchristos #include "config.h" 3398b9484cSchristos #endif 3498b9484cSchristos 3598b9484cSchristos #include <stdio.h> 3698b9484cSchristos 3798b9484cSchristos #ifdef HAVE_STRING_H 3898b9484cSchristos #include <string.h> 3998b9484cSchristos #endif 4098b9484cSchristos 4198b9484cSchristos #ifdef HAVE_STDLIB_H 4298b9484cSchristos #include <stdlib.h> 4398b9484cSchristos #endif 4498b9484cSchristos 4598b9484cSchristos #include "libiberty.h" 4698b9484cSchristos #include "dyn-string.h" 4798b9484cSchristos 4898b9484cSchristos /* Performs in-place initialization of a dyn_string struct. This 4998b9484cSchristos function can be used with a dyn_string struct on the stack or 5098b9484cSchristos embedded in another object. The contents of of the string itself 5198b9484cSchristos are still dynamically allocated. The string initially is capable 5298b9484cSchristos of holding at least SPACE characeters, including the terminating 5398b9484cSchristos NUL. If SPACE is 0, it will silently be increated to 1. 5498b9484cSchristos 5598b9484cSchristos If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation 5698b9484cSchristos fails, returns 0. Otherwise returns 1. */ 5798b9484cSchristos 5898b9484cSchristos int 5998b9484cSchristos dyn_string_init (struct dyn_string *ds_struct_ptr, int space) 6098b9484cSchristos { 6198b9484cSchristos /* We need at least one byte in which to store the terminating NUL. */ 6298b9484cSchristos if (space == 0) 6398b9484cSchristos space = 1; 6498b9484cSchristos 6598b9484cSchristos #ifdef RETURN_ON_ALLOCATION_FAILURE 6698b9484cSchristos ds_struct_ptr->s = (char *) malloc (space); 6798b9484cSchristos if (ds_struct_ptr->s == NULL) 6898b9484cSchristos return 0; 6998b9484cSchristos #else 7098b9484cSchristos ds_struct_ptr->s = XNEWVEC (char, space); 7198b9484cSchristos #endif 7298b9484cSchristos ds_struct_ptr->allocated = space; 7398b9484cSchristos ds_struct_ptr->length = 0; 7498b9484cSchristos ds_struct_ptr->s[0] = '\0'; 7598b9484cSchristos 7698b9484cSchristos return 1; 7798b9484cSchristos } 7898b9484cSchristos 7998b9484cSchristos /* Create a new dynamic string capable of holding at least SPACE 8098b9484cSchristos characters, including the terminating NUL. If SPACE is 0, it will 8198b9484cSchristos be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is 8298b9484cSchristos defined and memory allocation fails, returns NULL. Otherwise 8398b9484cSchristos returns the newly allocated string. */ 8498b9484cSchristos 8598b9484cSchristos dyn_string_t 8698b9484cSchristos dyn_string_new (int space) 8798b9484cSchristos { 8898b9484cSchristos dyn_string_t result; 8998b9484cSchristos #ifdef RETURN_ON_ALLOCATION_FAILURE 9098b9484cSchristos result = (dyn_string_t) malloc (sizeof (struct dyn_string)); 9198b9484cSchristos if (result == NULL) 9298b9484cSchristos return NULL; 9398b9484cSchristos if (!dyn_string_init (result, space)) 9498b9484cSchristos { 9598b9484cSchristos free (result); 9698b9484cSchristos return NULL; 9798b9484cSchristos } 9898b9484cSchristos #else 9998b9484cSchristos result = XNEW (struct dyn_string); 10098b9484cSchristos dyn_string_init (result, space); 10198b9484cSchristos #endif 10298b9484cSchristos return result; 10398b9484cSchristos } 10498b9484cSchristos 10598b9484cSchristos /* Free the memory used by DS. */ 10698b9484cSchristos 10798b9484cSchristos void 10898b9484cSchristos dyn_string_delete (dyn_string_t ds) 10998b9484cSchristos { 11098b9484cSchristos free (ds->s); 11198b9484cSchristos free (ds); 11298b9484cSchristos } 11398b9484cSchristos 11498b9484cSchristos /* Returns the contents of DS in a buffer allocated with malloc. It 11598b9484cSchristos is the caller's responsibility to deallocate the buffer using free. 11698b9484cSchristos DS is then set to the empty string. Deletes DS itself. */ 11798b9484cSchristos 11898b9484cSchristos char* 11998b9484cSchristos dyn_string_release (dyn_string_t ds) 12098b9484cSchristos { 12198b9484cSchristos /* Store the old buffer. */ 12298b9484cSchristos char* result = ds->s; 12398b9484cSchristos /* The buffer is no longer owned by DS. */ 12498b9484cSchristos ds->s = NULL; 12598b9484cSchristos /* Delete DS. */ 12698b9484cSchristos free (ds); 12798b9484cSchristos /* Return the old buffer. */ 12898b9484cSchristos return result; 12998b9484cSchristos } 13098b9484cSchristos 13198b9484cSchristos /* Increase the capacity of DS so it can hold at least SPACE 13298b9484cSchristos characters, plus the terminating NUL. This function will not (at 13398b9484cSchristos present) reduce the capacity of DS. Returns DS on success. 13498b9484cSchristos 13598b9484cSchristos If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation 13698b9484cSchristos operation fails, deletes DS and returns NULL. */ 13798b9484cSchristos 13898b9484cSchristos dyn_string_t 13998b9484cSchristos dyn_string_resize (dyn_string_t ds, int space) 14098b9484cSchristos { 14198b9484cSchristos int new_allocated = ds->allocated; 14298b9484cSchristos 14398b9484cSchristos /* Increase SPACE to hold the NUL termination. */ 14498b9484cSchristos ++space; 14598b9484cSchristos 14698b9484cSchristos /* Increase allocation by factors of two. */ 14798b9484cSchristos while (space > new_allocated) 14898b9484cSchristos new_allocated *= 2; 14998b9484cSchristos 15098b9484cSchristos if (new_allocated != ds->allocated) 15198b9484cSchristos { 15298b9484cSchristos ds->allocated = new_allocated; 15398b9484cSchristos /* We actually need more space. */ 15498b9484cSchristos #ifdef RETURN_ON_ALLOCATION_FAILURE 15598b9484cSchristos ds->s = (char *) realloc (ds->s, ds->allocated); 15698b9484cSchristos if (ds->s == NULL) 15798b9484cSchristos { 15898b9484cSchristos free (ds); 15998b9484cSchristos return NULL; 16098b9484cSchristos } 16198b9484cSchristos #else 16298b9484cSchristos ds->s = XRESIZEVEC (char, ds->s, ds->allocated); 16398b9484cSchristos #endif 16498b9484cSchristos } 16598b9484cSchristos 16698b9484cSchristos return ds; 16798b9484cSchristos } 16898b9484cSchristos 16998b9484cSchristos /* Sets the contents of DS to the empty string. */ 17098b9484cSchristos 17198b9484cSchristos void 17298b9484cSchristos dyn_string_clear (dyn_string_t ds) 17398b9484cSchristos { 17498b9484cSchristos /* A dyn_string always has room for at least the NUL terminator. */ 17598b9484cSchristos ds->s[0] = '\0'; 17698b9484cSchristos ds->length = 0; 17798b9484cSchristos } 17898b9484cSchristos 17998b9484cSchristos /* Makes the contents of DEST the same as the contents of SRC. DEST 18098b9484cSchristos and SRC must be distinct. Returns 1 on success. On failure, if 18198b9484cSchristos RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 18298b9484cSchristos 18398b9484cSchristos int 18498b9484cSchristos dyn_string_copy (dyn_string_t dest, dyn_string_t src) 18598b9484cSchristos { 18698b9484cSchristos if (dest == src) 18798b9484cSchristos abort (); 18898b9484cSchristos 18998b9484cSchristos /* Make room in DEST. */ 19098b9484cSchristos if (dyn_string_resize (dest, src->length) == NULL) 19198b9484cSchristos return 0; 19298b9484cSchristos /* Copy DEST into SRC. */ 19398b9484cSchristos strcpy (dest->s, src->s); 19498b9484cSchristos /* Update the size of DEST. */ 19598b9484cSchristos dest->length = src->length; 19698b9484cSchristos return 1; 19798b9484cSchristos } 19898b9484cSchristos 19998b9484cSchristos /* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on 20098b9484cSchristos success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 20198b9484cSchristos and returns 0. */ 20298b9484cSchristos 20398b9484cSchristos int 20498b9484cSchristos dyn_string_copy_cstr (dyn_string_t dest, const char *src) 20598b9484cSchristos { 20698b9484cSchristos int length = strlen (src); 20798b9484cSchristos /* Make room in DEST. */ 20898b9484cSchristos if (dyn_string_resize (dest, length) == NULL) 20998b9484cSchristos return 0; 21098b9484cSchristos /* Copy DEST into SRC. */ 21198b9484cSchristos strcpy (dest->s, src); 21298b9484cSchristos /* Update the size of DEST. */ 21398b9484cSchristos dest->length = length; 21498b9484cSchristos return 1; 21598b9484cSchristos } 21698b9484cSchristos 21798b9484cSchristos /* Inserts SRC at the beginning of DEST. DEST is expanded as 21898b9484cSchristos necessary. SRC and DEST must be distinct. Returns 1 on success. 21998b9484cSchristos On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 22098b9484cSchristos returns 0. */ 22198b9484cSchristos 22298b9484cSchristos int 22398b9484cSchristos dyn_string_prepend (dyn_string_t dest, dyn_string_t src) 22498b9484cSchristos { 22598b9484cSchristos return dyn_string_insert (dest, 0, src); 22698b9484cSchristos } 22798b9484cSchristos 22898b9484cSchristos /* Inserts SRC, a NUL-terminated string, at the beginning of DEST. 22998b9484cSchristos DEST is expanded as necessary. Returns 1 on success. On failure, 23098b9484cSchristos if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 23198b9484cSchristos 23298b9484cSchristos int 23398b9484cSchristos dyn_string_prepend_cstr (dyn_string_t dest, const char *src) 23498b9484cSchristos { 23598b9484cSchristos return dyn_string_insert_cstr (dest, 0, src); 23698b9484cSchristos } 23798b9484cSchristos 23898b9484cSchristos /* Inserts SRC into DEST starting at position POS. DEST is expanded 23998b9484cSchristos as necessary. SRC and DEST must be distinct. Returns 1 on 24098b9484cSchristos success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST 24198b9484cSchristos and returns 0. */ 24298b9484cSchristos 24398b9484cSchristos int 24498b9484cSchristos dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src) 24598b9484cSchristos { 24698b9484cSchristos int i; 24798b9484cSchristos 24898b9484cSchristos if (src == dest) 24998b9484cSchristos abort (); 25098b9484cSchristos 25198b9484cSchristos if (dyn_string_resize (dest, dest->length + src->length) == NULL) 25298b9484cSchristos return 0; 25398b9484cSchristos /* Make room for the insertion. Be sure to copy the NUL. */ 25498b9484cSchristos for (i = dest->length; i >= pos; --i) 25598b9484cSchristos dest->s[i + src->length] = dest->s[i]; 25698b9484cSchristos /* Splice in the new stuff. */ 25798b9484cSchristos strncpy (dest->s + pos, src->s, src->length); 25898b9484cSchristos /* Compute the new length. */ 25998b9484cSchristos dest->length += src->length; 26098b9484cSchristos return 1; 26198b9484cSchristos } 26298b9484cSchristos 26398b9484cSchristos /* Inserts SRC, a NUL-terminated string, into DEST starting at 26498b9484cSchristos position POS. DEST is expanded as necessary. Returns 1 on 26598b9484cSchristos success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST 26698b9484cSchristos and returns 0. */ 26798b9484cSchristos 26898b9484cSchristos int 26998b9484cSchristos dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) 27098b9484cSchristos { 27198b9484cSchristos int i; 27298b9484cSchristos int length = strlen (src); 27398b9484cSchristos 27498b9484cSchristos if (dyn_string_resize (dest, dest->length + length) == NULL) 27598b9484cSchristos return 0; 27698b9484cSchristos /* Make room for the insertion. Be sure to copy the NUL. */ 27798b9484cSchristos for (i = dest->length; i >= pos; --i) 27898b9484cSchristos dest->s[i + length] = dest->s[i]; 27998b9484cSchristos /* Splice in the new stuff. */ 2804b169a6bSchristos memcpy (dest->s + pos, src, length); 28198b9484cSchristos /* Compute the new length. */ 28298b9484cSchristos dest->length += length; 28398b9484cSchristos return 1; 28498b9484cSchristos } 28598b9484cSchristos 28698b9484cSchristos /* Inserts character C into DEST starting at position POS. DEST is 28798b9484cSchristos expanded as necessary. Returns 1 on success. On failure, 28898b9484cSchristos RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 28998b9484cSchristos 29098b9484cSchristos int 29198b9484cSchristos dyn_string_insert_char (dyn_string_t dest, int pos, int c) 29298b9484cSchristos { 29398b9484cSchristos int i; 29498b9484cSchristos 29598b9484cSchristos if (dyn_string_resize (dest, dest->length + 1) == NULL) 29698b9484cSchristos return 0; 29798b9484cSchristos /* Make room for the insertion. Be sure to copy the NUL. */ 29898b9484cSchristos for (i = dest->length; i >= pos; --i) 29998b9484cSchristos dest->s[i + 1] = dest->s[i]; 30098b9484cSchristos /* Add the new character. */ 30198b9484cSchristos dest->s[pos] = c; 30298b9484cSchristos /* Compute the new length. */ 30398b9484cSchristos ++dest->length; 30498b9484cSchristos return 1; 30598b9484cSchristos } 30698b9484cSchristos 30798b9484cSchristos /* Append S to DS, resizing DS if necessary. Returns 1 on success. 30898b9484cSchristos On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and 30998b9484cSchristos returns 0. */ 31098b9484cSchristos 31198b9484cSchristos int 31298b9484cSchristos dyn_string_append (dyn_string_t dest, dyn_string_t s) 31398b9484cSchristos { 31498b9484cSchristos if (dyn_string_resize (dest, dest->length + s->length) == 0) 31598b9484cSchristos return 0; 31698b9484cSchristos strcpy (dest->s + dest->length, s->s); 31798b9484cSchristos dest->length += s->length; 31898b9484cSchristos return 1; 31998b9484cSchristos } 32098b9484cSchristos 32198b9484cSchristos /* Append the NUL-terminated string S to DS, resizing DS if necessary. 32298b9484cSchristos Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 32398b9484cSchristos deletes DEST and returns 0. */ 32498b9484cSchristos 32598b9484cSchristos int 32698b9484cSchristos dyn_string_append_cstr (dyn_string_t dest, const char *s) 32798b9484cSchristos { 32898b9484cSchristos int len = strlen (s); 32998b9484cSchristos 33098b9484cSchristos /* The new length is the old length plus the size of our string, plus 33198b9484cSchristos one for the null at the end. */ 33298b9484cSchristos if (dyn_string_resize (dest, dest->length + len) == NULL) 33398b9484cSchristos return 0; 33498b9484cSchristos strcpy (dest->s + dest->length, s); 33598b9484cSchristos dest->length += len; 33698b9484cSchristos return 1; 33798b9484cSchristos } 33898b9484cSchristos 33998b9484cSchristos /* Appends C to the end of DEST. Returns 1 on success. On failure, 34098b9484cSchristos if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ 34198b9484cSchristos 34298b9484cSchristos int 34398b9484cSchristos dyn_string_append_char (dyn_string_t dest, int c) 34498b9484cSchristos { 34598b9484cSchristos /* Make room for the extra character. */ 34698b9484cSchristos if (dyn_string_resize (dest, dest->length + 1) == NULL) 34798b9484cSchristos return 0; 34898b9484cSchristos /* Append the character; it will overwrite the old NUL. */ 34998b9484cSchristos dest->s[dest->length] = c; 35098b9484cSchristos /* Add a new NUL at the end. */ 35198b9484cSchristos dest->s[dest->length + 1] = '\0'; 35298b9484cSchristos /* Update the length. */ 35398b9484cSchristos ++(dest->length); 35498b9484cSchristos return 1; 35598b9484cSchristos } 35698b9484cSchristos 35798b9484cSchristos /* Sets the contents of DEST to the substring of SRC starting at START 35898b9484cSchristos and ending before END. START must be less than or equal to END, 35998b9484cSchristos and both must be between zero and the length of SRC, inclusive. 36098b9484cSchristos Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, 36198b9484cSchristos deletes DEST and returns 0. */ 36298b9484cSchristos 36398b9484cSchristos int 36498b9484cSchristos dyn_string_substring (dyn_string_t dest, dyn_string_t src, 36598b9484cSchristos int start, int end) 36698b9484cSchristos { 36798b9484cSchristos int i; 36898b9484cSchristos int length = end - start; 36998b9484cSchristos 37098b9484cSchristos if (start > end || start > src->length || end > src->length) 37198b9484cSchristos abort (); 37298b9484cSchristos 37398b9484cSchristos /* Make room for the substring. */ 37498b9484cSchristos if (dyn_string_resize (dest, length) == NULL) 37598b9484cSchristos return 0; 37698b9484cSchristos /* Copy the characters in the substring, */ 37798b9484cSchristos for (i = length; --i >= 0; ) 37898b9484cSchristos dest->s[i] = src->s[start + i]; 37998b9484cSchristos /* NUL-terimate the result. */ 38098b9484cSchristos dest->s[length] = '\0'; 38198b9484cSchristos /* Record the length of the substring. */ 38298b9484cSchristos dest->length = length; 38398b9484cSchristos 38498b9484cSchristos return 1; 38598b9484cSchristos } 38698b9484cSchristos 38798b9484cSchristos /* Returns non-zero if DS1 and DS2 have the same contents. */ 38898b9484cSchristos 38998b9484cSchristos int 39098b9484cSchristos dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2) 39198b9484cSchristos { 39298b9484cSchristos /* If DS1 and DS2 have different lengths, they must not be the same. */ 39398b9484cSchristos if (ds1->length != ds2->length) 39498b9484cSchristos return 0; 39598b9484cSchristos else 39698b9484cSchristos return !strcmp (ds1->s, ds2->s); 39798b9484cSchristos } 398