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