Synced with libiberty in the gcc repository.
[external/binutils.git] / libiberty / dyn-string.c
1 /* An abstract string datatype.
2    Copyright (C) 1998, 1999, 2000 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 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #endif
31
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35
36 #include "libiberty.h"
37 #include "dyn-string.h"
38
39 /* Performs in-place initialization of a dyn_string struct.  This
40    function can be used with a dyn_string struct on the stack or
41    embedded in another object.  The contents of of the string itself
42    are still dynamically allocated.  The string initially is capable
43    of holding at least SPACE characeters, including the terminating
44    NUL.  If SPACE is 0, it will silently be increated to 1.  */
45
46 void
47 dyn_string_init (ds_struct_ptr, space)
48      struct dyn_string *ds_struct_ptr;
49      int space;
50 {
51   /* We need at least one byte in which to store the terminating NUL.  */
52   if (space == 0)
53     space = 1;
54
55   ds_struct_ptr->allocated = space;
56   ds_struct_ptr->s = (char *) xmalloc (space);
57   ds_struct_ptr->length = 0;
58   ds_struct_ptr->s[0] = '\0';
59 }    
60
61 /* Create a new dynamic string capable of holding at least SPACE characters,
62    including the terminating NUL.  If SPACE is 0, it will be silently
63    increased to 1.  */
64
65 dyn_string_t 
66 dyn_string_new (space)
67      int space;
68 {
69   dyn_string_t result = (dyn_string_t) xmalloc (sizeof (struct dyn_string));
70   dyn_string_init (result, space);
71   return result;
72 }
73
74 /* Free the memory used by DS.  */
75
76 void 
77 dyn_string_delete (ds)
78      dyn_string_t ds;
79 {
80   free (ds->s);
81   free (ds);
82 }
83
84 /* Returns the contents of DS in a buffer allocated with malloc.  It
85    is the caller's responsibility to deallocate the buffer using free.
86    DS is then set to the empty string.  */
87
88 char*
89 dyn_string_release (ds)
90      dyn_string_t ds;
91 {
92   /* Store the old buffer.  */
93   char* result = ds->s;
94   /* The buffer is no longer owned by DS.  */
95   ds->s = NULL;
96   /* Reinitialize DS to the empty string.  */
97   dyn_string_init (ds, 0);
98   /* Return the old buffer.  */
99   return result;
100 }
101
102 /* Increase the capacity of DS so it can hold at least SPACE
103    characters, plus the terminating NUL.  This function will not (at
104    present) reduce the capacity of DS.  */
105
106 dyn_string_t 
107 dyn_string_resize (ds, space)
108      dyn_string_t ds;
109      int space;
110 {
111   int new_allocated = ds->allocated;
112
113   /* Increase SPACE to hold the NUL termination.  */
114   ++space;
115
116   while (space > new_allocated)
117     new_allocated *= 2;
118     
119   if (new_allocated != ds->allocated)
120     {
121       /* We actually need more space.  */
122       ds->allocated = new_allocated;
123       ds->s = (char *) xrealloc (ds->s, ds->allocated);
124     }
125
126   return ds;
127 }
128
129 /* Sets the contents of DS to the empty string.  */
130
131 void
132 dyn_string_clear (ds)
133      dyn_string_t ds;
134 {
135   /* A dyn_string always has room for at least the NUL terminator.  */
136   ds->s[0] = '\0';
137   ds->length = 0;
138 }
139
140 /* Makes the contents of DEST the same as the contents of SRC.  DEST
141    and SRC must be distinct.  */
142
143 void
144 dyn_string_copy (dest, src)
145      dyn_string_t dest;
146      dyn_string_t src;
147 {
148   if (dest == src)
149     abort ();
150
151   /* Make room in DEST.  */
152   dyn_string_resize (dest, src->length);
153   /* Copy DEST into SRC.  */
154   strcpy (dest->s, src->s);
155   /* Update the size of DEST.  */
156   dest->length = src->length;
157 }
158
159 /* Copies SRC, a NUL-terminated string, into DEST.  */
160
161 void
162 dyn_string_copy_cstr (dest, src)
163      dyn_string_t dest;
164      const char *src;
165 {
166   int length = strlen (src);
167   /* Make room in DEST.  */
168   dyn_string_resize (dest, length);
169   /* Copy DEST into SRC.  */
170   strcpy (dest->s, src);
171   /* Update the size of DEST.  */
172   dest->length = length;
173 }
174
175 /* Inserts SRC at the beginning of DEST.  DEST is expanded as
176    necessary.  SRC and DEST must be distinct.  */
177
178 void 
179 dyn_string_prepend (dest, src)
180      dyn_string_t dest;
181      dyn_string_t src;
182 {
183   dyn_string_insert (dest, 0, src);
184 }
185
186 /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
187    DEST is expanded as necessary.  */
188
189 void 
190 dyn_string_prepend_cstr (dest, src)
191      dyn_string_t dest;
192      const char *src;
193 {
194   dyn_string_insert_cstr (dest, 0, src);
195 }
196
197 /* Inserts SRC into DEST starting at position POS.  DEST is expanded as
198    necessary.  SRC and DEST must be distinct.  */
199
200 void 
201 dyn_string_insert (dest, pos, src)
202      dyn_string_t dest;
203      int pos;
204      dyn_string_t src;
205 {
206   int i;
207
208   if (src == dest)
209     abort ();
210
211   dyn_string_resize (dest, dest->length + src->length);
212   /* Make room for the insertion.  Be sure to copy the NUL.  */
213   for (i = dest->length; i >= pos; --i)
214     dest->s[i + src->length] = dest->s[i];
215   /* Splice in the new stuff.  */
216   strncpy (dest->s + pos, src->s, src->length);
217   /* Compute the new length.  */
218   dest->length += src->length;
219 }
220
221 /* Inserts SRC, a NUL-terminated string, into DEST starting at
222    position POS.  DEST is expanded as necessary.  */
223
224 void 
225 dyn_string_insert_cstr (dest, pos, src)
226      dyn_string_t dest;
227      int pos;
228      const char *src;
229 {
230   int i;
231   int length = strlen (src);
232
233   dyn_string_resize (dest, dest->length + length);
234   /* Make room for the insertion.  Be sure to copy the NUL.  */
235   for (i = dest->length; i >= pos; --i)
236     dest->s[i + length] = dest->s[i];
237   /* Splice in the new stuff.  */
238   strncpy (dest->s + pos, src, length);
239   /* Compute the new length.  */
240   dest->length += length;
241 }
242
243 /* Append S to DS, resizing DS if necessary.  Returns DS.  */
244
245 dyn_string_t
246 dyn_string_append (ds, s)
247      dyn_string_t ds;
248      dyn_string_t s;
249 {
250   dyn_string_resize (ds, ds->length + s->length);
251   strcpy (ds->s + ds->length, s->s);
252   ds->length += s->length;
253   return ds;
254 }
255
256 /* Append the NUL-terminated string S to DS, resizing DS if necessary.
257    Returns DS.  */
258
259 dyn_string_t 
260 dyn_string_append_cstr (ds, s)
261      dyn_string_t ds;
262      const char *s;
263 {
264   int len = strlen (s);
265
266   /* The new length is the old length plus the size of our string, plus
267      one for the null at the end.  */
268   dyn_string_resize (ds, ds->length + len);
269   strcpy (ds->s + ds->length, s);
270   ds->length += len;
271
272   return ds;
273 }
274
275 /* Appends C to the end of DS.  */
276
277 dyn_string_t 
278 dyn_string_append_char (ds, c)
279      dyn_string_t ds;
280      int c;
281 {
282   /* Make room for the extra character.  */
283   dyn_string_resize (ds, ds->length + 1);
284   /* Append the character; it will overwrite the old NUL.  */
285   ds->s[ds->length] = c;
286   /* Add a new NUL at the end.  */
287   ds->s[ds->length + 1] = '\0';
288   /* Update the length.  */
289   ++(ds->length);
290   return ds;
291 }
292
293 /* Sets the contents of DEST to the substring of SRC starting at START
294    and ending before END.  START must be less than or equal to END,
295    and both must be between zero and the length of SRC, inclusive.  */
296
297 void
298 dyn_string_substring (dest, src, start, end)
299      dyn_string_t dest;
300      dyn_string_t src;
301      int start;
302      int end;
303 {
304   int i;
305   int length = end - start;
306
307   if (start > end || start > src->length || end > src->length)
308     abort ();
309
310   /* Make room for the substring.  */
311   dyn_string_resize (dest, length);
312   /* Copy the characters in the substring,  */
313   for (i = length; --i >= 0; )
314     dest->s[i] = src->s[start + i];
315   /* NUL-terimate the result.  */
316   dest->s[length] = '\0';
317   /* Record the length of the substring.  */
318   dest->length = length;
319 }
320
321 /* Returns non-zero if DS1 and DS2 have the same contents.  */
322
323 int
324 dyn_string_eq (ds1, ds2)
325      dyn_string_t ds1;
326      dyn_string_t ds2;
327 {
328   /* If DS1 and DS2 have different lengths, they must not be the same.  */
329   if (ds1->length != ds2->length)
330     return 0;
331   else
332     return !strcmp (ds1->s, ds2->s);
333 }