dyn-string.c revision 104834
1/* An abstract string datatype.
2   Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
3   Contributed by Mark Mitchell (mark@markmitchell.com).
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12In addition to the permissions in the GNU General Public License, the
13Free Software Foundation gives you unlimited permission to link the
14compiled version of this file into combinations with other programs,
15and to distribute those combinations without any restriction coming
16from the use of this file.  (The General Public License restrictions
17do apply in other respects; for example, they cover modification of
18the file, and distribution when not linked into a combined
19executable.)
20
21GNU CC is distributed in the hope that it will be useful,
22but WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24GNU General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with GNU CC; see the file COPYING.  If not, write to
28the Free Software Foundation, 59 Temple Place - Suite 330,
29Boston, MA 02111-1307, USA.  */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <stdio.h>
36
37#ifdef HAVE_STRING_H
38#include <string.h>
39#endif
40
41#ifdef HAVE_STDLIB_H
42#include <stdlib.h>
43#endif
44
45#include "libiberty.h"
46#include "dyn-string.h"
47
48/* If this file is being compiled for inclusion in the C++ runtime
49   library, as part of the demangler implementation, we don't want to
50   abort if an allocation fails.  Instead, percolate an error code up
51   through the call chain.  */
52
53#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
54#define RETURN_ON_ALLOCATION_FAILURE
55#endif
56
57/* Performs in-place initialization of a dyn_string struct.  This
58   function can be used with a dyn_string struct on the stack or
59   embedded in another object.  The contents of of the string itself
60   are still dynamically allocated.  The string initially is capable
61   of holding at least SPACE characeters, including the terminating
62   NUL.  If SPACE is 0, it will silently be increated to 1.
63
64   If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
65   fails, returns 0.  Otherwise returns 1.  */
66
67int
68dyn_string_init (ds_struct_ptr, space)
69     struct dyn_string *ds_struct_ptr;
70     int space;
71{
72  /* We need at least one byte in which to store the terminating NUL.  */
73  if (space == 0)
74    space = 1;
75
76#ifdef RETURN_ON_ALLOCATION_FAILURE
77  ds_struct_ptr->s = (char *) malloc (space);
78  if (ds_struct_ptr->s == NULL)
79    return 0;
80#else
81  ds_struct_ptr->s = (char *) xmalloc (space);
82#endif
83  ds_struct_ptr->allocated = space;
84  ds_struct_ptr->length = 0;
85  ds_struct_ptr->s[0] = '\0';
86
87  return 1;
88}
89
90/* Create a new dynamic string capable of holding at least SPACE
91   characters, including the terminating NUL.  If SPACE is 0, it will
92   be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
93   defined and memory allocation fails, returns NULL.  Otherwise
94   returns the newly allocated string.  */
95
96dyn_string_t
97dyn_string_new (space)
98     int space;
99{
100  dyn_string_t result;
101#ifdef RETURN_ON_ALLOCATION_FAILURE
102  result = (dyn_string_t) malloc (sizeof (struct dyn_string));
103  if (result == NULL)
104    return NULL;
105  if (!dyn_string_init (result, space))
106    {
107      free (result);
108      return NULL;
109    }
110#else
111  result = (dyn_string_t) xmalloc (sizeof (struct dyn_string));
112  dyn_string_init (result, space);
113#endif
114  return result;
115}
116
117/* Free the memory used by DS.  */
118
119void
120dyn_string_delete (ds)
121     dyn_string_t ds;
122{
123  free (ds->s);
124  free (ds);
125}
126
127/* Returns the contents of DS in a buffer allocated with malloc.  It
128   is the caller's responsibility to deallocate the buffer using free.
129   DS is then set to the empty string.  Deletes DS itself.  */
130
131char*
132dyn_string_release (ds)
133     dyn_string_t ds;
134{
135  /* Store the old buffer.  */
136  char* result = ds->s;
137  /* The buffer is no longer owned by DS.  */
138  ds->s = NULL;
139  /* Delete DS.  */
140  free (ds);
141  /* Return the old buffer.  */
142  return result;
143}
144
145/* Increase the capacity of DS so it can hold at least SPACE
146   characters, plus the terminating NUL.  This function will not (at
147   present) reduce the capacity of DS.  Returns DS on success.
148
149   If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
150   operation fails, deletes DS and returns NULL.  */
151
152dyn_string_t
153dyn_string_resize (ds, space)
154     dyn_string_t ds;
155     int space;
156{
157  int new_allocated = ds->allocated;
158
159  /* Increase SPACE to hold the NUL termination.  */
160  ++space;
161
162  /* Increase allocation by factors of two.  */
163  while (space > new_allocated)
164    new_allocated *= 2;
165
166  if (new_allocated != ds->allocated)
167    {
168      ds->allocated = new_allocated;
169      /* We actually need more space.  */
170#ifdef RETURN_ON_ALLOCATION_FAILURE
171      ds->s = (char *) realloc (ds->s, ds->allocated);
172      if (ds->s == NULL)
173	{
174	  free (ds);
175	  return NULL;
176	}
177#else
178      ds->s = (char *) xrealloc (ds->s, ds->allocated);
179#endif
180    }
181
182  return ds;
183}
184
185/* Sets the contents of DS to the empty string.  */
186
187void
188dyn_string_clear (ds)
189     dyn_string_t ds;
190{
191  /* A dyn_string always has room for at least the NUL terminator.  */
192  ds->s[0] = '\0';
193  ds->length = 0;
194}
195
196/* Makes the contents of DEST the same as the contents of SRC.  DEST
197   and SRC must be distinct.  Returns 1 on success.  On failure, if
198   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
199
200int
201dyn_string_copy (dest, src)
202     dyn_string_t dest;
203     dyn_string_t src;
204{
205  if (dest == src)
206    abort ();
207
208  /* Make room in DEST.  */
209  if (dyn_string_resize (dest, src->length) == NULL)
210    return 0;
211  /* Copy DEST into SRC.  */
212  strcpy (dest->s, src->s);
213  /* Update the size of DEST.  */
214  dest->length = src->length;
215  return 1;
216}
217
218/* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
219   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
220   and returns 0.  */
221
222int
223dyn_string_copy_cstr (dest, src)
224     dyn_string_t dest;
225     const char *src;
226{
227  int length = strlen (src);
228  /* Make room in DEST.  */
229  if (dyn_string_resize (dest, length) == NULL)
230    return 0;
231  /* Copy DEST into SRC.  */
232  strcpy (dest->s, src);
233  /* Update the size of DEST.  */
234  dest->length = length;
235  return 1;
236}
237
238/* Inserts SRC at the beginning of DEST.  DEST is expanded as
239   necessary.  SRC and DEST must be distinct.  Returns 1 on success.
240   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
241   returns 0.  */
242
243int
244dyn_string_prepend (dest, src)
245     dyn_string_t dest;
246     dyn_string_t src;
247{
248  return dyn_string_insert (dest, 0, src);
249}
250
251/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
252   DEST is expanded as necessary.  Returns 1 on success.  On failure,
253   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
254
255int
256dyn_string_prepend_cstr (dest, src)
257     dyn_string_t dest;
258     const char *src;
259{
260  return dyn_string_insert_cstr (dest, 0, src);
261}
262
263/* Inserts SRC into DEST starting at position POS.  DEST is expanded
264   as necessary.  SRC and DEST must be distinct.  Returns 1 on
265   success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
266   and returns 0.  */
267
268int
269dyn_string_insert (dest, pos, src)
270     dyn_string_t dest;
271     int pos;
272     dyn_string_t src;
273{
274  int i;
275
276  if (src == dest)
277    abort ();
278
279  if (dyn_string_resize (dest, dest->length + src->length) == NULL)
280    return 0;
281  /* Make room for the insertion.  Be sure to copy the NUL.  */
282  for (i = dest->length; i >= pos; --i)
283    dest->s[i + src->length] = dest->s[i];
284  /* Splice in the new stuff.  */
285  strncpy (dest->s + pos, src->s, src->length);
286  /* Compute the new length.  */
287  dest->length += src->length;
288  return 1;
289}
290
291/* Inserts SRC, a NUL-terminated string, into DEST starting at
292   position POS.  DEST is expanded as necessary.  Returns 1 on
293   success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
294   and returns 0.  */
295
296int
297dyn_string_insert_cstr (dest, pos, src)
298     dyn_string_t dest;
299     int pos;
300     const char *src;
301{
302  int i;
303  int length = strlen (src);
304
305  if (dyn_string_resize (dest, dest->length + length) == NULL)
306    return 0;
307  /* Make room for the insertion.  Be sure to copy the NUL.  */
308  for (i = dest->length; i >= pos; --i)
309    dest->s[i + length] = dest->s[i];
310  /* Splice in the new stuff.  */
311  strncpy (dest->s + pos, src, length);
312  /* Compute the new length.  */
313  dest->length += length;
314  return 1;
315}
316
317/* Inserts character C into DEST starting at position POS.  DEST is
318   expanded as necessary.  Returns 1 on success.  On failure,
319   RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
320
321int
322dyn_string_insert_char (dest, pos, c)
323     dyn_string_t dest;
324     int pos;
325     int c;
326{
327  int i;
328
329  if (dyn_string_resize (dest, dest->length + 1) == NULL)
330    return 0;
331  /* Make room for the insertion.  Be sure to copy the NUL.  */
332  for (i = dest->length; i >= pos; --i)
333    dest->s[i + 1] = dest->s[i];
334  /* Add the new character.  */
335  dest->s[pos] = c;
336  /* Compute the new length.  */
337  ++dest->length;
338  return 1;
339}
340
341/* Append S to DS, resizing DS if necessary.  Returns 1 on success.
342   On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
343   returns 0.  */
344
345int
346dyn_string_append (dest, s)
347     dyn_string_t dest;
348     dyn_string_t s;
349{
350  if (dyn_string_resize (dest, dest->length + s->length) == 0)
351    return 0;
352  strcpy (dest->s + dest->length, s->s);
353  dest->length += s->length;
354  return 1;
355}
356
357/* Append the NUL-terminated string S to DS, resizing DS if necessary.
358   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
359   deletes DEST and returns 0.  */
360
361int
362dyn_string_append_cstr (dest, s)
363     dyn_string_t dest;
364     const char *s;
365{
366  int len = strlen (s);
367
368  /* The new length is the old length plus the size of our string, plus
369     one for the null at the end.  */
370  if (dyn_string_resize (dest, dest->length + len) == NULL)
371    return 0;
372  strcpy (dest->s + dest->length, s);
373  dest->length += len;
374  return 1;
375}
376
377/* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
378   if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
379
380int
381dyn_string_append_char (dest, c)
382     dyn_string_t dest;
383     int c;
384{
385  /* Make room for the extra character.  */
386  if (dyn_string_resize (dest, dest->length + 1) == NULL)
387    return 0;
388  /* Append the character; it will overwrite the old NUL.  */
389  dest->s[dest->length] = c;
390  /* Add a new NUL at the end.  */
391  dest->s[dest->length + 1] = '\0';
392  /* Update the length.  */
393  ++(dest->length);
394  return 1;
395}
396
397/* Sets the contents of DEST to the substring of SRC starting at START
398   and ending before END.  START must be less than or equal to END,
399   and both must be between zero and the length of SRC, inclusive.
400   Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
401   deletes DEST and returns 0.  */
402
403int
404dyn_string_substring (dest, src, start, end)
405     dyn_string_t dest;
406     dyn_string_t src;
407     int start;
408     int end;
409{
410  int i;
411  int length = end - start;
412
413  if (start > end || start > src->length || end > src->length)
414    abort ();
415
416  /* Make room for the substring.  */
417  if (dyn_string_resize (dest, length) == NULL)
418    return 0;
419  /* Copy the characters in the substring,  */
420  for (i = length; --i >= 0; )
421    dest->s[i] = src->s[start + i];
422  /* NUL-terimate the result.  */
423  dest->s[length] = '\0';
424  /* Record the length of the substring.  */
425  dest->length = length;
426
427  return 1;
428}
429
430/* Returns non-zero if DS1 and DS2 have the same contents.  */
431
432int
433dyn_string_eq (ds1, ds2)
434     dyn_string_t ds1;
435     dyn_string_t ds2;
436{
437  /* If DS1 and DS2 have different lengths, they must not be the same.  */
438  if (ds1->length != ds2->length)
439    return 0;
440  else
441    return !strcmp (ds1->s, ds2->s);
442}
443