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