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