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