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