0
|
1 /* An abstract string datatype.
|
|
2 Copyright (C) 1998, 1999, 2000, 2002, 2004 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, 51 Franklin Street - Fifth Floor,
|
|
29 Boston, MA 02110-1301, 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 /* Performs in-place initialization of a dyn_string struct. This
|
|
49 function can be used with a dyn_string struct on the stack or
|
|
50 embedded in another object. The contents of of the string itself
|
|
51 are still dynamically allocated. The string initially is capable
|
|
52 of holding at least SPACE characeters, including the terminating
|
|
53 NUL. If SPACE is 0, it will silently be increated to 1.
|
|
54
|
|
55 If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
|
|
56 fails, returns 0. Otherwise returns 1. */
|
|
57
|
|
58 int
|
|
59 dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
|
|
60 {
|
|
61 /* We need at least one byte in which to store the terminating NUL. */
|
|
62 if (space == 0)
|
|
63 space = 1;
|
|
64
|
|
65 #ifdef RETURN_ON_ALLOCATION_FAILURE
|
|
66 ds_struct_ptr->s = (char *) malloc (space);
|
|
67 if (ds_struct_ptr->s == NULL)
|
|
68 return 0;
|
|
69 #else
|
|
70 ds_struct_ptr->s = XNEWVEC (char, space);
|
|
71 #endif
|
|
72 ds_struct_ptr->allocated = space;
|
|
73 ds_struct_ptr->length = 0;
|
|
74 ds_struct_ptr->s[0] = '\0';
|
|
75
|
|
76 return 1;
|
|
77 }
|
|
78
|
|
79 /* Create a new dynamic string capable of holding at least SPACE
|
|
80 characters, including the terminating NUL. If SPACE is 0, it will
|
|
81 be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is
|
|
82 defined and memory allocation fails, returns NULL. Otherwise
|
|
83 returns the newly allocated string. */
|
|
84
|
|
85 dyn_string_t
|
|
86 dyn_string_new (int space)
|
|
87 {
|
|
88 dyn_string_t result;
|
|
89 #ifdef RETURN_ON_ALLOCATION_FAILURE
|
|
90 result = (dyn_string_t) malloc (sizeof (struct dyn_string));
|
|
91 if (result == NULL)
|
|
92 return NULL;
|
|
93 if (!dyn_string_init (result, space))
|
|
94 {
|
|
95 free (result);
|
|
96 return NULL;
|
|
97 }
|
|
98 #else
|
|
99 result = XNEW (struct dyn_string);
|
|
100 dyn_string_init (result, space);
|
|
101 #endif
|
|
102 return result;
|
|
103 }
|
|
104
|
|
105 /* Free the memory used by DS. */
|
|
106
|
|
107 void
|
|
108 dyn_string_delete (dyn_string_t ds)
|
|
109 {
|
|
110 free (ds->s);
|
|
111 free (ds);
|
|
112 }
|
|
113
|
|
114 /* Returns the contents of DS in a buffer allocated with malloc. It
|
|
115 is the caller's responsibility to deallocate the buffer using free.
|
|
116 DS is then set to the empty string. Deletes DS itself. */
|
|
117
|
|
118 char*
|
|
119 dyn_string_release (dyn_string_t ds)
|
|
120 {
|
|
121 /* Store the old buffer. */
|
|
122 char* result = ds->s;
|
|
123 /* The buffer is no longer owned by DS. */
|
|
124 ds->s = NULL;
|
|
125 /* Delete DS. */
|
|
126 free (ds);
|
|
127 /* Return the old buffer. */
|
|
128 return result;
|
|
129 }
|
|
130
|
|
131 /* Increase the capacity of DS so it can hold at least SPACE
|
|
132 characters, plus the terminating NUL. This function will not (at
|
|
133 present) reduce the capacity of DS. Returns DS on success.
|
|
134
|
|
135 If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
|
|
136 operation fails, deletes DS and returns NULL. */
|
|
137
|
|
138 dyn_string_t
|
|
139 dyn_string_resize (dyn_string_t ds, int space)
|
|
140 {
|
|
141 int new_allocated = ds->allocated;
|
|
142
|
|
143 /* Increase SPACE to hold the NUL termination. */
|
|
144 ++space;
|
|
145
|
|
146 /* Increase allocation by factors of two. */
|
|
147 while (space > new_allocated)
|
|
148 new_allocated *= 2;
|
|
149
|
|
150 if (new_allocated != ds->allocated)
|
|
151 {
|
|
152 ds->allocated = new_allocated;
|
|
153 /* We actually need more space. */
|
|
154 #ifdef RETURN_ON_ALLOCATION_FAILURE
|
|
155 ds->s = (char *) realloc (ds->s, ds->allocated);
|
|
156 if (ds->s == NULL)
|
|
157 {
|
|
158 free (ds);
|
|
159 return NULL;
|
|
160 }
|
|
161 #else
|
|
162 ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
|
|
163 #endif
|
|
164 }
|
|
165
|
|
166 return ds;
|
|
167 }
|
|
168
|
|
169 /* Sets the contents of DS to the empty string. */
|
|
170
|
|
171 void
|
|
172 dyn_string_clear (dyn_string_t ds)
|
|
173 {
|
|
174 /* A dyn_string always has room for at least the NUL terminator. */
|
|
175 ds->s[0] = '\0';
|
|
176 ds->length = 0;
|
|
177 }
|
|
178
|
|
179 /* Makes the contents of DEST the same as the contents of SRC. DEST
|
|
180 and SRC must be distinct. Returns 1 on success. On failure, if
|
|
181 RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
|
|
182
|
|
183 int
|
|
184 dyn_string_copy (dyn_string_t dest, dyn_string_t src)
|
|
185 {
|
|
186 if (dest == src)
|
|
187 abort ();
|
|
188
|
|
189 /* Make room in DEST. */
|
|
190 if (dyn_string_resize (dest, src->length) == NULL)
|
|
191 return 0;
|
|
192 /* Copy DEST into SRC. */
|
|
193 strcpy (dest->s, src->s);
|
|
194 /* Update the size of DEST. */
|
|
195 dest->length = src->length;
|
|
196 return 1;
|
|
197 }
|
|
198
|
|
199 /* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on
|
|
200 success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
|
|
201 and returns 0. */
|
|
202
|
|
203 int
|
|
204 dyn_string_copy_cstr (dyn_string_t dest, const char *src)
|
|
205 {
|
|
206 int length = strlen (src);
|
|
207 /* Make room in DEST. */
|
|
208 if (dyn_string_resize (dest, length) == NULL)
|
|
209 return 0;
|
|
210 /* Copy DEST into SRC. */
|
|
211 strcpy (dest->s, src);
|
|
212 /* Update the size of DEST. */
|
|
213 dest->length = length;
|
|
214 return 1;
|
|
215 }
|
|
216
|
|
217 /* Inserts SRC at the beginning of DEST. DEST is expanded as
|
|
218 necessary. SRC and DEST must be distinct. Returns 1 on success.
|
|
219 On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
|
|
220 returns 0. */
|
|
221
|
|
222 int
|
|
223 dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
|
|
224 {
|
|
225 return dyn_string_insert (dest, 0, src);
|
|
226 }
|
|
227
|
|
228 /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
|
|
229 DEST is expanded as necessary. Returns 1 on success. On failure,
|
|
230 if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
|
|
231
|
|
232 int
|
|
233 dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
|
|
234 {
|
|
235 return dyn_string_insert_cstr (dest, 0, src);
|
|
236 }
|
|
237
|
|
238 /* Inserts SRC into DEST starting at position POS. DEST is expanded
|
|
239 as necessary. SRC and DEST must be distinct. Returns 1 on
|
|
240 success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
|
|
241 and returns 0. */
|
|
242
|
|
243 int
|
|
244 dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
|
|
245 {
|
|
246 int i;
|
|
247
|
|
248 if (src == dest)
|
|
249 abort ();
|
|
250
|
|
251 if (dyn_string_resize (dest, dest->length + src->length) == NULL)
|
|
252 return 0;
|
|
253 /* Make room for the insertion. Be sure to copy the NUL. */
|
|
254 for (i = dest->length; i >= pos; --i)
|
|
255 dest->s[i + src->length] = dest->s[i];
|
|
256 /* Splice in the new stuff. */
|
|
257 strncpy (dest->s + pos, src->s, src->length);
|
|
258 /* Compute the new length. */
|
|
259 dest->length += src->length;
|
|
260 return 1;
|
|
261 }
|
|
262
|
|
263 /* Inserts SRC, a NUL-terminated string, into DEST starting at
|
|
264 position POS. DEST is expanded as necessary. Returns 1 on
|
|
265 success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
|
|
266 and returns 0. */
|
|
267
|
|
268 int
|
|
269 dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
|
|
270 {
|
|
271 int i;
|
|
272 int length = strlen (src);
|
|
273
|
|
274 if (dyn_string_resize (dest, dest->length + length) == NULL)
|
|
275 return 0;
|
|
276 /* Make room for the insertion. Be sure to copy the NUL. */
|
|
277 for (i = dest->length; i >= pos; --i)
|
|
278 dest->s[i + length] = dest->s[i];
|
|
279 /* Splice in the new stuff. */
|
|
280 strncpy (dest->s + pos, src, length);
|
|
281 /* Compute the new length. */
|
|
282 dest->length += length;
|
|
283 return 1;
|
|
284 }
|
|
285
|
|
286 /* Inserts character C into DEST starting at position POS. DEST is
|
|
287 expanded as necessary. Returns 1 on success. On failure,
|
|
288 RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
|
|
289
|
|
290 int
|
|
291 dyn_string_insert_char (dyn_string_t dest, int pos, int c)
|
|
292 {
|
|
293 int i;
|
|
294
|
|
295 if (dyn_string_resize (dest, dest->length + 1) == NULL)
|
|
296 return 0;
|
|
297 /* Make room for the insertion. Be sure to copy the NUL. */
|
|
298 for (i = dest->length; i >= pos; --i)
|
|
299 dest->s[i + 1] = dest->s[i];
|
|
300 /* Add the new character. */
|
|
301 dest->s[pos] = c;
|
|
302 /* Compute the new length. */
|
|
303 ++dest->length;
|
|
304 return 1;
|
|
305 }
|
|
306
|
|
307 /* Append S to DS, resizing DS if necessary. Returns 1 on success.
|
|
308 On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
|
|
309 returns 0. */
|
|
310
|
|
311 int
|
|
312 dyn_string_append (dyn_string_t dest, dyn_string_t s)
|
|
313 {
|
|
314 if (dyn_string_resize (dest, dest->length + s->length) == 0)
|
|
315 return 0;
|
|
316 strcpy (dest->s + dest->length, s->s);
|
|
317 dest->length += s->length;
|
|
318 return 1;
|
|
319 }
|
|
320
|
|
321 /* Append the NUL-terminated string S to DS, resizing DS if necessary.
|
|
322 Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
|
|
323 deletes DEST and returns 0. */
|
|
324
|
|
325 int
|
|
326 dyn_string_append_cstr (dyn_string_t dest, const char *s)
|
|
327 {
|
|
328 int len = strlen (s);
|
|
329
|
|
330 /* The new length is the old length plus the size of our string, plus
|
|
331 one for the null at the end. */
|
|
332 if (dyn_string_resize (dest, dest->length + len) == NULL)
|
|
333 return 0;
|
|
334 strcpy (dest->s + dest->length, s);
|
|
335 dest->length += len;
|
|
336 return 1;
|
|
337 }
|
|
338
|
|
339 /* Appends C to the end of DEST. Returns 1 on success. On failiure,
|
|
340 if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
|
|
341
|
|
342 int
|
|
343 dyn_string_append_char (dyn_string_t dest, int c)
|
|
344 {
|
|
345 /* Make room for the extra character. */
|
|
346 if (dyn_string_resize (dest, dest->length + 1) == NULL)
|
|
347 return 0;
|
|
348 /* Append the character; it will overwrite the old NUL. */
|
|
349 dest->s[dest->length] = c;
|
|
350 /* Add a new NUL at the end. */
|
|
351 dest->s[dest->length + 1] = '\0';
|
|
352 /* Update the length. */
|
|
353 ++(dest->length);
|
|
354 return 1;
|
|
355 }
|
|
356
|
|
357 /* Sets the contents of DEST to the substring of SRC starting at START
|
|
358 and ending before END. START must be less than or equal to END,
|
|
359 and both must be between zero and the length of SRC, inclusive.
|
|
360 Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
|
|
361 deletes DEST and returns 0. */
|
|
362
|
|
363 int
|
|
364 dyn_string_substring (dyn_string_t dest, dyn_string_t src,
|
|
365 int start, int end)
|
|
366 {
|
|
367 int i;
|
|
368 int length = end - start;
|
|
369
|
|
370 if (start > end || start > src->length || end > src->length)
|
|
371 abort ();
|
|
372
|
|
373 /* Make room for the substring. */
|
|
374 if (dyn_string_resize (dest, length) == NULL)
|
|
375 return 0;
|
|
376 /* Copy the characters in the substring, */
|
|
377 for (i = length; --i >= 0; )
|
|
378 dest->s[i] = src->s[start + i];
|
|
379 /* NUL-terimate the result. */
|
|
380 dest->s[length] = '\0';
|
|
381 /* Record the length of the substring. */
|
|
382 dest->length = length;
|
|
383
|
|
384 return 1;
|
|
385 }
|
|
386
|
|
387 /* Returns non-zero if DS1 and DS2 have the same contents. */
|
|
388
|
|
389 int
|
|
390 dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
|
|
391 {
|
|
392 /* If DS1 and DS2 have different lengths, they must not be the same. */
|
|
393 if (ds1->length != ds2->length)
|
|
394 return 0;
|
|
395 else
|
|
396 return !strcmp (ds1->s, ds2->s);
|
|
397 }
|