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