(root)/
gcc-13.2.0/
libiberty/
dyn-string.c
       1  /* An abstract string datatype.
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3     Contributed by Mark Mitchell (mark@markmitchell.com).
       4  
       5  This file is part of GNU CC.
       6     
       7  GNU CC is free software; you can redistribute it and/or modify
       8  it under the terms of the GNU General Public License as published by
       9  the Free Software Foundation; either version 2, or (at your option)
      10  any later version.
      11  
      12  In addition to the permissions in the GNU General Public License, the
      13  Free Software Foundation gives you unlimited permission to link the
      14  compiled version of this file into combinations with other programs,
      15  and to distribute those combinations without any restriction coming
      16  from the use of this file.  (The General Public License restrictions
      17  do apply in other respects; for example, they cover modification of
      18  the file, and distribution when not linked into a combined
      19  executable.)
      20  
      21  GNU CC is distributed in the hope that it will be useful,
      22  but WITHOUT ANY WARRANTY; without even the implied warranty of
      23  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24  GNU General Public License for more details.
      25  
      26  You should have received a copy of the GNU General Public License
      27  along with GNU CC; see the file COPYING.  If not, write to
      28  the Free Software Foundation, 51 Franklin Street - Fifth Floor,
      29  Boston, MA 02110-1301, USA.  */
      30  
      31  #ifdef HAVE_CONFIG_H
      32  #include "config.h"
      33  #endif
      34  
      35  #include <stdio.h>
      36  
      37  #ifdef HAVE_STRING_H
      38  #include <string.h>
      39  #endif
      40  
      41  #ifdef HAVE_STDLIB_H
      42  #include <stdlib.h>
      43  #endif
      44  
      45  #include "libiberty.h"
      46  #include "dyn-string.h"
      47  
      48  /* Performs in-place initialization of a dyn_string struct.  This
      49     function can be used with a dyn_string struct on the stack or
      50     embedded in another object.  The contents of of the string itself
      51     are still dynamically allocated.  The string initially is capable
      52     of holding at least SPACE characeters, including the terminating
      53     NUL.  If SPACE is 0, it will silently be increated to 1.  
      54  
      55     If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
      56     fails, returns 0.  Otherwise returns 1.  */
      57  
      58  int
      59  dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
      60  {
      61    /* We need at least one byte in which to store the terminating NUL.  */
      62    if (space == 0)
      63      space = 1;
      64  
      65  #ifdef RETURN_ON_ALLOCATION_FAILURE
      66    ds_struct_ptr->s = (char *) malloc (space);
      67    if (ds_struct_ptr->s == NULL)
      68      return 0;
      69  #else
      70    ds_struct_ptr->s = XNEWVEC (char, space);
      71  #endif
      72    ds_struct_ptr->allocated = space;
      73    ds_struct_ptr->length = 0;
      74    ds_struct_ptr->s[0] = '\0';
      75  
      76    return 1;
      77  }
      78  
      79  /* Create a new dynamic string capable of holding at least SPACE
      80     characters, including the terminating NUL.  If SPACE is 0, it will
      81     be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
      82     defined and memory allocation fails, returns NULL.  Otherwise
      83     returns the newly allocated string.  */
      84  
      85  dyn_string_t 
      86  dyn_string_new (int space)
      87  {
      88    dyn_string_t result;
      89  #ifdef RETURN_ON_ALLOCATION_FAILURE
      90    result = (dyn_string_t) malloc (sizeof (struct dyn_string));
      91    if (result == NULL)
      92      return NULL;
      93    if (!dyn_string_init (result, space))
      94      {
      95        free (result);
      96        return NULL;
      97      }
      98  #else
      99    result = XNEW (struct dyn_string);
     100    dyn_string_init (result, space);
     101  #endif
     102    return result;
     103  }
     104  
     105  /* Free the memory used by DS.  */
     106  
     107  void 
     108  dyn_string_delete (dyn_string_t ds)
     109  {
     110    free (ds->s);
     111    free (ds);
     112  }
     113  
     114  /* Returns the contents of DS in a buffer allocated with malloc.  It
     115     is the caller's responsibility to deallocate the buffer using free.
     116     DS is then set to the empty string.  Deletes DS itself.  */
     117  
     118  char*
     119  dyn_string_release (dyn_string_t ds)
     120  {
     121    /* Store the old buffer.  */
     122    char* result = ds->s;
     123    /* The buffer is no longer owned by DS.  */
     124    ds->s = NULL;
     125    /* Delete DS.  */
     126    free (ds);
     127    /* Return the old buffer.  */
     128    return result;
     129  }
     130  
     131  /* Increase the capacity of DS so it can hold at least SPACE
     132     characters, plus the terminating NUL.  This function will not (at
     133     present) reduce the capacity of DS.  Returns DS on success. 
     134  
     135     If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
     136     operation fails, deletes DS and returns NULL.  */
     137  
     138  dyn_string_t 
     139  dyn_string_resize (dyn_string_t ds, int space)
     140  {
     141    int new_allocated = ds->allocated;
     142  
     143    /* Increase SPACE to hold the NUL termination.  */
     144    ++space;
     145  
     146    /* Increase allocation by factors of two.  */
     147    while (space > new_allocated)
     148      new_allocated *= 2;
     149      
     150    if (new_allocated != ds->allocated)
     151      {
     152        ds->allocated = new_allocated;
     153        /* We actually need more space.  */
     154  #ifdef RETURN_ON_ALLOCATION_FAILURE
     155        ds->s = (char *) realloc (ds->s, ds->allocated);
     156        if (ds->s == NULL)
     157  	{
     158  	  free (ds);
     159  	  return NULL;
     160  	}
     161  #else
     162        ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
     163  #endif
     164      }
     165  
     166    return ds;
     167  }
     168  
     169  /* Sets the contents of DS to the empty string.  */
     170  
     171  void
     172  dyn_string_clear (dyn_string_t ds)
     173  {
     174    /* A dyn_string always has room for at least the NUL terminator.  */
     175    ds->s[0] = '\0';
     176    ds->length = 0;
     177  }
     178  
     179  /* Makes the contents of DEST the same as the contents of SRC.  DEST
     180     and SRC must be distinct.  Returns 1 on success.  On failure, if
     181     RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
     182  
     183  int
     184  dyn_string_copy (dyn_string_t dest, dyn_string_t src)
     185  {
     186    if (dest == src)
     187      abort ();
     188  
     189    /* Make room in DEST.  */
     190    if (dyn_string_resize (dest, src->length) == NULL)
     191      return 0;
     192    /* Copy DEST into SRC.  */
     193    strcpy (dest->s, src->s);
     194    /* Update the size of DEST.  */
     195    dest->length = src->length;
     196    return 1;
     197  }
     198  
     199  /* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
     200     success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
     201     and returns 0.  */
     202  
     203  int
     204  dyn_string_copy_cstr (dyn_string_t dest, const char *src)
     205  {
     206    int length = strlen (src);
     207    /* Make room in DEST.  */
     208    if (dyn_string_resize (dest, length) == NULL)
     209      return 0;
     210    /* Copy DEST into SRC.  */
     211    strcpy (dest->s, src);
     212    /* Update the size of DEST.  */
     213    dest->length = length;
     214    return 1;
     215  }
     216  
     217  /* Inserts SRC at the beginning of DEST.  DEST is expanded as
     218     necessary.  SRC and DEST must be distinct.  Returns 1 on success.
     219     On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
     220     returns 0.  */
     221  
     222  int
     223  dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
     224  {
     225    return dyn_string_insert (dest, 0, src);
     226  }
     227  
     228  /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
     229     DEST is expanded as necessary.  Returns 1 on success.  On failure,
     230     if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
     231  
     232  int
     233  dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
     234  {
     235    return dyn_string_insert_cstr (dest, 0, src);
     236  }
     237  
     238  /* Inserts SRC into DEST starting at position POS.  DEST is expanded
     239     as necessary.  SRC and DEST must be distinct.  Returns 1 on
     240     success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
     241     and returns 0.  */
     242  
     243  int
     244  dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
     245  {
     246    int i;
     247  
     248    if (src == dest)
     249      abort ();
     250  
     251    if (dyn_string_resize (dest, dest->length + src->length) == NULL)
     252      return 0;
     253    /* Make room for the insertion.  Be sure to copy the NUL.  */
     254    for (i = dest->length; i >= pos; --i)
     255      dest->s[i + src->length] = dest->s[i];
     256    /* Splice in the new stuff.  */
     257    strncpy (dest->s + pos, src->s, src->length);
     258    /* Compute the new length.  */
     259    dest->length += src->length;
     260    return 1;
     261  }
     262  
     263  /* Inserts SRC, a NUL-terminated string, into DEST starting at
     264     position POS.  DEST is expanded as necessary.  Returns 1 on
     265     success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
     266     and returns 0.  */
     267  
     268  int
     269  dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
     270  {
     271    int i;
     272    int length = strlen (src);
     273  
     274    if (dyn_string_resize (dest, dest->length + length) == NULL)
     275      return 0;
     276    /* Make room for the insertion.  Be sure to copy the NUL.  */
     277    for (i = dest->length; i >= pos; --i)
     278      dest->s[i + length] = dest->s[i];
     279    /* Splice in the new stuff.  */
     280    memcpy (dest->s + pos, src, length);
     281    /* Compute the new length.  */
     282    dest->length += length;
     283    return 1;
     284  }
     285  
     286  /* Inserts character C into DEST starting at position POS.  DEST is
     287     expanded as necessary.  Returns 1 on success.  On failure,
     288     RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
     289  
     290  int
     291  dyn_string_insert_char (dyn_string_t dest, int pos, int c)
     292  {
     293    int i;
     294  
     295    if (dyn_string_resize (dest, dest->length + 1) == NULL)
     296      return 0;
     297    /* Make room for the insertion.  Be sure to copy the NUL.  */
     298    for (i = dest->length; i >= pos; --i)
     299      dest->s[i + 1] = dest->s[i];
     300    /* Add the new character.  */
     301    dest->s[pos] = c;
     302    /* Compute the new length.  */
     303    ++dest->length;
     304    return 1;
     305  }
     306       
     307  /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
     308     On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
     309     returns 0.  */
     310  
     311  int
     312  dyn_string_append (dyn_string_t dest, dyn_string_t s)
     313  {
     314    if (dyn_string_resize (dest, dest->length + s->length) == 0)
     315      return 0;
     316    strcpy (dest->s + dest->length, s->s);
     317    dest->length += s->length;
     318    return 1;
     319  }
     320  
     321  /* Append the NUL-terminated string S to DS, resizing DS if necessary.
     322     Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
     323     deletes DEST and returns 0.  */
     324  
     325  int
     326  dyn_string_append_cstr (dyn_string_t dest, const char *s)
     327  {
     328    int len = strlen (s);
     329  
     330    /* The new length is the old length plus the size of our string, plus
     331       one for the null at the end.  */
     332    if (dyn_string_resize (dest, dest->length + len) == NULL)
     333      return 0;
     334    strcpy (dest->s + dest->length, s);
     335    dest->length += len;
     336    return 1;
     337  }
     338  
     339  /* Appends C to the end of DEST.  Returns 1 on success.  On failure,
     340     if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
     341  
     342  int
     343  dyn_string_append_char (dyn_string_t dest, int c)
     344  {
     345    /* Make room for the extra character.  */
     346    if (dyn_string_resize (dest, dest->length + 1) == NULL)
     347      return 0;
     348    /* Append the character; it will overwrite the old NUL.  */
     349    dest->s[dest->length] = c;
     350    /* Add a new NUL at the end.  */
     351    dest->s[dest->length + 1] = '\0';
     352    /* Update the length.  */
     353    ++(dest->length);
     354    return 1;
     355  }
     356  
     357  /* Sets the contents of DEST to the substring of SRC starting at START
     358     and ending before END.  START must be less than or equal to END,
     359     and both must be between zero and the length of SRC, inclusive.
     360     Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
     361     deletes DEST and returns 0.  */
     362  
     363  int
     364  dyn_string_substring (dyn_string_t dest, dyn_string_t src,
     365                        int start, int end)
     366  {
     367    int i;
     368    int length = end - start;
     369  
     370    if (start > end || start > src->length || end > src->length)
     371      abort ();
     372  
     373    /* Make room for the substring.  */
     374    if (dyn_string_resize (dest, length) == NULL)
     375      return 0;
     376    /* Copy the characters in the substring,  */
     377    for (i = length; --i >= 0; )
     378      dest->s[i] = src->s[start + i];
     379    /* NUL-terimate the result.  */
     380    dest->s[length] = '\0';
     381    /* Record the length of the substring.  */
     382    dest->length = length;
     383  
     384    return 1;
     385  }
     386  
     387  /* Returns non-zero if DS1 and DS2 have the same contents.  */
     388  
     389  int
     390  dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
     391  {
     392    /* If DS1 and DS2 have different lengths, they must not be the same.  */
     393    if (ds1->length != ds2->length)
     394      return 0;
     395    else
     396      return !strcmp (ds1->s, ds2->s);
     397  }