1 |
|
|
/* $OpenBSD: inout.c,v 1.20 2017/02/26 11:29:55 otto Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <ctype.h> |
20 |
|
|
#include <err.h> |
21 |
|
|
#include <string.h> |
22 |
|
|
|
23 |
|
|
#include "extern.h" |
24 |
|
|
|
25 |
|
|
#define MAX_CHARS_PER_LINE 68 |
26 |
|
|
|
27 |
|
|
static int lastchar; |
28 |
|
|
static int charcount; |
29 |
|
|
|
30 |
|
|
static int src_getcharstream(struct source *); |
31 |
|
|
static void src_ungetcharstream(struct source *); |
32 |
|
|
static char *src_getlinestream(struct source *); |
33 |
|
|
static void src_freestream(struct source *); |
34 |
|
|
static int src_getcharstring(struct source *); |
35 |
|
|
static void src_ungetcharstring(struct source *); |
36 |
|
|
static char *src_getlinestring(struct source *); |
37 |
|
|
static void src_freestring(struct source *); |
38 |
|
|
static void flushwrap(FILE *); |
39 |
|
|
static void putcharwrap(FILE *, int); |
40 |
|
|
static void printwrap(FILE *, const char *); |
41 |
|
|
static char *get_digit(u_long, int, u_int); |
42 |
|
|
|
43 |
|
|
static struct vtable stream_vtable = { |
44 |
|
|
src_getcharstream, |
45 |
|
|
src_ungetcharstream, |
46 |
|
|
src_getlinestream, |
47 |
|
|
src_freestream |
48 |
|
|
}; |
49 |
|
|
|
50 |
|
|
static struct vtable string_vtable = { |
51 |
|
|
src_getcharstring, |
52 |
|
|
src_ungetcharstring, |
53 |
|
|
src_getlinestring, |
54 |
|
|
src_freestring |
55 |
|
|
}; |
56 |
|
|
|
57 |
|
|
void |
58 |
|
|
src_setstream(struct source *src, FILE *stream) |
59 |
|
|
{ |
60 |
|
4152 |
src->u.stream = stream; |
61 |
|
2076 |
src->vtable = &stream_vtable; |
62 |
|
2076 |
} |
63 |
|
|
|
64 |
|
|
void |
65 |
|
|
src_setstring(struct source *src, char *p) |
66 |
|
|
{ |
67 |
|
61864 |
src->u.string.buf = (u_char *)p; |
68 |
|
30932 |
src->u.string.pos = 0; |
69 |
|
30932 |
src->vtable = &string_vtable; |
70 |
|
30932 |
} |
71 |
|
|
|
72 |
|
|
static int |
73 |
|
|
src_getcharstream(struct source *src) |
74 |
|
|
{ |
75 |
✓✗✓✓
|
27330800 |
return src->lastchar = getc(src->u.stream); |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
static void |
79 |
|
|
src_ungetcharstream(struct source *src) |
80 |
|
|
{ |
81 |
|
28816 |
(void)ungetc(src->lastchar, src->u.stream); |
82 |
|
14408 |
} |
83 |
|
|
|
84 |
|
|
/* ARGSUSED */ |
85 |
|
|
static void |
86 |
|
|
src_freestream(struct source *src) |
87 |
|
|
{ |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
static char * |
91 |
|
|
src_getlinestream(struct source *src) |
92 |
|
|
{ |
93 |
|
|
char buf[BUFSIZ]; |
94 |
|
|
|
95 |
|
|
if (fgets(buf, BUFSIZ, src->u.stream) == NULL) |
96 |
|
|
return bstrdup(""); |
97 |
|
|
return bstrdup(buf); |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
static int |
101 |
|
|
src_getcharstring(struct source *src) |
102 |
|
|
{ |
103 |
|
4402984 |
src->lastchar = src->u.string.buf[src->u.string.pos]; |
104 |
✓✓ |
2201492 |
if (src->lastchar == '\0') |
105 |
|
39148 |
return EOF; |
106 |
|
|
else { |
107 |
|
2162344 |
src->u.string.pos++; |
108 |
|
2162344 |
return src->lastchar; |
109 |
|
|
} |
110 |
|
2201492 |
} |
111 |
|
|
|
112 |
|
|
static void |
113 |
|
|
src_ungetcharstring(struct source *src) |
114 |
|
|
{ |
115 |
✓✗ |
737232 |
if (src->u.string.pos > 0) { |
116 |
✓✓ |
368616 |
if (src->lastchar != '\0') |
117 |
|
350012 |
--src->u.string.pos; |
118 |
|
|
} |
119 |
|
368616 |
} |
120 |
|
|
|
121 |
|
|
static char * |
122 |
|
|
src_getlinestring(struct source *src) |
123 |
|
|
{ |
124 |
|
|
char buf[BUFSIZ]; |
125 |
|
|
int ch, i; |
126 |
|
|
|
127 |
|
|
i = 0; |
128 |
|
|
while (i < BUFSIZ-1) { |
129 |
|
|
ch = src_getcharstring(src); |
130 |
|
|
if (ch == EOF) |
131 |
|
|
break; |
132 |
|
|
buf[i++] = ch; |
133 |
|
|
if (ch == '\n') |
134 |
|
|
break; |
135 |
|
|
} |
136 |
|
|
buf[i] = '\0'; |
137 |
|
|
return bstrdup(buf); |
138 |
|
|
} |
139 |
|
|
|
140 |
|
|
static void |
141 |
|
|
src_freestring(struct source *src) |
142 |
|
|
{ |
143 |
|
61864 |
free(src->u.string.buf); |
144 |
|
30932 |
} |
145 |
|
|
|
146 |
|
|
static void |
147 |
|
|
flushwrap(FILE *f) |
148 |
|
|
{ |
149 |
✓✗ |
4152 |
if (lastchar != -1) |
150 |
✓✗ |
4152 |
(void)putc(lastchar, f); |
151 |
|
2076 |
} |
152 |
|
|
|
153 |
|
|
static void |
154 |
|
|
putcharwrap(FILE *f, int ch) |
155 |
|
|
{ |
156 |
✗✓ |
54648 |
if (charcount >= MAX_CHARS_PER_LINE) { |
157 |
|
|
charcount = 0; |
158 |
|
|
(void)fputs("\\\n", f); |
159 |
|
|
} |
160 |
✓✓ |
27324 |
if (lastchar != -1) { |
161 |
|
25248 |
charcount++; |
162 |
✓✗ |
50496 |
(void)putc(lastchar, f); |
163 |
|
|
} |
164 |
|
27324 |
lastchar = ch; |
165 |
|
27324 |
} |
166 |
|
|
|
167 |
|
|
static void |
168 |
|
|
printwrap(FILE *f, const char *p) |
169 |
|
|
{ |
170 |
|
48944 |
char buf[12]; |
171 |
|
24472 |
char *q = buf; |
172 |
|
|
|
173 |
|
24472 |
(void)strlcpy(buf, p, sizeof(buf)); |
174 |
✓✓ |
97888 |
while (*q) |
175 |
|
24472 |
putcharwrap(f, *q++); |
176 |
|
24472 |
} |
177 |
|
|
|
178 |
|
|
struct number * |
179 |
|
|
readnumber(struct source *src, u_int base) |
180 |
|
|
{ |
181 |
|
|
struct number *n; |
182 |
|
|
int ch; |
183 |
|
|
bool sign = false; |
184 |
|
|
bool dot = false; |
185 |
|
|
BN_ULONG v; |
186 |
|
|
u_int i; |
187 |
|
|
|
188 |
|
320664 |
n = new_number(); |
189 |
|
160332 |
bn_check(BN_set_word(n->number, 0)); |
190 |
|
|
|
191 |
✓✗ |
881092 |
while ((ch = (*src->vtable->readchar)(src)) != EOF) { |
192 |
|
|
|
193 |
✓✓ |
444760 |
if ('0' <= ch && ch <= '9') |
194 |
|
272276 |
v = ch - '0'; |
195 |
✓✓ |
172484 |
else if ('A' <= ch && ch <= 'F') |
196 |
|
3724 |
v = ch - 'A' + 10; |
197 |
✗✓ |
168760 |
else if (ch == '_') { |
198 |
|
|
sign = true; |
199 |
|
|
continue; |
200 |
✓✓ |
168760 |
} else if (ch == '.') { |
201 |
✓✗ |
8428 |
if (dot) |
202 |
|
|
break; |
203 |
|
|
dot = true; |
204 |
|
8428 |
continue; |
205 |
|
|
} else { |
206 |
|
160332 |
(*src->vtable->unreadchar)(src); |
207 |
|
160332 |
break; |
208 |
|
|
} |
209 |
✓✓ |
276000 |
if (dot) |
210 |
|
114240 |
n->scale++; |
211 |
|
|
|
212 |
|
276000 |
bn_check(BN_mul_word(n->number, base)); |
213 |
|
|
|
214 |
|
|
#if 0 |
215 |
|
|
/* work around a bug in BN_add_word: 0 += 0 is buggy.... */ |
216 |
|
|
if (v > 0) |
217 |
|
|
#endif |
218 |
|
276000 |
bn_check(BN_add_word(n->number, v)); |
219 |
|
|
} |
220 |
✗✓ |
160332 |
if (base != 10) { |
221 |
|
|
scale_number(n->number, n->scale); |
222 |
|
|
for (i = 0; i < n->scale; i++) |
223 |
|
|
(void)BN_div_word(n->number, base); |
224 |
|
|
} |
225 |
✗✓ |
160332 |
if (sign) |
226 |
|
|
negate(n); |
227 |
|
160332 |
return n; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
char * |
231 |
|
|
read_string(struct source *src) |
232 |
|
|
{ |
233 |
|
|
int count, i, sz, new_sz, ch; |
234 |
|
|
char *p; |
235 |
|
|
bool escape; |
236 |
|
|
|
237 |
|
|
escape = false; |
238 |
|
|
count = 1; |
239 |
|
|
i = 0; |
240 |
|
|
sz = 15; |
241 |
|
165760 |
p = bmalloc(sz + 1); |
242 |
|
|
|
243 |
✓✗ |
9974608 |
while ((ch = (*src->vtable->readchar)(src)) != EOF) { |
244 |
✓✗ |
4987304 |
if (!escape) { |
245 |
✗✓ |
4987304 |
if (ch == '[') |
246 |
|
|
count++; |
247 |
✓✓ |
4987304 |
else if (ch == ']') |
248 |
|
82880 |
count--; |
249 |
✓✓ |
4987304 |
if (count == 0) |
250 |
|
|
break; |
251 |
|
|
} |
252 |
✗✓✗✗
|
4904424 |
if (ch == '\\' && !escape) |
253 |
|
|
escape = true; |
254 |
|
|
else { |
255 |
|
|
escape = false; |
256 |
✓✓ |
4904424 |
if (i == sz) { |
257 |
|
155400 |
new_sz = sz * 2; |
258 |
|
155400 |
p = breallocarray(p, 1, new_sz + 1); |
259 |
|
|
sz = new_sz; |
260 |
|
155400 |
} |
261 |
|
4904424 |
p[i++] = ch; |
262 |
|
|
} |
263 |
|
|
} |
264 |
|
82880 |
p[i] = '\0'; |
265 |
|
82880 |
return p; |
266 |
|
|
} |
267 |
|
|
|
268 |
|
|
static char * |
269 |
|
|
get_digit(u_long num, int digits, u_int base) |
270 |
|
|
{ |
271 |
|
48944 |
char *p; |
272 |
|
|
|
273 |
✓✗ |
24472 |
if (base <= 16) { |
274 |
|
24472 |
p = bmalloc(2); |
275 |
|
24472 |
p[0] = num >= 10 ? num + 'A' - 10 : num + '0'; |
276 |
|
24472 |
p[1] = '\0'; |
277 |
|
24472 |
} else { |
278 |
|
|
if (asprintf(&p, "%0*lu", digits, num) == -1) |
279 |
|
|
err(1, NULL); |
280 |
|
|
} |
281 |
|
48944 |
return p; |
282 |
|
24472 |
} |
283 |
|
|
|
284 |
|
|
void |
285 |
|
|
printnumber(FILE *f, const struct number *b, u_int base) |
286 |
|
|
{ |
287 |
|
|
struct number *int_part, *fract_part; |
288 |
|
|
int digits; |
289 |
|
4152 |
char buf[11]; |
290 |
|
|
size_t sz; |
291 |
|
|
int i; |
292 |
|
2076 |
struct stack stack; |
293 |
|
|
char *p; |
294 |
|
|
|
295 |
|
2076 |
charcount = 0; |
296 |
|
2076 |
lastchar = -1; |
297 |
✓✓ |
2076 |
if (BN_is_zero(b->number)) |
298 |
|
168 |
putcharwrap(f, '0'); |
299 |
|
|
|
300 |
|
2076 |
int_part = new_number(); |
301 |
|
2076 |
fract_part = new_number(); |
302 |
|
2076 |
fract_part->scale = b->scale; |
303 |
|
|
|
304 |
✓✗ |
2076 |
if (base <= 16) |
305 |
|
2076 |
digits = 1; |
306 |
|
|
else { |
307 |
|
|
digits = snprintf(buf, sizeof(buf), "%u", base-1); |
308 |
|
|
} |
309 |
|
2076 |
split_number(b, int_part->number, fract_part->number); |
310 |
|
|
|
311 |
|
|
i = 0; |
312 |
|
2076 |
stack_init(&stack); |
313 |
✓✓ |
10328 |
while (!BN_is_zero(int_part->number)) { |
314 |
|
3088 |
BN_ULONG rem = BN_div_word(int_part->number, base); |
315 |
|
3088 |
stack_pushstring(&stack, get_digit(rem, digits, base)); |
316 |
|
3088 |
i++; |
317 |
|
|
} |
318 |
|
2076 |
sz = i; |
319 |
✓✓ |
2076 |
if (BN_is_negative(b->number)) |
320 |
|
836 |
putcharwrap(f, '-'); |
321 |
✓✓ |
10328 |
for (i = 0; i < sz; i++) { |
322 |
|
3088 |
p = stack_popstring(&stack); |
323 |
✗✓ |
3088 |
if (base > 16) |
324 |
|
|
putcharwrap(f, ' '); |
325 |
|
3088 |
printwrap(f, p); |
326 |
|
3088 |
free(p); |
327 |
|
|
} |
328 |
|
2076 |
stack_clear(&stack); |
329 |
✓✓ |
2076 |
if (b->scale > 0) { |
330 |
|
|
struct number *num_base; |
331 |
|
1848 |
BIGNUM mult, stop; |
332 |
|
|
|
333 |
|
1848 |
putcharwrap(f, '.'); |
334 |
|
1848 |
num_base = new_number(); |
335 |
|
1848 |
bn_check(BN_set_word(num_base->number, base)); |
336 |
|
1848 |
BN_init(&mult); |
337 |
|
1848 |
bn_check(BN_one(&mult)); |
338 |
|
1848 |
BN_init(&stop); |
339 |
|
1848 |
bn_check(BN_one(&stop)); |
340 |
|
1848 |
scale_number(&stop, b->scale); |
341 |
|
|
|
342 |
|
|
i = 0; |
343 |
✓✓ |
46464 |
while (BN_cmp(&mult, &stop) < 0) { |
344 |
|
|
u_long rem; |
345 |
|
|
|
346 |
✗✓ |
21384 |
if (i && base > 16) |
347 |
|
|
putcharwrap(f, ' '); |
348 |
|
|
i = 1; |
349 |
|
|
|
350 |
|
21384 |
bmul_number(fract_part, fract_part, num_base, |
351 |
|
21384 |
bmachine_scale()); |
352 |
|
21384 |
split_number(fract_part, int_part->number, NULL); |
353 |
|
21384 |
rem = BN_get_word(int_part->number); |
354 |
|
21384 |
p = get_digit(rem, digits, base); |
355 |
|
21384 |
int_part->scale = 0; |
356 |
|
21384 |
normalize(int_part, fract_part->scale); |
357 |
|
42768 |
bn_check(BN_sub(fract_part->number, fract_part->number, |
358 |
|
21384 |
int_part->number)); |
359 |
|
21384 |
printwrap(f, p); |
360 |
|
21384 |
free(p); |
361 |
|
21384 |
bn_check(BN_mul_word(&mult, base)); |
362 |
|
|
} |
363 |
|
1848 |
free_number(num_base); |
364 |
|
1848 |
BN_free(&mult); |
365 |
|
1848 |
BN_free(&stop); |
366 |
|
1848 |
} |
367 |
|
2076 |
flushwrap(f); |
368 |
|
2076 |
free_number(int_part); |
369 |
|
2076 |
free_number(fract_part); |
370 |
|
2076 |
} |
371 |
|
|
|
372 |
|
|
void |
373 |
|
|
print_value(FILE *f, const struct value *value, const char *prefix, u_int base) |
374 |
|
|
{ |
375 |
|
6228 |
(void)fputs(prefix, f); |
376 |
✗✓✗✓
|
4152 |
switch (value->type) { |
377 |
|
|
case BCODE_NONE: |
378 |
|
|
if (value->array != NULL) |
379 |
|
|
(void)fputs("<array>", f); |
380 |
|
|
break; |
381 |
|
|
case BCODE_NUMBER: |
382 |
|
2076 |
printnumber(f, value->u.num, base); |
383 |
|
2076 |
break; |
384 |
|
|
case BCODE_STRING: |
385 |
|
|
(void)fputs(value->u.string, f); |
386 |
|
|
break; |
387 |
|
|
} |
388 |
|
2076 |
} |
389 |
|
|
|
390 |
|
|
void |
391 |
|
|
print_ascii(FILE *f, const struct number *n) |
392 |
|
|
{ |
393 |
|
|
BIGNUM *v; |
394 |
|
|
int numbits, i, ch; |
395 |
|
|
|
396 |
|
|
v = BN_dup(n->number); |
397 |
|
|
bn_checkp(v); |
398 |
|
|
|
399 |
|
|
if (BN_is_negative(v)) |
400 |
|
|
BN_set_negative(v, 0); |
401 |
|
|
|
402 |
|
|
numbits = BN_num_bytes(v) * 8; |
403 |
|
|
while (numbits > 0) { |
404 |
|
|
ch = 0; |
405 |
|
|
for (i = 0; i < 8; i++) |
406 |
|
|
ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i); |
407 |
|
|
(void)putc(ch, f); |
408 |
|
|
numbits -= 8; |
409 |
|
|
} |
410 |
|
|
BN_free(v); |
411 |
|
|
} |