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