xref: /netbsd-src/external/gpl3/binutils.old/dist/libiberty/dyn-string.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
116dce513Schristos /* An abstract string datatype.
2*e992f068Schristos    Copyright (C) 1998-2022 Free Software Foundation, Inc.
316dce513Schristos    Contributed by Mark Mitchell (mark@markmitchell.com).
416dce513Schristos 
516dce513Schristos This file is part of GNU CC.
616dce513Schristos 
716dce513Schristos GNU CC is free software; you can redistribute it and/or modify
816dce513Schristos it under the terms of the GNU General Public License as published by
916dce513Schristos the Free Software Foundation; either version 2, or (at your option)
1016dce513Schristos any later version.
1116dce513Schristos 
1216dce513Schristos In addition to the permissions in the GNU General Public License, the
1316dce513Schristos Free Software Foundation gives you unlimited permission to link the
1416dce513Schristos compiled version of this file into combinations with other programs,
1516dce513Schristos and to distribute those combinations without any restriction coming
1616dce513Schristos from the use of this file.  (The General Public License restrictions
1716dce513Schristos do apply in other respects; for example, they cover modification of
1816dce513Schristos the file, and distribution when not linked into a combined
1916dce513Schristos executable.)
2016dce513Schristos 
2116dce513Schristos GNU CC is distributed in the hope that it will be useful,
2216dce513Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
2316dce513Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2416dce513Schristos GNU General Public License for more details.
2516dce513Schristos 
2616dce513Schristos You should have received a copy of the GNU General Public License
2716dce513Schristos along with GNU CC; see the file COPYING.  If not, write to
2816dce513Schristos the Free Software Foundation, 51 Franklin Street - Fifth Floor,
2916dce513Schristos Boston, MA 02110-1301, USA.  */
3016dce513Schristos 
3116dce513Schristos #ifdef HAVE_CONFIG_H
3216dce513Schristos #include "config.h"
3316dce513Schristos #endif
3416dce513Schristos 
3516dce513Schristos #include <stdio.h>
3616dce513Schristos 
3716dce513Schristos #ifdef HAVE_STRING_H
3816dce513Schristos #include <string.h>
3916dce513Schristos #endif
4016dce513Schristos 
4116dce513Schristos #ifdef HAVE_STDLIB_H
4216dce513Schristos #include <stdlib.h>
4316dce513Schristos #endif
4416dce513Schristos 
4516dce513Schristos #include "libiberty.h"
4616dce513Schristos #include "dyn-string.h"
4716dce513Schristos 
4816dce513Schristos /* Performs in-place initialization of a dyn_string struct.  This
4916dce513Schristos    function can be used with a dyn_string struct on the stack or
5016dce513Schristos    embedded in another object.  The contents of of the string itself
5116dce513Schristos    are still dynamically allocated.  The string initially is capable
5216dce513Schristos    of holding at least SPACE characeters, including the terminating
5316dce513Schristos    NUL.  If SPACE is 0, it will silently be increated to 1.
5416dce513Schristos 
5516dce513Schristos    If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
5616dce513Schristos    fails, returns 0.  Otherwise returns 1.  */
5716dce513Schristos 
5816dce513Schristos int
dyn_string_init(struct dyn_string * ds_struct_ptr,int space)5916dce513Schristos dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
6016dce513Schristos {
6116dce513Schristos   /* We need at least one byte in which to store the terminating NUL.  */
6216dce513Schristos   if (space == 0)
6316dce513Schristos     space = 1;
6416dce513Schristos 
6516dce513Schristos #ifdef RETURN_ON_ALLOCATION_FAILURE
6616dce513Schristos   ds_struct_ptr->s = (char *) malloc (space);
6716dce513Schristos   if (ds_struct_ptr->s == NULL)
6816dce513Schristos     return 0;
6916dce513Schristos #else
7016dce513Schristos   ds_struct_ptr->s = XNEWVEC (char, space);
7116dce513Schristos #endif
7216dce513Schristos   ds_struct_ptr->allocated = space;
7316dce513Schristos   ds_struct_ptr->length = 0;
7416dce513Schristos   ds_struct_ptr->s[0] = '\0';
7516dce513Schristos 
7616dce513Schristos   return 1;
7716dce513Schristos }
7816dce513Schristos 
7916dce513Schristos /* Create a new dynamic string capable of holding at least SPACE
8016dce513Schristos    characters, including the terminating NUL.  If SPACE is 0, it will
8116dce513Schristos    be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
8216dce513Schristos    defined and memory allocation fails, returns NULL.  Otherwise
8316dce513Schristos    returns the newly allocated string.  */
8416dce513Schristos 
8516dce513Schristos dyn_string_t
dyn_string_new(int space)8616dce513Schristos dyn_string_new (int space)
8716dce513Schristos {
8816dce513Schristos   dyn_string_t result;
8916dce513Schristos #ifdef RETURN_ON_ALLOCATION_FAILURE
9016dce513Schristos   result = (dyn_string_t) malloc (sizeof (struct dyn_string));
9116dce513Schristos   if (result == NULL)
9216dce513Schristos     return NULL;
9316dce513Schristos   if (!dyn_string_init (result, space))
9416dce513Schristos     {
9516dce513Schristos       free (result);
9616dce513Schristos       return NULL;
9716dce513Schristos     }
9816dce513Schristos #else
9916dce513Schristos   result = XNEW (struct dyn_string);
10016dce513Schristos   dyn_string_init (result, space);
10116dce513Schristos #endif
10216dce513Schristos   return result;
10316dce513Schristos }
10416dce513Schristos 
10516dce513Schristos /* Free the memory used by DS.  */
10616dce513Schristos 
10716dce513Schristos void
dyn_string_delete(dyn_string_t ds)10816dce513Schristos dyn_string_delete (dyn_string_t ds)
10916dce513Schristos {
11016dce513Schristos   free (ds->s);
11116dce513Schristos   free (ds);
11216dce513Schristos }
11316dce513Schristos 
11416dce513Schristos /* Returns the contents of DS in a buffer allocated with malloc.  It
11516dce513Schristos    is the caller's responsibility to deallocate the buffer using free.
11616dce513Schristos    DS is then set to the empty string.  Deletes DS itself.  */
11716dce513Schristos 
11816dce513Schristos char*
dyn_string_release(dyn_string_t ds)11916dce513Schristos dyn_string_release (dyn_string_t ds)
12016dce513Schristos {
12116dce513Schristos   /* Store the old buffer.  */
12216dce513Schristos   char* result = ds->s;
12316dce513Schristos   /* The buffer is no longer owned by DS.  */
12416dce513Schristos   ds->s = NULL;
12516dce513Schristos   /* Delete DS.  */
12616dce513Schristos   free (ds);
12716dce513Schristos   /* Return the old buffer.  */
12816dce513Schristos   return result;
12916dce513Schristos }
13016dce513Schristos 
13116dce513Schristos /* Increase the capacity of DS so it can hold at least SPACE
13216dce513Schristos    characters, plus the terminating NUL.  This function will not (at
13316dce513Schristos    present) reduce the capacity of DS.  Returns DS on success.
13416dce513Schristos 
13516dce513Schristos    If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
13616dce513Schristos    operation fails, deletes DS and returns NULL.  */
13716dce513Schristos 
13816dce513Schristos dyn_string_t
dyn_string_resize(dyn_string_t ds,int space)13916dce513Schristos dyn_string_resize (dyn_string_t ds, int space)
14016dce513Schristos {
14116dce513Schristos   int new_allocated = ds->allocated;
14216dce513Schristos 
14316dce513Schristos   /* Increase SPACE to hold the NUL termination.  */
14416dce513Schristos   ++space;
14516dce513Schristos 
14616dce513Schristos   /* Increase allocation by factors of two.  */
14716dce513Schristos   while (space > new_allocated)
14816dce513Schristos     new_allocated *= 2;
14916dce513Schristos 
15016dce513Schristos   if (new_allocated != ds->allocated)
15116dce513Schristos     {
15216dce513Schristos       ds->allocated = new_allocated;
15316dce513Schristos       /* We actually need more space.  */
15416dce513Schristos #ifdef RETURN_ON_ALLOCATION_FAILURE
15516dce513Schristos       ds->s = (char *) realloc (ds->s, ds->allocated);
15616dce513Schristos       if (ds->s == NULL)
15716dce513Schristos 	{
15816dce513Schristos 	  free (ds);
15916dce513Schristos 	  return NULL;
16016dce513Schristos 	}
16116dce513Schristos #else
16216dce513Schristos       ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
16316dce513Schristos #endif
16416dce513Schristos     }
16516dce513Schristos 
16616dce513Schristos   return ds;
16716dce513Schristos }
16816dce513Schristos 
16916dce513Schristos /* Sets the contents of DS to the empty string.  */
17016dce513Schristos 
17116dce513Schristos void
dyn_string_clear(dyn_string_t ds)17216dce513Schristos dyn_string_clear (dyn_string_t ds)
17316dce513Schristos {
17416dce513Schristos   /* A dyn_string always has room for at least the NUL terminator.  */
17516dce513Schristos   ds->s[0] = '\0';
17616dce513Schristos   ds->length = 0;
17716dce513Schristos }
17816dce513Schristos 
17916dce513Schristos /* Makes the contents of DEST the same as the contents of SRC.  DEST
18016dce513Schristos    and SRC must be distinct.  Returns 1 on success.  On failure, if
18116dce513Schristos    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
18216dce513Schristos 
18316dce513Schristos int
dyn_string_copy(dyn_string_t dest,dyn_string_t src)18416dce513Schristos dyn_string_copy (dyn_string_t dest, dyn_string_t src)
18516dce513Schristos {
18616dce513Schristos   if (dest == src)
18716dce513Schristos     abort ();
18816dce513Schristos 
18916dce513Schristos   /* Make room in DEST.  */
19016dce513Schristos   if (dyn_string_resize (dest, src->length) == NULL)
19116dce513Schristos     return 0;
19216dce513Schristos   /* Copy DEST into SRC.  */
19316dce513Schristos   strcpy (dest->s, src->s);
19416dce513Schristos   /* Update the size of DEST.  */
19516dce513Schristos   dest->length = src->length;
19616dce513Schristos   return 1;
19716dce513Schristos }
19816dce513Schristos 
19916dce513Schristos /* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
20016dce513Schristos    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
20116dce513Schristos    and returns 0.  */
20216dce513Schristos 
20316dce513Schristos int
dyn_string_copy_cstr(dyn_string_t dest,const char * src)20416dce513Schristos dyn_string_copy_cstr (dyn_string_t dest, const char *src)
20516dce513Schristos {
20616dce513Schristos   int length = strlen (src);
20716dce513Schristos   /* Make room in DEST.  */
20816dce513Schristos   if (dyn_string_resize (dest, length) == NULL)
20916dce513Schristos     return 0;
21016dce513Schristos   /* Copy DEST into SRC.  */
21116dce513Schristos   strcpy (dest->s, src);
21216dce513Schristos   /* Update the size of DEST.  */
21316dce513Schristos   dest->length = length;
21416dce513Schristos   return 1;
21516dce513Schristos }
21616dce513Schristos 
21716dce513Schristos /* Inserts SRC at the beginning of DEST.  DEST is expanded as
21816dce513Schristos    necessary.  SRC and DEST must be distinct.  Returns 1 on success.
21916dce513Schristos    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
22016dce513Schristos    returns 0.  */
22116dce513Schristos 
22216dce513Schristos int
dyn_string_prepend(dyn_string_t dest,dyn_string_t src)22316dce513Schristos dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
22416dce513Schristos {
22516dce513Schristos   return dyn_string_insert (dest, 0, src);
22616dce513Schristos }
22716dce513Schristos 
22816dce513Schristos /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
22916dce513Schristos    DEST is expanded as necessary.  Returns 1 on success.  On failure,
23016dce513Schristos    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
23116dce513Schristos 
23216dce513Schristos int
dyn_string_prepend_cstr(dyn_string_t dest,const char * src)23316dce513Schristos dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
23416dce513Schristos {
23516dce513Schristos   return dyn_string_insert_cstr (dest, 0, src);
23616dce513Schristos }
23716dce513Schristos 
23816dce513Schristos /* Inserts SRC into DEST starting at position POS.  DEST is expanded
23916dce513Schristos    as necessary.  SRC and DEST must be distinct.  Returns 1 on
24016dce513Schristos    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
24116dce513Schristos    and returns 0.  */
24216dce513Schristos 
24316dce513Schristos int
dyn_string_insert(dyn_string_t dest,int pos,dyn_string_t src)24416dce513Schristos dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
24516dce513Schristos {
24616dce513Schristos   int i;
24716dce513Schristos 
24816dce513Schristos   if (src == dest)
24916dce513Schristos     abort ();
25016dce513Schristos 
25116dce513Schristos   if (dyn_string_resize (dest, dest->length + src->length) == NULL)
25216dce513Schristos     return 0;
25316dce513Schristos   /* Make room for the insertion.  Be sure to copy the NUL.  */
25416dce513Schristos   for (i = dest->length; i >= pos; --i)
25516dce513Schristos     dest->s[i + src->length] = dest->s[i];
25616dce513Schristos   /* Splice in the new stuff.  */
25716dce513Schristos   strncpy (dest->s + pos, src->s, src->length);
25816dce513Schristos   /* Compute the new length.  */
25916dce513Schristos   dest->length += src->length;
26016dce513Schristos   return 1;
26116dce513Schristos }
26216dce513Schristos 
26316dce513Schristos /* Inserts SRC, a NUL-terminated string, into DEST starting at
26416dce513Schristos    position POS.  DEST is expanded as necessary.  Returns 1 on
26516dce513Schristos    success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
26616dce513Schristos    and returns 0.  */
26716dce513Schristos 
26816dce513Schristos int
dyn_string_insert_cstr(dyn_string_t dest,int pos,const char * src)26916dce513Schristos dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
27016dce513Schristos {
27116dce513Schristos   int i;
27216dce513Schristos   int length = strlen (src);
27316dce513Schristos 
27416dce513Schristos   if (dyn_string_resize (dest, dest->length + length) == NULL)
27516dce513Schristos     return 0;
27616dce513Schristos   /* Make room for the insertion.  Be sure to copy the NUL.  */
27716dce513Schristos   for (i = dest->length; i >= pos; --i)
27816dce513Schristos     dest->s[i + length] = dest->s[i];
27916dce513Schristos   /* Splice in the new stuff.  */
280*e992f068Schristos   memcpy (dest->s + pos, src, length);
28116dce513Schristos   /* Compute the new length.  */
28216dce513Schristos   dest->length += length;
28316dce513Schristos   return 1;
28416dce513Schristos }
28516dce513Schristos 
28616dce513Schristos /* Inserts character C into DEST starting at position POS.  DEST is
28716dce513Schristos    expanded as necessary.  Returns 1 on success.  On failure,
28816dce513Schristos    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
28916dce513Schristos 
29016dce513Schristos int
dyn_string_insert_char(dyn_string_t dest,int pos,int c)29116dce513Schristos dyn_string_insert_char (dyn_string_t dest, int pos, int c)
29216dce513Schristos {
29316dce513Schristos   int i;
29416dce513Schristos 
29516dce513Schristos   if (dyn_string_resize (dest, dest->length + 1) == NULL)
29616dce513Schristos     return 0;
29716dce513Schristos   /* Make room for the insertion.  Be sure to copy the NUL.  */
29816dce513Schristos   for (i = dest->length; i >= pos; --i)
29916dce513Schristos     dest->s[i + 1] = dest->s[i];
30016dce513Schristos   /* Add the new character.  */
30116dce513Schristos   dest->s[pos] = c;
30216dce513Schristos   /* Compute the new length.  */
30316dce513Schristos   ++dest->length;
30416dce513Schristos   return 1;
30516dce513Schristos }
30616dce513Schristos 
30716dce513Schristos /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
30816dce513Schristos    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
30916dce513Schristos    returns 0.  */
31016dce513Schristos 
31116dce513Schristos int
dyn_string_append(dyn_string_t dest,dyn_string_t s)31216dce513Schristos dyn_string_append (dyn_string_t dest, dyn_string_t s)
31316dce513Schristos {
31416dce513Schristos   if (dyn_string_resize (dest, dest->length + s->length) == 0)
31516dce513Schristos     return 0;
31616dce513Schristos   strcpy (dest->s + dest->length, s->s);
31716dce513Schristos   dest->length += s->length;
31816dce513Schristos   return 1;
31916dce513Schristos }
32016dce513Schristos 
32116dce513Schristos /* Append the NUL-terminated string S to DS, resizing DS if necessary.
32216dce513Schristos    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
32316dce513Schristos    deletes DEST and returns 0.  */
32416dce513Schristos 
32516dce513Schristos int
dyn_string_append_cstr(dyn_string_t dest,const char * s)32616dce513Schristos dyn_string_append_cstr (dyn_string_t dest, const char *s)
32716dce513Schristos {
32816dce513Schristos   int len = strlen (s);
32916dce513Schristos 
33016dce513Schristos   /* The new length is the old length plus the size of our string, plus
33116dce513Schristos      one for the null at the end.  */
33216dce513Schristos   if (dyn_string_resize (dest, dest->length + len) == NULL)
33316dce513Schristos     return 0;
33416dce513Schristos   strcpy (dest->s + dest->length, s);
33516dce513Schristos   dest->length += len;
33616dce513Schristos   return 1;
33716dce513Schristos }
33816dce513Schristos 
33916dce513Schristos /* Appends C to the end of DEST.  Returns 1 on success.  On failure,
34016dce513Schristos    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
34116dce513Schristos 
34216dce513Schristos int
dyn_string_append_char(dyn_string_t dest,int c)34316dce513Schristos dyn_string_append_char (dyn_string_t dest, int c)
34416dce513Schristos {
34516dce513Schristos   /* Make room for the extra character.  */
34616dce513Schristos   if (dyn_string_resize (dest, dest->length + 1) == NULL)
34716dce513Schristos     return 0;
34816dce513Schristos   /* Append the character; it will overwrite the old NUL.  */
34916dce513Schristos   dest->s[dest->length] = c;
35016dce513Schristos   /* Add a new NUL at the end.  */
35116dce513Schristos   dest->s[dest->length + 1] = '\0';
35216dce513Schristos   /* Update the length.  */
35316dce513Schristos   ++(dest->length);
35416dce513Schristos   return 1;
35516dce513Schristos }
35616dce513Schristos 
35716dce513Schristos /* Sets the contents of DEST to the substring of SRC starting at START
35816dce513Schristos    and ending before END.  START must be less than or equal to END,
35916dce513Schristos    and both must be between zero and the length of SRC, inclusive.
36016dce513Schristos    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
36116dce513Schristos    deletes DEST and returns 0.  */
36216dce513Schristos 
36316dce513Schristos int
dyn_string_substring(dyn_string_t dest,dyn_string_t src,int start,int end)36416dce513Schristos dyn_string_substring (dyn_string_t dest, dyn_string_t src,
36516dce513Schristos                       int start, int end)
36616dce513Schristos {
36716dce513Schristos   int i;
36816dce513Schristos   int length = end - start;
36916dce513Schristos 
37016dce513Schristos   if (start > end || start > src->length || end > src->length)
37116dce513Schristos     abort ();
37216dce513Schristos 
37316dce513Schristos   /* Make room for the substring.  */
37416dce513Schristos   if (dyn_string_resize (dest, length) == NULL)
37516dce513Schristos     return 0;
37616dce513Schristos   /* Copy the characters in the substring,  */
37716dce513Schristos   for (i = length; --i >= 0; )
37816dce513Schristos     dest->s[i] = src->s[start + i];
37916dce513Schristos   /* NUL-terimate the result.  */
38016dce513Schristos   dest->s[length] = '\0';
38116dce513Schristos   /* Record the length of the substring.  */
38216dce513Schristos   dest->length = length;
38316dce513Schristos 
38416dce513Schristos   return 1;
38516dce513Schristos }
38616dce513Schristos 
38716dce513Schristos /* Returns non-zero if DS1 and DS2 have the same contents.  */
38816dce513Schristos 
38916dce513Schristos int
dyn_string_eq(dyn_string_t ds1,dyn_string_t ds2)39016dce513Schristos dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
39116dce513Schristos {
39216dce513Schristos   /* If DS1 and DS2 have different lengths, they must not be the same.  */
39316dce513Schristos   if (ds1->length != ds2->length)
39416dce513Schristos     return 0;
39516dce513Schristos   else
39616dce513Schristos     return !strcmp (ds1->s, ds2->s);
39716dce513Schristos }
398