11debfc3dSmrg /* An abstract string datatype.
2*8feb0f0bSmrg Copyright (C) 1998-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Mark Mitchell (mark@markmitchell.com).
41debfc3dSmrg
51debfc3dSmrg This file is part of GNU CC.
61debfc3dSmrg
71debfc3dSmrg GNU CC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 2, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg
121debfc3dSmrg In addition to the permissions in the GNU General Public License, the
131debfc3dSmrg Free Software Foundation gives you unlimited permission to link the
141debfc3dSmrg compiled version of this file into combinations with other programs,
151debfc3dSmrg and to distribute those combinations without any restriction coming
161debfc3dSmrg from the use of this file. (The General Public License restrictions
171debfc3dSmrg do apply in other respects; for example, they cover modification of
181debfc3dSmrg the file, and distribution when not linked into a combined
191debfc3dSmrg executable.)
201debfc3dSmrg
211debfc3dSmrg GNU CC is distributed in the hope that it will be useful,
221debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
231debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
241debfc3dSmrg GNU General Public License for more details.
251debfc3dSmrg
261debfc3dSmrg You should have received a copy of the GNU General Public License
271debfc3dSmrg along with GNU CC; see the file COPYING. If not, write to
281debfc3dSmrg the Free Software Foundation, 51 Franklin Street - Fifth Floor,
291debfc3dSmrg Boston, MA 02110-1301, USA. */
301debfc3dSmrg
311debfc3dSmrg #ifdef HAVE_CONFIG_H
321debfc3dSmrg #include "config.h"
331debfc3dSmrg #endif
341debfc3dSmrg
351debfc3dSmrg #include <stdio.h>
361debfc3dSmrg
371debfc3dSmrg #ifdef HAVE_STRING_H
381debfc3dSmrg #include <string.h>
391debfc3dSmrg #endif
401debfc3dSmrg
411debfc3dSmrg #ifdef HAVE_STDLIB_H
421debfc3dSmrg #include <stdlib.h>
431debfc3dSmrg #endif
441debfc3dSmrg
451debfc3dSmrg #include "libiberty.h"
461debfc3dSmrg #include "dyn-string.h"
471debfc3dSmrg
481debfc3dSmrg /* Performs in-place initialization of a dyn_string struct. This
491debfc3dSmrg function can be used with a dyn_string struct on the stack or
501debfc3dSmrg embedded in another object. The contents of of the string itself
511debfc3dSmrg are still dynamically allocated. The string initially is capable
521debfc3dSmrg of holding at least SPACE characeters, including the terminating
531debfc3dSmrg NUL. If SPACE is 0, it will silently be increated to 1.
541debfc3dSmrg
551debfc3dSmrg If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
561debfc3dSmrg fails, returns 0. Otherwise returns 1. */
571debfc3dSmrg
581debfc3dSmrg int
dyn_string_init(struct dyn_string * ds_struct_ptr,int space)591debfc3dSmrg dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
601debfc3dSmrg {
611debfc3dSmrg /* We need at least one byte in which to store the terminating NUL. */
621debfc3dSmrg if (space == 0)
631debfc3dSmrg space = 1;
641debfc3dSmrg
651debfc3dSmrg #ifdef RETURN_ON_ALLOCATION_FAILURE
661debfc3dSmrg ds_struct_ptr->s = (char *) malloc (space);
671debfc3dSmrg if (ds_struct_ptr->s == NULL)
681debfc3dSmrg return 0;
691debfc3dSmrg #else
701debfc3dSmrg ds_struct_ptr->s = XNEWVEC (char, space);
711debfc3dSmrg #endif
721debfc3dSmrg ds_struct_ptr->allocated = space;
731debfc3dSmrg ds_struct_ptr->length = 0;
741debfc3dSmrg ds_struct_ptr->s[0] = '\0';
751debfc3dSmrg
761debfc3dSmrg return 1;
771debfc3dSmrg }
781debfc3dSmrg
791debfc3dSmrg /* Create a new dynamic string capable of holding at least SPACE
801debfc3dSmrg characters, including the terminating NUL. If SPACE is 0, it will
811debfc3dSmrg be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is
821debfc3dSmrg defined and memory allocation fails, returns NULL. Otherwise
831debfc3dSmrg returns the newly allocated string. */
841debfc3dSmrg
851debfc3dSmrg dyn_string_t
dyn_string_new(int space)861debfc3dSmrg dyn_string_new (int space)
871debfc3dSmrg {
881debfc3dSmrg dyn_string_t result;
891debfc3dSmrg #ifdef RETURN_ON_ALLOCATION_FAILURE
901debfc3dSmrg result = (dyn_string_t) malloc (sizeof (struct dyn_string));
911debfc3dSmrg if (result == NULL)
921debfc3dSmrg return NULL;
931debfc3dSmrg if (!dyn_string_init (result, space))
941debfc3dSmrg {
951debfc3dSmrg free (result);
961debfc3dSmrg return NULL;
971debfc3dSmrg }
981debfc3dSmrg #else
991debfc3dSmrg result = XNEW (struct dyn_string);
1001debfc3dSmrg dyn_string_init (result, space);
1011debfc3dSmrg #endif
1021debfc3dSmrg return result;
1031debfc3dSmrg }
1041debfc3dSmrg
1051debfc3dSmrg /* Free the memory used by DS. */
1061debfc3dSmrg
1071debfc3dSmrg void
dyn_string_delete(dyn_string_t ds)1081debfc3dSmrg dyn_string_delete (dyn_string_t ds)
1091debfc3dSmrg {
1101debfc3dSmrg free (ds->s);
1111debfc3dSmrg free (ds);
1121debfc3dSmrg }
1131debfc3dSmrg
1141debfc3dSmrg /* Returns the contents of DS in a buffer allocated with malloc. It
1151debfc3dSmrg is the caller's responsibility to deallocate the buffer using free.
1161debfc3dSmrg DS is then set to the empty string. Deletes DS itself. */
1171debfc3dSmrg
1181debfc3dSmrg char*
dyn_string_release(dyn_string_t ds)1191debfc3dSmrg dyn_string_release (dyn_string_t ds)
1201debfc3dSmrg {
1211debfc3dSmrg /* Store the old buffer. */
1221debfc3dSmrg char* result = ds->s;
1231debfc3dSmrg /* The buffer is no longer owned by DS. */
1241debfc3dSmrg ds->s = NULL;
1251debfc3dSmrg /* Delete DS. */
1261debfc3dSmrg free (ds);
1271debfc3dSmrg /* Return the old buffer. */
1281debfc3dSmrg return result;
1291debfc3dSmrg }
1301debfc3dSmrg
1311debfc3dSmrg /* Increase the capacity of DS so it can hold at least SPACE
1321debfc3dSmrg characters, plus the terminating NUL. This function will not (at
1331debfc3dSmrg present) reduce the capacity of DS. Returns DS on success.
1341debfc3dSmrg
1351debfc3dSmrg If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
1361debfc3dSmrg operation fails, deletes DS and returns NULL. */
1371debfc3dSmrg
1381debfc3dSmrg dyn_string_t
dyn_string_resize(dyn_string_t ds,int space)1391debfc3dSmrg dyn_string_resize (dyn_string_t ds, int space)
1401debfc3dSmrg {
1411debfc3dSmrg int new_allocated = ds->allocated;
1421debfc3dSmrg
1431debfc3dSmrg /* Increase SPACE to hold the NUL termination. */
1441debfc3dSmrg ++space;
1451debfc3dSmrg
1461debfc3dSmrg /* Increase allocation by factors of two. */
1471debfc3dSmrg while (space > new_allocated)
1481debfc3dSmrg new_allocated *= 2;
1491debfc3dSmrg
1501debfc3dSmrg if (new_allocated != ds->allocated)
1511debfc3dSmrg {
1521debfc3dSmrg ds->allocated = new_allocated;
1531debfc3dSmrg /* We actually need more space. */
1541debfc3dSmrg #ifdef RETURN_ON_ALLOCATION_FAILURE
1551debfc3dSmrg ds->s = (char *) realloc (ds->s, ds->allocated);
1561debfc3dSmrg if (ds->s == NULL)
1571debfc3dSmrg {
1581debfc3dSmrg free (ds);
1591debfc3dSmrg return NULL;
1601debfc3dSmrg }
1611debfc3dSmrg #else
1621debfc3dSmrg ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
1631debfc3dSmrg #endif
1641debfc3dSmrg }
1651debfc3dSmrg
1661debfc3dSmrg return ds;
1671debfc3dSmrg }
1681debfc3dSmrg
1691debfc3dSmrg /* Sets the contents of DS to the empty string. */
1701debfc3dSmrg
1711debfc3dSmrg void
dyn_string_clear(dyn_string_t ds)1721debfc3dSmrg dyn_string_clear (dyn_string_t ds)
1731debfc3dSmrg {
1741debfc3dSmrg /* A dyn_string always has room for at least the NUL terminator. */
1751debfc3dSmrg ds->s[0] = '\0';
1761debfc3dSmrg ds->length = 0;
1771debfc3dSmrg }
1781debfc3dSmrg
1791debfc3dSmrg /* Makes the contents of DEST the same as the contents of SRC. DEST
1801debfc3dSmrg and SRC must be distinct. Returns 1 on success. On failure, if
1811debfc3dSmrg RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
1821debfc3dSmrg
1831debfc3dSmrg int
dyn_string_copy(dyn_string_t dest,dyn_string_t src)1841debfc3dSmrg dyn_string_copy (dyn_string_t dest, dyn_string_t src)
1851debfc3dSmrg {
1861debfc3dSmrg if (dest == src)
1871debfc3dSmrg abort ();
1881debfc3dSmrg
1891debfc3dSmrg /* Make room in DEST. */
1901debfc3dSmrg if (dyn_string_resize (dest, src->length) == NULL)
1911debfc3dSmrg return 0;
1921debfc3dSmrg /* Copy DEST into SRC. */
1931debfc3dSmrg strcpy (dest->s, src->s);
1941debfc3dSmrg /* Update the size of DEST. */
1951debfc3dSmrg dest->length = src->length;
1961debfc3dSmrg return 1;
1971debfc3dSmrg }
1981debfc3dSmrg
1991debfc3dSmrg /* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on
2001debfc3dSmrg success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2011debfc3dSmrg and returns 0. */
2021debfc3dSmrg
2031debfc3dSmrg int
dyn_string_copy_cstr(dyn_string_t dest,const char * src)2041debfc3dSmrg dyn_string_copy_cstr (dyn_string_t dest, const char *src)
2051debfc3dSmrg {
2061debfc3dSmrg int length = strlen (src);
2071debfc3dSmrg /* Make room in DEST. */
2081debfc3dSmrg if (dyn_string_resize (dest, length) == NULL)
2091debfc3dSmrg return 0;
2101debfc3dSmrg /* Copy DEST into SRC. */
2111debfc3dSmrg strcpy (dest->s, src);
2121debfc3dSmrg /* Update the size of DEST. */
2131debfc3dSmrg dest->length = length;
2141debfc3dSmrg return 1;
2151debfc3dSmrg }
2161debfc3dSmrg
2171debfc3dSmrg /* Inserts SRC at the beginning of DEST. DEST is expanded as
2181debfc3dSmrg necessary. SRC and DEST must be distinct. Returns 1 on success.
2191debfc3dSmrg On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
2201debfc3dSmrg returns 0. */
2211debfc3dSmrg
2221debfc3dSmrg int
dyn_string_prepend(dyn_string_t dest,dyn_string_t src)2231debfc3dSmrg dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
2241debfc3dSmrg {
2251debfc3dSmrg return dyn_string_insert (dest, 0, src);
2261debfc3dSmrg }
2271debfc3dSmrg
2281debfc3dSmrg /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
2291debfc3dSmrg DEST is expanded as necessary. Returns 1 on success. On failure,
2301debfc3dSmrg if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
2311debfc3dSmrg
2321debfc3dSmrg int
dyn_string_prepend_cstr(dyn_string_t dest,const char * src)2331debfc3dSmrg dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
2341debfc3dSmrg {
2351debfc3dSmrg return dyn_string_insert_cstr (dest, 0, src);
2361debfc3dSmrg }
2371debfc3dSmrg
2381debfc3dSmrg /* Inserts SRC into DEST starting at position POS. DEST is expanded
2391debfc3dSmrg as necessary. SRC and DEST must be distinct. Returns 1 on
2401debfc3dSmrg success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2411debfc3dSmrg and returns 0. */
2421debfc3dSmrg
2431debfc3dSmrg int
dyn_string_insert(dyn_string_t dest,int pos,dyn_string_t src)2441debfc3dSmrg dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
2451debfc3dSmrg {
2461debfc3dSmrg int i;
2471debfc3dSmrg
2481debfc3dSmrg if (src == dest)
2491debfc3dSmrg abort ();
2501debfc3dSmrg
2511debfc3dSmrg if (dyn_string_resize (dest, dest->length + src->length) == NULL)
2521debfc3dSmrg return 0;
2531debfc3dSmrg /* Make room for the insertion. Be sure to copy the NUL. */
2541debfc3dSmrg for (i = dest->length; i >= pos; --i)
2551debfc3dSmrg dest->s[i + src->length] = dest->s[i];
2561debfc3dSmrg /* Splice in the new stuff. */
2571debfc3dSmrg strncpy (dest->s + pos, src->s, src->length);
2581debfc3dSmrg /* Compute the new length. */
2591debfc3dSmrg dest->length += src->length;
2601debfc3dSmrg return 1;
2611debfc3dSmrg }
2621debfc3dSmrg
2631debfc3dSmrg /* Inserts SRC, a NUL-terminated string, into DEST starting at
2641debfc3dSmrg position POS. DEST is expanded as necessary. Returns 1 on
2651debfc3dSmrg success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2661debfc3dSmrg and returns 0. */
2671debfc3dSmrg
2681debfc3dSmrg int
dyn_string_insert_cstr(dyn_string_t dest,int pos,const char * src)2691debfc3dSmrg dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
2701debfc3dSmrg {
2711debfc3dSmrg int i;
2721debfc3dSmrg int length = strlen (src);
2731debfc3dSmrg
2741debfc3dSmrg if (dyn_string_resize (dest, dest->length + length) == NULL)
2751debfc3dSmrg return 0;
2761debfc3dSmrg /* Make room for the insertion. Be sure to copy the NUL. */
2771debfc3dSmrg for (i = dest->length; i >= pos; --i)
2781debfc3dSmrg dest->s[i + length] = dest->s[i];
2791debfc3dSmrg /* Splice in the new stuff. */
2801debfc3dSmrg strncpy (dest->s + pos, src, length);
2811debfc3dSmrg /* Compute the new length. */
2821debfc3dSmrg dest->length += length;
2831debfc3dSmrg return 1;
2841debfc3dSmrg }
2851debfc3dSmrg
2861debfc3dSmrg /* Inserts character C into DEST starting at position POS. DEST is
2871debfc3dSmrg expanded as necessary. Returns 1 on success. On failure,
2881debfc3dSmrg RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
2891debfc3dSmrg
2901debfc3dSmrg int
dyn_string_insert_char(dyn_string_t dest,int pos,int c)2911debfc3dSmrg dyn_string_insert_char (dyn_string_t dest, int pos, int c)
2921debfc3dSmrg {
2931debfc3dSmrg int i;
2941debfc3dSmrg
2951debfc3dSmrg if (dyn_string_resize (dest, dest->length + 1) == NULL)
2961debfc3dSmrg return 0;
2971debfc3dSmrg /* Make room for the insertion. Be sure to copy the NUL. */
2981debfc3dSmrg for (i = dest->length; i >= pos; --i)
2991debfc3dSmrg dest->s[i + 1] = dest->s[i];
3001debfc3dSmrg /* Add the new character. */
3011debfc3dSmrg dest->s[pos] = c;
3021debfc3dSmrg /* Compute the new length. */
3031debfc3dSmrg ++dest->length;
3041debfc3dSmrg return 1;
3051debfc3dSmrg }
3061debfc3dSmrg
3071debfc3dSmrg /* Append S to DS, resizing DS if necessary. Returns 1 on success.
3081debfc3dSmrg On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
3091debfc3dSmrg returns 0. */
3101debfc3dSmrg
3111debfc3dSmrg int
dyn_string_append(dyn_string_t dest,dyn_string_t s)3121debfc3dSmrg dyn_string_append (dyn_string_t dest, dyn_string_t s)
3131debfc3dSmrg {
3141debfc3dSmrg if (dyn_string_resize (dest, dest->length + s->length) == 0)
3151debfc3dSmrg return 0;
3161debfc3dSmrg strcpy (dest->s + dest->length, s->s);
3171debfc3dSmrg dest->length += s->length;
3181debfc3dSmrg return 1;
3191debfc3dSmrg }
3201debfc3dSmrg
3211debfc3dSmrg /* Append the NUL-terminated string S to DS, resizing DS if necessary.
3221debfc3dSmrg Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
3231debfc3dSmrg deletes DEST and returns 0. */
3241debfc3dSmrg
3251debfc3dSmrg int
dyn_string_append_cstr(dyn_string_t dest,const char * s)3261debfc3dSmrg dyn_string_append_cstr (dyn_string_t dest, const char *s)
3271debfc3dSmrg {
3281debfc3dSmrg int len = strlen (s);
3291debfc3dSmrg
3301debfc3dSmrg /* The new length is the old length plus the size of our string, plus
3311debfc3dSmrg one for the null at the end. */
3321debfc3dSmrg if (dyn_string_resize (dest, dest->length + len) == NULL)
3331debfc3dSmrg return 0;
3341debfc3dSmrg strcpy (dest->s + dest->length, s);
3351debfc3dSmrg dest->length += len;
3361debfc3dSmrg return 1;
3371debfc3dSmrg }
3381debfc3dSmrg
3391debfc3dSmrg /* Appends C to the end of DEST. Returns 1 on success. On failure,
3401debfc3dSmrg if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
3411debfc3dSmrg
3421debfc3dSmrg int
dyn_string_append_char(dyn_string_t dest,int c)3431debfc3dSmrg dyn_string_append_char (dyn_string_t dest, int c)
3441debfc3dSmrg {
3451debfc3dSmrg /* Make room for the extra character. */
3461debfc3dSmrg if (dyn_string_resize (dest, dest->length + 1) == NULL)
3471debfc3dSmrg return 0;
3481debfc3dSmrg /* Append the character; it will overwrite the old NUL. */
3491debfc3dSmrg dest->s[dest->length] = c;
3501debfc3dSmrg /* Add a new NUL at the end. */
3511debfc3dSmrg dest->s[dest->length + 1] = '\0';
3521debfc3dSmrg /* Update the length. */
3531debfc3dSmrg ++(dest->length);
3541debfc3dSmrg return 1;
3551debfc3dSmrg }
3561debfc3dSmrg
3571debfc3dSmrg /* Sets the contents of DEST to the substring of SRC starting at START
3581debfc3dSmrg and ending before END. START must be less than or equal to END,
3591debfc3dSmrg and both must be between zero and the length of SRC, inclusive.
3601debfc3dSmrg Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
3611debfc3dSmrg deletes DEST and returns 0. */
3621debfc3dSmrg
3631debfc3dSmrg int
dyn_string_substring(dyn_string_t dest,dyn_string_t src,int start,int end)3641debfc3dSmrg dyn_string_substring (dyn_string_t dest, dyn_string_t src,
3651debfc3dSmrg int start, int end)
3661debfc3dSmrg {
3671debfc3dSmrg int i;
3681debfc3dSmrg int length = end - start;
3691debfc3dSmrg
3701debfc3dSmrg if (start > end || start > src->length || end > src->length)
3711debfc3dSmrg abort ();
3721debfc3dSmrg
3731debfc3dSmrg /* Make room for the substring. */
3741debfc3dSmrg if (dyn_string_resize (dest, length) == NULL)
3751debfc3dSmrg return 0;
3761debfc3dSmrg /* Copy the characters in the substring, */
3771debfc3dSmrg for (i = length; --i >= 0; )
3781debfc3dSmrg dest->s[i] = src->s[start + i];
3791debfc3dSmrg /* NUL-terimate the result. */
3801debfc3dSmrg dest->s[length] = '\0';
3811debfc3dSmrg /* Record the length of the substring. */
3821debfc3dSmrg dest->length = length;
3831debfc3dSmrg
3841debfc3dSmrg return 1;
3851debfc3dSmrg }
3861debfc3dSmrg
3871debfc3dSmrg /* Returns non-zero if DS1 and DS2 have the same contents. */
3881debfc3dSmrg
3891debfc3dSmrg int
dyn_string_eq(dyn_string_t ds1,dyn_string_t ds2)3901debfc3dSmrg dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
3911debfc3dSmrg {
3921debfc3dSmrg /* If DS1 and DS2 have different lengths, they must not be the same. */
3931debfc3dSmrg if (ds1->length != ds2->length)
3941debfc3dSmrg return 0;
3951debfc3dSmrg else
3961debfc3dSmrg return !strcmp (ds1->s, ds2->s);
3971debfc3dSmrg }
398