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