1 /* sb.c - string buffer manipulation routines 2 Copyright (C) 1994-2020 Free Software Foundation, Inc. 3 4 Written by Steve and Judy Chamberlain of Cygnus Support, 5 sac@cygnus.com 6 7 This file is part of GAS, the GNU Assembler. 8 9 GAS 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 3, or (at your option) 12 any later version. 13 14 GAS is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with GAS; see the file COPYING. If not, write to the Free 21 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 22 02110-1301, USA. */ 23 24 #include "as.h" 25 #include "sb.h" 26 27 #ifdef HAVE_LIMITS_H 28 #include <limits.h> 29 #endif 30 #ifndef CHAR_BIT 31 #define CHAR_BIT 8 32 #endif 33 34 /* These routines are about manipulating strings. 35 36 They are managed in things called `sb's which is an abbreviation 37 for string buffers. An sb has to be created, things can be glued 38 on to it, and at the end of it's life it should be freed. The 39 contents should never be pointed at whilst it is still growing, 40 since it could be moved at any time 41 42 eg: 43 sb_new (&foo); 44 sb_grow... (&foo,...); 45 use foo->ptr[*]; 46 sb_kill (&foo); */ 47 48 /* Buffers start at INIT_ALLOC size, and roughly double each time we 49 go over the current allocation. MALLOC_OVERHEAD is a guess at the 50 system malloc overhead. We aim to not waste any memory in the 51 underlying page/chunk allocated by the system malloc. */ 52 #define MALLOC_OVERHEAD (2 * sizeof (size_t)) 53 #define INIT_ALLOC (64 - MALLOC_OVERHEAD - 1) 54 55 static void sb_check (sb *, size_t); 56 57 /* Initializes an sb. */ 58 59 void 60 sb_build (sb *ptr, size_t size) 61 { 62 ptr->ptr = XNEWVEC (char, size + 1); 63 ptr->max = size; 64 ptr->len = 0; 65 } 66 67 void 68 sb_new (sb *ptr) 69 { 70 sb_build (ptr, INIT_ALLOC); 71 } 72 73 /* Deallocate the sb at ptr. */ 74 75 void 76 sb_kill (sb *ptr) 77 { 78 free (ptr->ptr); 79 } 80 81 /* Add the sb at s to the end of the sb at ptr. */ 82 83 void 84 sb_add_sb (sb *ptr, sb *s) 85 { 86 sb_check (ptr, s->len); 87 memcpy (ptr->ptr + ptr->len, s->ptr, s->len); 88 ptr->len += s->len; 89 } 90 91 /* Helper for sb_scrub_and_add_sb. */ 92 93 static sb *sb_to_scrub; 94 static char *scrub_position; 95 static size_t 96 scrub_from_sb (char *buf, size_t buflen) 97 { 98 size_t copy; 99 copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr); 100 if (copy > buflen) 101 copy = buflen; 102 memcpy (buf, scrub_position, copy); 103 scrub_position += copy; 104 return copy; 105 } 106 107 /* Run the sb at s through do_scrub_chars and add the result to the sb 108 at ptr. */ 109 110 void 111 sb_scrub_and_add_sb (sb *ptr, sb *s) 112 { 113 sb_to_scrub = s; 114 scrub_position = s->ptr; 115 116 sb_check (ptr, s->len); 117 ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len, s->len); 118 119 sb_to_scrub = 0; 120 scrub_position = 0; 121 } 122 123 /* Make sure that the sb at ptr has room for another len characters, 124 and grow it if it doesn't. */ 125 126 static void 127 sb_check (sb *ptr, size_t len) 128 { 129 size_t want = ptr->len + len; 130 131 if (want > ptr->max) 132 { 133 size_t max; 134 135 want += MALLOC_OVERHEAD + 1; 136 if ((ssize_t) want < 0) 137 as_fatal ("string buffer overflow"); 138 #if GCC_VERSION >= 3004 139 max = (size_t) 1 << (CHAR_BIT * sizeof (want) 140 - (sizeof (want) <= sizeof (long) 141 ? __builtin_clzl ((long) want) 142 : __builtin_clzll ((long long) want))); 143 #else 144 max = 128; 145 while (want > max) 146 max <<= 1; 147 #endif 148 max -= MALLOC_OVERHEAD + 1; 149 ptr->max = max; 150 ptr->ptr = XRESIZEVEC (char, ptr->ptr, max + 1); 151 } 152 } 153 154 /* Make the sb at ptr point back to the beginning. */ 155 156 void 157 sb_reset (sb *ptr) 158 { 159 ptr->len = 0; 160 } 161 162 /* Add character c to the end of the sb at ptr. */ 163 164 void 165 sb_add_char (sb *ptr, size_t c) 166 { 167 sb_check (ptr, 1); 168 ptr->ptr[ptr->len++] = c; 169 } 170 171 /* Add null terminated string s to the end of sb at ptr. */ 172 173 void 174 sb_add_string (sb *ptr, const char *s) 175 { 176 size_t len = strlen (s); 177 sb_check (ptr, len); 178 memcpy (ptr->ptr + ptr->len, s, len); 179 ptr->len += len; 180 } 181 182 /* Add string at s of length len to sb at ptr */ 183 184 void 185 sb_add_buffer (sb *ptr, const char *s, size_t len) 186 { 187 sb_check (ptr, len); 188 memcpy (ptr->ptr + ptr->len, s, len); 189 ptr->len += len; 190 } 191 192 /* Write terminating NUL and return string. */ 193 194 char * 195 sb_terminate (sb *in) 196 { 197 in->ptr[in->len] = 0; 198 return in->ptr; 199 } 200 201 /* Start at the index idx into the string in sb at ptr and skip 202 whitespace. return the index of the first non whitespace character. */ 203 204 size_t 205 sb_skip_white (size_t idx, sb *ptr) 206 { 207 while (idx < ptr->len 208 && (ptr->ptr[idx] == ' ' 209 || ptr->ptr[idx] == '\t')) 210 idx++; 211 return idx; 212 } 213 214 /* Start at the index idx into the sb at ptr. skips whitespace, 215 a comma and any following whitespace. returns the index of the 216 next character. */ 217 218 size_t 219 sb_skip_comma (size_t idx, sb *ptr) 220 { 221 while (idx < ptr->len 222 && (ptr->ptr[idx] == ' ' 223 || ptr->ptr[idx] == '\t')) 224 idx++; 225 226 if (idx < ptr->len 227 && ptr->ptr[idx] == ',') 228 idx++; 229 230 while (idx < ptr->len 231 && (ptr->ptr[idx] == ' ' 232 || ptr->ptr[idx] == '\t')) 233 idx++; 234 235 return idx; 236 } 237