Rev 5222 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5222 | serge | 1 | /* sb.c - string buffer manipulation routines |
6324 | serge | 2 | Copyright (C) 1994-2015 Free Software Foundation, Inc. |
5222 | serge | 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 |
||
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 = xmalloc (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 = xrealloc (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 | }>>>>=><=>=>><>> |