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