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