1/* $OpenBSD: inout.c,v 1.18 2014/12/01 13:13:00 deraadt 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 <sys/cdefs.h> 20#include <openssl/ssl.h> 21#include <ctype.h> 22#include <err.h> 23#include <string.h> 24 25#include "extern.h" 26 27#define MAX_CHARS_PER_LINE 68 28 29static int lastchar; 30static int charcount; 31 32static int src_getcharstream(struct source *); 33static void src_ungetcharstream(struct source *); 34static char *src_getlinestream(struct source *); 35static int src_getcharstring(struct source *); 36static void src_ungetcharstring(struct source *); 37static char *src_getlinestring(struct source *); 38static void src_freestring(struct source *); 39static void flushwrap(FILE *); 40static void putcharwrap(FILE *, int); 41static void printwrap(FILE *, const char *); 42static char *get_digit(u_long, int, u_int); 43 44static struct vtable stream_vtable = { 45 src_getcharstream, 46 src_ungetcharstream, 47 src_getlinestream, 48 NULL 49}; 50 51static struct vtable string_vtable = { 52 src_getcharstring, 53 src_ungetcharstring, 54 src_getlinestring, 55 src_freestring 56}; 57 58void 59src_setstream(struct source *src, FILE *stream) 60{ 61 62 src->u.stream = stream; 63 src->vtable = &stream_vtable; 64} 65 66void 67src_setstring(struct source *src, char *p) 68{ 69 70 src->u.string.buf = (u_char *)p; 71 src->u.string.pos = 0; 72 src->vtable = &string_vtable; 73} 74 75static int 76src_getcharstream(struct source *src) 77{ 78 79 return (src->lastchar = getc(src->u.stream)); 80} 81 82static void 83src_ungetcharstream(struct source *src) 84{ 85 86 ungetc(src->lastchar, src->u.stream); 87} 88 89static char * 90src_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 99static int 100src_getcharstring(struct source *src) 101{ 102 103 src->lastchar = src->u.string.buf[src->u.string.pos]; 104 if (src->lastchar == '\0') 105 return (EOF); 106 else { 107 src->u.string.pos++; 108 return (src->lastchar); 109 } 110} 111 112static void 113src_ungetcharstring(struct source *src) 114{ 115 116 if (src->u.string.pos > 0) { 117 if (src->lastchar != '\0') 118 --src->u.string.pos; 119 } 120} 121 122static char * 123src_getlinestring(struct source *src) 124{ 125 char buf[BUFSIZ]; 126 int i, ch; 127 128 i = 0; 129 while (i < BUFSIZ-1) { 130 ch = src_getcharstring(src); 131 if (ch == EOF) 132 break; 133 buf[i++] = ch; 134 if (ch == '\n') 135 break; 136 } 137 buf[i] = '\0'; 138 return (bstrdup(buf)); 139} 140 141static void 142src_freestring(struct source *src) 143{ 144 145 free(src->u.string.buf); 146} 147 148static void 149flushwrap(FILE *f) 150{ 151 152 if (lastchar != -1) 153 putc(lastchar, f); 154} 155 156static void 157putcharwrap(FILE *f, int ch) 158{ 159 160 if (charcount >= MAX_CHARS_PER_LINE) { 161 charcount = 0; 162 fputs("\\\n", f); 163 } 164 if (lastchar != -1) { 165 charcount++; 166 putc(lastchar, f); 167 } 168 lastchar = ch; 169} 170 171static void 172printwrap(FILE *f, const char *p) 173{ 174 char *q; 175 char buf[12]; 176 177 q = buf; 178 strlcpy(buf, p, sizeof(buf)); 179 while (*q) 180 putcharwrap(f, *q++); 181} 182 183struct number * 184readnumber(struct source *src, u_int base, u_int bscale) 185{ 186 struct number *n; 187 BN_ULONG v; 188 int ch; 189 u_int iscale = 0; 190 bool dot = false, sign = false; 191 192 n = new_number(); 193 BN_zero(n->number); 194 195 while ((ch = (*src->vtable->readchar)(src)) != EOF) { 196 197 if ('0' <= ch && ch <= '9') 198 v = ch - '0'; 199 else if ('A' <= ch && ch <= 'F') 200 v = ch - 'A' + 10; 201 else if (ch == '_') { 202 sign = true; 203 continue; 204 } else if (ch == '.') { 205 if (dot) 206 break; 207 dot = true; 208 continue; 209 } else { 210 (*src->vtable->unreadchar)(src); 211 break; 212 } 213 if (dot) 214 iscale++; 215 216 bn_check(BN_mul_word(n->number, base)); 217 bn_check(BN_add_word(n->number, v)); 218 } 219 if (base == 10) { 220 n->scale = iscale; 221 } else { 222 /* At this point, the desired result is n->number / base^iscale*/ 223 struct number *quotient, *divisor, *_n; 224 BIGNUM *base_n, *exponent; 225 BN_CTX *ctx; 226 227 ctx = BN_CTX_new(); 228 base_n = BN_new(); 229 exponent = BN_new(); 230 divisor = new_number(); 231 BN_zero(base_n); 232 BN_zero(exponent); 233 234 bn_check(BN_add_word(base_n, base)); 235 bn_check(BN_add_word(exponent, iscale)); 236 bn_check(BN_exp(divisor->number, base_n, exponent, ctx)); 237 divisor->scale = 0; 238 quotient = div_number(n, divisor, bscale); 239 _n = n; 240 n = quotient; 241 242 /* 243 * Trim off trailing zeros to yield the smallest scale without 244 * loss of accuracy 245 */ 246 while ( n->scale > 0 && 247 BN_mod_word(n->number, 10) == 0) { 248 normalize(n, n->scale - 1); 249 } 250 251 free_number(_n); 252 free_number(divisor); 253 BN_CTX_free(ctx); 254 BN_free(base_n); 255 BN_free(exponent); 256 } 257 if (sign) 258 negate(n); 259 return (n); 260} 261 262char * 263read_string(struct source *src) 264{ 265 char *p; 266 int count, ch, i, new_sz, sz; 267 bool escape; 268 269 escape = false; 270 count = 1; 271 i = 0; 272 sz = 15; 273 p = bmalloc(sz + 1); 274 275 while ((ch = (*src->vtable->readchar)(src)) != EOF) { 276 if (!escape) { 277 if (ch == '[') 278 count++; 279 else if (ch == ']') 280 count--; 281 if (count == 0) 282 break; 283 } 284 if (ch == '\\' && !escape) 285 escape = true; 286 else { 287 escape = false; 288 if (i == sz) { 289 new_sz = sz * 2; 290 p = breallocarray(p, 1, new_sz + 1); 291 sz = new_sz; 292 } 293 p[i++] = ch; 294 } 295 } 296 p[i] = '\0'; 297 return (p); 298} 299 300static char * 301get_digit(u_long num, int digits, u_int base) 302{ 303 char *p; 304 305 if (base <= 16) { 306 p = bmalloc(2); 307 p[0] = num >= 10 ? num + 'A' - 10 : num + '0'; 308 p[1] = '\0'; 309 } else { 310 if (asprintf(&p, "%0*lu", digits, num) == -1) 311 err(1, NULL); 312 } 313 return (p); 314} 315 316void 317printnumber(FILE *f, const struct number *b, u_int base) 318{ 319 struct number *fract_part, *int_part; 320 struct stack stack; 321 char *p; 322 char buf[11]; 323 size_t sz; 324 unsigned int i; 325 int digits; 326 327 charcount = 0; 328 lastchar = -1; 329 if (BN_is_zero(b->number)) 330 putcharwrap(f, '0'); 331 332 int_part = new_number(); 333 fract_part = new_number(); 334 fract_part->scale = b->scale; 335 336 if (base <= 16) 337 digits = 1; 338 else { 339 digits = snprintf(buf, sizeof(buf), "%u", base-1); 340 } 341 split_number(b, int_part->number, fract_part->number); 342 343 i = 0; 344 stack_init(&stack); 345 while (!BN_is_zero(int_part->number)) { 346 BN_ULONG rem = BN_div_word(int_part->number, base); 347 stack_pushstring(&stack, get_digit(rem, digits, base)); 348 i++; 349 } 350 sz = i; 351 if (BN_is_negative(b->number)) 352 putcharwrap(f, '-'); 353 for (i = 0; i < sz; i++) { 354 p = stack_popstring(&stack); 355 if (base > 16) 356 putcharwrap(f, ' '); 357 printwrap(f, p); 358 free(p); 359 } 360 stack_clear(&stack); 361 if (b->scale > 0) { 362 struct number *num_base; 363 BIGNUM *mult, *stop; 364 365 putcharwrap(f, '.'); 366 num_base = new_number(); 367 bn_check(BN_set_word(num_base->number, base)); 368 mult = BN_new(); 369 bn_checkp(mult); 370 bn_check(BN_one(mult)); 371 stop = BN_new(); 372 bn_checkp(stop); 373 bn_check(BN_one(stop)); 374 scale_number(stop, b->scale); 375 376 i = 0; 377 while (BN_cmp(mult, stop) < 0) { 378 u_long rem; 379 380 if (i && base > 16) 381 putcharwrap(f, ' '); 382 i = 1; 383 384 bmul_number(fract_part, fract_part, num_base, 385 bmachine_scale()); 386 split_number(fract_part, int_part->number, NULL); 387 rem = BN_get_word(int_part->number); 388 p = get_digit(rem, digits, base); 389 int_part->scale = 0; 390 normalize(int_part, fract_part->scale); 391 bn_check(BN_sub(fract_part->number, fract_part->number, 392 int_part->number)); 393 printwrap(f, p); 394 free(p); 395 bn_check(BN_mul_word(mult, base)); 396 } 397 free_number(num_base); 398 BN_free(mult); 399 BN_free(stop); 400 } 401 flushwrap(f); 402 free_number(int_part); 403 free_number(fract_part); 404} 405 406void 407print_value(FILE *f, const struct value *value, const char *prefix, u_int base) 408{ 409 410 fputs(prefix, f); 411 switch (value->type) { 412 case BCODE_NONE: 413 if (value->array != NULL) 414 fputs("<array>", f); 415 break; 416 case BCODE_NUMBER: 417 printnumber(f, value->u.num, base); 418 break; 419 case BCODE_STRING: 420 fputs(value->u.string, f); 421 break; 422 } 423} 424 425void 426print_ascii(FILE *f, const struct number *n) 427{ 428 BIGNUM *v; 429 int ch, i, numbits; 430 431 v = BN_dup(n->number); 432 bn_checkp(v); 433 434 if (BN_is_negative(v)) 435 BN_set_negative(v, 0); 436 437 numbits = BN_num_bytes(v) * 8; 438 while (numbits > 0) { 439 ch = 0; 440 for (i = 0; i < 8; i++) 441 ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i); 442 putc(ch, f); 443 numbits -= 8; 444 } 445 BN_free(v); 446} 447