fatbase

portable OpenBSD tools
git clone git://git.2f30.org/fatbase
Log | Files | Refs

inout.c (8045B)


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