dyn-string.c revision 169695
1239310Sdim/* An abstract string datatype.
2239310Sdim   Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
3239310Sdim   Contributed by Mark Mitchell (mark@markmitchell.com).
4239310Sdim
5239310SdimThis file is part of GNU CC.
6239310Sdim
7239310SdimGNU CC is free software; you can redistribute it and/or modify
8239310Sdimit under the terms of the GNU General Public License as published by
9239310Sdimthe Free Software Foundation; either version 2, or (at your option)
10239310Sdimany later version.
11239310Sdim
12239310SdimIn addition to the permissions in the GNU General Public License, the
13239310SdimFree Software Foundation gives you unlimited permission to link the
14239310Sdimcompiled version of this file into combinations with other programs,
15239310Sdimand to distribute those combinations without any restriction coming
16239310Sdimfrom the use of this file.  (The General Public License restrictions
17239310Sdimdo apply in other respects; for example, they cover modification of
18239310Sdimthe file, and distribution when not linked into a combined
19239310Sdimexecutable.)
20239310Sdim
21239310SdimGNU CC is distributed in the hope that it will be useful,
22239310Sdimbut WITHOUT ANY WARRANTY; without even the implied warranty of
23239310SdimMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24239310SdimGNU General Public License for more details.
25239310Sdim
26239310SdimYou should have received a copy of the GNU General Public License
27239310Sdimalong with GNU CC; see the file COPYING.  If not, write to
28239310Sdimthe Free Software Foundation, 51 Franklin Street - Fifth Floor,
29239310SdimBoston, MA 02110-1301, USA.  */
30239310Sdim
31239310Sdim#ifdef HAVE_CONFIG_H
32249423Sdim#include "config.h"
33239310Sdim#endif
34249423Sdim
35249423Sdim#include <stdio.h>
36249423Sdim
37239310Sdim#ifdef HAVE_STRING_H
38239310Sdim#include <string.h>
39243830Sdim#endif
40239310Sdim
41239310Sdim#ifdef HAVE_STDLIB_H
42239310Sdim#include <stdlib.h>
43239310Sdim#endif
44239310Sdim
45239310Sdim#include "libiberty.h"
46239310Sdim#include "dyn-string.h"
47239310Sdim
48239310Sdim/* Performs in-place initialization of a dyn_string struct.  This
49239310Sdim   function can be used with a dyn_string struct on the stack or
50239310Sdim   embedded in another object.  The contents of of the string itself
51239310Sdim   are still dynamically allocated.  The string initially is capable
52239310Sdim   of holding at least SPACE characeters, including the terminating
53239310Sdim   NUL.  If SPACE is 0, it will silently be increated to 1.
54239310Sdim
55239310Sdim   If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
56239310Sdim   fails, returns 0.  Otherwise returns 1.  */
57239310Sdim
58239310Sdimint
59239310Sdimdyn_string_init (struct dyn_string *ds_struct_ptr, int space)
60239310Sdim{
61239310Sdim  /* We need at least one byte in which to store the terminating NUL.  */
62239310Sdim  if (space == 0)
63239310Sdim    space = 1;
64239310Sdim
65239310Sdim#ifdef RETURN_ON_ALLOCATION_FAILURE
66239310Sdim  ds_struct_ptr->s = (char *) malloc (space);
67239310Sdim  if (ds_struct_ptr->s == NULL)
68239310Sdim    return 0;
69239310Sdim#else
70239310Sdim  ds_struct_ptr->s = XNEWVEC (char, space);
71239310Sdim#endif
72239310Sdim  ds_struct_ptr->allocated = space;
73239310Sdim  ds_struct_ptr->length = 0;
74239310Sdim  ds_struct_ptr->s[0] = '\0';
75239310Sdim
76239310Sdim  return 1;
77239310Sdim}
78239310Sdim
79239310Sdim/* Create a new dynamic string capable of holding at least SPACE
80239310Sdim   characters, including the terminating NUL.  If SPACE is 0, it will
81239310Sdim   be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
82239310Sdim   defined and memory allocation fails, returns NULL.  Otherwise
83239310Sdim   returns the newly allocated string.  */
84239310Sdim
85239310Sdimdyn_string_t
86239310Sdimdyn_string_new (int space)
87239310Sdim{
88239310Sdim  dyn_string_t result;
89239310Sdim#ifdef RETURN_ON_ALLOCATION_FAILURE
90239310Sdim  result = (dyn_string_t) malloc (sizeof (struct dyn_string));
91239310Sdim  if (result == NULL)
92239310Sdim    return NULL;
93239310Sdim  if (!dyn_string_init (result, space))
94239310Sdim    {
95239310Sdim      free (result);
96239310Sdim      return NULL;
97239310Sdim    }
98239310Sdim#else
99239310Sdim  result = XNEW (struct dyn_string);
100239310Sdim  dyn_string_init (result, space);
101239310Sdim#endif
102239310Sdim  return result;
103239310Sdim}
104239310Sdim
105239310Sdim/* Free the memory used by DS.  */
106239310Sdim
107239310Sdimvoid
108239310Sdimdyn_string_delete (dyn_string_t ds)
109239310Sdim{
110239310Sdim  free (ds->s);
111239310Sdim  free (ds);
112239310Sdim}
113239310Sdim
114239310Sdim/* Returns the contents of DS in a buffer allocated with malloc.  It
115239310Sdim   is the caller's responsibility to deallocate the buffer using free.
116239310Sdim   DS is then set to the empty string.  Deletes DS itself.  */
117239310Sdim
118239310Sdimchar*
119239310Sdimdyn_string_release (dyn_string_t ds)
120239310Sdim{
121239310Sdim  /* Store the old buffer.  */
122239310Sdim  char* result = ds->s;
123239310Sdim  /* The buffer is no longer owned by DS.  */
124239310Sdim  ds->s = NULL;
125239310Sdim  /* Delete DS.  */
126239310Sdim  free (ds);
127239310Sdim  /* Return the old buffer.  */
128239310Sdim  return result;
129239310Sdim}
130239310Sdim
131239310Sdim/* Increase the capacity of DS so it can hold at least SPACE
132239310Sdim   characters, plus the terminating NUL.  This function will not (at
133239310Sdim   present) reduce the capacity of DS.  Returns DS on success.
134239310Sdim
135239310Sdim   If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
136239310Sdim   operation fails, deletes DS and returns NULL.  */
137239310Sdim
138239310Sdimdyn_string_t
139239310Sdimdyn_string_resize (dyn_string_t ds, int space)
140239310Sdim{
141239310Sdim  int new_allocated = ds->allocated;
142239310Sdim
143239310Sdim  /* Increase SPACE to hold the NUL termination.  */
144239310Sdim  ++space;
145239310Sdim
146239310Sdim  /* Increase allocation by factors of two.  */
147239310Sdim  while (space > new_allocated)
148239310Sdim    new_allocated *= 2;
149239310Sdim
150239310Sdim  if (new_allocated != ds->allocated)
151239310Sdim    {
152239310Sdim      ds->allocated = new_allocated;
153239310Sdim      /* We actually need more space.  */
154239310Sdim#ifdef RETURN_ON_ALLOCATION_FAILURE
155239310Sdim      ds->s = (char *) realloc (ds->s, ds->allocated);
156239310Sdim      if (ds->s == NULL)
157239310Sdim	{
158239310Sdim	  free (ds);
159239310Sdim	  return NULL;
160239310Sdim	}
161239310Sdim#else
162239310Sdim      ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
163239310Sdim#endif
164239310Sdim    }
165239310Sdim
166239310Sdim  return ds;
167239310Sdim}
168239310Sdim
169239310Sdim/* Sets the contents of DS to the empty string.  */
170239310Sdim
171239310Sdimvoid
172239310Sdimdyn_string_clear (dyn_string_t ds)
173239310Sdim{
174239310Sdim  /* A dyn_string always has room for at least the NUL terminator.  */
175239310Sdim  ds->s[0] = '\0';
176239310Sdim  ds->length = 0;
177239310Sdim}
178239310Sdim
179239310Sdim/* Makes the contents of DEST the same as the contents of SRC.  DEST
180239310Sdim   and SRC must be distinct.  Returns 1 on success.  On failure, if
181239310Sdim   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
182239310Sdim
183239310Sdimint
184239310Sdimdyn_string_copy (dyn_string_t dest, dyn_string_t src)
185239310Sdim{
186239310Sdim  if (dest == src)
187239310Sdim    abort ();
188239310Sdim
189239310Sdim  /* Make room in DEST.  */
190239310Sdim  if (dyn_string_resize (dest, src->length) == NULL)
191239310Sdim    return 0;
192239310Sdim  /* Copy DEST into SRC.  */
193239310Sdim  strcpy (dest->s, src->s);
194239310Sdim  /* Update the size of DEST.  */
195239310Sdim  dest->length = src->length;
196239310Sdim  return 1;
197239310Sdim}
198239310Sdim
199239310Sdim/* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
200239310Sdim   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
201239310Sdim   and returns 0.  */
202239310Sdim
203239310Sdimint
204239310Sdimdyn_string_copy_cstr (dyn_string_t dest, const char *src)
205239310Sdim{
206239310Sdim  int length = strlen (src);
207239310Sdim  /* Make room in DEST.  */
208239310Sdim  if (dyn_string_resize (dest, length) == NULL)
209239310Sdim    return 0;
210239310Sdim  /* Copy DEST into SRC.  */
211239310Sdim  strcpy (dest->s, src);
212239310Sdim  /* Update the size of DEST.  */
213239310Sdim  dest->length = length;
214239310Sdim  return 1;
215239310Sdim}
216239310Sdim
217239310Sdim/* Inserts SRC at the beginning of DEST.  DEST is expanded as
218239310Sdim   necessary.  SRC and DEST must be distinct.  Returns 1 on success.
219239310Sdim   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
220239310Sdim   returns 0.  */
221239310Sdim
222239310Sdimint
223239310Sdimdyn_string_prepend (dyn_string_t dest, dyn_string_t src)
224239310Sdim{
225239310Sdim  return dyn_string_insert (dest, 0, src);
226239310Sdim}
227239310Sdim
228239310Sdim/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
229239310Sdim   DEST is expanded as necessary.  Returns 1 on success.  On failure,
230239310Sdim   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
231239310Sdim
232239310Sdimint
233239310Sdimdyn_string_prepend_cstr (dyn_string_t dest, const char *src)
234239310Sdim{
235239310Sdim  return dyn_string_insert_cstr (dest, 0, src);
236239310Sdim}
237239310Sdim
238239310Sdim/* Inserts SRC into DEST starting at position POS.  DEST is expanded
239239310Sdim   as necessary.  SRC and DEST must be distinct.  Returns 1 on
240239310Sdim   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
241239310Sdim   and returns 0.  */
242239310Sdim
243239310Sdimint
244239310Sdimdyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
245239310Sdim{
246239310Sdim  int i;
247239310Sdim
248239310Sdim  if (src == dest)
249239310Sdim    abort ();
250239310Sdim
251239310Sdim  if (dyn_string_resize (dest, dest->length + src->length) == NULL)
252239310Sdim    return 0;
253239310Sdim  /* Make room for the insertion.  Be sure to copy the NUL.  */
254239310Sdim  for (i = dest->length; i >= pos; --i)
255239310Sdim    dest->s[i + src->length] = dest->s[i];
256239310Sdim  /* Splice in the new stuff.  */
257239310Sdim  strncpy (dest->s + pos, src->s, src->length);
258239310Sdim  /* Compute the new length.  */
259239310Sdim  dest->length += src->length;
260239310Sdim  return 1;
261239310Sdim}
262239310Sdim
263239310Sdim/* Inserts SRC, a NUL-terminated string, into DEST starting at
264239310Sdim   position POS.  DEST is expanded as necessary.  Returns 1 on
265239310Sdim   success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
266239310Sdim   and returns 0.  */
267239310Sdim
268239310Sdimint
269239310Sdimdyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
270239310Sdim{
271239310Sdim  int i;
272239310Sdim  int length = strlen (src);
273239310Sdim
274239310Sdim  if (dyn_string_resize (dest, dest->length + length) == NULL)
275239310Sdim    return 0;
276239310Sdim  /* Make room for the insertion.  Be sure to copy the NUL.  */
277239310Sdim  for (i = dest->length; i >= pos; --i)
278239310Sdim    dest->s[i + length] = dest->s[i];
279239310Sdim  /* Splice in the new stuff.  */
280239310Sdim  strncpy (dest->s + pos, src, length);
281239310Sdim  /* Compute the new length.  */
282239310Sdim  dest->length += length;
283239310Sdim  return 1;
284239310Sdim}
285239310Sdim
286239310Sdim/* Inserts character C into DEST starting at position POS.  DEST is
287239310Sdim   expanded as necessary.  Returns 1 on success.  On failure,
288239310Sdim   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
289239310Sdim
290239310Sdimint
291239310Sdimdyn_string_insert_char (dyn_string_t dest, int pos, int c)
292239310Sdim{
293239310Sdim  int i;
294239310Sdim
295239310Sdim  if (dyn_string_resize (dest, dest->length + 1) == NULL)
296239310Sdim    return 0;
297239310Sdim  /* Make room for the insertion.  Be sure to copy the NUL.  */
298239310Sdim  for (i = dest->length; i >= pos; --i)
299239310Sdim    dest->s[i + 1] = dest->s[i];
300239310Sdim  /* Add the new character.  */
301239310Sdim  dest->s[pos] = c;
302239310Sdim  /* Compute the new length.  */
303239310Sdim  ++dest->length;
304239310Sdim  return 1;
305239310Sdim}
306239310Sdim
307239310Sdim/* Append S to DS, resizing DS if necessary.  Returns 1 on success.
308239310Sdim   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
309239310Sdim   returns 0.  */
310239310Sdim
311239310Sdimint
312239310Sdimdyn_string_append (dyn_string_t dest, dyn_string_t s)
313239310Sdim{
314239310Sdim  if (dyn_string_resize (dest, dest->length + s->length) == 0)
315239310Sdim    return 0;
316239310Sdim  strcpy (dest->s + dest->length, s->s);
317239310Sdim  dest->length += s->length;
318239310Sdim  return 1;
319239310Sdim}
320239310Sdim
321239310Sdim/* Append the NUL-terminated string S to DS, resizing DS if necessary.
322239310Sdim   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
323239310Sdim   deletes DEST and returns 0.  */
324239310Sdim
325239310Sdimint
326239310Sdimdyn_string_append_cstr (dyn_string_t dest, const char *s)
327239310Sdim{
328239310Sdim  int len = strlen (s);
329239310Sdim
330239310Sdim  /* The new length is the old length plus the size of our string, plus
331239310Sdim     one for the null at the end.  */
332239310Sdim  if (dyn_string_resize (dest, dest->length + len) == NULL)
333239310Sdim    return 0;
334239310Sdim  strcpy (dest->s + dest->length, s);
335239310Sdim  dest->length += len;
336239310Sdim  return 1;
337239310Sdim}
338239310Sdim
339239310Sdim/* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
340239310Sdim   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
341239310Sdim
342239310Sdimint
343239310Sdimdyn_string_append_char (dyn_string_t dest, int c)
344239310Sdim{
345239310Sdim  /* Make room for the extra character.  */
346239310Sdim  if (dyn_string_resize (dest, dest->length + 1) == NULL)
347239310Sdim    return 0;
348239310Sdim  /* Append the character; it will overwrite the old NUL.  */
349239310Sdim  dest->s[dest->length] = c;
350239310Sdim  /* Add a new NUL at the end.  */
351239310Sdim  dest->s[dest->length + 1] = '\0';
352239310Sdim  /* Update the length.  */
353239310Sdim  ++(dest->length);
354239310Sdim  return 1;
355239310Sdim}
356239310Sdim
357239310Sdim/* Sets the contents of DEST to the substring of SRC starting at START
358239310Sdim   and ending before END.  START must be less than or equal to END,
359239310Sdim   and both must be between zero and the length of SRC, inclusive.
360239310Sdim   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
361239310Sdim   deletes DEST and returns 0.  */
362239310Sdim
363239310Sdimint
364239310Sdimdyn_string_substring (dyn_string_t dest, dyn_string_t src,
365239310Sdim                      int start, int end)
366239310Sdim{
367239310Sdim  int i;
368239310Sdim  int length = end - start;
369239310Sdim
370239310Sdim  if (start > end || start > src->length || end > src->length)
371239310Sdim    abort ();
372239310Sdim
373239310Sdim  /* Make room for the substring.  */
374239310Sdim  if (dyn_string_resize (dest, length) == NULL)
375239310Sdim    return 0;
376239310Sdim  /* Copy the characters in the substring,  */
377239310Sdim  for (i = length; --i >= 0; )
378239310Sdim    dest->s[i] = src->s[start + i];
379239310Sdim  /* NUL-terimate the result.  */
380239310Sdim  dest->s[length] = '\0';
381239310Sdim  /* Record the length of the substring.  */
382239310Sdim  dest->length = length;
383239310Sdim
384239310Sdim  return 1;
385239310Sdim}
386239310Sdim
387239310Sdim/* Returns non-zero if DS1 and DS2 have the same contents.  */
388239310Sdim
389239310Sdimint
390239310Sdimdyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
391239310Sdim{
392239310Sdim  /* If DS1 and DS2 have different lengths, they must not be the same.  */
393239310Sdim  if (ds1->length != ds2->length)
394239310Sdim    return 0;
395239310Sdim  else
396239310Sdim    return !strcmp (ds1->s, ds2->s);
397239310Sdim}
398239310Sdim