/src/binutils-gdb/gas/sb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* sb.c - string buffer manipulation routines |
2 | | Copyright (C) 1994-2025 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 | 21.5k | #define MALLOC_OVERHEAD (2 * sizeof (size_t)) |
51 | 16.8k | #define INIT_ALLOC (64 - MALLOC_OVERHEAD - 1) |
52 | | |
53 | | static void sb_check (sb *, size_t); |
54 | | |
55 | | /* Initializes an sb. */ |
56 | | |
57 | | void |
58 | | sb_build (sb *ptr, size_t size) |
59 | 20.1k | { |
60 | 20.1k | ptr->ptr = XNEWVEC (char, size + 1); |
61 | 20.1k | ptr->max = size; |
62 | 20.1k | ptr->len = 0; |
63 | 20.1k | } |
64 | | |
65 | | void |
66 | | sb_new (sb *ptr) |
67 | 16.8k | { |
68 | 16.8k | sb_build (ptr, INIT_ALLOC); |
69 | 16.8k | } |
70 | | |
71 | | /* Deallocate the sb at ptr. */ |
72 | | |
73 | | void |
74 | | sb_kill (sb *ptr) |
75 | 18.7k | { |
76 | 18.7k | free (ptr->ptr); |
77 | 18.7k | } |
78 | | |
79 | | /* Add the sb at s to the end of the sb at ptr. */ |
80 | | |
81 | | void |
82 | | sb_add_sb (sb *ptr, sb *s) |
83 | 58.4k | { |
84 | 58.4k | sb_check (ptr, s->len); |
85 | 58.4k | memcpy (ptr->ptr + ptr->len, s->ptr, s->len); |
86 | 58.4k | ptr->len += s->len; |
87 | 58.4k | } |
88 | | |
89 | | /* Helper for sb_scrub_and_add_sb. */ |
90 | | |
91 | | static sb *sb_to_scrub; |
92 | | static char *scrub_position; |
93 | | static size_t |
94 | | scrub_from_sb (char *buf, size_t buflen) |
95 | 2.92k | { |
96 | 2.92k | size_t copy; |
97 | 2.92k | copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr); |
98 | 2.92k | if (copy > buflen) |
99 | 448 | copy = buflen; |
100 | 2.92k | memcpy (buf, scrub_position, copy); |
101 | 2.92k | scrub_position += copy; |
102 | 2.92k | return copy; |
103 | 2.92k | } |
104 | | |
105 | | /* Run the sb at s through do_scrub_chars and add the result to the sb |
106 | | at ptr. */ |
107 | | |
108 | | void |
109 | | sb_scrub_and_add_sb (sb *ptr, sb *s) |
110 | 1.38k | { |
111 | 1.38k | sb_to_scrub = s; |
112 | 1.38k | 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 | 2.56k | while (1) |
121 | 2.56k | { |
122 | 2.56k | size_t copy = s->len - (scrub_position - s->ptr) + do_scrub_pending (); |
123 | 2.56k | if (copy == 0) |
124 | 1.38k | break; |
125 | 1.18k | sb_check (ptr, copy); |
126 | 1.18k | ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len, |
127 | 1.18k | ptr->max - ptr->len, false); |
128 | 1.18k | } |
129 | | |
130 | 1.38k | sb_to_scrub = 0; |
131 | 1.38k | scrub_position = 0; |
132 | 1.38k | } |
133 | | |
134 | | /* Make sure that the sb at ptr has room for another len characters, |
135 | | and grow it if it doesn't. */ |
136 | | |
137 | | static void |
138 | | sb_check (sb *ptr, size_t len) |
139 | 455k | { |
140 | 455k | size_t want = ptr->len + len; |
141 | | |
142 | 455k | if (want > ptr->max) |
143 | 2.35k | { |
144 | 2.35k | size_t max; |
145 | | |
146 | 2.35k | want += MALLOC_OVERHEAD + 1; |
147 | 2.35k | if ((ssize_t) want < 0) |
148 | 0 | as_fatal ("string buffer overflow"); |
149 | 2.35k | #if GCC_VERSION >= 3004 |
150 | 2.35k | max = (size_t) 1 << (CHAR_BIT * sizeof (want) |
151 | 2.35k | - (sizeof (want) <= sizeof (long) |
152 | 2.35k | ? __builtin_clzl ((long) want) |
153 | 2.35k | : __builtin_clzll ((long long) want))); |
154 | | #else |
155 | | max = 128; |
156 | | while (want > max) |
157 | | max <<= 1; |
158 | | #endif |
159 | 2.35k | max -= MALLOC_OVERHEAD + 1; |
160 | 2.35k | ptr->max = max; |
161 | 2.35k | ptr->ptr = XRESIZEVEC (char, ptr->ptr, max + 1); |
162 | 2.35k | } |
163 | 455k | } |
164 | | |
165 | | /* Make the sb at ptr point back to the beginning. */ |
166 | | |
167 | | void |
168 | | sb_reset (sb *ptr) |
169 | 25.5k | { |
170 | 25.5k | ptr->len = 0; |
171 | 25.5k | } |
172 | | |
173 | | /* Add character c to the end of the sb at ptr. */ |
174 | | |
175 | | void |
176 | | sb_add_char (sb *ptr, char c) |
177 | 381k | { |
178 | 381k | sb_check (ptr, 1); |
179 | 381k | ptr->ptr[ptr->len++] = c; |
180 | 381k | } |
181 | | |
182 | | /* Add null terminated string s to the end of sb at ptr. */ |
183 | | |
184 | | void |
185 | | sb_add_string (sb *ptr, const char *s) |
186 | 3.42k | { |
187 | 3.42k | size_t len = strlen (s); |
188 | 3.42k | sb_check (ptr, len); |
189 | 3.42k | memcpy (ptr->ptr + ptr->len, s, len); |
190 | 3.42k | ptr->len += len; |
191 | 3.42k | } |
192 | | |
193 | | /* Add string at s of length len to sb at ptr */ |
194 | | |
195 | | void |
196 | | sb_add_buffer (sb *ptr, const char *s, size_t len) |
197 | 10.8k | { |
198 | 10.8k | sb_check (ptr, len); |
199 | 10.8k | memcpy (ptr->ptr + ptr->len, s, len); |
200 | 10.8k | ptr->len += len; |
201 | 10.8k | } |
202 | | |
203 | | /* Write terminating NUL and return string. */ |
204 | | |
205 | | char * |
206 | | sb_terminate (sb *in) |
207 | 25.4k | { |
208 | 25.4k | in->ptr[in->len] = 0; |
209 | 25.4k | return in->ptr; |
210 | 25.4k | } |
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 | | |
215 | | size_t |
216 | | sb_skip_white (size_t idx, sb *ptr) |
217 | 29.9k | { |
218 | 31.7k | while (idx < ptr->len && is_whitespace (ptr->ptr[idx])) |
219 | 1.82k | idx++; |
220 | 29.9k | return idx; |
221 | 29.9k | } |
222 | | |
223 | | /* Start at the index idx into the sb at ptr. skips whitespace, |
224 | | a comma and any following whitespace. returns the index of the |
225 | | next character. */ |
226 | | |
227 | | size_t |
228 | | sb_skip_comma (size_t idx, sb *ptr) |
229 | 2.48k | { |
230 | 2.50k | while (idx < ptr->len && is_whitespace (ptr->ptr[idx])) |
231 | 19 | idx++; |
232 | | |
233 | 2.48k | if (idx < ptr->len |
234 | 2.48k | && ptr->ptr[idx] == ',') |
235 | 680 | idx++; |
236 | | |
237 | 2.48k | while (idx < ptr->len && is_whitespace (ptr->ptr[idx])) |
238 | 0 | idx++; |
239 | | |
240 | 2.48k | return idx; |
241 | 2.48k | } |