dyn-string.c revision 68765
168765Sobrien/* An abstract string datatype.
268765Sobrien   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
368765Sobrien   Contributed by Mark Mitchell (mark@markmitchell.com).
468765Sobrien
568765SobrienThis file is part of GNU CC.
668765Sobrien
768765SobrienGNU CC is free software; you can redistribute it and/or modify
868765Sobrienit under the terms of the GNU General Public License as published by
968765Sobrienthe Free Software Foundation; either version 2, or (at your option)
1068765Sobrienany later version.
1168765Sobrien
1268765SobrienGNU CC is distributed in the hope that it will be useful,
1368765Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1468765SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1568765SobrienGNU General Public License for more details.
1668765Sobrien
1768765SobrienYou should have received a copy of the GNU General Public License
1868765Sobrienalong with GNU CC; see the file COPYING.  If not, write to
1968765Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330,
2068765SobrienBoston, MA 02111-1307, USA.  */
2168765Sobrien
2268765Sobrien#ifdef HAVE_CONFIG_H
2368765Sobrien#include "config.h"
2468765Sobrien#endif
2568765Sobrien
2668765Sobrien#include <stdio.h>
2768765Sobrien
2868765Sobrien#ifdef HAVE_STRING_H
2968765Sobrien#include <string.h>
3068765Sobrien#endif
3168765Sobrien
3268765Sobrien#ifdef HAVE_STDLIB_H
3368765Sobrien#include <stdlib.h>
3468765Sobrien#endif
3568765Sobrien
3668765Sobrien#include "libiberty.h"
3768765Sobrien#include "dyn-string.h"
3868765Sobrien
3968765Sobrien/* If this file is being compiled for inclusion in the C++ runtime
4068765Sobrien   library, as part of the demangler implementation, we don't want to
4168765Sobrien   abort if an allocation fails.  Instead, percolate an error code up
4268765Sobrien   through the call chain.  */
4368765Sobrien
4468765Sobrien#ifdef IN_LIBGCC2
4568765Sobrien#define RETURN_ON_ALLOCATION_FAILURE
4668765Sobrien#endif
4768765Sobrien
4868765Sobrien/* Performs in-place initialization of a dyn_string struct.  This
4968765Sobrien   function can be used with a dyn_string struct on the stack or
5068765Sobrien   embedded in another object.  The contents of of the string itself
5168765Sobrien   are still dynamically allocated.  The string initially is capable
5268765Sobrien   of holding at least SPACE characeters, including the terminating
5368765Sobrien   NUL.  If SPACE is 0, it will silently be increated to 1.
5468765Sobrien
5568765Sobrien   If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
5668765Sobrien   fails, returns 0.  Otherwise returns 1.  */
5768765Sobrien
5868765Sobrienint
5968765Sobriendyn_string_init (ds_struct_ptr, space)
6068765Sobrien     struct dyn_string *ds_struct_ptr;
6168765Sobrien     int space;
6268765Sobrien{
6368765Sobrien  /* We need at least one byte in which to store the terminating NUL.  */
6468765Sobrien  if (space == 0)
6568765Sobrien    space = 1;
6668765Sobrien
6768765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE
6868765Sobrien  ds_struct_ptr->s = (char *) malloc (space);
6968765Sobrien  if (ds_struct_ptr->s == NULL)
7068765Sobrien    return 0;
7168765Sobrien#else
7268765Sobrien  ds_struct_ptr->s = (char *) xmalloc (space);
7368765Sobrien#endif
7468765Sobrien  ds_struct_ptr->allocated = space;
7568765Sobrien  ds_struct_ptr->length = 0;
7668765Sobrien  ds_struct_ptr->s[0] = '\0';
7768765Sobrien
7868765Sobrien  return 1;
7968765Sobrien}
8068765Sobrien
8168765Sobrien/* Create a new dynamic string capable of holding at least SPACE
8268765Sobrien   characters, including the terminating NUL.  If SPACE is 0, it will
8368765Sobrien   be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
8468765Sobrien   defined and memory allocation fails, returns NULL.  Otherwise
8568765Sobrien   returns the newly allocated string.  */
8668765Sobrien
8768765Sobriendyn_string_t
8868765Sobriendyn_string_new (space)
8968765Sobrien     int space;
9068765Sobrien{
9168765Sobrien  dyn_string_t result;
9268765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE
9368765Sobrien  result = (dyn_string_t) malloc (sizeof (struct dyn_string));
9468765Sobrien  if (result == NULL)
9568765Sobrien    return NULL;
9668765Sobrien  if (!dyn_string_init (result, space))
9768765Sobrien    {
9868765Sobrien      free (result);
9968765Sobrien      return NULL;
10068765Sobrien    }
10168765Sobrien#else
10268765Sobrien  result = (dyn_string_t) xmalloc (sizeof (struct dyn_string));
10368765Sobrien  dyn_string_init (result, space);
10468765Sobrien#endif
10568765Sobrien  return result;
10668765Sobrien}
10768765Sobrien
10868765Sobrien/* Free the memory used by DS.  */
10968765Sobrien
11068765Sobrienvoid
11168765Sobriendyn_string_delete (ds)
11268765Sobrien     dyn_string_t ds;
11368765Sobrien{
11468765Sobrien  free (ds->s);
11568765Sobrien  free (ds);
11668765Sobrien}
11768765Sobrien
11868765Sobrien/* Returns the contents of DS in a buffer allocated with malloc.  It
11968765Sobrien   is the caller's responsibility to deallocate the buffer using free.
12068765Sobrien   DS is then set to the empty string.  Deletes DS itself.  */
12168765Sobrien
12268765Sobrienchar*
12368765Sobriendyn_string_release (ds)
12468765Sobrien     dyn_string_t ds;
12568765Sobrien{
12668765Sobrien  /* Store the old buffer.  */
12768765Sobrien  char* result = ds->s;
12868765Sobrien  /* The buffer is no longer owned by DS.  */
12968765Sobrien  ds->s = NULL;
13068765Sobrien  /* Delete DS.  */
13168765Sobrien  free (ds);
13268765Sobrien  /* Return the old buffer.  */
13368765Sobrien  return result;
13468765Sobrien}
13568765Sobrien
13668765Sobrien/* Increase the capacity of DS so it can hold at least SPACE
13768765Sobrien   characters, plus the terminating NUL.  This function will not (at
13868765Sobrien   present) reduce the capacity of DS.  Returns DS on success.
13968765Sobrien
14068765Sobrien   If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
14168765Sobrien   operation fails, deletes DS and returns NULL.  */
14268765Sobrien
14368765Sobriendyn_string_t
14468765Sobriendyn_string_resize (ds, space)
14568765Sobrien     dyn_string_t ds;
14668765Sobrien     int space;
14768765Sobrien{
14868765Sobrien  int new_allocated = ds->allocated;
14968765Sobrien
15068765Sobrien  /* Increase SPACE to hold the NUL termination.  */
15168765Sobrien  ++space;
15268765Sobrien
15368765Sobrien  /* Increase allocation by factors of two.  */
15468765Sobrien  while (space > new_allocated)
15568765Sobrien    new_allocated *= 2;
15668765Sobrien
15768765Sobrien  if (new_allocated != ds->allocated)
15868765Sobrien    {
15968765Sobrien      ds->allocated = new_allocated;
16068765Sobrien      /* We actually need more space.  */
16168765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE
16268765Sobrien      ds->s = (char *) realloc (ds->s, ds->allocated);
16368765Sobrien      if (ds->s == NULL)
16468765Sobrien	{
16568765Sobrien	  free (ds);
16668765Sobrien	  return NULL;
16768765Sobrien	}
16868765Sobrien#else
16968765Sobrien      ds->s = (char *) xrealloc (ds->s, ds->allocated);
17068765Sobrien#endif
17168765Sobrien    }
17268765Sobrien
17368765Sobrien  return ds;
17468765Sobrien}
17568765Sobrien
17668765Sobrien/* Sets the contents of DS to the empty string.  */
17768765Sobrien
17868765Sobrienvoid
17968765Sobriendyn_string_clear (ds)
18068765Sobrien     dyn_string_t ds;
18168765Sobrien{
18268765Sobrien  /* A dyn_string always has room for at least the NUL terminator.  */
18368765Sobrien  ds->s[0] = '\0';
18468765Sobrien  ds->length = 0;
18568765Sobrien}
18668765Sobrien
18768765Sobrien/* Makes the contents of DEST the same as the contents of SRC.  DEST
18868765Sobrien   and SRC must be distinct.  Returns 1 on success.  On failure, if
18968765Sobrien   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
19068765Sobrien
19168765Sobrienint
19268765Sobriendyn_string_copy (dest, src)
19368765Sobrien     dyn_string_t dest;
19468765Sobrien     dyn_string_t src;
19568765Sobrien{
19668765Sobrien  if (dest == src)
19768765Sobrien    abort ();
19868765Sobrien
19968765Sobrien  /* Make room in DEST.  */
20068765Sobrien  if (dyn_string_resize (dest, src->length) == NULL)
20168765Sobrien    return 0;
20268765Sobrien  /* Copy DEST into SRC.  */
20368765Sobrien  strcpy (dest->s, src->s);
20468765Sobrien  /* Update the size of DEST.  */
20568765Sobrien  dest->length = src->length;
20668765Sobrien  return 1;
20768765Sobrien}
20868765Sobrien
20968765Sobrien/* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
21068765Sobrien   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
21168765Sobrien   and returns 0.  */
21268765Sobrien
21368765Sobrienint
21468765Sobriendyn_string_copy_cstr (dest, src)
21568765Sobrien     dyn_string_t dest;
21668765Sobrien     const char *src;
21768765Sobrien{
21868765Sobrien  int length = strlen (src);
21968765Sobrien  /* Make room in DEST.  */
22068765Sobrien  if (dyn_string_resize (dest, length) == NULL)
22168765Sobrien    return 0;
22268765Sobrien  /* Copy DEST into SRC.  */
22368765Sobrien  strcpy (dest->s, src);
22468765Sobrien  /* Update the size of DEST.  */
22568765Sobrien  dest->length = length;
22668765Sobrien  return 1;
22768765Sobrien}
22868765Sobrien
22968765Sobrien/* Inserts SRC at the beginning of DEST.  DEST is expanded as
23068765Sobrien   necessary.  SRC and DEST must be distinct.  Returns 1 on success.
23168765Sobrien   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
23268765Sobrien   returns 0.  */
23368765Sobrien
23468765Sobrienint
23568765Sobriendyn_string_prepend (dest, src)
23668765Sobrien     dyn_string_t dest;
23768765Sobrien     dyn_string_t src;
23868765Sobrien{
23968765Sobrien  return dyn_string_insert (dest, 0, src);
24068765Sobrien}
24168765Sobrien
24268765Sobrien/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
24368765Sobrien   DEST is expanded as necessary.  Returns 1 on success.  On failure,
24468765Sobrien   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
24568765Sobrien
24668765Sobrienint
24768765Sobriendyn_string_prepend_cstr (dest, src)
24868765Sobrien     dyn_string_t dest;
24968765Sobrien     const char *src;
25068765Sobrien{
25168765Sobrien  return dyn_string_insert_cstr (dest, 0, src);
25268765Sobrien}
25368765Sobrien
25468765Sobrien/* Inserts SRC into DEST starting at position POS.  DEST is expanded
25568765Sobrien   as necessary.  SRC and DEST must be distinct.  Returns 1 on
25668765Sobrien   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
25768765Sobrien   and returns 0.  */
25868765Sobrien
25968765Sobrienint
26068765Sobriendyn_string_insert (dest, pos, src)
26168765Sobrien     dyn_string_t dest;
26268765Sobrien     int pos;
26368765Sobrien     dyn_string_t src;
26468765Sobrien{
26568765Sobrien  int i;
26668765Sobrien
26768765Sobrien  if (src == dest)
26868765Sobrien    abort ();
26968765Sobrien
27068765Sobrien  if (dyn_string_resize (dest, dest->length + src->length) == NULL)
27168765Sobrien    return 0;
27268765Sobrien  /* Make room for the insertion.  Be sure to copy the NUL.  */
27368765Sobrien  for (i = dest->length; i >= pos; --i)
27468765Sobrien    dest->s[i + src->length] = dest->s[i];
27568765Sobrien  /* Splice in the new stuff.  */
27668765Sobrien  strncpy (dest->s + pos, src->s, src->length);
27768765Sobrien  /* Compute the new length.  */
27868765Sobrien  dest->length += src->length;
27968765Sobrien  return 1;
28068765Sobrien}
28168765Sobrien
28268765Sobrien/* Inserts SRC, a NUL-terminated string, into DEST starting at
28368765Sobrien   position POS.  DEST is expanded as necessary.  Returns 1 on
28468765Sobrien   success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
28568765Sobrien   and returns 0.  */
28668765Sobrien
28768765Sobrienint
28868765Sobriendyn_string_insert_cstr (dest, pos, src)
28968765Sobrien     dyn_string_t dest;
29068765Sobrien     int pos;
29168765Sobrien     const char *src;
29268765Sobrien{
29368765Sobrien  int i;
29468765Sobrien  int length = strlen (src);
29568765Sobrien
29668765Sobrien  if (dyn_string_resize (dest, dest->length + length) == NULL)
29768765Sobrien    return 0;
29868765Sobrien  /* Make room for the insertion.  Be sure to copy the NUL.  */
29968765Sobrien  for (i = dest->length; i >= pos; --i)
30068765Sobrien    dest->s[i + length] = dest->s[i];
30168765Sobrien  /* Splice in the new stuff.  */
30268765Sobrien  strncpy (dest->s + pos, src, length);
30368765Sobrien  /* Compute the new length.  */
30468765Sobrien  dest->length += length;
30568765Sobrien  return 1;
30668765Sobrien}
30768765Sobrien
30868765Sobrien/* Append S to DS, resizing DS if necessary.  Returns 1 on success.
30968765Sobrien   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
31068765Sobrien   returns 0.  */
31168765Sobrien
31268765Sobrienint
31368765Sobriendyn_string_append (dest, s)
31468765Sobrien     dyn_string_t dest;
31568765Sobrien     dyn_string_t s;
31668765Sobrien{
31768765Sobrien  if (dyn_string_resize (dest, dest->length + s->length) == 0)
31868765Sobrien    return 0;
31968765Sobrien  strcpy (dest->s + dest->length, s->s);
32068765Sobrien  dest->length += s->length;
32168765Sobrien  return 1;
32268765Sobrien}
32368765Sobrien
32468765Sobrien/* Append the NUL-terminated string S to DS, resizing DS if necessary.
32568765Sobrien   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
32668765Sobrien   deletes DEST and returns 0.  */
32768765Sobrien
32868765Sobrienint
32968765Sobriendyn_string_append_cstr (dest, s)
33068765Sobrien     dyn_string_t dest;
33168765Sobrien     const char *s;
33268765Sobrien{
33368765Sobrien  int len = strlen (s);
33468765Sobrien
33568765Sobrien  /* The new length is the old length plus the size of our string, plus
33668765Sobrien     one for the null at the end.  */
33768765Sobrien  if (dyn_string_resize (dest, dest->length + len) == NULL)
33868765Sobrien    return 0;
33968765Sobrien  strcpy (dest->s + dest->length, s);
34068765Sobrien  dest->length += len;
34168765Sobrien  return 1;
34268765Sobrien}
34368765Sobrien
34468765Sobrien/* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
34568765Sobrien   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
34668765Sobrien
34768765Sobrienint
34868765Sobriendyn_string_append_char (dest, c)
34968765Sobrien     dyn_string_t dest;
35068765Sobrien     int c;
35168765Sobrien{
35268765Sobrien  /* Make room for the extra character.  */
35368765Sobrien  if (dyn_string_resize (dest, dest->length + 1) == NULL)
35468765Sobrien    return 0;
35568765Sobrien  /* Append the character; it will overwrite the old NUL.  */
35668765Sobrien  dest->s[dest->length] = c;
35768765Sobrien  /* Add a new NUL at the end.  */
35868765Sobrien  dest->s[dest->length + 1] = '\0';
35968765Sobrien  /* Update the length.  */
36068765Sobrien  ++(dest->length);
36168765Sobrien  return 1;
36268765Sobrien}
36368765Sobrien
36468765Sobrien/* Sets the contents of DEST to the substring of SRC starting at START
36568765Sobrien   and ending before END.  START must be less than or equal to END,
36668765Sobrien   and both must be between zero and the length of SRC, inclusive.
36768765Sobrien   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
36868765Sobrien   deletes DEST and returns 0.  */
36968765Sobrien
37068765Sobrienint
37168765Sobriendyn_string_substring (dest, src, start, end)
37268765Sobrien     dyn_string_t dest;
37368765Sobrien     dyn_string_t src;
37468765Sobrien     int start;
37568765Sobrien     int end;
37668765Sobrien{
37768765Sobrien  int i;
37868765Sobrien  int length = end - start;
37968765Sobrien
38068765Sobrien  if (start > end || start > src->length || end > src->length)
38168765Sobrien    abort ();
38268765Sobrien
38368765Sobrien  /* Make room for the substring.  */
38468765Sobrien  if (dyn_string_resize (dest, length) == NULL)
38568765Sobrien    return 0;
38668765Sobrien  /* Copy the characters in the substring,  */
38768765Sobrien  for (i = length; --i >= 0; )
38868765Sobrien    dest->s[i] = src->s[start + i];
38968765Sobrien  /* NUL-terimate the result.  */
39068765Sobrien  dest->s[length] = '\0';
39168765Sobrien  /* Record the length of the substring.  */
39268765Sobrien  dest->length = length;
39368765Sobrien
39468765Sobrien  return 1;
39568765Sobrien}
39668765Sobrien
39768765Sobrien/* Returns non-zero if DS1 and DS2 have the same contents.  */
39868765Sobrien
39968765Sobrienint
40068765Sobriendyn_string_eq (ds1, ds2)
40168765Sobrien     dyn_string_t ds1;
40268765Sobrien     dyn_string_t ds2;
40368765Sobrien{
40468765Sobrien  /* If DS1 and DS2 have different lengths, they must not be the same.  */
40568765Sobrien  if (ds1->length != ds2->length)
40668765Sobrien    return 0;
40768765Sobrien  else
40868765Sobrien    return !strcmp (ds1->s, ds2->s);
40968765Sobrien}
410