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