xref: /netbsd-src/external/gpl3/gcc/dist/libiberty/dyn-string.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
14fee23f9Smrg /* An abstract string datatype.
2*b1e83836Smrg    Copyright (C) 1998-2022 Free Software Foundation, Inc.
34fee23f9Smrg    Contributed by Mark Mitchell (mark@markmitchell.com).
44fee23f9Smrg 
54fee23f9Smrg This file is part of GNU CC.
64fee23f9Smrg 
74fee23f9Smrg GNU CC is free software; you can redistribute it and/or modify
84fee23f9Smrg it under the terms of the GNU General Public License as published by
94fee23f9Smrg the Free Software Foundation; either version 2, or (at your option)
104fee23f9Smrg any later version.
114fee23f9Smrg 
124fee23f9Smrg In addition to the permissions in the GNU General Public License, the
134fee23f9Smrg Free Software Foundation gives you unlimited permission to link the
144fee23f9Smrg compiled version of this file into combinations with other programs,
154fee23f9Smrg and to distribute those combinations without any restriction coming
164fee23f9Smrg from the use of this file.  (The General Public License restrictions
174fee23f9Smrg do apply in other respects; for example, they cover modification of
184fee23f9Smrg the file, and distribution when not linked into a combined
194fee23f9Smrg executable.)
204fee23f9Smrg 
214fee23f9Smrg GNU CC is distributed in the hope that it will be useful,
224fee23f9Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
234fee23f9Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
244fee23f9Smrg GNU General Public License for more details.
254fee23f9Smrg 
264fee23f9Smrg You should have received a copy of the GNU General Public License
274fee23f9Smrg along with GNU CC; see the file COPYING.  If not, write to
284fee23f9Smrg the Free Software Foundation, 51 Franklin Street - Fifth Floor,
294fee23f9Smrg Boston, MA 02110-1301, USA.  */
304fee23f9Smrg 
314fee23f9Smrg #ifdef HAVE_CONFIG_H
324fee23f9Smrg #include "config.h"
334fee23f9Smrg #endif
344fee23f9Smrg 
354fee23f9Smrg #include <stdio.h>
364fee23f9Smrg 
374fee23f9Smrg #ifdef HAVE_STRING_H
384fee23f9Smrg #include <string.h>
394fee23f9Smrg #endif
404fee23f9Smrg 
414fee23f9Smrg #ifdef HAVE_STDLIB_H
424fee23f9Smrg #include <stdlib.h>
434fee23f9Smrg #endif
444fee23f9Smrg 
454fee23f9Smrg #include "libiberty.h"
464fee23f9Smrg #include "dyn-string.h"
474fee23f9Smrg 
484fee23f9Smrg /* Performs in-place initialization of a dyn_string struct.  This
494fee23f9Smrg    function can be used with a dyn_string struct on the stack or
504fee23f9Smrg    embedded in another object.  The contents of of the string itself
514fee23f9Smrg    are still dynamically allocated.  The string initially is capable
524fee23f9Smrg    of holding at least SPACE characeters, including the terminating
534fee23f9Smrg    NUL.  If SPACE is 0, it will silently be increated to 1.
544fee23f9Smrg 
554fee23f9Smrg    If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
564fee23f9Smrg    fails, returns 0.  Otherwise returns 1.  */
574fee23f9Smrg 
584fee23f9Smrg int
dyn_string_init(struct dyn_string * ds_struct_ptr,int space)594fee23f9Smrg dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
604fee23f9Smrg {
614fee23f9Smrg   /* We need at least one byte in which to store the terminating NUL.  */
624fee23f9Smrg   if (space == 0)
634fee23f9Smrg     space = 1;
644fee23f9Smrg 
654fee23f9Smrg #ifdef RETURN_ON_ALLOCATION_FAILURE
664fee23f9Smrg   ds_struct_ptr->s = (char *) malloc (space);
674fee23f9Smrg   if (ds_struct_ptr->s == NULL)
684fee23f9Smrg     return 0;
694fee23f9Smrg #else
704fee23f9Smrg   ds_struct_ptr->s = XNEWVEC (char, space);
714fee23f9Smrg #endif
724fee23f9Smrg   ds_struct_ptr->allocated = space;
734fee23f9Smrg   ds_struct_ptr->length = 0;
744fee23f9Smrg   ds_struct_ptr->s[0] = '\0';
754fee23f9Smrg 
764fee23f9Smrg   return 1;
774fee23f9Smrg }
784fee23f9Smrg 
794fee23f9Smrg /* Create a new dynamic string capable of holding at least SPACE
804fee23f9Smrg    characters, including the terminating NUL.  If SPACE is 0, it will
814fee23f9Smrg    be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
824fee23f9Smrg    defined and memory allocation fails, returns NULL.  Otherwise
834fee23f9Smrg    returns the newly allocated string.  */
844fee23f9Smrg 
854fee23f9Smrg dyn_string_t
dyn_string_new(int space)864fee23f9Smrg dyn_string_new (int space)
874fee23f9Smrg {
884fee23f9Smrg   dyn_string_t result;
894fee23f9Smrg #ifdef RETURN_ON_ALLOCATION_FAILURE
904fee23f9Smrg   result = (dyn_string_t) malloc (sizeof (struct dyn_string));
914fee23f9Smrg   if (result == NULL)
924fee23f9Smrg     return NULL;
934fee23f9Smrg   if (!dyn_string_init (result, space))
944fee23f9Smrg     {
954fee23f9Smrg       free (result);
964fee23f9Smrg       return NULL;
974fee23f9Smrg     }
984fee23f9Smrg #else
994fee23f9Smrg   result = XNEW (struct dyn_string);
1004fee23f9Smrg   dyn_string_init (result, space);
1014fee23f9Smrg #endif
1024fee23f9Smrg   return result;
1034fee23f9Smrg }
1044fee23f9Smrg 
1054fee23f9Smrg /* Free the memory used by DS.  */
1064fee23f9Smrg 
1074fee23f9Smrg void
dyn_string_delete(dyn_string_t ds)1084fee23f9Smrg dyn_string_delete (dyn_string_t ds)
1094fee23f9Smrg {
1104fee23f9Smrg   free (ds->s);
1114fee23f9Smrg   free (ds);
1124fee23f9Smrg }
1134fee23f9Smrg 
1144fee23f9Smrg /* Returns the contents of DS in a buffer allocated with malloc.  It
1154fee23f9Smrg    is the caller's responsibility to deallocate the buffer using free.
1164fee23f9Smrg    DS is then set to the empty string.  Deletes DS itself.  */
1174fee23f9Smrg 
1184fee23f9Smrg char*
dyn_string_release(dyn_string_t ds)1194fee23f9Smrg dyn_string_release (dyn_string_t ds)
1204fee23f9Smrg {
1214fee23f9Smrg   /* Store the old buffer.  */
1224fee23f9Smrg   char* result = ds->s;
1234fee23f9Smrg   /* The buffer is no longer owned by DS.  */
1244fee23f9Smrg   ds->s = NULL;
1254fee23f9Smrg   /* Delete DS.  */
1264fee23f9Smrg   free (ds);
1274fee23f9Smrg   /* Return the old buffer.  */
1284fee23f9Smrg   return result;
1294fee23f9Smrg }
1304fee23f9Smrg 
1314fee23f9Smrg /* Increase the capacity of DS so it can hold at least SPACE
1324fee23f9Smrg    characters, plus the terminating NUL.  This function will not (at
1334fee23f9Smrg    present) reduce the capacity of DS.  Returns DS on success.
1344fee23f9Smrg 
1354fee23f9Smrg    If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
1364fee23f9Smrg    operation fails, deletes DS and returns NULL.  */
1374fee23f9Smrg 
1384fee23f9Smrg dyn_string_t
dyn_string_resize(dyn_string_t ds,int space)1394fee23f9Smrg dyn_string_resize (dyn_string_t ds, int space)
1404fee23f9Smrg {
1414fee23f9Smrg   int new_allocated = ds->allocated;
1424fee23f9Smrg 
1434fee23f9Smrg   /* Increase SPACE to hold the NUL termination.  */
1444fee23f9Smrg   ++space;
1454fee23f9Smrg 
1464fee23f9Smrg   /* Increase allocation by factors of two.  */
1474fee23f9Smrg   while (space > new_allocated)
1484fee23f9Smrg     new_allocated *= 2;
1494fee23f9Smrg 
1504fee23f9Smrg   if (new_allocated != ds->allocated)
1514fee23f9Smrg     {
1524fee23f9Smrg       ds->allocated = new_allocated;
1534fee23f9Smrg       /* We actually need more space.  */
1544fee23f9Smrg #ifdef RETURN_ON_ALLOCATION_FAILURE
1554fee23f9Smrg       ds->s = (char *) realloc (ds->s, ds->allocated);
1564fee23f9Smrg       if (ds->s == NULL)
1574fee23f9Smrg 	{
1584fee23f9Smrg 	  free (ds);
1594fee23f9Smrg 	  return NULL;
1604fee23f9Smrg 	}
1614fee23f9Smrg #else
1624fee23f9Smrg       ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
1634fee23f9Smrg #endif
1644fee23f9Smrg     }
1654fee23f9Smrg 
1664fee23f9Smrg   return ds;
1674fee23f9Smrg }
1684fee23f9Smrg 
1694fee23f9Smrg /* Sets the contents of DS to the empty string.  */
1704fee23f9Smrg 
1714fee23f9Smrg void
dyn_string_clear(dyn_string_t ds)1724fee23f9Smrg dyn_string_clear (dyn_string_t ds)
1734fee23f9Smrg {
1744fee23f9Smrg   /* A dyn_string always has room for at least the NUL terminator.  */
1754fee23f9Smrg   ds->s[0] = '\0';
1764fee23f9Smrg   ds->length = 0;
1774fee23f9Smrg }
1784fee23f9Smrg 
1794fee23f9Smrg /* Makes the contents of DEST the same as the contents of SRC.  DEST
1804fee23f9Smrg    and SRC must be distinct.  Returns 1 on success.  On failure, if
1814fee23f9Smrg    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
1824fee23f9Smrg 
1834fee23f9Smrg int
dyn_string_copy(dyn_string_t dest,dyn_string_t src)1844fee23f9Smrg dyn_string_copy (dyn_string_t dest, dyn_string_t src)
1854fee23f9Smrg {
1864fee23f9Smrg   if (dest == src)
1874fee23f9Smrg     abort ();
1884fee23f9Smrg 
1894fee23f9Smrg   /* Make room in DEST.  */
1904fee23f9Smrg   if (dyn_string_resize (dest, src->length) == NULL)
1914fee23f9Smrg     return 0;
1924fee23f9Smrg   /* Copy DEST into SRC.  */
1934fee23f9Smrg   strcpy (dest->s, src->s);
1944fee23f9Smrg   /* Update the size of DEST.  */
1954fee23f9Smrg   dest->length = src->length;
1964fee23f9Smrg   return 1;
1974fee23f9Smrg }
1984fee23f9Smrg 
1994fee23f9Smrg /* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
2004fee23f9Smrg    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2014fee23f9Smrg    and returns 0.  */
2024fee23f9Smrg 
2034fee23f9Smrg int
dyn_string_copy_cstr(dyn_string_t dest,const char * src)2044fee23f9Smrg dyn_string_copy_cstr (dyn_string_t dest, const char *src)
2054fee23f9Smrg {
2064fee23f9Smrg   int length = strlen (src);
2074fee23f9Smrg   /* Make room in DEST.  */
2084fee23f9Smrg   if (dyn_string_resize (dest, length) == NULL)
2094fee23f9Smrg     return 0;
2104fee23f9Smrg   /* Copy DEST into SRC.  */
2114fee23f9Smrg   strcpy (dest->s, src);
2124fee23f9Smrg   /* Update the size of DEST.  */
2134fee23f9Smrg   dest->length = length;
2144fee23f9Smrg   return 1;
2154fee23f9Smrg }
2164fee23f9Smrg 
2174fee23f9Smrg /* Inserts SRC at the beginning of DEST.  DEST is expanded as
2184fee23f9Smrg    necessary.  SRC and DEST must be distinct.  Returns 1 on success.
2194fee23f9Smrg    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
2204fee23f9Smrg    returns 0.  */
2214fee23f9Smrg 
2224fee23f9Smrg int
dyn_string_prepend(dyn_string_t dest,dyn_string_t src)2234fee23f9Smrg dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
2244fee23f9Smrg {
2254fee23f9Smrg   return dyn_string_insert (dest, 0, src);
2264fee23f9Smrg }
2274fee23f9Smrg 
2284fee23f9Smrg /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
2294fee23f9Smrg    DEST is expanded as necessary.  Returns 1 on success.  On failure,
2304fee23f9Smrg    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
2314fee23f9Smrg 
2324fee23f9Smrg int
dyn_string_prepend_cstr(dyn_string_t dest,const char * src)2334fee23f9Smrg dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
2344fee23f9Smrg {
2354fee23f9Smrg   return dyn_string_insert_cstr (dest, 0, src);
2364fee23f9Smrg }
2374fee23f9Smrg 
2384fee23f9Smrg /* Inserts SRC into DEST starting at position POS.  DEST is expanded
2394fee23f9Smrg    as necessary.  SRC and DEST must be distinct.  Returns 1 on
2404fee23f9Smrg    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2414fee23f9Smrg    and returns 0.  */
2424fee23f9Smrg 
2434fee23f9Smrg int
dyn_string_insert(dyn_string_t dest,int pos,dyn_string_t src)2444fee23f9Smrg dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
2454fee23f9Smrg {
2464fee23f9Smrg   int i;
2474fee23f9Smrg 
2484fee23f9Smrg   if (src == dest)
2494fee23f9Smrg     abort ();
2504fee23f9Smrg 
2514fee23f9Smrg   if (dyn_string_resize (dest, dest->length + src->length) == NULL)
2524fee23f9Smrg     return 0;
2534fee23f9Smrg   /* Make room for the insertion.  Be sure to copy the NUL.  */
2544fee23f9Smrg   for (i = dest->length; i >= pos; --i)
2554fee23f9Smrg     dest->s[i + src->length] = dest->s[i];
2564fee23f9Smrg   /* Splice in the new stuff.  */
2574fee23f9Smrg   strncpy (dest->s + pos, src->s, src->length);
2584fee23f9Smrg   /* Compute the new length.  */
2594fee23f9Smrg   dest->length += src->length;
2604fee23f9Smrg   return 1;
2614fee23f9Smrg }
2624fee23f9Smrg 
2634fee23f9Smrg /* Inserts SRC, a NUL-terminated string, into DEST starting at
2644fee23f9Smrg    position POS.  DEST is expanded as necessary.  Returns 1 on
2654fee23f9Smrg    success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2664fee23f9Smrg    and returns 0.  */
2674fee23f9Smrg 
2684fee23f9Smrg int
dyn_string_insert_cstr(dyn_string_t dest,int pos,const char * src)2694fee23f9Smrg dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
2704fee23f9Smrg {
2714fee23f9Smrg   int i;
2724fee23f9Smrg   int length = strlen (src);
2734fee23f9Smrg 
2744fee23f9Smrg   if (dyn_string_resize (dest, dest->length + length) == NULL)
2754fee23f9Smrg     return 0;
2764fee23f9Smrg   /* Make room for the insertion.  Be sure to copy the NUL.  */
2774fee23f9Smrg   for (i = dest->length; i >= pos; --i)
2784fee23f9Smrg     dest->s[i + length] = dest->s[i];
2794fee23f9Smrg   /* Splice in the new stuff.  */
280*b1e83836Smrg   memcpy (dest->s + pos, src, length);
2814fee23f9Smrg   /* Compute the new length.  */
2824fee23f9Smrg   dest->length += length;
2834fee23f9Smrg   return 1;
2844fee23f9Smrg }
2854fee23f9Smrg 
2864fee23f9Smrg /* Inserts character C into DEST starting at position POS.  DEST is
2874fee23f9Smrg    expanded as necessary.  Returns 1 on success.  On failure,
2884fee23f9Smrg    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
2894fee23f9Smrg 
2904fee23f9Smrg int
dyn_string_insert_char(dyn_string_t dest,int pos,int c)2914fee23f9Smrg dyn_string_insert_char (dyn_string_t dest, int pos, int c)
2924fee23f9Smrg {
2934fee23f9Smrg   int i;
2944fee23f9Smrg 
2954fee23f9Smrg   if (dyn_string_resize (dest, dest->length + 1) == NULL)
2964fee23f9Smrg     return 0;
2974fee23f9Smrg   /* Make room for the insertion.  Be sure to copy the NUL.  */
2984fee23f9Smrg   for (i = dest->length; i >= pos; --i)
2994fee23f9Smrg     dest->s[i + 1] = dest->s[i];
3004fee23f9Smrg   /* Add the new character.  */
3014fee23f9Smrg   dest->s[pos] = c;
3024fee23f9Smrg   /* Compute the new length.  */
3034fee23f9Smrg   ++dest->length;
3044fee23f9Smrg   return 1;
3054fee23f9Smrg }
3064fee23f9Smrg 
3074fee23f9Smrg /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
3084fee23f9Smrg    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
3094fee23f9Smrg    returns 0.  */
3104fee23f9Smrg 
3114fee23f9Smrg int
dyn_string_append(dyn_string_t dest,dyn_string_t s)3124fee23f9Smrg dyn_string_append (dyn_string_t dest, dyn_string_t s)
3134fee23f9Smrg {
3144fee23f9Smrg   if (dyn_string_resize (dest, dest->length + s->length) == 0)
3154fee23f9Smrg     return 0;
3164fee23f9Smrg   strcpy (dest->s + dest->length, s->s);
3174fee23f9Smrg   dest->length += s->length;
3184fee23f9Smrg   return 1;
3194fee23f9Smrg }
3204fee23f9Smrg 
3214fee23f9Smrg /* Append the NUL-terminated string S to DS, resizing DS if necessary.
3224fee23f9Smrg    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
3234fee23f9Smrg    deletes DEST and returns 0.  */
3244fee23f9Smrg 
3254fee23f9Smrg int
dyn_string_append_cstr(dyn_string_t dest,const char * s)3264fee23f9Smrg dyn_string_append_cstr (dyn_string_t dest, const char *s)
3274fee23f9Smrg {
3284fee23f9Smrg   int len = strlen (s);
3294fee23f9Smrg 
3304fee23f9Smrg   /* The new length is the old length plus the size of our string, plus
3314fee23f9Smrg      one for the null at the end.  */
3324fee23f9Smrg   if (dyn_string_resize (dest, dest->length + len) == NULL)
3334fee23f9Smrg     return 0;
3344fee23f9Smrg   strcpy (dest->s + dest->length, s);
3354fee23f9Smrg   dest->length += len;
3364fee23f9Smrg   return 1;
3374fee23f9Smrg }
3384fee23f9Smrg 
3394fee23f9Smrg /* Appends C to the end of DEST.  Returns 1 on success.  On failure,
3404fee23f9Smrg    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
3414fee23f9Smrg 
3424fee23f9Smrg int
dyn_string_append_char(dyn_string_t dest,int c)3434fee23f9Smrg dyn_string_append_char (dyn_string_t dest, int c)
3444fee23f9Smrg {
3454fee23f9Smrg   /* Make room for the extra character.  */
3464fee23f9Smrg   if (dyn_string_resize (dest, dest->length + 1) == NULL)
3474fee23f9Smrg     return 0;
3484fee23f9Smrg   /* Append the character; it will overwrite the old NUL.  */
3494fee23f9Smrg   dest->s[dest->length] = c;
3504fee23f9Smrg   /* Add a new NUL at the end.  */
3514fee23f9Smrg   dest->s[dest->length + 1] = '\0';
3524fee23f9Smrg   /* Update the length.  */
3534fee23f9Smrg   ++(dest->length);
3544fee23f9Smrg   return 1;
3554fee23f9Smrg }
3564fee23f9Smrg 
3574fee23f9Smrg /* Sets the contents of DEST to the substring of SRC starting at START
3584fee23f9Smrg    and ending before END.  START must be less than or equal to END,
3594fee23f9Smrg    and both must be between zero and the length of SRC, inclusive.
3604fee23f9Smrg    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
3614fee23f9Smrg    deletes DEST and returns 0.  */
3624fee23f9Smrg 
3634fee23f9Smrg int
dyn_string_substring(dyn_string_t dest,dyn_string_t src,int start,int end)3644fee23f9Smrg dyn_string_substring (dyn_string_t dest, dyn_string_t src,
3654fee23f9Smrg                       int start, int end)
3664fee23f9Smrg {
3674fee23f9Smrg   int i;
3684fee23f9Smrg   int length = end - start;
3694fee23f9Smrg 
3704fee23f9Smrg   if (start > end || start > src->length || end > src->length)
3714fee23f9Smrg     abort ();
3724fee23f9Smrg 
3734fee23f9Smrg   /* Make room for the substring.  */
3744fee23f9Smrg   if (dyn_string_resize (dest, length) == NULL)
3754fee23f9Smrg     return 0;
3764fee23f9Smrg   /* Copy the characters in the substring,  */
3774fee23f9Smrg   for (i = length; --i >= 0; )
3784fee23f9Smrg     dest->s[i] = src->s[start + i];
3794fee23f9Smrg   /* NUL-terimate the result.  */
3804fee23f9Smrg   dest->s[length] = '\0';
3814fee23f9Smrg   /* Record the length of the substring.  */
3824fee23f9Smrg   dest->length = length;
3834fee23f9Smrg 
3844fee23f9Smrg   return 1;
3854fee23f9Smrg }
3864fee23f9Smrg 
3874fee23f9Smrg /* Returns non-zero if DS1 and DS2 have the same contents.  */
3884fee23f9Smrg 
3894fee23f9Smrg int
dyn_string_eq(dyn_string_t ds1,dyn_string_t ds2)3904fee23f9Smrg dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
3914fee23f9Smrg {
3924fee23f9Smrg   /* If DS1 and DS2 have different lengths, they must not be the same.  */
3934fee23f9Smrg   if (ds1->length != ds2->length)
3944fee23f9Smrg     return 0;
3954fee23f9Smrg   else
3964fee23f9Smrg     return !strcmp (ds1->s, ds2->s);
3974fee23f9Smrg }
398