xref: /openbsd/gnu/lib/libiberty/src/dyn-string.c (revision 37c53322)
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 
5 This file is part of GNU CC.
6 
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file.  (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combined
19 executable.)
20 
21 GNU CC is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 GNU General Public License for more details.
25 
26 You should have received a copy of the GNU General Public License
27 along with GNU CC; see the file COPYING.  If not, write to
28 the Free Software Foundation, 59 Temple Place - Suite 330,
29 Boston, 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 
67 int
68 dyn_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 
96 dyn_string_t
97 dyn_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 
119 void
120 dyn_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 
131 char*
132 dyn_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 
152 dyn_string_t
153 dyn_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 
187 void
188 dyn_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 
200 int
201 dyn_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 
222 int
223 dyn_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 
243 int
244 dyn_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 
255 int
256 dyn_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 
268 int
269 dyn_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 
296 int
297 dyn_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 /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
318    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
319    returns 0.  */
320 
321 int
322 dyn_string_append (dest, s)
323      dyn_string_t dest;
324      dyn_string_t s;
325 {
326   if (dyn_string_resize (dest, dest->length + s->length) == 0)
327     return 0;
328   strcpy (dest->s + dest->length, s->s);
329   dest->length += s->length;
330   return 1;
331 }
332 
333 /* Append the NUL-terminated string S to DS, resizing DS if necessary.
334    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
335    deletes DEST and returns 0.  */
336 
337 int
338 dyn_string_append_cstr (dest, s)
339      dyn_string_t dest;
340      const char *s;
341 {
342   int len = strlen (s);
343 
344   /* The new length is the old length plus the size of our string, plus
345      one for the null at the end.  */
346   if (dyn_string_resize (dest, dest->length + len) == NULL)
347     return 0;
348   strcpy (dest->s + dest->length, s);
349   dest->length += len;
350   return 1;
351 }
352 
353 /* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
354    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
355 
356 int
357 dyn_string_append_char (dest, c)
358      dyn_string_t dest;
359      int c;
360 {
361   /* Make room for the extra character.  */
362   if (dyn_string_resize (dest, dest->length + 1) == NULL)
363     return 0;
364   /* Append the character; it will overwrite the old NUL.  */
365   dest->s[dest->length] = c;
366   /* Add a new NUL at the end.  */
367   dest->s[dest->length + 1] = '\0';
368   /* Update the length.  */
369   ++(dest->length);
370   return 1;
371 }
372 
373 /* Sets the contents of DEST to the substring of SRC starting at START
374    and ending before END.  START must be less than or equal to END,
375    and both must be between zero and the length of SRC, inclusive.
376    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
377    deletes DEST and returns 0.  */
378 
379 int
380 dyn_string_substring (dest, src, start, end)
381      dyn_string_t dest;
382      dyn_string_t src;
383      int start;
384      int end;
385 {
386   int i;
387   int length = end - start;
388 
389   if (start > end || start > src->length || end > src->length)
390     abort ();
391 
392   /* Make room for the substring.  */
393   if (dyn_string_resize (dest, length) == NULL)
394     return 0;
395   /* Copy the characters in the substring,  */
396   for (i = length; --i >= 0; )
397     dest->s[i] = src->s[start + i];
398   /* NUL-terimate the result.  */
399   dest->s[length] = '\0';
400   /* Record the length of the substring.  */
401   dest->length = length;
402 
403   return 1;
404 }
405 
406 /* Returns non-zero if DS1 and DS2 have the same contents.  */
407 
408 int
409 dyn_string_eq (ds1, ds2)
410      dyn_string_t ds1;
411      dyn_string_t ds2;
412 {
413   /* If DS1 and DS2 have different lengths, they must not be the same.  */
414   if (ds1->length != ds2->length)
415     return 0;
416   else
417     return !strcmp (ds1->s, ds2->s);
418 }
419