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