Home | History | Annotate | Line # | Download | only in dc
      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