12e0724c7Sespie /* An abstract string datatype.
2*150b7e42Smiod Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
32e0724c7Sespie Contributed by Mark Mitchell (mark@markmitchell.com).
42e0724c7Sespie
52e0724c7Sespie This file is part of GNU CC.
62e0724c7Sespie
72e0724c7Sespie GNU CC is free software; you can redistribute it and/or modify
82e0724c7Sespie it under the terms of the GNU General Public License as published by
92e0724c7Sespie the Free Software Foundation; either version 2, or (at your option)
102e0724c7Sespie any later version.
112e0724c7Sespie
1237c53322Sespie In addition to the permissions in the GNU General Public License, the
1337c53322Sespie Free Software Foundation gives you unlimited permission to link the
1437c53322Sespie compiled version of this file into combinations with other programs,
1537c53322Sespie and to distribute those combinations without any restriction coming
1637c53322Sespie from the use of this file. (The General Public License restrictions
1737c53322Sespie do apply in other respects; for example, they cover modification of
1837c53322Sespie the file, and distribution when not linked into a combined
1937c53322Sespie executable.)
2037c53322Sespie
212e0724c7Sespie GNU CC is distributed in the hope that it will be useful,
222e0724c7Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
232e0724c7Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
242e0724c7Sespie GNU General Public License for more details.
252e0724c7Sespie
262e0724c7Sespie You should have received a copy of the GNU General Public License
272e0724c7Sespie along with GNU CC; see the file COPYING. If not, write to
28*150b7e42Smiod the Free Software Foundation, 51 Franklin Street - Fifth Floor,
29*150b7e42Smiod Boston, MA 02110-1301, USA. */
302e0724c7Sespie
312e0724c7Sespie #ifdef HAVE_CONFIG_H
322e0724c7Sespie #include "config.h"
332e0724c7Sespie #endif
342e0724c7Sespie
352e0724c7Sespie #include <stdio.h>
362e0724c7Sespie
372e0724c7Sespie #ifdef HAVE_STRING_H
382e0724c7Sespie #include <string.h>
392e0724c7Sespie #endif
402e0724c7Sespie
412e0724c7Sespie #ifdef HAVE_STDLIB_H
422e0724c7Sespie #include <stdlib.h>
432e0724c7Sespie #endif
442e0724c7Sespie
452e0724c7Sespie #include "libiberty.h"
462e0724c7Sespie #include "dyn-string.h"
472e0724c7Sespie
482e0724c7Sespie /* If this file is being compiled for inclusion in the C++ runtime
492e0724c7Sespie library, as part of the demangler implementation, we don't want to
502e0724c7Sespie abort if an allocation fails. Instead, percolate an error code up
512e0724c7Sespie through the call chain. */
522e0724c7Sespie
5337c53322Sespie #if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
542e0724c7Sespie #define RETURN_ON_ALLOCATION_FAILURE
552e0724c7Sespie #endif
562e0724c7Sespie
572e0724c7Sespie /* Performs in-place initialization of a dyn_string struct. This
582e0724c7Sespie function can be used with a dyn_string struct on the stack or
592e0724c7Sespie embedded in another object. The contents of of the string itself
602e0724c7Sespie are still dynamically allocated. The string initially is capable
612e0724c7Sespie of holding at least SPACE characeters, including the terminating
622e0724c7Sespie NUL. If SPACE is 0, it will silently be increated to 1.
632e0724c7Sespie
642e0724c7Sespie If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
652e0724c7Sespie fails, returns 0. Otherwise returns 1. */
662e0724c7Sespie
672e0724c7Sespie int
dyn_string_init(struct dyn_string * ds_struct_ptr,int space)68*150b7e42Smiod dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
692e0724c7Sespie {
702e0724c7Sespie /* We need at least one byte in which to store the terminating NUL. */
712e0724c7Sespie if (space == 0)
722e0724c7Sespie space = 1;
732e0724c7Sespie
742e0724c7Sespie #ifdef RETURN_ON_ALLOCATION_FAILURE
752e0724c7Sespie ds_struct_ptr->s = (char *) malloc (space);
762e0724c7Sespie if (ds_struct_ptr->s == NULL)
772e0724c7Sespie return 0;
782e0724c7Sespie #else
79*150b7e42Smiod ds_struct_ptr->s = XNEWVEC (char, space);
802e0724c7Sespie #endif
812e0724c7Sespie ds_struct_ptr->allocated = space;
822e0724c7Sespie ds_struct_ptr->length = 0;
832e0724c7Sespie ds_struct_ptr->s[0] = '\0';
842e0724c7Sespie
852e0724c7Sespie return 1;
862e0724c7Sespie }
872e0724c7Sespie
882e0724c7Sespie /* Create a new dynamic string capable of holding at least SPACE
892e0724c7Sespie characters, including the terminating NUL. If SPACE is 0, it will
902e0724c7Sespie be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is
912e0724c7Sespie defined and memory allocation fails, returns NULL. Otherwise
922e0724c7Sespie returns the newly allocated string. */
932e0724c7Sespie
942e0724c7Sespie dyn_string_t
dyn_string_new(int space)95*150b7e42Smiod dyn_string_new (int space)
962e0724c7Sespie {
972e0724c7Sespie dyn_string_t result;
982e0724c7Sespie #ifdef RETURN_ON_ALLOCATION_FAILURE
992e0724c7Sespie result = (dyn_string_t) malloc (sizeof (struct dyn_string));
1002e0724c7Sespie if (result == NULL)
1012e0724c7Sespie return NULL;
1022e0724c7Sespie if (!dyn_string_init (result, space))
1032e0724c7Sespie {
1042e0724c7Sespie free (result);
1052e0724c7Sespie return NULL;
1062e0724c7Sespie }
1072e0724c7Sespie #else
108*150b7e42Smiod result = XNEW (struct dyn_string);
1092e0724c7Sespie dyn_string_init (result, space);
1102e0724c7Sespie #endif
1112e0724c7Sespie return result;
1122e0724c7Sespie }
1132e0724c7Sespie
1142e0724c7Sespie /* Free the memory used by DS. */
1152e0724c7Sespie
1162e0724c7Sespie void
dyn_string_delete(dyn_string_t ds)117*150b7e42Smiod dyn_string_delete (dyn_string_t ds)
1182e0724c7Sespie {
1192e0724c7Sespie free (ds->s);
1202e0724c7Sespie free (ds);
1212e0724c7Sespie }
1222e0724c7Sespie
1232e0724c7Sespie /* Returns the contents of DS in a buffer allocated with malloc. It
1242e0724c7Sespie is the caller's responsibility to deallocate the buffer using free.
1252e0724c7Sespie DS is then set to the empty string. Deletes DS itself. */
1262e0724c7Sespie
1272e0724c7Sespie char*
dyn_string_release(dyn_string_t ds)128*150b7e42Smiod dyn_string_release (dyn_string_t ds)
1292e0724c7Sespie {
1302e0724c7Sespie /* Store the old buffer. */
1312e0724c7Sespie char* result = ds->s;
1322e0724c7Sespie /* The buffer is no longer owned by DS. */
1332e0724c7Sespie ds->s = NULL;
1342e0724c7Sespie /* Delete DS. */
1352e0724c7Sespie free (ds);
1362e0724c7Sespie /* Return the old buffer. */
1372e0724c7Sespie return result;
1382e0724c7Sespie }
1392e0724c7Sespie
1402e0724c7Sespie /* Increase the capacity of DS so it can hold at least SPACE
1412e0724c7Sespie characters, plus the terminating NUL. This function will not (at
1422e0724c7Sespie present) reduce the capacity of DS. Returns DS on success.
1432e0724c7Sespie
1442e0724c7Sespie If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
1452e0724c7Sespie operation fails, deletes DS and returns NULL. */
1462e0724c7Sespie
1472e0724c7Sespie dyn_string_t
dyn_string_resize(dyn_string_t ds,int space)148*150b7e42Smiod dyn_string_resize (dyn_string_t ds, int space)
1492e0724c7Sespie {
1502e0724c7Sespie int new_allocated = ds->allocated;
1512e0724c7Sespie
1522e0724c7Sespie /* Increase SPACE to hold the NUL termination. */
1532e0724c7Sespie ++space;
1542e0724c7Sespie
1552e0724c7Sespie /* Increase allocation by factors of two. */
1562e0724c7Sespie while (space > new_allocated)
1572e0724c7Sespie new_allocated *= 2;
1582e0724c7Sespie
1592e0724c7Sespie if (new_allocated != ds->allocated)
1602e0724c7Sespie {
1612e0724c7Sespie ds->allocated = new_allocated;
1622e0724c7Sespie /* We actually need more space. */
1632e0724c7Sespie #ifdef RETURN_ON_ALLOCATION_FAILURE
1642e0724c7Sespie ds->s = (char *) realloc (ds->s, ds->allocated);
1652e0724c7Sespie if (ds->s == NULL)
1662e0724c7Sespie {
1672e0724c7Sespie free (ds);
1682e0724c7Sespie return NULL;
1692e0724c7Sespie }
1702e0724c7Sespie #else
171*150b7e42Smiod ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
1722e0724c7Sespie #endif
1732e0724c7Sespie }
1742e0724c7Sespie
1752e0724c7Sespie return ds;
1762e0724c7Sespie }
1772e0724c7Sespie
1782e0724c7Sespie /* Sets the contents of DS to the empty string. */
1792e0724c7Sespie
1802e0724c7Sespie void
dyn_string_clear(dyn_string_t ds)181*150b7e42Smiod dyn_string_clear (dyn_string_t ds)
1822e0724c7Sespie {
1832e0724c7Sespie /* A dyn_string always has room for at least the NUL terminator. */
1842e0724c7Sespie ds->s[0] = '\0';
1852e0724c7Sespie ds->length = 0;
1862e0724c7Sespie }
1872e0724c7Sespie
1882e0724c7Sespie /* Makes the contents of DEST the same as the contents of SRC. DEST
1892e0724c7Sespie and SRC must be distinct. Returns 1 on success. On failure, if
1902e0724c7Sespie RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
1912e0724c7Sespie
1922e0724c7Sespie int
dyn_string_copy(dyn_string_t dest,dyn_string_t src)193*150b7e42Smiod dyn_string_copy (dyn_string_t dest, dyn_string_t src)
1942e0724c7Sespie {
1952e0724c7Sespie if (dest == src)
1962e0724c7Sespie abort ();
1972e0724c7Sespie
1982e0724c7Sespie /* Make room in DEST. */
1992e0724c7Sespie if (dyn_string_resize (dest, src->length) == NULL)
2002e0724c7Sespie return 0;
2012e0724c7Sespie /* Copy DEST into SRC. */
2022aa20281Sespie strlcpy (dest->s, src->s, dest->allocated);
2032e0724c7Sespie /* Update the size of DEST. */
2042e0724c7Sespie dest->length = src->length;
2052e0724c7Sespie return 1;
2062e0724c7Sespie }
2072e0724c7Sespie
2082e0724c7Sespie /* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on
2092e0724c7Sespie success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2102e0724c7Sespie and returns 0. */
2112e0724c7Sespie
2122e0724c7Sespie int
dyn_string_copy_cstr(dyn_string_t dest,const char * src)213*150b7e42Smiod dyn_string_copy_cstr (dyn_string_t dest, const char *src)
2142e0724c7Sespie {
2152e0724c7Sespie int length = strlen (src);
2162e0724c7Sespie /* Make room in DEST. */
2172e0724c7Sespie if (dyn_string_resize (dest, length) == NULL)
2182e0724c7Sespie return 0;
2192e0724c7Sespie /* Copy DEST into SRC. */
2202aa20281Sespie strlcpy (dest->s, src, dest->allocated);
2212e0724c7Sespie /* Update the size of DEST. */
2222e0724c7Sespie dest->length = length;
2232e0724c7Sespie return 1;
2242e0724c7Sespie }
2252e0724c7Sespie
2262e0724c7Sespie /* Inserts SRC at the beginning of DEST. DEST is expanded as
2272e0724c7Sespie necessary. SRC and DEST must be distinct. Returns 1 on success.
2282e0724c7Sespie On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
2292e0724c7Sespie returns 0. */
2302e0724c7Sespie
2312e0724c7Sespie int
dyn_string_prepend(dyn_string_t dest,dyn_string_t src)232*150b7e42Smiod dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
2332e0724c7Sespie {
2342e0724c7Sespie return dyn_string_insert (dest, 0, src);
2352e0724c7Sespie }
2362e0724c7Sespie
2372e0724c7Sespie /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
2382e0724c7Sespie DEST is expanded as necessary. Returns 1 on success. On failure,
2392e0724c7Sespie if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
2402e0724c7Sespie
2412e0724c7Sespie int
dyn_string_prepend_cstr(dyn_string_t dest,const char * src)242*150b7e42Smiod dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
2432e0724c7Sespie {
2442e0724c7Sespie return dyn_string_insert_cstr (dest, 0, src);
2452e0724c7Sespie }
2462e0724c7Sespie
2472e0724c7Sespie /* Inserts SRC into DEST starting at position POS. DEST is expanded
2482e0724c7Sespie as necessary. SRC and DEST must be distinct. Returns 1 on
2492e0724c7Sespie success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2502e0724c7Sespie and returns 0. */
2512e0724c7Sespie
2522e0724c7Sespie int
dyn_string_insert(dyn_string_t dest,int pos,dyn_string_t src)253*150b7e42Smiod dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
2542e0724c7Sespie {
2552e0724c7Sespie int i;
2562e0724c7Sespie
2572e0724c7Sespie if (src == dest)
2582e0724c7Sespie abort ();
2592e0724c7Sespie
2602e0724c7Sespie if (dyn_string_resize (dest, dest->length + src->length) == NULL)
2612e0724c7Sespie return 0;
2622e0724c7Sespie /* Make room for the insertion. Be sure to copy the NUL. */
2632e0724c7Sespie for (i = dest->length; i >= pos; --i)
2642e0724c7Sespie dest->s[i + src->length] = dest->s[i];
2652e0724c7Sespie /* Splice in the new stuff. */
2662e0724c7Sespie strncpy (dest->s + pos, src->s, src->length);
2672e0724c7Sespie /* Compute the new length. */
2682e0724c7Sespie dest->length += src->length;
2692e0724c7Sespie return 1;
2702e0724c7Sespie }
2712e0724c7Sespie
2722e0724c7Sespie /* Inserts SRC, a NUL-terminated string, into DEST starting at
2732e0724c7Sespie position POS. DEST is expanded as necessary. Returns 1 on
2742e0724c7Sespie success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2752e0724c7Sespie and returns 0. */
2762e0724c7Sespie
2772e0724c7Sespie int
dyn_string_insert_cstr(dyn_string_t dest,int pos,const char * src)278*150b7e42Smiod dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
2792e0724c7Sespie {
2802e0724c7Sespie int i;
2812e0724c7Sespie int length = strlen (src);
2822e0724c7Sespie
2832e0724c7Sespie if (dyn_string_resize (dest, dest->length + length) == NULL)
2842e0724c7Sespie return 0;
2852e0724c7Sespie /* Make room for the insertion. Be sure to copy the NUL. */
2862e0724c7Sespie for (i = dest->length; i >= pos; --i)
2872e0724c7Sespie dest->s[i + length] = dest->s[i];
2882e0724c7Sespie /* Splice in the new stuff. */
2892e0724c7Sespie strncpy (dest->s + pos, src, length);
2902e0724c7Sespie /* Compute the new length. */
2912e0724c7Sespie dest->length += length;
2922e0724c7Sespie return 1;
2932e0724c7Sespie }
2942e0724c7Sespie
295f5dd06f4Sespie /* Inserts character C into DEST starting at position POS. DEST is
296f5dd06f4Sespie expanded as necessary. Returns 1 on success. On failure,
297f5dd06f4Sespie RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
298f5dd06f4Sespie
299f5dd06f4Sespie int
dyn_string_insert_char(dyn_string_t dest,int pos,int c)300*150b7e42Smiod dyn_string_insert_char (dyn_string_t dest, int pos, int c)
301f5dd06f4Sespie {
302f5dd06f4Sespie int i;
303f5dd06f4Sespie
304f5dd06f4Sespie if (dyn_string_resize (dest, dest->length + 1) == NULL)
305f5dd06f4Sespie return 0;
306f5dd06f4Sespie /* Make room for the insertion. Be sure to copy the NUL. */
307f5dd06f4Sespie for (i = dest->length; i >= pos; --i)
308f5dd06f4Sespie dest->s[i + 1] = dest->s[i];
309f5dd06f4Sespie /* Add the new character. */
310f5dd06f4Sespie dest->s[pos] = c;
311f5dd06f4Sespie /* Compute the new length. */
312f5dd06f4Sespie ++dest->length;
313f5dd06f4Sespie return 1;
314f5dd06f4Sespie }
315f5dd06f4Sespie
3162e0724c7Sespie /* Append S to DS, resizing DS if necessary. Returns 1 on success.
3172e0724c7Sespie On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
3182e0724c7Sespie returns 0. */
3192e0724c7Sespie
3202e0724c7Sespie int
dyn_string_append(dyn_string_t dest,dyn_string_t s)321*150b7e42Smiod dyn_string_append (dyn_string_t dest, dyn_string_t s)
3222e0724c7Sespie {
3232e0724c7Sespie if (dyn_string_resize (dest, dest->length + s->length) == 0)
3242e0724c7Sespie return 0;
3252aa20281Sespie strlcpy (dest->s + dest->length, s->s, dest->allocated - dest->length);
3262e0724c7Sespie dest->length += s->length;
3272e0724c7Sespie return 1;
3282e0724c7Sespie }
3292e0724c7Sespie
3302e0724c7Sespie /* Append the NUL-terminated string S to DS, resizing DS if necessary.
3312e0724c7Sespie Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
3322e0724c7Sespie deletes DEST and returns 0. */
3332e0724c7Sespie
3342e0724c7Sespie int
dyn_string_append_cstr(dyn_string_t dest,const char * s)335*150b7e42Smiod dyn_string_append_cstr (dyn_string_t dest, const char *s)
3362e0724c7Sespie {
3372e0724c7Sespie int len = strlen (s);
3382e0724c7Sespie
3392e0724c7Sespie /* The new length is the old length plus the size of our string, plus
3402e0724c7Sespie one for the null at the end. */
3412e0724c7Sespie if (dyn_string_resize (dest, dest->length + len) == NULL)
3422e0724c7Sespie return 0;
3432aa20281Sespie strlcpy (dest->s + dest->length, s, dest->allocated - dest->length);
3442e0724c7Sespie dest->length += len;
3452e0724c7Sespie return 1;
3462e0724c7Sespie }
3472e0724c7Sespie
3482e0724c7Sespie /* Appends C to the end of DEST. Returns 1 on success. On failiure,
3492e0724c7Sespie if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
3502e0724c7Sespie
3512e0724c7Sespie int
dyn_string_append_char(dyn_string_t dest,int c)352*150b7e42Smiod dyn_string_append_char (dyn_string_t dest, int c)
3532e0724c7Sespie {
3542e0724c7Sespie /* Make room for the extra character. */
3552e0724c7Sespie if (dyn_string_resize (dest, dest->length + 1) == NULL)
3562e0724c7Sespie return 0;
3572e0724c7Sespie /* Append the character; it will overwrite the old NUL. */
3582e0724c7Sespie dest->s[dest->length] = c;
3592e0724c7Sespie /* Add a new NUL at the end. */
3602e0724c7Sespie dest->s[dest->length + 1] = '\0';
3612e0724c7Sespie /* Update the length. */
3622e0724c7Sespie ++(dest->length);
3632e0724c7Sespie return 1;
3642e0724c7Sespie }
3652e0724c7Sespie
3662e0724c7Sespie /* Sets the contents of DEST to the substring of SRC starting at START
3672e0724c7Sespie and ending before END. START must be less than or equal to END,
3682e0724c7Sespie and both must be between zero and the length of SRC, inclusive.
3692e0724c7Sespie Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
3702e0724c7Sespie deletes DEST and returns 0. */
3712e0724c7Sespie
3722e0724c7Sespie int
dyn_string_substring(dyn_string_t dest,dyn_string_t src,int start,int end)373*150b7e42Smiod dyn_string_substring (dyn_string_t dest, dyn_string_t src,
374*150b7e42Smiod int start, int end)
3752e0724c7Sespie {
3762e0724c7Sespie int i;
3772e0724c7Sespie int length = end - start;
3782e0724c7Sespie
3792e0724c7Sespie if (start > end || start > src->length || end > src->length)
3802e0724c7Sespie abort ();
3812e0724c7Sespie
3822e0724c7Sespie /* Make room for the substring. */
3832e0724c7Sespie if (dyn_string_resize (dest, length) == NULL)
3842e0724c7Sespie return 0;
3852e0724c7Sespie /* Copy the characters in the substring, */
3862e0724c7Sespie for (i = length; --i >= 0; )
3872e0724c7Sespie dest->s[i] = src->s[start + i];
3882e0724c7Sespie /* NUL-terimate the result. */
3892e0724c7Sespie dest->s[length] = '\0';
3902e0724c7Sespie /* Record the length of the substring. */
3912e0724c7Sespie dest->length = length;
3922e0724c7Sespie
3932e0724c7Sespie return 1;
3942e0724c7Sespie }
3952e0724c7Sespie
3962e0724c7Sespie /* Returns non-zero if DS1 and DS2 have the same contents. */
3972e0724c7Sespie
3982e0724c7Sespie int
dyn_string_eq(dyn_string_t ds1,dyn_string_t ds2)399*150b7e42Smiod dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
4002e0724c7Sespie {
4012e0724c7Sespie /* If DS1 and DS2 have different lengths, they must not be the same. */
4022e0724c7Sespie if (ds1->length != ds2->length)
4032e0724c7Sespie return 0;
4042e0724c7Sespie else
4052e0724c7Sespie return !strcmp (ds1->s, ds2->s);
4062e0724c7Sespie }
407