1 /* $OpenBSD: inout.c,v 1.24 2024/11/07 16:20:00 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 void get_digit(u_long, int, u_int, char *, size_t); 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 src->u.stream = stream; 61 src->vtable = &stream_vtable; 62 } 63 64 void 65 src_setstring(struct source *src, char *p) 66 { 67 src->u.string.buf = (u_char *)p; 68 src->u.string.pos = 0; 69 src->vtable = &string_vtable; 70 } 71 72 static int 73 src_getcharstream(struct source *src) 74 { 75 return src->lastchar = getc(src->u.stream); 76 } 77 78 static void 79 src_ungetcharstream(struct source *src) 80 { 81 (void)ungetc(src->lastchar, src->u.stream); 82 } 83 84 static void 85 src_freestream(struct source *src) 86 { 87 } 88 89 static char * 90 src_getlinestream(struct source *src) 91 { 92 char buf[BUFSIZ]; 93 94 if (fgets(buf, BUFSIZ, src->u.stream) == NULL) 95 return bstrdup(""); 96 return bstrdup(buf); 97 } 98 99 static int 100 src_getcharstring(struct source *src) 101 { 102 src->lastchar = src->u.string.buf[src->u.string.pos]; 103 if (src->lastchar == '\0') 104 return EOF; 105 else { 106 src->u.string.pos++; 107 return src->lastchar; 108 } 109 } 110 111 static void 112 src_ungetcharstring(struct source *src) 113 { 114 if (src->u.string.pos > 0) { 115 if (src->lastchar != '\0') 116 --src->u.string.pos; 117 } 118 } 119 120 static char * 121 src_getlinestring(struct source *src) 122 { 123 char buf[BUFSIZ]; 124 int ch, i; 125 126 i = 0; 127 while (i < BUFSIZ-1) { 128 ch = src_getcharstring(src); 129 if (ch == EOF) 130 break; 131 buf[i++] = ch; 132 if (ch == '\n') 133 break; 134 } 135 buf[i] = '\0'; 136 return bstrdup(buf); 137 } 138 139 static void 140 src_freestring(struct source *src) 141 { 142 free(src->u.string.buf); 143 } 144 145 static void 146 flushwrap(FILE *f) 147 { 148 if (lastchar != -1) 149 (void)putc(lastchar, f); 150 } 151 152 static void 153 putcharwrap(FILE *f, int ch) 154 { 155 if (charcount >= MAX_CHARS_PER_LINE) { 156 charcount = 0; 157 (void)fputs("\\\n", f); 158 } 159 if (lastchar != -1) { 160 charcount++; 161 (void)putc(lastchar, f); 162 } 163 lastchar = ch; 164 } 165 166 static void 167 printwrap(FILE *f, const char *p) 168 { 169 char buf[12]; 170 char *q = buf; 171 172 (void)strlcpy(buf, p, sizeof(buf)); 173 while (*q) 174 putcharwrap(f, *q++); 175 } 176 177 struct number * 178 readnumber(struct source *src, u_int base) 179 { 180 struct number *n; 181 int ch; 182 bool sign = false; 183 bool dot = false; 184 BN_ULONG v; 185 u_int i; 186 187 n = new_number(); 188 bn_check(BN_set_word(n->number, 0)); 189 190 while ((ch = (*src->vtable->readchar)(src)) != EOF) { 191 192 if ('0' <= ch && ch <= '9') 193 v = ch - '0'; 194 else if ('A' <= ch && ch <= 'F') 195 v = ch - 'A' + 10; 196 else if (ch == '_') { 197 sign = true; 198 continue; 199 } else if (ch == '.') { 200 if (dot) 201 break; 202 dot = true; 203 continue; 204 } else { 205 (*src->vtable->unreadchar)(src); 206 break; 207 } 208 if (dot) 209 n->scale++; 210 211 bn_check(BN_mul_word(n->number, base)); 212 213 #if 0 214 /* work around a bug in BN_add_word: 0 += 0 is buggy.... */ 215 if (v > 0) 216 #endif 217 bn_check(BN_add_word(n->number, v)); 218 } 219 if (base != 10) { 220 scale_number(n->number, n->scale); 221 for (i = 0; i < n->scale; i++) 222 (void)BN_div_word(n->number, base); 223 } 224 if (sign) 225 negate(n); 226 return n; 227 } 228 229 char * 230 read_string(struct source *src) 231 { 232 int count, i, sz, new_sz, ch; 233 char *p; 234 bool escape; 235 236 escape = false; 237 count = 1; 238 i = 0; 239 sz = 15; 240 p = bmalloc(sz + 1); 241 242 while ((ch = (*src->vtable->readchar)(src)) != EOF) { 243 if (!escape) { 244 if (ch == '[') 245 count++; 246 else if (ch == ']') 247 count--; 248 if (count == 0) 249 break; 250 } 251 if (ch == '\\' && !escape) 252 escape = true; 253 else { 254 escape = false; 255 if (i == sz) { 256 new_sz = sz * 2; 257 p = breallocarray(p, 1, new_sz + 1); 258 sz = new_sz; 259 } 260 p[i++] = ch; 261 } 262 } 263 p[i] = '\0'; 264 return p; 265 } 266 267 static void 268 get_digit(u_long num, int digits, u_int base, char *buf, size_t sz) 269 { 270 if (base <= 16) { 271 buf[0] = num >= 10 ? num + 'A' - 10 : num + '0'; 272 buf[1] = '\0'; 273 } else { 274 int ret = snprintf(buf, sz, "%0*lu", digits, num); 275 if (ret < 0 || (size_t)ret >= sz) 276 err(1, "truncation"); 277 } 278 } 279 280 void 281 printnumber(FILE *f, const struct number *b, u_int base) 282 { 283 struct number *int_part, *fract_part; 284 int digits; 285 char buf[12], *str, *p; 286 size_t allocated; 287 int i; 288 BN_ULONG *mem; 289 290 charcount = 0; 291 lastchar = -1; 292 if (BN_is_zero(b->number)) 293 putcharwrap(f, '0'); 294 295 int_part = new_number(); 296 fract_part = new_number(); 297 fract_part->scale = b->scale; 298 299 if (base <= 16) 300 digits = 1; 301 else { 302 digits = snprintf(buf, sizeof(buf), "%u", base-1); 303 } 304 split_number(b, int_part->number, fract_part->number); 305 306 if (base == 10 && !BN_is_zero(int_part->number)) { 307 str = BN_bn2dec(int_part->number); 308 bn_checkp(str); 309 p = str; 310 while (*p) 311 putcharwrap(f, *p++); 312 free(str); 313 } else if (base == 16 && !BN_is_zero(int_part->number)) { 314 str = BN_bn2hex(int_part->number); 315 bn_checkp(str); 316 p = str; 317 if (*p == '-') 318 putcharwrap(f, *p++); 319 /* skip leading zero's */ 320 while (*p == '0') 321 p++; 322 while (*p) 323 putcharwrap(f, *p++); 324 free(str); 325 } else { 326 i = 0; 327 allocated = 1; 328 mem = breallocarray(NULL, allocated, sizeof(BN_ULONG)); 329 while (!BN_is_zero(int_part->number)) { 330 if (i >= allocated) { 331 allocated *= 2; 332 mem = breallocarray(mem, allocated, 333 sizeof(BN_ULONG)); 334 } 335 mem[i++] = BN_div_word(int_part->number, base); 336 } 337 if (BN_is_negative(b->number)) 338 putcharwrap(f, '-'); 339 for (i = i - 1; i >= 0; i--) { 340 get_digit(mem[i], digits, base, buf, 341 sizeof(buf)); 342 if (base > 16) 343 putcharwrap(f, ' '); 344 printwrap(f, buf); 345 } 346 free(mem); 347 } 348 349 if (b->scale > 0) { 350 struct number *num_base; 351 BIGNUM *mult, *stop; 352 353 putcharwrap(f, '.'); 354 num_base = new_number(); 355 bn_check(BN_set_word(num_base->number, base)); 356 mult = BN_new(); 357 bn_checkp(mult); 358 bn_check(BN_one(mult)); 359 stop = BN_new(); 360 bn_checkp(stop); 361 bn_check(BN_one(stop)); 362 scale_number(stop, b->scale); 363 364 i = 0; 365 while (BN_cmp(mult, stop) < 0) { 366 u_long rem; 367 368 if (i && base > 16) 369 putcharwrap(f, ' '); 370 i = 1; 371 372 bmul_number(fract_part, fract_part, num_base, 373 bmachine_scale()); 374 split_number(fract_part, int_part->number, NULL); 375 rem = BN_get_word(int_part->number); 376 get_digit(rem, digits, base, buf, sizeof(buf)); 377 int_part->scale = 0; 378 normalize(int_part, fract_part->scale); 379 bn_check(BN_sub(fract_part->number, fract_part->number, 380 int_part->number)); 381 printwrap(f, buf); 382 bn_check(BN_mul_word(mult, base)); 383 } 384 free_number(num_base); 385 BN_free(mult); 386 BN_free(stop); 387 } 388 flushwrap(f); 389 free_number(int_part); 390 free_number(fract_part); 391 } 392 393 void 394 print_value(FILE *f, const struct value *value, const char *prefix, u_int base) 395 { 396 (void)fputs(prefix, f); 397 switch (value->type) { 398 case BCODE_NONE: 399 if (value->array != NULL) 400 (void)fputs("<array>", f); 401 break; 402 case BCODE_NUMBER: 403 printnumber(f, value->u.num, base); 404 break; 405 case BCODE_STRING: 406 (void)fputs(value->u.string, f); 407 break; 408 } 409 } 410 411 void 412 print_ascii(FILE *f, const struct number *n) 413 { 414 int numbits, i, ch; 415 416 numbits = BN_num_bytes(n->number) * 8; 417 while (numbits > 0) { 418 ch = 0; 419 for (i = 0; i < 8; i++) 420 ch |= BN_is_bit_set(n->number, numbits-i-1) << (7 - i); 421 (void)putc(ch, f); 422 numbits -= 8; 423 } 424 } 425