1/* sb.c - string buffer manipulation routines 2 Copyright (C) 1994-2022 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#include <limits.h> 28#ifndef CHAR_BIT 29#define CHAR_BIT 8 30#endif 31 32/* These routines are about manipulating strings. 33 34 They are managed in things called `sb's which is an abbreviation 35 for string buffers. An sb has to be created, things can be glued 36 on to it, and at the end of it's life it should be freed. The 37 contents should never be pointed at whilst it is still growing, 38 since it could be moved at any time 39 40 eg: 41 sb_new (&foo); 42 sb_grow... (&foo,...); 43 use foo->ptr[*]; 44 sb_kill (&foo); */ 45 46/* Buffers start at INIT_ALLOC size, and roughly double each time we 47 go over the current allocation. MALLOC_OVERHEAD is a guess at the 48 system malloc overhead. We aim to not waste any memory in the 49 underlying page/chunk allocated by the system malloc. */ 50#define MALLOC_OVERHEAD (2 * sizeof (size_t)) 51#define INIT_ALLOC (64 - MALLOC_OVERHEAD - 1) 52 53static void sb_check (sb *, size_t); 54 55/* Initializes an sb. */ 56 57void 58sb_build (sb *ptr, size_t size) 59{ 60 ptr->ptr = XNEWVEC (char, size + 1); 61 ptr->max = size; 62 ptr->len = 0; 63} 64 65void 66sb_new (sb *ptr) 67{ 68 sb_build (ptr, INIT_ALLOC); 69} 70 71/* Deallocate the sb at ptr. */ 72 73void 74sb_kill (sb *ptr) 75{ 76 free (ptr->ptr); 77} 78 79/* Add the sb at s to the end of the sb at ptr. */ 80 81void 82sb_add_sb (sb *ptr, sb *s) 83{ 84 sb_check (ptr, s->len); 85 memcpy (ptr->ptr + ptr->len, s->ptr, s->len); 86 ptr->len += s->len; 87} 88 89/* Helper for sb_scrub_and_add_sb. */ 90 91static sb *sb_to_scrub; 92static char *scrub_position; 93static size_t 94scrub_from_sb (char *buf, size_t buflen) 95{ 96 size_t copy; 97 copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr); 98 if (copy > buflen) 99 copy = buflen; 100 memcpy (buf, scrub_position, copy); 101 scrub_position += copy; 102 return copy; 103} 104 105/* Run the sb at s through do_scrub_chars and add the result to the sb 106 at ptr. */ 107 108void 109sb_scrub_and_add_sb (sb *ptr, sb *s) 110{ 111 sb_to_scrub = s; 112 scrub_position = s->ptr; 113 114 /* do_scrub_chars can expand text, for example when replacing 115 # 123 "filename" 116 with 117 \t.linefile 123 "filename" 118 or when replacing a 'c with the decimal ascii number for c. 119 So we loop until the input S is consumed. */ 120 while (1) 121 { 122 size_t copy = s->len - (scrub_position - s->ptr) + do_scrub_pending (); 123 if (copy == 0) 124 break; 125 sb_check (ptr, copy); 126 ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len, 127 ptr->max - ptr->len); 128 } 129 130 sb_to_scrub = 0; 131 scrub_position = 0; 132} 133 134/* Make sure that the sb at ptr has room for another len characters, 135 and grow it if it doesn't. */ 136 137static void 138sb_check (sb *ptr, size_t len) 139{ 140 size_t want = ptr->len + len; 141 142 if (want > ptr->max) 143 { 144 size_t max; 145 146 want += MALLOC_OVERHEAD + 1; 147 if ((ssize_t) want < 0) 148 as_fatal ("string buffer overflow"); 149#if GCC_VERSION >= 3004 150 max = (size_t) 1 << (CHAR_BIT * sizeof (want) 151 - (sizeof (want) <= sizeof (long) 152 ? __builtin_clzl ((long) want) 153 : __builtin_clzll ((long long) want))); 154#else 155 max = 128; 156 while (want > max) 157 max <<= 1; 158#endif 159 max -= MALLOC_OVERHEAD + 1; 160 ptr->max = max; 161 ptr->ptr = XRESIZEVEC (char, ptr->ptr, max + 1); 162 } 163} 164 165/* Make the sb at ptr point back to the beginning. */ 166 167void 168sb_reset (sb *ptr) 169{ 170 ptr->len = 0; 171} 172 173/* Add character c to the end of the sb at ptr. */ 174 175void 176sb_add_char (sb *ptr, size_t c) 177{ 178 sb_check (ptr, 1); 179 ptr->ptr[ptr->len++] = c; 180} 181 182/* Add null terminated string s to the end of sb at ptr. */ 183 184void 185sb_add_string (sb *ptr, const char *s) 186{ 187 size_t len = strlen (s); 188 sb_check (ptr, len); 189 memcpy (ptr->ptr + ptr->len, s, len); 190 ptr->len += len; 191} 192 193/* Add string at s of length len to sb at ptr */ 194 195void 196sb_add_buffer (sb *ptr, const char *s, size_t len) 197{ 198 sb_check (ptr, len); 199 memcpy (ptr->ptr + ptr->len, s, len); 200 ptr->len += len; 201} 202 203/* Write terminating NUL and return string. */ 204 205char * 206sb_terminate (sb *in) 207{ 208 in->ptr[in->len] = 0; 209 return in->ptr; 210} 211 212/* Start at the index idx into the string in sb at ptr and skip 213 whitespace. return the index of the first non whitespace character. */ 214 215size_t 216sb_skip_white (size_t idx, sb *ptr) 217{ 218 while (idx < ptr->len 219 && (ptr->ptr[idx] == ' ' 220 || ptr->ptr[idx] == '\t')) 221 idx++; 222 return idx; 223} 224 225/* Start at the index idx into the sb at ptr. skips whitespace, 226 a comma and any following whitespace. returns the index of the 227 next character. */ 228 229size_t 230sb_skip_comma (size_t idx, sb *ptr) 231{ 232 while (idx < ptr->len 233 && (ptr->ptr[idx] == ' ' 234 || ptr->ptr[idx] == '\t')) 235 idx++; 236 237 if (idx < ptr->len 238 && ptr->ptr[idx] == ',') 239 idx++; 240 241 while (idx < ptr->len 242 && (ptr->ptr[idx] == ' ' 243 || ptr->ptr[idx] == '\t')) 244 idx++; 245 246 return idx; 247} 248