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