xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/dyn-string.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
198b9484cSchristos /* An abstract string datatype.
2*5173eb0aSchristos    Copyright (C) 1998-2024 Free Software Foundation, Inc.
398b9484cSchristos    Contributed by Mark Mitchell (mark@markmitchell.com).
498b9484cSchristos 
598b9484cSchristos This file is part of GNU CC.
698b9484cSchristos 
798b9484cSchristos GNU CC is free software; you can redistribute it and/or modify
898b9484cSchristos it under the terms of the GNU General Public License as published by
998b9484cSchristos the Free Software Foundation; either version 2, or (at your option)
1098b9484cSchristos any later version.
1198b9484cSchristos 
1298b9484cSchristos In addition to the permissions in the GNU General Public License, the
1398b9484cSchristos Free Software Foundation gives you unlimited permission to link the
1498b9484cSchristos compiled version of this file into combinations with other programs,
1598b9484cSchristos and to distribute those combinations without any restriction coming
1698b9484cSchristos from the use of this file.  (The General Public License restrictions
1798b9484cSchristos do apply in other respects; for example, they cover modification of
1898b9484cSchristos the file, and distribution when not linked into a combined
1998b9484cSchristos executable.)
2098b9484cSchristos 
2198b9484cSchristos GNU CC is distributed in the hope that it will be useful,
2298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
2398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2498b9484cSchristos GNU General Public License for more details.
2598b9484cSchristos 
2698b9484cSchristos You should have received a copy of the GNU General Public License
2798b9484cSchristos along with GNU CC; see the file COPYING.  If not, write to
2898b9484cSchristos the Free Software Foundation, 51 Franklin Street - Fifth Floor,
2998b9484cSchristos Boston, MA 02110-1301, USA.  */
3098b9484cSchristos 
3198b9484cSchristos #ifdef HAVE_CONFIG_H
3298b9484cSchristos #include "config.h"
3398b9484cSchristos #endif
3498b9484cSchristos 
3598b9484cSchristos #include <stdio.h>
3698b9484cSchristos 
3798b9484cSchristos #ifdef HAVE_STRING_H
3898b9484cSchristos #include <string.h>
3998b9484cSchristos #endif
4098b9484cSchristos 
4198b9484cSchristos #ifdef HAVE_STDLIB_H
4298b9484cSchristos #include <stdlib.h>
4398b9484cSchristos #endif
4498b9484cSchristos 
4598b9484cSchristos #include "libiberty.h"
4698b9484cSchristos #include "dyn-string.h"
4798b9484cSchristos 
4898b9484cSchristos /* Performs in-place initialization of a dyn_string struct.  This
4998b9484cSchristos    function can be used with a dyn_string struct on the stack or
5098b9484cSchristos    embedded in another object.  The contents of of the string itself
5198b9484cSchristos    are still dynamically allocated.  The string initially is capable
5298b9484cSchristos    of holding at least SPACE characeters, including the terminating
5398b9484cSchristos    NUL.  If SPACE is 0, it will silently be increated to 1.
5498b9484cSchristos 
5598b9484cSchristos    If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
5698b9484cSchristos    fails, returns 0.  Otherwise returns 1.  */
5798b9484cSchristos 
5898b9484cSchristos int
5998b9484cSchristos dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
6098b9484cSchristos {
6198b9484cSchristos   /* We need at least one byte in which to store the terminating NUL.  */
6298b9484cSchristos   if (space == 0)
6398b9484cSchristos     space = 1;
6498b9484cSchristos 
6598b9484cSchristos #ifdef RETURN_ON_ALLOCATION_FAILURE
6698b9484cSchristos   ds_struct_ptr->s = (char *) malloc (space);
6798b9484cSchristos   if (ds_struct_ptr->s == NULL)
6898b9484cSchristos     return 0;
6998b9484cSchristos #else
7098b9484cSchristos   ds_struct_ptr->s = XNEWVEC (char, space);
7198b9484cSchristos #endif
7298b9484cSchristos   ds_struct_ptr->allocated = space;
7398b9484cSchristos   ds_struct_ptr->length = 0;
7498b9484cSchristos   ds_struct_ptr->s[0] = '\0';
7598b9484cSchristos 
7698b9484cSchristos   return 1;
7798b9484cSchristos }
7898b9484cSchristos 
7998b9484cSchristos /* Create a new dynamic string capable of holding at least SPACE
8098b9484cSchristos    characters, including the terminating NUL.  If SPACE is 0, it will
8198b9484cSchristos    be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
8298b9484cSchristos    defined and memory allocation fails, returns NULL.  Otherwise
8398b9484cSchristos    returns the newly allocated string.  */
8498b9484cSchristos 
8598b9484cSchristos dyn_string_t
8698b9484cSchristos dyn_string_new (int space)
8798b9484cSchristos {
8898b9484cSchristos   dyn_string_t result;
8998b9484cSchristos #ifdef RETURN_ON_ALLOCATION_FAILURE
9098b9484cSchristos   result = (dyn_string_t) malloc (sizeof (struct dyn_string));
9198b9484cSchristos   if (result == NULL)
9298b9484cSchristos     return NULL;
9398b9484cSchristos   if (!dyn_string_init (result, space))
9498b9484cSchristos     {
9598b9484cSchristos       free (result);
9698b9484cSchristos       return NULL;
9798b9484cSchristos     }
9898b9484cSchristos #else
9998b9484cSchristos   result = XNEW (struct dyn_string);
10098b9484cSchristos   dyn_string_init (result, space);
10198b9484cSchristos #endif
10298b9484cSchristos   return result;
10398b9484cSchristos }
10498b9484cSchristos 
10598b9484cSchristos /* Free the memory used by DS.  */
10698b9484cSchristos 
10798b9484cSchristos void
10898b9484cSchristos dyn_string_delete (dyn_string_t ds)
10998b9484cSchristos {
11098b9484cSchristos   free (ds->s);
11198b9484cSchristos   free (ds);
11298b9484cSchristos }
11398b9484cSchristos 
11498b9484cSchristos /* Returns the contents of DS in a buffer allocated with malloc.  It
11598b9484cSchristos    is the caller's responsibility to deallocate the buffer using free.
11698b9484cSchristos    DS is then set to the empty string.  Deletes DS itself.  */
11798b9484cSchristos 
11898b9484cSchristos char*
11998b9484cSchristos dyn_string_release (dyn_string_t ds)
12098b9484cSchristos {
12198b9484cSchristos   /* Store the old buffer.  */
12298b9484cSchristos   char* result = ds->s;
12398b9484cSchristos   /* The buffer is no longer owned by DS.  */
12498b9484cSchristos   ds->s = NULL;
12598b9484cSchristos   /* Delete DS.  */
12698b9484cSchristos   free (ds);
12798b9484cSchristos   /* Return the old buffer.  */
12898b9484cSchristos   return result;
12998b9484cSchristos }
13098b9484cSchristos 
13198b9484cSchristos /* Increase the capacity of DS so it can hold at least SPACE
13298b9484cSchristos    characters, plus the terminating NUL.  This function will not (at
13398b9484cSchristos    present) reduce the capacity of DS.  Returns DS on success.
13498b9484cSchristos 
13598b9484cSchristos    If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
13698b9484cSchristos    operation fails, deletes DS and returns NULL.  */
13798b9484cSchristos 
13898b9484cSchristos dyn_string_t
13998b9484cSchristos dyn_string_resize (dyn_string_t ds, int space)
14098b9484cSchristos {
14198b9484cSchristos   int new_allocated = ds->allocated;
14298b9484cSchristos 
14398b9484cSchristos   /* Increase SPACE to hold the NUL termination.  */
14498b9484cSchristos   ++space;
14598b9484cSchristos 
14698b9484cSchristos   /* Increase allocation by factors of two.  */
14798b9484cSchristos   while (space > new_allocated)
14898b9484cSchristos     new_allocated *= 2;
14998b9484cSchristos 
15098b9484cSchristos   if (new_allocated != ds->allocated)
15198b9484cSchristos     {
15298b9484cSchristos       ds->allocated = new_allocated;
15398b9484cSchristos       /* We actually need more space.  */
15498b9484cSchristos #ifdef RETURN_ON_ALLOCATION_FAILURE
15598b9484cSchristos       ds->s = (char *) realloc (ds->s, ds->allocated);
15698b9484cSchristos       if (ds->s == NULL)
15798b9484cSchristos 	{
15898b9484cSchristos 	  free (ds);
15998b9484cSchristos 	  return NULL;
16098b9484cSchristos 	}
16198b9484cSchristos #else
16298b9484cSchristos       ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
16398b9484cSchristos #endif
16498b9484cSchristos     }
16598b9484cSchristos 
16698b9484cSchristos   return ds;
16798b9484cSchristos }
16898b9484cSchristos 
16998b9484cSchristos /* Sets the contents of DS to the empty string.  */
17098b9484cSchristos 
17198b9484cSchristos void
17298b9484cSchristos dyn_string_clear (dyn_string_t ds)
17398b9484cSchristos {
17498b9484cSchristos   /* A dyn_string always has room for at least the NUL terminator.  */
17598b9484cSchristos   ds->s[0] = '\0';
17698b9484cSchristos   ds->length = 0;
17798b9484cSchristos }
17898b9484cSchristos 
17998b9484cSchristos /* Makes the contents of DEST the same as the contents of SRC.  DEST
18098b9484cSchristos    and SRC must be distinct.  Returns 1 on success.  On failure, if
18198b9484cSchristos    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
18298b9484cSchristos 
18398b9484cSchristos int
18498b9484cSchristos dyn_string_copy (dyn_string_t dest, dyn_string_t src)
18598b9484cSchristos {
18698b9484cSchristos   if (dest == src)
18798b9484cSchristos     abort ();
18898b9484cSchristos 
18998b9484cSchristos   /* Make room in DEST.  */
19098b9484cSchristos   if (dyn_string_resize (dest, src->length) == NULL)
19198b9484cSchristos     return 0;
19298b9484cSchristos   /* Copy DEST into SRC.  */
19398b9484cSchristos   strcpy (dest->s, src->s);
19498b9484cSchristos   /* Update the size of DEST.  */
19598b9484cSchristos   dest->length = src->length;
19698b9484cSchristos   return 1;
19798b9484cSchristos }
19898b9484cSchristos 
19998b9484cSchristos /* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
20098b9484cSchristos    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
20198b9484cSchristos    and returns 0.  */
20298b9484cSchristos 
20398b9484cSchristos int
20498b9484cSchristos dyn_string_copy_cstr (dyn_string_t dest, const char *src)
20598b9484cSchristos {
20698b9484cSchristos   int length = strlen (src);
20798b9484cSchristos   /* Make room in DEST.  */
20898b9484cSchristos   if (dyn_string_resize (dest, length) == NULL)
20998b9484cSchristos     return 0;
21098b9484cSchristos   /* Copy DEST into SRC.  */
21198b9484cSchristos   strcpy (dest->s, src);
21298b9484cSchristos   /* Update the size of DEST.  */
21398b9484cSchristos   dest->length = length;
21498b9484cSchristos   return 1;
21598b9484cSchristos }
21698b9484cSchristos 
21798b9484cSchristos /* Inserts SRC at the beginning of DEST.  DEST is expanded as
21898b9484cSchristos    necessary.  SRC and DEST must be distinct.  Returns 1 on success.
21998b9484cSchristos    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
22098b9484cSchristos    returns 0.  */
22198b9484cSchristos 
22298b9484cSchristos int
22398b9484cSchristos dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
22498b9484cSchristos {
22598b9484cSchristos   return dyn_string_insert (dest, 0, src);
22698b9484cSchristos }
22798b9484cSchristos 
22898b9484cSchristos /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
22998b9484cSchristos    DEST is expanded as necessary.  Returns 1 on success.  On failure,
23098b9484cSchristos    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
23198b9484cSchristos 
23298b9484cSchristos int
23398b9484cSchristos dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
23498b9484cSchristos {
23598b9484cSchristos   return dyn_string_insert_cstr (dest, 0, src);
23698b9484cSchristos }
23798b9484cSchristos 
23898b9484cSchristos /* Inserts SRC into DEST starting at position POS.  DEST is expanded
23998b9484cSchristos    as necessary.  SRC and DEST must be distinct.  Returns 1 on
24098b9484cSchristos    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
24198b9484cSchristos    and returns 0.  */
24298b9484cSchristos 
24398b9484cSchristos int
24498b9484cSchristos dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
24598b9484cSchristos {
24698b9484cSchristos   int i;
24798b9484cSchristos 
24898b9484cSchristos   if (src == dest)
24998b9484cSchristos     abort ();
25098b9484cSchristos 
25198b9484cSchristos   if (dyn_string_resize (dest, dest->length + src->length) == NULL)
25298b9484cSchristos     return 0;
25398b9484cSchristos   /* Make room for the insertion.  Be sure to copy the NUL.  */
25498b9484cSchristos   for (i = dest->length; i >= pos; --i)
25598b9484cSchristos     dest->s[i + src->length] = dest->s[i];
25698b9484cSchristos   /* Splice in the new stuff.  */
25798b9484cSchristos   strncpy (dest->s + pos, src->s, src->length);
25898b9484cSchristos   /* Compute the new length.  */
25998b9484cSchristos   dest->length += src->length;
26098b9484cSchristos   return 1;
26198b9484cSchristos }
26298b9484cSchristos 
26398b9484cSchristos /* Inserts SRC, a NUL-terminated string, into DEST starting at
26498b9484cSchristos    position POS.  DEST is expanded as necessary.  Returns 1 on
26598b9484cSchristos    success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
26698b9484cSchristos    and returns 0.  */
26798b9484cSchristos 
26898b9484cSchristos int
26998b9484cSchristos dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
27098b9484cSchristos {
27198b9484cSchristos   int i;
27298b9484cSchristos   int length = strlen (src);
27398b9484cSchristos 
27498b9484cSchristos   if (dyn_string_resize (dest, dest->length + length) == NULL)
27598b9484cSchristos     return 0;
27698b9484cSchristos   /* Make room for the insertion.  Be sure to copy the NUL.  */
27798b9484cSchristos   for (i = dest->length; i >= pos; --i)
27898b9484cSchristos     dest->s[i + length] = dest->s[i];
27998b9484cSchristos   /* Splice in the new stuff.  */
2804b169a6bSchristos   memcpy (dest->s + pos, src, length);
28198b9484cSchristos   /* Compute the new length.  */
28298b9484cSchristos   dest->length += length;
28398b9484cSchristos   return 1;
28498b9484cSchristos }
28598b9484cSchristos 
28698b9484cSchristos /* Inserts character C into DEST starting at position POS.  DEST is
28798b9484cSchristos    expanded as necessary.  Returns 1 on success.  On failure,
28898b9484cSchristos    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
28998b9484cSchristos 
29098b9484cSchristos int
29198b9484cSchristos dyn_string_insert_char (dyn_string_t dest, int pos, int c)
29298b9484cSchristos {
29398b9484cSchristos   int i;
29498b9484cSchristos 
29598b9484cSchristos   if (dyn_string_resize (dest, dest->length + 1) == NULL)
29698b9484cSchristos     return 0;
29798b9484cSchristos   /* Make room for the insertion.  Be sure to copy the NUL.  */
29898b9484cSchristos   for (i = dest->length; i >= pos; --i)
29998b9484cSchristos     dest->s[i + 1] = dest->s[i];
30098b9484cSchristos   /* Add the new character.  */
30198b9484cSchristos   dest->s[pos] = c;
30298b9484cSchristos   /* Compute the new length.  */
30398b9484cSchristos   ++dest->length;
30498b9484cSchristos   return 1;
30598b9484cSchristos }
30698b9484cSchristos 
30798b9484cSchristos /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
30898b9484cSchristos    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
30998b9484cSchristos    returns 0.  */
31098b9484cSchristos 
31198b9484cSchristos int
31298b9484cSchristos dyn_string_append (dyn_string_t dest, dyn_string_t s)
31398b9484cSchristos {
31498b9484cSchristos   if (dyn_string_resize (dest, dest->length + s->length) == 0)
31598b9484cSchristos     return 0;
31698b9484cSchristos   strcpy (dest->s + dest->length, s->s);
31798b9484cSchristos   dest->length += s->length;
31898b9484cSchristos   return 1;
31998b9484cSchristos }
32098b9484cSchristos 
32198b9484cSchristos /* Append the NUL-terminated string S to DS, resizing DS if necessary.
32298b9484cSchristos    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
32398b9484cSchristos    deletes DEST and returns 0.  */
32498b9484cSchristos 
32598b9484cSchristos int
32698b9484cSchristos dyn_string_append_cstr (dyn_string_t dest, const char *s)
32798b9484cSchristos {
32898b9484cSchristos   int len = strlen (s);
32998b9484cSchristos 
33098b9484cSchristos   /* The new length is the old length plus the size of our string, plus
33198b9484cSchristos      one for the null at the end.  */
33298b9484cSchristos   if (dyn_string_resize (dest, dest->length + len) == NULL)
33398b9484cSchristos     return 0;
33498b9484cSchristos   strcpy (dest->s + dest->length, s);
33598b9484cSchristos   dest->length += len;
33698b9484cSchristos   return 1;
33798b9484cSchristos }
33898b9484cSchristos 
33998b9484cSchristos /* Appends C to the end of DEST.  Returns 1 on success.  On failure,
34098b9484cSchristos    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
34198b9484cSchristos 
34298b9484cSchristos int
34398b9484cSchristos dyn_string_append_char (dyn_string_t dest, int c)
34498b9484cSchristos {
34598b9484cSchristos   /* Make room for the extra character.  */
34698b9484cSchristos   if (dyn_string_resize (dest, dest->length + 1) == NULL)
34798b9484cSchristos     return 0;
34898b9484cSchristos   /* Append the character; it will overwrite the old NUL.  */
34998b9484cSchristos   dest->s[dest->length] = c;
35098b9484cSchristos   /* Add a new NUL at the end.  */
35198b9484cSchristos   dest->s[dest->length + 1] = '\0';
35298b9484cSchristos   /* Update the length.  */
35398b9484cSchristos   ++(dest->length);
35498b9484cSchristos   return 1;
35598b9484cSchristos }
35698b9484cSchristos 
35798b9484cSchristos /* Sets the contents of DEST to the substring of SRC starting at START
35898b9484cSchristos    and ending before END.  START must be less than or equal to END,
35998b9484cSchristos    and both must be between zero and the length of SRC, inclusive.
36098b9484cSchristos    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
36198b9484cSchristos    deletes DEST and returns 0.  */
36298b9484cSchristos 
36398b9484cSchristos int
36498b9484cSchristos dyn_string_substring (dyn_string_t dest, dyn_string_t src,
36598b9484cSchristos                       int start, int end)
36698b9484cSchristos {
36798b9484cSchristos   int i;
36898b9484cSchristos   int length = end - start;
36998b9484cSchristos 
37098b9484cSchristos   if (start > end || start > src->length || end > src->length)
37198b9484cSchristos     abort ();
37298b9484cSchristos 
37398b9484cSchristos   /* Make room for the substring.  */
37498b9484cSchristos   if (dyn_string_resize (dest, length) == NULL)
37598b9484cSchristos     return 0;
37698b9484cSchristos   /* Copy the characters in the substring,  */
37798b9484cSchristos   for (i = length; --i >= 0; )
37898b9484cSchristos     dest->s[i] = src->s[start + i];
37998b9484cSchristos   /* NUL-terimate the result.  */
38098b9484cSchristos   dest->s[length] = '\0';
38198b9484cSchristos   /* Record the length of the substring.  */
38298b9484cSchristos   dest->length = length;
38398b9484cSchristos 
38498b9484cSchristos   return 1;
38598b9484cSchristos }
38698b9484cSchristos 
38798b9484cSchristos /* Returns non-zero if DS1 and DS2 have the same contents.  */
38898b9484cSchristos 
38998b9484cSchristos int
39098b9484cSchristos dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
39198b9484cSchristos {
39298b9484cSchristos   /* If DS1 and DS2 have different lengths, they must not be the same.  */
39398b9484cSchristos   if (ds1->length != ds2->length)
39498b9484cSchristos     return 0;
39598b9484cSchristos   else
39698b9484cSchristos     return !strcmp (ds1->s, ds2->s);
39798b9484cSchristos }
398