dyn-string.c revision 77298
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
30877298Sobrien/* Inserts character C into DEST starting at position POS.  DEST is
30977298Sobrien   expanded as necessary.  Returns 1 on success.  On failure,
31077298Sobrien   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
31177298Sobrien
31277298Sobrienint
31377298Sobriendyn_string_insert_char (dest, pos, c)
31477298Sobrien     dyn_string_t dest;
31577298Sobrien     int pos;
31677298Sobrien     int c;
31777298Sobrien{
31877298Sobrien  int i;
31977298Sobrien
32077298Sobrien  if (dyn_string_resize (dest, dest->length + 1) == NULL)
32177298Sobrien    return 0;
32277298Sobrien  /* Make room for the insertion.  Be sure to copy the NUL.  */
32377298Sobrien  for (i = dest->length; i >= pos; --i)
32477298Sobrien    dest->s[i + 1] = dest->s[i];
32577298Sobrien  /* Add the new character.  */
32677298Sobrien  dest->s[pos] = c;
32777298Sobrien  /* Compute the new length.  */
32877298Sobrien  ++dest->length;
32977298Sobrien  return 1;
33077298Sobrien}
33177298Sobrien
33268765Sobrien/* Append S to DS, resizing DS if necessary.  Returns 1 on success.
33368765Sobrien   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
33468765Sobrien   returns 0.  */
33568765Sobrien
33668765Sobrienint
33768765Sobriendyn_string_append (dest, s)
33868765Sobrien     dyn_string_t dest;
33968765Sobrien     dyn_string_t s;
34068765Sobrien{
34168765Sobrien  if (dyn_string_resize (dest, dest->length + s->length) == 0)
34268765Sobrien    return 0;
34368765Sobrien  strcpy (dest->s + dest->length, s->s);
34468765Sobrien  dest->length += s->length;
34568765Sobrien  return 1;
34668765Sobrien}
34768765Sobrien
34868765Sobrien/* Append the NUL-terminated string S to DS, resizing DS if necessary.
34968765Sobrien   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
35068765Sobrien   deletes DEST and returns 0.  */
35168765Sobrien
35268765Sobrienint
35368765Sobriendyn_string_append_cstr (dest, s)
35468765Sobrien     dyn_string_t dest;
35568765Sobrien     const char *s;
35668765Sobrien{
35768765Sobrien  int len = strlen (s);
35868765Sobrien
35968765Sobrien  /* The new length is the old length plus the size of our string, plus
36068765Sobrien     one for the null at the end.  */
36168765Sobrien  if (dyn_string_resize (dest, dest->length + len) == NULL)
36268765Sobrien    return 0;
36368765Sobrien  strcpy (dest->s + dest->length, s);
36468765Sobrien  dest->length += len;
36568765Sobrien  return 1;
36668765Sobrien}
36768765Sobrien
36868765Sobrien/* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
36968765Sobrien   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
37068765Sobrien
37168765Sobrienint
37268765Sobriendyn_string_append_char (dest, c)
37368765Sobrien     dyn_string_t dest;
37468765Sobrien     int c;
37568765Sobrien{
37668765Sobrien  /* Make room for the extra character.  */
37768765Sobrien  if (dyn_string_resize (dest, dest->length + 1) == NULL)
37868765Sobrien    return 0;
37968765Sobrien  /* Append the character; it will overwrite the old NUL.  */
38068765Sobrien  dest->s[dest->length] = c;
38168765Sobrien  /* Add a new NUL at the end.  */
38268765Sobrien  dest->s[dest->length + 1] = '\0';
38368765Sobrien  /* Update the length.  */
38468765Sobrien  ++(dest->length);
38568765Sobrien  return 1;
38668765Sobrien}
38768765Sobrien
38868765Sobrien/* Sets the contents of DEST to the substring of SRC starting at START
38968765Sobrien   and ending before END.  START must be less than or equal to END,
39068765Sobrien   and both must be between zero and the length of SRC, inclusive.
39168765Sobrien   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
39268765Sobrien   deletes DEST and returns 0.  */
39368765Sobrien
39468765Sobrienint
39568765Sobriendyn_string_substring (dest, src, start, end)
39668765Sobrien     dyn_string_t dest;
39768765Sobrien     dyn_string_t src;
39868765Sobrien     int start;
39968765Sobrien     int end;
40068765Sobrien{
40168765Sobrien  int i;
40268765Sobrien  int length = end - start;
40368765Sobrien
40468765Sobrien  if (start > end || start > src->length || end > src->length)
40568765Sobrien    abort ();
40668765Sobrien
40768765Sobrien  /* Make room for the substring.  */
40868765Sobrien  if (dyn_string_resize (dest, length) == NULL)
40968765Sobrien    return 0;
41068765Sobrien  /* Copy the characters in the substring,  */
41168765Sobrien  for (i = length; --i >= 0; )
41268765Sobrien    dest->s[i] = src->s[start + i];
41368765Sobrien  /* NUL-terimate the result.  */
41468765Sobrien  dest->s[length] = '\0';
41568765Sobrien  /* Record the length of the substring.  */
41668765Sobrien  dest->length = length;
41768765Sobrien
41868765Sobrien  return 1;
41968765Sobrien}
42068765Sobrien
42168765Sobrien/* Returns non-zero if DS1 and DS2 have the same contents.  */
42268765Sobrien
42368765Sobrienint
42468765Sobriendyn_string_eq (ds1, ds2)
42568765Sobrien     dyn_string_t ds1;
42668765Sobrien     dyn_string_t ds2;
42768765Sobrien{
42868765Sobrien  /* If DS1 and DS2 have different lengths, they must not be the same.  */
42968765Sobrien  if (ds1->length != ds2->length)
43068765Sobrien    return 0;
43168765Sobrien  else
43268765Sobrien    return !strcmp (ds1->s, ds2->s);
43368765Sobrien}
434