1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2017 SRI International.
4 *
5 * Yices is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Yices is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Yices. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * Resizable string buffers
21 */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <assert.h>
27
28 #include "utils/memalloc.h"
29 #include "utils/string_buffers.h"
30
31
32 /*
33 * Initialize: n = initial size
34 */
init_string_buffer(string_buffer_t * s,uint32_t n)35 void init_string_buffer(string_buffer_t *s, uint32_t n) {
36 s->size = n;
37 s->index = 0;
38 s->data = NULL;
39 if (n > 0) {
40 s->data = (char *) safe_malloc(n);
41 }
42 }
43
44
45 /*
46 * Expand: make room for at least n extra characters after index.
47 */
string_buffer_extend(string_buffer_t * s,uint32_t n)48 static void string_buffer_extend(string_buffer_t *s, uint32_t n) {
49 uint32_t p;
50
51 n += s->index;
52 if (n < s->index) {
53 // integer overflow: can't make s large enough
54 out_of_memory();
55 }
56
57 // try 50% larger. If that's still too small, take n as the new size
58 p = s->size;
59 if (p < n) {
60 p ++;
61 p += p>>1;
62 if (p < n) p = n;
63
64 s->data = (char *) safe_realloc(s->data, p);
65 s->size = p;
66 }
67 }
68
69
70 /*
71 * Faster version: make room for one character
72 */
string_buffer_extend1(string_buffer_t * s)73 static void string_buffer_extend1(string_buffer_t *s) {
74 uint32_t p;
75
76 if (s->index == s->size) {
77 if (s->size == UINT32_MAX) {
78 out_of_memory();
79 }
80 p = s->size + 1;
81 p += p>>1;
82
83 s->data = (char *) safe_realloc(s->data, p);
84 s->size = p;
85 }
86 }
87
88
89 /*
90 * Delete: free data array
91 */
delete_string_buffer(string_buffer_t * s)92 void delete_string_buffer(string_buffer_t *s) {
93 safe_free(s->data);
94 s->data = NULL;
95 s->size = 0;
96 s->index = 0;
97 }
98
99
100 /*
101 * Close: append '\0', do not increment the index
102 */
string_buffer_close(string_buffer_t * s)103 void string_buffer_close(string_buffer_t *s) {
104 string_buffer_extend1(s);
105 s->data[s->index] = '\0';
106 }
107
108
109 /*
110 * Append operations
111 */
string_buffer_append_char(string_buffer_t * s,char c)112 void string_buffer_append_char(string_buffer_t *s, char c) {
113 string_buffer_extend1(s);
114 s->data[s->index] = c;
115 s->index ++;
116 }
117
118 // s1 must be null-terminated, the '\0' is not copied in s
string_buffer_append_string(string_buffer_t * s,const char * s1)119 void string_buffer_append_string(string_buffer_t *s, const char *s1) {
120 size_t n;
121
122 n = strlen(s1);
123 if (n > UINT32_MAX) {
124 out_of_memory();
125 }
126 string_buffer_extend(s, (uint32_t) n);
127 memcpy(s->data + s->index, s1, n);
128 s->index += n;
129 }
130
string_buffer_append_buffer(string_buffer_t * s,string_buffer_t * s1)131 void string_buffer_append_buffer(string_buffer_t *s, string_buffer_t *s1) {
132 uint32_t n;
133
134 n = string_buffer_length(s1);
135 string_buffer_extend(s, n);
136 memcpy(s->data + s->index, s1->data, n);
137 s->index += n;
138 }
139
140
string_buffer_append_int32(string_buffer_t * s,int32_t x)141 void string_buffer_append_int32(string_buffer_t *s, int32_t x) {
142 int32_t n;
143 // max space to print a 32bit number in decimal is
144 // 12 character (including sign and trailing zero)
145 string_buffer_extend(s, 12);
146 n = sprintf(s->data + s->index, "%"PRId32, x);
147 assert(n <= 12 && n > 0);
148 s->index += n;
149 }
150
string_buffer_append_uint32(string_buffer_t * s,uint32_t x)151 void string_buffer_append_uint32(string_buffer_t *s, uint32_t x) {
152 int32_t n;
153 // max space to print a 32bit number in decimal is
154 // 12 character (including sign and trailing zero)
155 string_buffer_extend(s, 12);
156 n = sprintf(s->data + s->index, "%"PRIu32, x);
157 assert(n <= 12 && n > 0);
158 s->index += n;
159 }
160
string_buffer_append_double(string_buffer_t * s,double x)161 void string_buffer_append_double(string_buffer_t *s, double x) {
162 int32_t n, size;
163
164 size = 0;
165 do {
166 size += 100;
167 string_buffer_extend(s, size);
168 n = snprintf(s->data + s->index, size, "%f", x);
169 assert(n > 0);
170 } while (n >= s->size);
171
172 s->index += n;
173 }
174
string_buffer_append_mpz(string_buffer_t * s,mpz_t z)175 void string_buffer_append_mpz(string_buffer_t *s, mpz_t z) {
176 size_t n;
177 char *s0;
178
179 // sizeinbase may overestimate the actual length by one
180 n = mpz_sizeinbase(z, 10);
181 if (n > UINT32_MAX - 2) {
182 out_of_memory();
183 }
184 string_buffer_extend(s, (uint32_t) (n + 2));
185 s0 = s->data + s->index;
186 mpz_get_str(s0, 10, z);
187 // we can't use n here
188 s->index += strlen(s0);
189 }
190
string_buffer_append_mpq(string_buffer_t * s,mpq_t q)191 void string_buffer_append_mpq(string_buffer_t *s, mpq_t q) {
192 size_t n1, n;
193 char *s0;
194
195 n1 = mpz_sizeinbase(mpq_numref(q), 10);
196 n = n1 + mpz_sizeinbase(mpq_denref(q), 10);
197 if (n > UINT32_MAX - 3 || n < n1) {
198 // too large or numerical overflow
199 out_of_memory();
200 }
201 string_buffer_extend(s, (uint32_t) (n + 3));
202 s0 = s->data + s->index;
203 mpq_get_str(s0, 10, q);
204 s->index += strlen(s0);
205 }
206
string_buffer_append_rational(string_buffer_t * s,rational_t * r)207 void string_buffer_append_rational(string_buffer_t *s, rational_t *r) {
208 if (is_ratgmp(r)) {
209 string_buffer_append_mpq(s, get_gmp(r));
210 } else {
211 string_buffer_append_int32(s, get_num(r));
212 if (get_den(r) != 1) {
213 string_buffer_append_char(s, '/');
214 string_buffer_append_uint32(s, get_den(r));
215 }
216 }
217 }
218
string_buffer_append_bvconst(string_buffer_t * s,uint32_t * bv,uint32_t n)219 void string_buffer_append_bvconst(string_buffer_t *s, uint32_t *bv, uint32_t n) {
220 char *s0;
221
222 assert(n>0);
223 string_buffer_extend(s, n);
224 s0 = s->data + s->index;
225 s->index += n;
226
227 do {
228 n --;
229 *s0 ++ = bvconst_tst_bit(bv, n) ? '1' : '0';
230 } while (n>0);
231 }
232
233
234 /*
235 * Print the full buffer
236 */
string_buffer_print(FILE * f,string_buffer_t * s)237 void string_buffer_print(FILE *f, string_buffer_t *s) {
238 string_buffer_close(s);
239 fputs(s->data, f);
240 }
241
242
243 /*
244 * Export:
245 * - close the string (add '\0') then return it
246 * - store the string's size in *len
247 * - then reset the buffer.
248 */
string_buffer_export(string_buffer_t * s,uint32_t * len)249 char *string_buffer_export(string_buffer_t *s, uint32_t *len) {
250 char *tmp;
251
252 string_buffer_close(s);
253 tmp = s->data;
254 *len = s->index;
255
256 // reset to an empty buffer
257 s->size = 0;
258 s->index = 0;
259 s->data = NULL;
260
261 return tmp;
262 }
263
264