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 58a6ce4a44Sotto src_setstream(struct source *src, FILE *stream) 59a6ce4a44Sotto { 60a6ce4a44Sotto src->u.stream = stream; 61a6ce4a44Sotto src->vtable = &stream_vtable; 62a6ce4a44Sotto } 63a6ce4a44Sotto 64a6ce4a44Sotto void 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 73a6ce4a44Sotto src_getcharstream(struct source *src) 74a6ce4a44Sotto { 75a6ce4a44Sotto return src->lastchar = getc(src->u.stream); 76a6ce4a44Sotto } 77a6ce4a44Sotto 78a1a9dfc3Sotto static void 79a6ce4a44Sotto src_ungetcharstream(struct source *src) 80a6ce4a44Sotto { 81a1a9dfc3Sotto (void)ungetc(src->lastchar, src->u.stream); 82a6ce4a44Sotto } 83a6ce4a44Sotto 84a6ce4a44Sotto static void 85a6ce4a44Sotto src_freestream(struct source *src) 86a6ce4a44Sotto { 87a6ce4a44Sotto } 88a6ce4a44Sotto 89a6ce4a44Sotto static char * 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 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 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 * 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 140a6ce4a44Sotto src_freestring(struct source *src) 141a6ce4a44Sotto { 142a6ce4a44Sotto free(src->u.string.buf); 143a6ce4a44Sotto } 144a6ce4a44Sotto 145a6ce4a44Sotto static void 146f0690440Sotto flushwrap(FILE *f) 147f0690440Sotto { 148f0690440Sotto if (lastchar != -1) 149a1a9dfc3Sotto (void)putc(lastchar, f); 150f0690440Sotto } 151f0690440Sotto 152f0690440Sotto static void 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 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 * 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 * 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 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 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 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 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