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