168765Sobrien/* An abstract string datatype.
2218822Sdim   Copyright (C) 1998, 1999, 2000, 2002, 2004 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
12104834SobrienIn addition to the permissions in the GNU General Public License, the
13104834SobrienFree Software Foundation gives you unlimited permission to link the
14104834Sobriencompiled version of this file into combinations with other programs,
15104834Sobrienand to distribute those combinations without any restriction coming
16104834Sobrienfrom the use of this file.  (The General Public License restrictions
17104834Sobriendo apply in other respects; for example, they cover modification of
18104834Sobrienthe file, and distribution when not linked into a combined
19104834Sobrienexecutable.)
20104834Sobrien
2168765SobrienGNU CC is distributed in the hope that it will be useful,
2268765Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
2368765SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2468765SobrienGNU General Public License for more details.
2568765Sobrien
2668765SobrienYou should have received a copy of the GNU General Public License
2768765Sobrienalong with GNU CC; see the file COPYING.  If not, write to
28218822Sdimthe Free Software Foundation, 51 Franklin Street - Fifth Floor,
29218822SdimBoston, MA 02110-1301, USA.  */
3068765Sobrien
3168765Sobrien#ifdef HAVE_CONFIG_H
3268765Sobrien#include "config.h"
3368765Sobrien#endif
3468765Sobrien
3568765Sobrien#include <stdio.h>
3668765Sobrien
3768765Sobrien#ifdef HAVE_STRING_H
3868765Sobrien#include <string.h>
3968765Sobrien#endif
4068765Sobrien
4168765Sobrien#ifdef HAVE_STDLIB_H
4268765Sobrien#include <stdlib.h>
4368765Sobrien#endif
4468765Sobrien
4568765Sobrien#include "libiberty.h"
4668765Sobrien#include "dyn-string.h"
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
59218822Sdimdyn_string_init (struct dyn_string *ds_struct_ptr, int space)
6068765Sobrien{
6168765Sobrien  /* We need at least one byte in which to store the terminating NUL.  */
6268765Sobrien  if (space == 0)
6368765Sobrien    space = 1;
6468765Sobrien
6568765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE
6668765Sobrien  ds_struct_ptr->s = (char *) malloc (space);
6768765Sobrien  if (ds_struct_ptr->s == NULL)
6868765Sobrien    return 0;
6968765Sobrien#else
70218822Sdim  ds_struct_ptr->s = XNEWVEC (char, space);
7168765Sobrien#endif
7268765Sobrien  ds_struct_ptr->allocated = space;
7368765Sobrien  ds_struct_ptr->length = 0;
7468765Sobrien  ds_struct_ptr->s[0] = '\0';
7568765Sobrien
7668765Sobrien  return 1;
7768765Sobrien}
7868765Sobrien
7968765Sobrien/* Create a new dynamic string capable of holding at least SPACE
8068765Sobrien   characters, including the terminating NUL.  If SPACE is 0, it will
8168765Sobrien   be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
8268765Sobrien   defined and memory allocation fails, returns NULL.  Otherwise
8368765Sobrien   returns the newly allocated string.  */
8468765Sobrien
8568765Sobriendyn_string_t
86218822Sdimdyn_string_new (int space)
8768765Sobrien{
8868765Sobrien  dyn_string_t result;
8968765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE
9068765Sobrien  result = (dyn_string_t) malloc (sizeof (struct dyn_string));
9168765Sobrien  if (result == NULL)
9268765Sobrien    return NULL;
9368765Sobrien  if (!dyn_string_init (result, space))
9468765Sobrien    {
9568765Sobrien      free (result);
9668765Sobrien      return NULL;
9768765Sobrien    }
9868765Sobrien#else
99218822Sdim  result = XNEW (struct dyn_string);
10068765Sobrien  dyn_string_init (result, space);
10168765Sobrien#endif
10268765Sobrien  return result;
10368765Sobrien}
10468765Sobrien
10568765Sobrien/* Free the memory used by DS.  */
10668765Sobrien
10768765Sobrienvoid
108218822Sdimdyn_string_delete (dyn_string_t ds)
10968765Sobrien{
11068765Sobrien  free (ds->s);
11168765Sobrien  free (ds);
11268765Sobrien}
11368765Sobrien
11468765Sobrien/* Returns the contents of DS in a buffer allocated with malloc.  It
11568765Sobrien   is the caller's responsibility to deallocate the buffer using free.
11668765Sobrien   DS is then set to the empty string.  Deletes DS itself.  */
11768765Sobrien
11868765Sobrienchar*
119218822Sdimdyn_string_release (dyn_string_t ds)
12068765Sobrien{
12168765Sobrien  /* Store the old buffer.  */
12268765Sobrien  char* result = ds->s;
12368765Sobrien  /* The buffer is no longer owned by DS.  */
12468765Sobrien  ds->s = NULL;
12568765Sobrien  /* Delete DS.  */
12668765Sobrien  free (ds);
12768765Sobrien  /* Return the old buffer.  */
12868765Sobrien  return result;
12968765Sobrien}
13068765Sobrien
13168765Sobrien/* Increase the capacity of DS so it can hold at least SPACE
13268765Sobrien   characters, plus the terminating NUL.  This function will not (at
13368765Sobrien   present) reduce the capacity of DS.  Returns DS on success.
13468765Sobrien
13568765Sobrien   If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
13668765Sobrien   operation fails, deletes DS and returns NULL.  */
13768765Sobrien
13868765Sobriendyn_string_t
139218822Sdimdyn_string_resize (dyn_string_t ds, int space)
14068765Sobrien{
14168765Sobrien  int new_allocated = ds->allocated;
14268765Sobrien
14368765Sobrien  /* Increase SPACE to hold the NUL termination.  */
14468765Sobrien  ++space;
14568765Sobrien
14668765Sobrien  /* Increase allocation by factors of two.  */
14768765Sobrien  while (space > new_allocated)
14868765Sobrien    new_allocated *= 2;
14968765Sobrien
15068765Sobrien  if (new_allocated != ds->allocated)
15168765Sobrien    {
15268765Sobrien      ds->allocated = new_allocated;
15368765Sobrien      /* We actually need more space.  */
15468765Sobrien#ifdef RETURN_ON_ALLOCATION_FAILURE
15568765Sobrien      ds->s = (char *) realloc (ds->s, ds->allocated);
15668765Sobrien      if (ds->s == NULL)
15768765Sobrien	{
15868765Sobrien	  free (ds);
15968765Sobrien	  return NULL;
16068765Sobrien	}
16168765Sobrien#else
162218822Sdim      ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
16368765Sobrien#endif
16468765Sobrien    }
16568765Sobrien
16668765Sobrien  return ds;
16768765Sobrien}
16868765Sobrien
16968765Sobrien/* Sets the contents of DS to the empty string.  */
17068765Sobrien
17168765Sobrienvoid
172218822Sdimdyn_string_clear (dyn_string_t ds)
17368765Sobrien{
17468765Sobrien  /* A dyn_string always has room for at least the NUL terminator.  */
17568765Sobrien  ds->s[0] = '\0';
17668765Sobrien  ds->length = 0;
17768765Sobrien}
17868765Sobrien
17968765Sobrien/* Makes the contents of DEST the same as the contents of SRC.  DEST
18068765Sobrien   and SRC must be distinct.  Returns 1 on success.  On failure, if
18168765Sobrien   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
18268765Sobrien
18368765Sobrienint
184218822Sdimdyn_string_copy (dyn_string_t dest, dyn_string_t src)
18568765Sobrien{
18668765Sobrien  if (dest == src)
18768765Sobrien    abort ();
18868765Sobrien
18968765Sobrien  /* Make room in DEST.  */
19068765Sobrien  if (dyn_string_resize (dest, src->length) == NULL)
19168765Sobrien    return 0;
19268765Sobrien  /* Copy DEST into SRC.  */
19368765Sobrien  strcpy (dest->s, src->s);
19468765Sobrien  /* Update the size of DEST.  */
19568765Sobrien  dest->length = src->length;
19668765Sobrien  return 1;
19768765Sobrien}
19868765Sobrien
19968765Sobrien/* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
20068765Sobrien   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
20168765Sobrien   and returns 0.  */
20268765Sobrien
20368765Sobrienint
204218822Sdimdyn_string_copy_cstr (dyn_string_t dest, const char *src)
20568765Sobrien{
20668765Sobrien  int length = strlen (src);
20768765Sobrien  /* Make room in DEST.  */
20868765Sobrien  if (dyn_string_resize (dest, length) == NULL)
20968765Sobrien    return 0;
21068765Sobrien  /* Copy DEST into SRC.  */
21168765Sobrien  strcpy (dest->s, src);
21268765Sobrien  /* Update the size of DEST.  */
21368765Sobrien  dest->length = length;
21468765Sobrien  return 1;
21568765Sobrien}
21668765Sobrien
21768765Sobrien/* Inserts SRC at the beginning of DEST.  DEST is expanded as
21868765Sobrien   necessary.  SRC and DEST must be distinct.  Returns 1 on success.
21968765Sobrien   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
22068765Sobrien   returns 0.  */
22168765Sobrien
22268765Sobrienint
223218822Sdimdyn_string_prepend (dyn_string_t dest, dyn_string_t src)
22468765Sobrien{
22568765Sobrien  return dyn_string_insert (dest, 0, src);
22668765Sobrien}
22768765Sobrien
22868765Sobrien/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
22968765Sobrien   DEST is expanded as necessary.  Returns 1 on success.  On failure,
23068765Sobrien   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
23168765Sobrien
23268765Sobrienint
233218822Sdimdyn_string_prepend_cstr (dyn_string_t dest, const char *src)
23468765Sobrien{
23568765Sobrien  return dyn_string_insert_cstr (dest, 0, src);
23668765Sobrien}
23768765Sobrien
23868765Sobrien/* Inserts SRC into DEST starting at position POS.  DEST is expanded
23968765Sobrien   as necessary.  SRC and DEST must be distinct.  Returns 1 on
24068765Sobrien   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
24168765Sobrien   and returns 0.  */
24268765Sobrien
24368765Sobrienint
244218822Sdimdyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
24568765Sobrien{
24668765Sobrien  int i;
24768765Sobrien
24868765Sobrien  if (src == dest)
24968765Sobrien    abort ();
25068765Sobrien
25168765Sobrien  if (dyn_string_resize (dest, dest->length + src->length) == NULL)
25268765Sobrien    return 0;
25368765Sobrien  /* Make room for the insertion.  Be sure to copy the NUL.  */
25468765Sobrien  for (i = dest->length; i >= pos; --i)
25568765Sobrien    dest->s[i + src->length] = dest->s[i];
25668765Sobrien  /* Splice in the new stuff.  */
25768765Sobrien  strncpy (dest->s + pos, src->s, src->length);
25868765Sobrien  /* Compute the new length.  */
25968765Sobrien  dest->length += src->length;
26068765Sobrien  return 1;
26168765Sobrien}
26268765Sobrien
26368765Sobrien/* Inserts SRC, a NUL-terminated string, into DEST starting at
26468765Sobrien   position POS.  DEST is expanded as necessary.  Returns 1 on
26568765Sobrien   success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
26668765Sobrien   and returns 0.  */
26768765Sobrien
26868765Sobrienint
269218822Sdimdyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
27068765Sobrien{
27168765Sobrien  int i;
27268765Sobrien  int length = strlen (src);
27368765Sobrien
27468765Sobrien  if (dyn_string_resize (dest, dest->length + length) == NULL)
27568765Sobrien    return 0;
27668765Sobrien  /* Make room for the insertion.  Be sure to copy the NUL.  */
27768765Sobrien  for (i = dest->length; i >= pos; --i)
27868765Sobrien    dest->s[i + length] = dest->s[i];
27968765Sobrien  /* Splice in the new stuff.  */
28068765Sobrien  strncpy (dest->s + pos, src, length);
28168765Sobrien  /* Compute the new length.  */
28268765Sobrien  dest->length += length;
28368765Sobrien  return 1;
28468765Sobrien}
28568765Sobrien
28677298Sobrien/* Inserts character C into DEST starting at position POS.  DEST is
28777298Sobrien   expanded as necessary.  Returns 1 on success.  On failure,
28877298Sobrien   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
28977298Sobrien
29077298Sobrienint
291218822Sdimdyn_string_insert_char (dyn_string_t dest, int pos, int c)
29277298Sobrien{
29377298Sobrien  int i;
29477298Sobrien
29577298Sobrien  if (dyn_string_resize (dest, dest->length + 1) == NULL)
29677298Sobrien    return 0;
29777298Sobrien  /* Make room for the insertion.  Be sure to copy the NUL.  */
29877298Sobrien  for (i = dest->length; i >= pos; --i)
29977298Sobrien    dest->s[i + 1] = dest->s[i];
30077298Sobrien  /* Add the new character.  */
30177298Sobrien  dest->s[pos] = c;
30277298Sobrien  /* Compute the new length.  */
30377298Sobrien  ++dest->length;
30477298Sobrien  return 1;
30577298Sobrien}
30677298Sobrien
30768765Sobrien/* Append S to DS, resizing DS if necessary.  Returns 1 on success.
30868765Sobrien   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
30968765Sobrien   returns 0.  */
31068765Sobrien
31168765Sobrienint
312218822Sdimdyn_string_append (dyn_string_t dest, dyn_string_t s)
31368765Sobrien{
31468765Sobrien  if (dyn_string_resize (dest, dest->length + s->length) == 0)
31568765Sobrien    return 0;
31668765Sobrien  strcpy (dest->s + dest->length, s->s);
31768765Sobrien  dest->length += s->length;
31868765Sobrien  return 1;
31968765Sobrien}
32068765Sobrien
32168765Sobrien/* Append the NUL-terminated string S to DS, resizing DS if necessary.
32268765Sobrien   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
32368765Sobrien   deletes DEST and returns 0.  */
32468765Sobrien
32568765Sobrienint
326218822Sdimdyn_string_append_cstr (dyn_string_t dest, const char *s)
32768765Sobrien{
32868765Sobrien  int len = strlen (s);
32968765Sobrien
33068765Sobrien  /* The new length is the old length plus the size of our string, plus
33168765Sobrien     one for the null at the end.  */
33268765Sobrien  if (dyn_string_resize (dest, dest->length + len) == NULL)
33368765Sobrien    return 0;
33468765Sobrien  strcpy (dest->s + dest->length, s);
33568765Sobrien  dest->length += len;
33668765Sobrien  return 1;
33768765Sobrien}
33868765Sobrien
33968765Sobrien/* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
34068765Sobrien   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
34168765Sobrien
34268765Sobrienint
343218822Sdimdyn_string_append_char (dyn_string_t dest, int c)
34468765Sobrien{
34568765Sobrien  /* Make room for the extra character.  */
34668765Sobrien  if (dyn_string_resize (dest, dest->length + 1) == NULL)
34768765Sobrien    return 0;
34868765Sobrien  /* Append the character; it will overwrite the old NUL.  */
34968765Sobrien  dest->s[dest->length] = c;
35068765Sobrien  /* Add a new NUL at the end.  */
35168765Sobrien  dest->s[dest->length + 1] = '\0';
35268765Sobrien  /* Update the length.  */
35368765Sobrien  ++(dest->length);
35468765Sobrien  return 1;
35568765Sobrien}
35668765Sobrien
35768765Sobrien/* Sets the contents of DEST to the substring of SRC starting at START
35868765Sobrien   and ending before END.  START must be less than or equal to END,
35968765Sobrien   and both must be between zero and the length of SRC, inclusive.
36068765Sobrien   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
36168765Sobrien   deletes DEST and returns 0.  */
36268765Sobrien
36368765Sobrienint
364218822Sdimdyn_string_substring (dyn_string_t dest, dyn_string_t src,
365218822Sdim                      int start, int end)
36668765Sobrien{
36768765Sobrien  int i;
36868765Sobrien  int length = end - start;
36968765Sobrien
37068765Sobrien  if (start > end || start > src->length || end > src->length)
37168765Sobrien    abort ();
37268765Sobrien
37368765Sobrien  /* Make room for the substring.  */
37468765Sobrien  if (dyn_string_resize (dest, length) == NULL)
37568765Sobrien    return 0;
37668765Sobrien  /* Copy the characters in the substring,  */
37768765Sobrien  for (i = length; --i >= 0; )
37868765Sobrien    dest->s[i] = src->s[start + i];
37968765Sobrien  /* NUL-terimate the result.  */
38068765Sobrien  dest->s[length] = '\0';
38168765Sobrien  /* Record the length of the substring.  */
38268765Sobrien  dest->length = length;
38368765Sobrien
38468765Sobrien  return 1;
38568765Sobrien}
38668765Sobrien
38768765Sobrien/* Returns non-zero if DS1 and DS2 have the same contents.  */
38868765Sobrien
38968765Sobrienint
390218822Sdimdyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
39168765Sobrien{
39268765Sobrien  /* If DS1 and DS2 have different lengths, they must not be the same.  */
39368765Sobrien  if (ds1->length != ds2->length)
39468765Sobrien    return 0;
39568765Sobrien  else
39668765Sobrien    return !strcmp (ds1->s, ds2->s);
39768765Sobrien}
398