1169695Skan/* An abstract string datatype.
2169695Skan   Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
3169695Skan   Contributed by Mark Mitchell (mark@markmitchell.com).
4169695Skan
5169695SkanThis file is part of GNU CC.
6169695Skan
7169695SkanGNU CC is free software; you can redistribute it and/or modify
8169695Skanit under the terms of the GNU General Public License as published by
9169695Skanthe Free Software Foundation; either version 2, or (at your option)
10169695Skanany later version.
11169695Skan
12169695SkanIn addition to the permissions in the GNU General Public License, the
13169695SkanFree Software Foundation gives you unlimited permission to link the
14169695Skancompiled version of this file into combinations with other programs,
15169695Skanand to distribute those combinations without any restriction coming
16169695Skanfrom the use of this file.  (The General Public License restrictions
17169695Skando apply in other respects; for example, they cover modification of
18169695Skanthe file, and distribution when not linked into a combined
19169695Skanexecutable.)
20169695Skan
21169695SkanGNU CC is distributed in the hope that it will be useful,
22169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
23169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24169695SkanGNU General Public License for more details.
25169695Skan
26169695SkanYou should have received a copy of the GNU General Public License
27169695Skanalong with GNU CC; see the file COPYING.  If not, write to
28169695Skanthe Free Software Foundation, 51 Franklin Street - Fifth Floor,
29169695SkanBoston, MA 02110-1301, USA.  */
30169695Skan
31169695Skan#ifdef HAVE_CONFIG_H
32169695Skan#include "config.h"
33169695Skan#endif
34169695Skan
35169695Skan#include <stdio.h>
36169695Skan
37169695Skan#ifdef HAVE_STRING_H
38169695Skan#include <string.h>
39169695Skan#endif
40169695Skan
41169695Skan#ifdef HAVE_STDLIB_H
42169695Skan#include <stdlib.h>
43169695Skan#endif
44169695Skan
45169695Skan#include "libiberty.h"
46169695Skan#include "dyn-string.h"
47169695Skan
48169695Skan/* Performs in-place initialization of a dyn_string struct.  This
49169695Skan   function can be used with a dyn_string struct on the stack or
50169695Skan   embedded in another object.  The contents of of the string itself
51169695Skan   are still dynamically allocated.  The string initially is capable
52169695Skan   of holding at least SPACE characeters, including the terminating
53169695Skan   NUL.  If SPACE is 0, it will silently be increated to 1.
54169695Skan
55169695Skan   If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
56169695Skan   fails, returns 0.  Otherwise returns 1.  */
57169695Skan
58169695Skanint
59169695Skandyn_string_init (struct dyn_string *ds_struct_ptr, int space)
60169695Skan{
61169695Skan  /* We need at least one byte in which to store the terminating NUL.  */
62169695Skan  if (space == 0)
63169695Skan    space = 1;
64169695Skan
65169695Skan#ifdef RETURN_ON_ALLOCATION_FAILURE
66169695Skan  ds_struct_ptr->s = (char *) malloc (space);
67169695Skan  if (ds_struct_ptr->s == NULL)
68169695Skan    return 0;
69169695Skan#else
70169695Skan  ds_struct_ptr->s = XNEWVEC (char, space);
71169695Skan#endif
72169695Skan  ds_struct_ptr->allocated = space;
73169695Skan  ds_struct_ptr->length = 0;
74169695Skan  ds_struct_ptr->s[0] = '\0';
75169695Skan
76169695Skan  return 1;
77169695Skan}
78169695Skan
79169695Skan/* Create a new dynamic string capable of holding at least SPACE
80169695Skan   characters, including the terminating NUL.  If SPACE is 0, it will
81169695Skan   be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
82169695Skan   defined and memory allocation fails, returns NULL.  Otherwise
83169695Skan   returns the newly allocated string.  */
84169695Skan
85169695Skandyn_string_t
86169695Skandyn_string_new (int space)
87169695Skan{
88169695Skan  dyn_string_t result;
89169695Skan#ifdef RETURN_ON_ALLOCATION_FAILURE
90169695Skan  result = (dyn_string_t) malloc (sizeof (struct dyn_string));
91169695Skan  if (result == NULL)
92169695Skan    return NULL;
93169695Skan  if (!dyn_string_init (result, space))
94169695Skan    {
95169695Skan      free (result);
96169695Skan      return NULL;
97169695Skan    }
98169695Skan#else
99169695Skan  result = XNEW (struct dyn_string);
100169695Skan  dyn_string_init (result, space);
101169695Skan#endif
102169695Skan  return result;
103169695Skan}
104169695Skan
105169695Skan/* Free the memory used by DS.  */
106169695Skan
107169695Skanvoid
108169695Skandyn_string_delete (dyn_string_t ds)
109169695Skan{
110169695Skan  free (ds->s);
111169695Skan  free (ds);
112169695Skan}
113169695Skan
114169695Skan/* Returns the contents of DS in a buffer allocated with malloc.  It
115169695Skan   is the caller's responsibility to deallocate the buffer using free.
116169695Skan   DS is then set to the empty string.  Deletes DS itself.  */
117169695Skan
118169695Skanchar*
119169695Skandyn_string_release (dyn_string_t ds)
120169695Skan{
121169695Skan  /* Store the old buffer.  */
122169695Skan  char* result = ds->s;
123169695Skan  /* The buffer is no longer owned by DS.  */
124169695Skan  ds->s = NULL;
125169695Skan  /* Delete DS.  */
126169695Skan  free (ds);
127169695Skan  /* Return the old buffer.  */
128169695Skan  return result;
129169695Skan}
130169695Skan
131169695Skan/* Increase the capacity of DS so it can hold at least SPACE
132169695Skan   characters, plus the terminating NUL.  This function will not (at
133169695Skan   present) reduce the capacity of DS.  Returns DS on success.
134169695Skan
135169695Skan   If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
136169695Skan   operation fails, deletes DS and returns NULL.  */
137169695Skan
138169695Skandyn_string_t
139169695Skandyn_string_resize (dyn_string_t ds, int space)
140169695Skan{
141169695Skan  int new_allocated = ds->allocated;
142169695Skan
143169695Skan  /* Increase SPACE to hold the NUL termination.  */
144169695Skan  ++space;
145169695Skan
146169695Skan  /* Increase allocation by factors of two.  */
147169695Skan  while (space > new_allocated)
148169695Skan    new_allocated *= 2;
149169695Skan
150169695Skan  if (new_allocated != ds->allocated)
151169695Skan    {
152169695Skan      ds->allocated = new_allocated;
153169695Skan      /* We actually need more space.  */
154169695Skan#ifdef RETURN_ON_ALLOCATION_FAILURE
155169695Skan      ds->s = (char *) realloc (ds->s, ds->allocated);
156169695Skan      if (ds->s == NULL)
157169695Skan	{
158169695Skan	  free (ds);
159169695Skan	  return NULL;
160169695Skan	}
161169695Skan#else
162169695Skan      ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
163169695Skan#endif
164169695Skan    }
165169695Skan
166169695Skan  return ds;
167169695Skan}
168169695Skan
169169695Skan/* Sets the contents of DS to the empty string.  */
170169695Skan
171169695Skanvoid
172169695Skandyn_string_clear (dyn_string_t ds)
173169695Skan{
174169695Skan  /* A dyn_string always has room for at least the NUL terminator.  */
175169695Skan  ds->s[0] = '\0';
176169695Skan  ds->length = 0;
177169695Skan}
178169695Skan
179169695Skan/* Makes the contents of DEST the same as the contents of SRC.  DEST
180169695Skan   and SRC must be distinct.  Returns 1 on success.  On failure, if
181169695Skan   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
182169695Skan
183169695Skanint
184169695Skandyn_string_copy (dyn_string_t dest, dyn_string_t src)
185169695Skan{
186169695Skan  if (dest == src)
187169695Skan    abort ();
188169695Skan
189169695Skan  /* Make room in DEST.  */
190169695Skan  if (dyn_string_resize (dest, src->length) == NULL)
191169695Skan    return 0;
192169695Skan  /* Copy DEST into SRC.  */
193169695Skan  strcpy (dest->s, src->s);
194169695Skan  /* Update the size of DEST.  */
195169695Skan  dest->length = src->length;
196169695Skan  return 1;
197169695Skan}
198169695Skan
199169695Skan/* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
200169695Skan   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
201169695Skan   and returns 0.  */
202169695Skan
203169695Skanint
204169695Skandyn_string_copy_cstr (dyn_string_t dest, const char *src)
205169695Skan{
206169695Skan  int length = strlen (src);
207169695Skan  /* Make room in DEST.  */
208169695Skan  if (dyn_string_resize (dest, length) == NULL)
209169695Skan    return 0;
210169695Skan  /* Copy DEST into SRC.  */
211169695Skan  strcpy (dest->s, src);
212169695Skan  /* Update the size of DEST.  */
213169695Skan  dest->length = length;
214169695Skan  return 1;
215169695Skan}
216169695Skan
217169695Skan/* Inserts SRC at the beginning of DEST.  DEST is expanded as
218169695Skan   necessary.  SRC and DEST must be distinct.  Returns 1 on success.
219169695Skan   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
220169695Skan   returns 0.  */
221169695Skan
222169695Skanint
223169695Skandyn_string_prepend (dyn_string_t dest, dyn_string_t src)
224169695Skan{
225169695Skan  return dyn_string_insert (dest, 0, src);
226169695Skan}
227169695Skan
228169695Skan/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
229169695Skan   DEST is expanded as necessary.  Returns 1 on success.  On failure,
230169695Skan   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
231169695Skan
232169695Skanint
233169695Skandyn_string_prepend_cstr (dyn_string_t dest, const char *src)
234169695Skan{
235169695Skan  return dyn_string_insert_cstr (dest, 0, src);
236169695Skan}
237169695Skan
238169695Skan/* Inserts SRC into DEST starting at position POS.  DEST is expanded
239169695Skan   as necessary.  SRC and DEST must be distinct.  Returns 1 on
240169695Skan   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
241169695Skan   and returns 0.  */
242169695Skan
243169695Skanint
244169695Skandyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
245169695Skan{
246169695Skan  int i;
247169695Skan
248169695Skan  if (src == dest)
249169695Skan    abort ();
250169695Skan
251169695Skan  if (dyn_string_resize (dest, dest->length + src->length) == NULL)
252169695Skan    return 0;
253169695Skan  /* Make room for the insertion.  Be sure to copy the NUL.  */
254169695Skan  for (i = dest->length; i >= pos; --i)
255169695Skan    dest->s[i + src->length] = dest->s[i];
256169695Skan  /* Splice in the new stuff.  */
257169695Skan  strncpy (dest->s + pos, src->s, src->length);
258169695Skan  /* Compute the new length.  */
259169695Skan  dest->length += src->length;
260169695Skan  return 1;
261169695Skan}
262169695Skan
263169695Skan/* Inserts SRC, a NUL-terminated string, into DEST starting at
264169695Skan   position POS.  DEST is expanded as necessary.  Returns 1 on
265169695Skan   success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
266169695Skan   and returns 0.  */
267169695Skan
268169695Skanint
269169695Skandyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
270169695Skan{
271169695Skan  int i;
272169695Skan  int length = strlen (src);
273169695Skan
274169695Skan  if (dyn_string_resize (dest, dest->length + length) == NULL)
275169695Skan    return 0;
276169695Skan  /* Make room for the insertion.  Be sure to copy the NUL.  */
277169695Skan  for (i = dest->length; i >= pos; --i)
278169695Skan    dest->s[i + length] = dest->s[i];
279169695Skan  /* Splice in the new stuff.  */
280169695Skan  strncpy (dest->s + pos, src, length);
281169695Skan  /* Compute the new length.  */
282169695Skan  dest->length += length;
283169695Skan  return 1;
284169695Skan}
285169695Skan
286169695Skan/* Inserts character C into DEST starting at position POS.  DEST is
287169695Skan   expanded as necessary.  Returns 1 on success.  On failure,
288169695Skan   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
289169695Skan
290169695Skanint
291169695Skandyn_string_insert_char (dyn_string_t dest, int pos, int c)
292169695Skan{
293169695Skan  int i;
294169695Skan
295169695Skan  if (dyn_string_resize (dest, dest->length + 1) == NULL)
296169695Skan    return 0;
297169695Skan  /* Make room for the insertion.  Be sure to copy the NUL.  */
298169695Skan  for (i = dest->length; i >= pos; --i)
299169695Skan    dest->s[i + 1] = dest->s[i];
300169695Skan  /* Add the new character.  */
301169695Skan  dest->s[pos] = c;
302169695Skan  /* Compute the new length.  */
303169695Skan  ++dest->length;
304169695Skan  return 1;
305169695Skan}
306169695Skan
307169695Skan/* Append S to DS, resizing DS if necessary.  Returns 1 on success.
308169695Skan   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
309169695Skan   returns 0.  */
310169695Skan
311169695Skanint
312169695Skandyn_string_append (dyn_string_t dest, dyn_string_t s)
313169695Skan{
314169695Skan  if (dyn_string_resize (dest, dest->length + s->length) == 0)
315169695Skan    return 0;
316169695Skan  strcpy (dest->s + dest->length, s->s);
317169695Skan  dest->length += s->length;
318169695Skan  return 1;
319169695Skan}
320169695Skan
321169695Skan/* Append the NUL-terminated string S to DS, resizing DS if necessary.
322169695Skan   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
323169695Skan   deletes DEST and returns 0.  */
324169695Skan
325169695Skanint
326169695Skandyn_string_append_cstr (dyn_string_t dest, const char *s)
327169695Skan{
328169695Skan  int len = strlen (s);
329169695Skan
330169695Skan  /* The new length is the old length plus the size of our string, plus
331169695Skan     one for the null at the end.  */
332169695Skan  if (dyn_string_resize (dest, dest->length + len) == NULL)
333169695Skan    return 0;
334169695Skan  strcpy (dest->s + dest->length, s);
335169695Skan  dest->length += len;
336169695Skan  return 1;
337169695Skan}
338169695Skan
339169695Skan/* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
340169695Skan   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
341169695Skan
342169695Skanint
343169695Skandyn_string_append_char (dyn_string_t dest, int c)
344169695Skan{
345169695Skan  /* Make room for the extra character.  */
346169695Skan  if (dyn_string_resize (dest, dest->length + 1) == NULL)
347169695Skan    return 0;
348169695Skan  /* Append the character; it will overwrite the old NUL.  */
349169695Skan  dest->s[dest->length] = c;
350169695Skan  /* Add a new NUL at the end.  */
351169695Skan  dest->s[dest->length + 1] = '\0';
352169695Skan  /* Update the length.  */
353169695Skan  ++(dest->length);
354169695Skan  return 1;
355169695Skan}
356169695Skan
357169695Skan/* Sets the contents of DEST to the substring of SRC starting at START
358169695Skan   and ending before END.  START must be less than or equal to END,
359169695Skan   and both must be between zero and the length of SRC, inclusive.
360169695Skan   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
361169695Skan   deletes DEST and returns 0.  */
362169695Skan
363169695Skanint
364169695Skandyn_string_substring (dyn_string_t dest, dyn_string_t src,
365169695Skan                      int start, int end)
366169695Skan{
367169695Skan  int i;
368169695Skan  int length = end - start;
369169695Skan
370169695Skan  if (start > end || start > src->length || end > src->length)
371169695Skan    abort ();
372169695Skan
373169695Skan  /* Make room for the substring.  */
374169695Skan  if (dyn_string_resize (dest, length) == NULL)
375169695Skan    return 0;
376169695Skan  /* Copy the characters in the substring,  */
377169695Skan  for (i = length; --i >= 0; )
378169695Skan    dest->s[i] = src->s[start + i];
379169695Skan  /* NUL-terimate the result.  */
380169695Skan  dest->s[length] = '\0';
381169695Skan  /* Record the length of the substring.  */
382169695Skan  dest->length = length;
383169695Skan
384169695Skan  return 1;
385169695Skan}
386169695Skan
387169695Skan/* Returns non-zero if DS1 and DS2 have the same contents.  */
388169695Skan
389169695Skanint
390169695Skandyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
391169695Skan{
392169695Skan  /* If DS1 and DS2 have different lengths, they must not be the same.  */
393169695Skan  if (ds1->length != ds2->length)
394169695Skan    return 0;
395169695Skan  else
396169695Skan    return !strcmp (ds1->s, ds2->s);
397169695Skan}
398