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