xref: /freebsd-14.2/usr.bin/dc/bcode.c (revision 4ef08904)
1fdf1f88bSGabor Kovesdan /*	$OpenBSD: bcode.c,v 1.40 2009/10/27 23:59:37 deraadt Exp $	*/
2fdf1f88bSGabor Kovesdan 
3fdf1f88bSGabor Kovesdan /*
4fdf1f88bSGabor Kovesdan  * Copyright (c) 2003, Otto Moerbeek <[email protected]>
5fdf1f88bSGabor Kovesdan  *
6fdf1f88bSGabor Kovesdan  * Permission to use, copy, modify, and distribute this software for any
7fdf1f88bSGabor Kovesdan  * purpose with or without fee is hereby granted, provided that the above
8fdf1f88bSGabor Kovesdan  * copyright notice and this permission notice appear in all copies.
9fdf1f88bSGabor Kovesdan  *
10fdf1f88bSGabor Kovesdan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11fdf1f88bSGabor Kovesdan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12fdf1f88bSGabor Kovesdan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13fdf1f88bSGabor Kovesdan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14fdf1f88bSGabor Kovesdan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15fdf1f88bSGabor Kovesdan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16fdf1f88bSGabor Kovesdan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17fdf1f88bSGabor Kovesdan  */
18fdf1f88bSGabor Kovesdan 
19fdf1f88bSGabor Kovesdan #include <sys/cdefs.h>
20fdf1f88bSGabor Kovesdan __FBSDID("$FreeBSD$");
21fdf1f88bSGabor Kovesdan 
22fdf1f88bSGabor Kovesdan #include <err.h>
23fdf1f88bSGabor Kovesdan #include <limits.h>
24fdf1f88bSGabor Kovesdan #include <openssl/ssl.h>
25fdf1f88bSGabor Kovesdan #include <signal.h>
26fdf1f88bSGabor Kovesdan #include <stdio.h>
27fdf1f88bSGabor Kovesdan #include <stdlib.h>
28fdf1f88bSGabor Kovesdan #include <string.h>
29fdf1f88bSGabor Kovesdan 
30fdf1f88bSGabor Kovesdan #include "extern.h"
31fdf1f88bSGabor Kovesdan 
32fdf1f88bSGabor Kovesdan BIGNUM		zero;
33fdf1f88bSGabor Kovesdan 
34fdf1f88bSGabor Kovesdan #define __inline
35fdf1f88bSGabor Kovesdan 
36fdf1f88bSGabor Kovesdan #define MAX_ARRAY_INDEX		2048
37fdf1f88bSGabor Kovesdan #define READSTACK_SIZE		8
38fdf1f88bSGabor Kovesdan 
39fdf1f88bSGabor Kovesdan #define NO_ELSE			-2	/* -1 is EOF */
40fdf1f88bSGabor Kovesdan #define REG_ARRAY_SIZE_SMALL	(UCHAR_MAX + 1)
41fdf1f88bSGabor Kovesdan #define REG_ARRAY_SIZE_BIG	(UCHAR_MAX + 1 + USHRT_MAX + 1)
42fdf1f88bSGabor Kovesdan 
43fdf1f88bSGabor Kovesdan struct bmachine {
44fdf1f88bSGabor Kovesdan 	struct stack		 stack;
45fdf1f88bSGabor Kovesdan 	u_int			 scale;
46fdf1f88bSGabor Kovesdan 	u_int			 obase;
47fdf1f88bSGabor Kovesdan 	u_int			 ibase;
48fdf1f88bSGabor Kovesdan 	size_t			 readsp;
49fdf1f88bSGabor Kovesdan 	bool			 extended_regs;
50fdf1f88bSGabor Kovesdan 	size_t			 reg_array_size;
51fdf1f88bSGabor Kovesdan 	struct stack		*reg;
52fdf1f88bSGabor Kovesdan 	volatile sig_atomic_t	 interrupted;
53fdf1f88bSGabor Kovesdan 	struct source		*readstack;
54fdf1f88bSGabor Kovesdan 	size_t			 readstack_sz;
55fdf1f88bSGabor Kovesdan };
56fdf1f88bSGabor Kovesdan 
57fdf1f88bSGabor Kovesdan static struct bmachine	 bmachine;
58fdf1f88bSGabor Kovesdan static void		 sighandler(int);
59fdf1f88bSGabor Kovesdan 
60fdf1f88bSGabor Kovesdan static __inline int	 readch(void);
61fdf1f88bSGabor Kovesdan static __inline void	 unreadch(void);
62fdf1f88bSGabor Kovesdan static __inline char	*readline(void);
63fdf1f88bSGabor Kovesdan static __inline void	 src_free(void);
64fdf1f88bSGabor Kovesdan 
65fdf1f88bSGabor Kovesdan static __inline u_int	 max(u_int, u_int);
66fdf1f88bSGabor Kovesdan static u_long		 get_ulong(struct number *);
67fdf1f88bSGabor Kovesdan 
68fdf1f88bSGabor Kovesdan static __inline void	 push_number(struct number *);
69fdf1f88bSGabor Kovesdan static __inline void	 push_string(char *);
70fdf1f88bSGabor Kovesdan static __inline void	 push(struct value *);
71fdf1f88bSGabor Kovesdan static __inline struct value *tos(void);
72fdf1f88bSGabor Kovesdan static __inline struct number	*pop_number(void);
73fdf1f88bSGabor Kovesdan static __inline char	*pop_string(void);
74fdf1f88bSGabor Kovesdan static __inline void	 clear_stack(void);
75fdf1f88bSGabor Kovesdan static __inline void	 print_tos(void);
76fdf1f88bSGabor Kovesdan static void		 pop_print(void);
77fdf1f88bSGabor Kovesdan static void		 pop_printn(void);
78fdf1f88bSGabor Kovesdan static __inline void	 print_stack(void);
79fdf1f88bSGabor Kovesdan static __inline void	 dup(void);
80fdf1f88bSGabor Kovesdan static void		 swap(void);
81fdf1f88bSGabor Kovesdan static void		 drop(void);
82fdf1f88bSGabor Kovesdan 
83fdf1f88bSGabor Kovesdan static void		 get_scale(void);
84fdf1f88bSGabor Kovesdan static void		 set_scale(void);
85fdf1f88bSGabor Kovesdan static void		 get_obase(void);
86fdf1f88bSGabor Kovesdan static void		 set_obase(void);
87fdf1f88bSGabor Kovesdan static void		 get_ibase(void);
88fdf1f88bSGabor Kovesdan static void		 set_ibase(void);
89fdf1f88bSGabor Kovesdan static void		 stackdepth(void);
90fdf1f88bSGabor Kovesdan static void		 push_scale(void);
91fdf1f88bSGabor Kovesdan static u_int		 count_digits(const struct number *);
92fdf1f88bSGabor Kovesdan static void		 num_digits(void);
93fdf1f88bSGabor Kovesdan static void		 to_ascii(void);
94fdf1f88bSGabor Kovesdan static void		 push_line(void);
95fdf1f88bSGabor Kovesdan static void		 comment(void);
96fdf1f88bSGabor Kovesdan static void		 bexec(char *);
97fdf1f88bSGabor Kovesdan static void		 badd(void);
98fdf1f88bSGabor Kovesdan static void		 bsub(void);
99fdf1f88bSGabor Kovesdan static void		 bmul(void);
100fdf1f88bSGabor Kovesdan static void		 bdiv(void);
101fdf1f88bSGabor Kovesdan static void		 bmod(void);
102fdf1f88bSGabor Kovesdan static void		 bdivmod(void);
103fdf1f88bSGabor Kovesdan static void		 bexp(void);
104fdf1f88bSGabor Kovesdan static bool		 bsqrt_stop(const BIGNUM *, const BIGNUM *, u_int *);
105fdf1f88bSGabor Kovesdan static void		 bsqrt(void);
106fdf1f88bSGabor Kovesdan static void		 not(void);
107fdf1f88bSGabor Kovesdan static void		 equal_numbers(void);
108fdf1f88bSGabor Kovesdan static void		 less_numbers(void);
109fdf1f88bSGabor Kovesdan static void		 lesseq_numbers(void);
110fdf1f88bSGabor Kovesdan static void		 equal(void);
111fdf1f88bSGabor Kovesdan static void		 not_equal(void);
112fdf1f88bSGabor Kovesdan static void		 less(void);
113fdf1f88bSGabor Kovesdan static void		 not_less(void);
114fdf1f88bSGabor Kovesdan static void		 greater(void);
115fdf1f88bSGabor Kovesdan static void		 not_greater(void);
116fdf1f88bSGabor Kovesdan static void		 not_compare(void);
117fdf1f88bSGabor Kovesdan static bool		 compare_numbers(enum bcode_compare, struct number *,
118fdf1f88bSGabor Kovesdan 			     struct number *);
119fdf1f88bSGabor Kovesdan static void		 compare(enum bcode_compare);
120fdf1f88bSGabor Kovesdan static int		 readreg(void);
121fdf1f88bSGabor Kovesdan static void		 load(void);
122fdf1f88bSGabor Kovesdan static void		 store(void);
123fdf1f88bSGabor Kovesdan static void		 load_stack(void);
124fdf1f88bSGabor Kovesdan static void		 store_stack(void);
125fdf1f88bSGabor Kovesdan static void		 load_array(void);
126fdf1f88bSGabor Kovesdan static void		 store_array(void);
127fdf1f88bSGabor Kovesdan static void		 nop(void);
128fdf1f88bSGabor Kovesdan static void		 quit(void);
129fdf1f88bSGabor Kovesdan static void		 quitN(void);
130fdf1f88bSGabor Kovesdan static void		 skipN(void);
131fdf1f88bSGabor Kovesdan static void		 skip_until_mark(void);
132fdf1f88bSGabor Kovesdan static void		 parse_number(void);
133fdf1f88bSGabor Kovesdan static void		 unknown(void);
134fdf1f88bSGabor Kovesdan static void		 eval_string(char *);
135fdf1f88bSGabor Kovesdan static void		 eval_line(void);
136fdf1f88bSGabor Kovesdan static void		 eval_tos(void);
137fdf1f88bSGabor Kovesdan 
138fdf1f88bSGabor Kovesdan 
139fdf1f88bSGabor Kovesdan typedef void		(*opcode_function)(void);
140fdf1f88bSGabor Kovesdan 
141fdf1f88bSGabor Kovesdan struct jump_entry {
142fdf1f88bSGabor Kovesdan 	u_char		 ch;
143fdf1f88bSGabor Kovesdan 	opcode_function	 f;
144fdf1f88bSGabor Kovesdan };
145fdf1f88bSGabor Kovesdan 
146fdf1f88bSGabor Kovesdan static opcode_function jump_table[UCHAR_MAX];
147fdf1f88bSGabor Kovesdan 
148fdf1f88bSGabor Kovesdan static const struct jump_entry jump_table_data[] = {
149fdf1f88bSGabor Kovesdan 	{ ' ',	nop		},
150fdf1f88bSGabor Kovesdan 	{ '!',	not_compare	},
151fdf1f88bSGabor Kovesdan 	{ '#',	comment		},
152fdf1f88bSGabor Kovesdan 	{ '%',	bmod		},
153fdf1f88bSGabor Kovesdan 	{ '(',	less_numbers	},
154fdf1f88bSGabor Kovesdan 	{ '*',	bmul		},
155fdf1f88bSGabor Kovesdan 	{ '+',	badd		},
156fdf1f88bSGabor Kovesdan 	{ '-',	bsub		},
157fdf1f88bSGabor Kovesdan 	{ '.',	parse_number	},
158fdf1f88bSGabor Kovesdan 	{ '/',	bdiv		},
159fdf1f88bSGabor Kovesdan 	{ '0',	parse_number	},
160fdf1f88bSGabor Kovesdan 	{ '1',	parse_number	},
161fdf1f88bSGabor Kovesdan 	{ '2',	parse_number	},
162fdf1f88bSGabor Kovesdan 	{ '3',	parse_number	},
163fdf1f88bSGabor Kovesdan 	{ '4',	parse_number	},
164fdf1f88bSGabor Kovesdan 	{ '5',	parse_number	},
165fdf1f88bSGabor Kovesdan 	{ '6',	parse_number	},
166fdf1f88bSGabor Kovesdan 	{ '7',	parse_number	},
167fdf1f88bSGabor Kovesdan 	{ '8',	parse_number	},
168fdf1f88bSGabor Kovesdan 	{ '9',	parse_number	},
169fdf1f88bSGabor Kovesdan 	{ ':',	store_array	},
170fdf1f88bSGabor Kovesdan 	{ ';',	load_array	},
171fdf1f88bSGabor Kovesdan 	{ '<',	less		},
172fdf1f88bSGabor Kovesdan 	{ '=',	equal		},
173fdf1f88bSGabor Kovesdan 	{ '>',	greater		},
174fdf1f88bSGabor Kovesdan 	{ '?',	eval_line	},
175fdf1f88bSGabor Kovesdan 	{ 'A',	parse_number	},
176fdf1f88bSGabor Kovesdan 	{ 'B',	parse_number	},
177fdf1f88bSGabor Kovesdan 	{ 'C',	parse_number	},
178fdf1f88bSGabor Kovesdan 	{ 'D',	parse_number	},
179fdf1f88bSGabor Kovesdan 	{ 'E',	parse_number	},
180fdf1f88bSGabor Kovesdan 	{ 'F',	parse_number	},
181fdf1f88bSGabor Kovesdan 	{ 'G',	equal_numbers	},
182fdf1f88bSGabor Kovesdan 	{ 'I',	get_ibase	},
183fdf1f88bSGabor Kovesdan 	{ 'J',	skipN		},
184fdf1f88bSGabor Kovesdan 	{ 'K',	get_scale	},
185fdf1f88bSGabor Kovesdan 	{ 'L',	load_stack	},
186fdf1f88bSGabor Kovesdan 	{ 'M',	nop		},
187fdf1f88bSGabor Kovesdan 	{ 'N',	not		},
188fdf1f88bSGabor Kovesdan 	{ 'O',	get_obase	},
189fdf1f88bSGabor Kovesdan 	{ 'P',	pop_print	},
190fdf1f88bSGabor Kovesdan 	{ 'Q',	quitN		},
191fdf1f88bSGabor Kovesdan 	{ 'R',	drop		},
192fdf1f88bSGabor Kovesdan 	{ 'S',	store_stack	},
193fdf1f88bSGabor Kovesdan 	{ 'X',	push_scale	},
194fdf1f88bSGabor Kovesdan 	{ 'Z',	num_digits	},
195fdf1f88bSGabor Kovesdan 	{ '[',	push_line	},
196fdf1f88bSGabor Kovesdan 	{ '\f',	nop		},
197fdf1f88bSGabor Kovesdan 	{ '\n',	nop		},
198fdf1f88bSGabor Kovesdan 	{ '\r',	nop		},
199fdf1f88bSGabor Kovesdan 	{ '\t',	nop		},
200fdf1f88bSGabor Kovesdan 	{ '^',	bexp		},
201fdf1f88bSGabor Kovesdan 	{ '_',	parse_number	},
202fdf1f88bSGabor Kovesdan 	{ 'a',	to_ascii	},
203fdf1f88bSGabor Kovesdan 	{ 'c',	clear_stack	},
204fdf1f88bSGabor Kovesdan 	{ 'd',	dup		},
205fdf1f88bSGabor Kovesdan 	{ 'f',	print_stack	},
206fdf1f88bSGabor Kovesdan 	{ 'i',	set_ibase	},
207fdf1f88bSGabor Kovesdan 	{ 'k',	set_scale	},
208fdf1f88bSGabor Kovesdan 	{ 'l',	load		},
209fdf1f88bSGabor Kovesdan 	{ 'n',	pop_printn	},
210fdf1f88bSGabor Kovesdan 	{ 'o',	set_obase	},
211fdf1f88bSGabor Kovesdan 	{ 'p',	print_tos	},
212fdf1f88bSGabor Kovesdan 	{ 'q',	quit		},
213fdf1f88bSGabor Kovesdan 	{ 'r',	swap		},
214fdf1f88bSGabor Kovesdan 	{ 's',	store		},
215fdf1f88bSGabor Kovesdan 	{ 'v',	bsqrt		},
216fdf1f88bSGabor Kovesdan 	{ 'x',	eval_tos	},
217fdf1f88bSGabor Kovesdan 	{ 'z',	stackdepth	},
218fdf1f88bSGabor Kovesdan 	{ '{',	lesseq_numbers	},
219fdf1f88bSGabor Kovesdan 	{ '~',	bdivmod		}
220fdf1f88bSGabor Kovesdan };
221fdf1f88bSGabor Kovesdan 
222fdf1f88bSGabor Kovesdan #define JUMP_TABLE_DATA_SIZE \
223fdf1f88bSGabor Kovesdan 	(sizeof(jump_table_data)/sizeof(jump_table_data[0]))
224fdf1f88bSGabor Kovesdan 
225fdf1f88bSGabor Kovesdan static void
226fdf1f88bSGabor Kovesdan sighandler(int ignored)
227fdf1f88bSGabor Kovesdan {
228fdf1f88bSGabor Kovesdan 
229fdf1f88bSGabor Kovesdan 	switch (ignored)
230fdf1f88bSGabor Kovesdan 	{
231fdf1f88bSGabor Kovesdan 	default:
232fdf1f88bSGabor Kovesdan 		bmachine.interrupted = true;
233fdf1f88bSGabor Kovesdan 	}
234fdf1f88bSGabor Kovesdan }
235fdf1f88bSGabor Kovesdan 
236fdf1f88bSGabor Kovesdan void
237fdf1f88bSGabor Kovesdan init_bmachine(bool extended_registers)
238fdf1f88bSGabor Kovesdan {
239fdf1f88bSGabor Kovesdan 	unsigned int	 i;
240fdf1f88bSGabor Kovesdan 
241fdf1f88bSGabor Kovesdan 	bmachine.extended_regs = extended_registers;
242fdf1f88bSGabor Kovesdan 	bmachine.reg_array_size = bmachine.extended_regs ?
243fdf1f88bSGabor Kovesdan 	    REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL;
244fdf1f88bSGabor Kovesdan 
245fdf1f88bSGabor Kovesdan 	bmachine.reg = calloc(bmachine.reg_array_size,
246fdf1f88bSGabor Kovesdan 	    sizeof(bmachine.reg[0]));
247fdf1f88bSGabor Kovesdan 	if (bmachine.reg == NULL)
248fdf1f88bSGabor Kovesdan 		err(1, NULL);
249fdf1f88bSGabor Kovesdan 
250fdf1f88bSGabor Kovesdan 	for (i = 0; i < UCHAR_MAX; i++)
251fdf1f88bSGabor Kovesdan 		jump_table[i] = unknown;
252fdf1f88bSGabor Kovesdan 	for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++)
253fdf1f88bSGabor Kovesdan 		jump_table[jump_table_data[i].ch] = jump_table_data[i].f;
254fdf1f88bSGabor Kovesdan 
255fdf1f88bSGabor Kovesdan 	stack_init(&bmachine.stack);
256fdf1f88bSGabor Kovesdan 
257fdf1f88bSGabor Kovesdan 	for (i = 0; i < bmachine.reg_array_size; i++)
258fdf1f88bSGabor Kovesdan 		stack_init(&bmachine.reg[i]);
259fdf1f88bSGabor Kovesdan 
260fdf1f88bSGabor Kovesdan 	bmachine.readstack_sz = READSTACK_SIZE;
261fdf1f88bSGabor Kovesdan 	bmachine.readstack = calloc(sizeof(struct source),
262fdf1f88bSGabor Kovesdan 	    bmachine.readstack_sz);
263fdf1f88bSGabor Kovesdan 	if (bmachine.readstack == NULL)
264fdf1f88bSGabor Kovesdan 		err(1, NULL);
265fdf1f88bSGabor Kovesdan 	bmachine.obase = bmachine.ibase = 10;
266fdf1f88bSGabor Kovesdan 	BN_init(&zero);
267fdf1f88bSGabor Kovesdan 	bn_check(BN_zero(&zero));
268fdf1f88bSGabor Kovesdan 	signal(SIGINT, sighandler);
269fdf1f88bSGabor Kovesdan }
270fdf1f88bSGabor Kovesdan 
271fdf1f88bSGabor Kovesdan /* Reset the things needed before processing a (new) file */
272fdf1f88bSGabor Kovesdan void
273fdf1f88bSGabor Kovesdan reset_bmachine(struct source *src)
274fdf1f88bSGabor Kovesdan {
275fdf1f88bSGabor Kovesdan 
276fdf1f88bSGabor Kovesdan 	bmachine.readsp = 0;
277fdf1f88bSGabor Kovesdan 	bmachine.readstack[0] = *src;
278fdf1f88bSGabor Kovesdan }
279fdf1f88bSGabor Kovesdan 
280fdf1f88bSGabor Kovesdan static __inline int
281fdf1f88bSGabor Kovesdan readch(void)
282fdf1f88bSGabor Kovesdan {
283fdf1f88bSGabor Kovesdan 	struct source	*src = &bmachine.readstack[bmachine.readsp];
284fdf1f88bSGabor Kovesdan 
285fdf1f88bSGabor Kovesdan 	return (src->vtable->readchar(src));
286fdf1f88bSGabor Kovesdan }
287fdf1f88bSGabor Kovesdan 
288fdf1f88bSGabor Kovesdan static __inline void
289fdf1f88bSGabor Kovesdan unreadch(void)
290fdf1f88bSGabor Kovesdan {
291fdf1f88bSGabor Kovesdan 	struct source	*src = &bmachine.readstack[bmachine.readsp];
292fdf1f88bSGabor Kovesdan 
293fdf1f88bSGabor Kovesdan 	src->vtable->unreadchar(src);
294fdf1f88bSGabor Kovesdan }
295fdf1f88bSGabor Kovesdan 
296fdf1f88bSGabor Kovesdan static __inline char *
297fdf1f88bSGabor Kovesdan readline(void)
298fdf1f88bSGabor Kovesdan {
299fdf1f88bSGabor Kovesdan 	struct source	*src = &bmachine.readstack[bmachine.readsp];
300fdf1f88bSGabor Kovesdan 
301fdf1f88bSGabor Kovesdan 	return (src->vtable->readline(src));
302fdf1f88bSGabor Kovesdan }
303fdf1f88bSGabor Kovesdan 
304fdf1f88bSGabor Kovesdan static __inline void
305fdf1f88bSGabor Kovesdan src_free(void)
306fdf1f88bSGabor Kovesdan {
307fdf1f88bSGabor Kovesdan 	struct source	*src = &bmachine.readstack[bmachine.readsp];
308fdf1f88bSGabor Kovesdan 
309fdf1f88bSGabor Kovesdan 	src->vtable->free(src);
310fdf1f88bSGabor Kovesdan }
311fdf1f88bSGabor Kovesdan 
312fdf1f88bSGabor Kovesdan #ifdef DEBUGGING
313fdf1f88bSGabor Kovesdan void
314fdf1f88bSGabor Kovesdan pn(const char *str, const struct number *n)
315fdf1f88bSGabor Kovesdan {
316fdf1f88bSGabor Kovesdan 	char	*p = BN_bn2dec(n->number);
317fdf1f88bSGabor Kovesdan 
318fdf1f88bSGabor Kovesdan 	if (p == NULL)
319fdf1f88bSGabor Kovesdan 		err(1, "BN_bn2dec failed");
320fdf1f88bSGabor Kovesdan 	fputs(str, stderr);
321fdf1f88bSGabor Kovesdan 	fprintf(stderr, " %s (%u)\n" , p, n->scale);
322fdf1f88bSGabor Kovesdan 	OPENSSL_free(p);
323fdf1f88bSGabor Kovesdan }
324fdf1f88bSGabor Kovesdan 
325fdf1f88bSGabor Kovesdan void
326fdf1f88bSGabor Kovesdan pbn(const char *str, const BIGNUM *n)
327fdf1f88bSGabor Kovesdan {
328fdf1f88bSGabor Kovesdan 	char	*p = BN_bn2dec(n);
329fdf1f88bSGabor Kovesdan 
330fdf1f88bSGabor Kovesdan 	if (p == NULL)
331fdf1f88bSGabor Kovesdan 		err(1, "BN_bn2dec failed");
332fdf1f88bSGabor Kovesdan 	fputs(str, stderr);
333fdf1f88bSGabor Kovesdan 	fprintf(stderr, " %s\n", p);
334fdf1f88bSGabor Kovesdan 	OPENSSL_free(p);
335fdf1f88bSGabor Kovesdan }
336fdf1f88bSGabor Kovesdan 
337fdf1f88bSGabor Kovesdan #endif
338fdf1f88bSGabor Kovesdan 
339fdf1f88bSGabor Kovesdan static __inline u_int
340fdf1f88bSGabor Kovesdan max(u_int a, u_int b)
341fdf1f88bSGabor Kovesdan {
342fdf1f88bSGabor Kovesdan 
343fdf1f88bSGabor Kovesdan 	return (a > b ? a : b);
344fdf1f88bSGabor Kovesdan }
345fdf1f88bSGabor Kovesdan 
346fdf1f88bSGabor Kovesdan static unsigned long factors[] = {
347fdf1f88bSGabor Kovesdan 	0, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
348fdf1f88bSGabor Kovesdan 	100000000, 1000000000
349fdf1f88bSGabor Kovesdan };
350fdf1f88bSGabor Kovesdan 
351fdf1f88bSGabor Kovesdan void
352fdf1f88bSGabor Kovesdan scale_number(BIGNUM *n, int s)
353fdf1f88bSGabor Kovesdan {
354fdf1f88bSGabor Kovesdan 	unsigned int	 abs_scale;
355fdf1f88bSGabor Kovesdan 
356fdf1f88bSGabor Kovesdan 	if (s == 0)
357fdf1f88bSGabor Kovesdan 		return;
358fdf1f88bSGabor Kovesdan 
359fdf1f88bSGabor Kovesdan 	abs_scale = s > 0 ? s : -s;
360fdf1f88bSGabor Kovesdan 
361fdf1f88bSGabor Kovesdan 	if (abs_scale < sizeof(factors)/sizeof(factors[0])) {
362fdf1f88bSGabor Kovesdan 		if (s > 0)
363fdf1f88bSGabor Kovesdan 			bn_check(BN_mul_word(n, factors[abs_scale]));
364fdf1f88bSGabor Kovesdan 		else
365fdf1f88bSGabor Kovesdan 			BN_div_word(n, factors[abs_scale]);
366fdf1f88bSGabor Kovesdan 	} else {
367fdf1f88bSGabor Kovesdan 		BIGNUM	*a, *p;
368fdf1f88bSGabor Kovesdan 		BN_CTX	*ctx;
369fdf1f88bSGabor Kovesdan 
370fdf1f88bSGabor Kovesdan 		a = BN_new();
371fdf1f88bSGabor Kovesdan 		bn_checkp(a);
372fdf1f88bSGabor Kovesdan 		p = BN_new();
373fdf1f88bSGabor Kovesdan 		bn_checkp(p);
374fdf1f88bSGabor Kovesdan 		ctx = BN_CTX_new();
375fdf1f88bSGabor Kovesdan 		bn_checkp(ctx);
376fdf1f88bSGabor Kovesdan 
377fdf1f88bSGabor Kovesdan 		bn_check(BN_set_word(a, 10));
378fdf1f88bSGabor Kovesdan 		bn_check(BN_set_word(p, abs_scale));
379fdf1f88bSGabor Kovesdan 		bn_check(BN_exp(a, a, p, ctx));
380fdf1f88bSGabor Kovesdan 		if (s > 0)
381fdf1f88bSGabor Kovesdan 			bn_check(BN_mul(n, n, a, ctx));
382fdf1f88bSGabor Kovesdan 		else
383fdf1f88bSGabor Kovesdan 			bn_check(BN_div(n, NULL, n, a, ctx));
384fdf1f88bSGabor Kovesdan 		BN_CTX_free(ctx);
385fdf1f88bSGabor Kovesdan 		BN_free(a);
386fdf1f88bSGabor Kovesdan 		BN_free(p);
387fdf1f88bSGabor Kovesdan 	}
388fdf1f88bSGabor Kovesdan }
389fdf1f88bSGabor Kovesdan 
390fdf1f88bSGabor Kovesdan void
391fdf1f88bSGabor Kovesdan split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
392fdf1f88bSGabor Kovesdan {
393fdf1f88bSGabor Kovesdan 	u_long	 rem;
394fdf1f88bSGabor Kovesdan 
395fdf1f88bSGabor Kovesdan 	bn_checkp(BN_copy(i, n->number));
396fdf1f88bSGabor Kovesdan 
397fdf1f88bSGabor Kovesdan 	if (n->scale == 0 && f != NULL)
398fdf1f88bSGabor Kovesdan 		bn_check(BN_zero(f));
399fdf1f88bSGabor Kovesdan 	else if (n->scale < sizeof(factors)/sizeof(factors[0])) {
400fdf1f88bSGabor Kovesdan 		rem = BN_div_word(i, factors[n->scale]);
401fdf1f88bSGabor Kovesdan 		if (f != NULL)
402fdf1f88bSGabor Kovesdan 			bn_check(BN_set_word(f, rem));
403fdf1f88bSGabor Kovesdan 	} else {
404fdf1f88bSGabor Kovesdan 		BIGNUM	*a, *p;
405fdf1f88bSGabor Kovesdan 		BN_CTX	*ctx;
406fdf1f88bSGabor Kovesdan 
407fdf1f88bSGabor Kovesdan 		a = BN_new();
408fdf1f88bSGabor Kovesdan 		bn_checkp(a);
409fdf1f88bSGabor Kovesdan 		p = BN_new();
410fdf1f88bSGabor Kovesdan 		bn_checkp(p);
411fdf1f88bSGabor Kovesdan 		ctx = BN_CTX_new();
412fdf1f88bSGabor Kovesdan 		bn_checkp(ctx);
413fdf1f88bSGabor Kovesdan 
414fdf1f88bSGabor Kovesdan 		bn_check(BN_set_word(a, 10));
415fdf1f88bSGabor Kovesdan 		bn_check(BN_set_word(p, n->scale));
416fdf1f88bSGabor Kovesdan 		bn_check(BN_exp(a, a, p, ctx));
417fdf1f88bSGabor Kovesdan 		bn_check(BN_div(i, f, n->number, a, ctx));
418fdf1f88bSGabor Kovesdan 		BN_CTX_free(ctx);
419fdf1f88bSGabor Kovesdan 		BN_free(a);
420fdf1f88bSGabor Kovesdan 		BN_free(p);
421fdf1f88bSGabor Kovesdan 	}
422fdf1f88bSGabor Kovesdan }
423fdf1f88bSGabor Kovesdan 
424fdf1f88bSGabor Kovesdan __inline void
425fdf1f88bSGabor Kovesdan normalize(struct number *n, u_int s)
426fdf1f88bSGabor Kovesdan {
427fdf1f88bSGabor Kovesdan 
428fdf1f88bSGabor Kovesdan 	scale_number(n->number, s - n->scale);
429fdf1f88bSGabor Kovesdan 	n->scale = s;
430fdf1f88bSGabor Kovesdan }
431fdf1f88bSGabor Kovesdan 
432fdf1f88bSGabor Kovesdan static u_long
433fdf1f88bSGabor Kovesdan get_ulong(struct number *n)
434fdf1f88bSGabor Kovesdan {
435fdf1f88bSGabor Kovesdan 
436fdf1f88bSGabor Kovesdan 	normalize(n, 0);
437fdf1f88bSGabor Kovesdan 	return (BN_get_word(n->number));
438fdf1f88bSGabor Kovesdan }
439fdf1f88bSGabor Kovesdan 
440fdf1f88bSGabor Kovesdan void
441fdf1f88bSGabor Kovesdan negate(struct number *n)
442fdf1f88bSGabor Kovesdan {
443fdf1f88bSGabor Kovesdan 
444fdf1f88bSGabor Kovesdan 	bn_check(BN_sub(n->number, &zero, n->number));
445fdf1f88bSGabor Kovesdan }
446fdf1f88bSGabor Kovesdan 
447fdf1f88bSGabor Kovesdan static __inline void
448fdf1f88bSGabor Kovesdan push_number(struct number *n)
449fdf1f88bSGabor Kovesdan {
450fdf1f88bSGabor Kovesdan 
451fdf1f88bSGabor Kovesdan 	stack_pushnumber(&bmachine.stack, n);
452fdf1f88bSGabor Kovesdan }
453fdf1f88bSGabor Kovesdan 
454fdf1f88bSGabor Kovesdan static __inline void
455fdf1f88bSGabor Kovesdan push_string(char *string)
456fdf1f88bSGabor Kovesdan {
457fdf1f88bSGabor Kovesdan 
458fdf1f88bSGabor Kovesdan 	stack_pushstring(&bmachine.stack, string);
459fdf1f88bSGabor Kovesdan }
460fdf1f88bSGabor Kovesdan 
461fdf1f88bSGabor Kovesdan static __inline void
462fdf1f88bSGabor Kovesdan push(struct value *v)
463fdf1f88bSGabor Kovesdan {
464fdf1f88bSGabor Kovesdan 
465fdf1f88bSGabor Kovesdan 	stack_push(&bmachine.stack, v);
466fdf1f88bSGabor Kovesdan }
467fdf1f88bSGabor Kovesdan 
468fdf1f88bSGabor Kovesdan static __inline struct value *
469fdf1f88bSGabor Kovesdan tos(void)
470fdf1f88bSGabor Kovesdan {
471fdf1f88bSGabor Kovesdan 
472fdf1f88bSGabor Kovesdan 	return (stack_tos(&bmachine.stack));
473fdf1f88bSGabor Kovesdan }
474fdf1f88bSGabor Kovesdan 
475fdf1f88bSGabor Kovesdan static __inline struct value *
476fdf1f88bSGabor Kovesdan pop(void)
477fdf1f88bSGabor Kovesdan {
478fdf1f88bSGabor Kovesdan 
479fdf1f88bSGabor Kovesdan 	return (stack_pop(&bmachine.stack));
480fdf1f88bSGabor Kovesdan }
481fdf1f88bSGabor Kovesdan 
482fdf1f88bSGabor Kovesdan static __inline struct number *
483fdf1f88bSGabor Kovesdan pop_number(void)
484fdf1f88bSGabor Kovesdan {
485fdf1f88bSGabor Kovesdan 
486fdf1f88bSGabor Kovesdan 	return (stack_popnumber(&bmachine.stack));
487fdf1f88bSGabor Kovesdan }
488fdf1f88bSGabor Kovesdan 
489fdf1f88bSGabor Kovesdan static __inline char *
490fdf1f88bSGabor Kovesdan pop_string(void)
491fdf1f88bSGabor Kovesdan {
492fdf1f88bSGabor Kovesdan 
493fdf1f88bSGabor Kovesdan 	return (stack_popstring(&bmachine.stack));
494fdf1f88bSGabor Kovesdan }
495fdf1f88bSGabor Kovesdan 
496fdf1f88bSGabor Kovesdan static __inline void
497fdf1f88bSGabor Kovesdan clear_stack(void)
498fdf1f88bSGabor Kovesdan {
499fdf1f88bSGabor Kovesdan 
500fdf1f88bSGabor Kovesdan 	stack_clear(&bmachine.stack);
501fdf1f88bSGabor Kovesdan }
502fdf1f88bSGabor Kovesdan 
503fdf1f88bSGabor Kovesdan static __inline void
504fdf1f88bSGabor Kovesdan print_stack(void)
505fdf1f88bSGabor Kovesdan {
506fdf1f88bSGabor Kovesdan 
507fdf1f88bSGabor Kovesdan 	stack_print(stdout, &bmachine.stack, "", bmachine.obase);
508fdf1f88bSGabor Kovesdan }
509fdf1f88bSGabor Kovesdan 
510fdf1f88bSGabor Kovesdan static __inline void
511fdf1f88bSGabor Kovesdan print_tos(void)
512fdf1f88bSGabor Kovesdan {
513fdf1f88bSGabor Kovesdan 	struct value	*value = tos();
514fdf1f88bSGabor Kovesdan 
515fdf1f88bSGabor Kovesdan 	if (value != NULL) {
516fdf1f88bSGabor Kovesdan 		print_value(stdout, value, "", bmachine.obase);
517fdf1f88bSGabor Kovesdan 		putchar('\n');
518fdf1f88bSGabor Kovesdan 	}
519fdf1f88bSGabor Kovesdan 	else
520fdf1f88bSGabor Kovesdan 		warnx("stack empty");
521fdf1f88bSGabor Kovesdan }
522fdf1f88bSGabor Kovesdan 
523fdf1f88bSGabor Kovesdan static void
524fdf1f88bSGabor Kovesdan pop_print(void)
525fdf1f88bSGabor Kovesdan {
526fdf1f88bSGabor Kovesdan 	struct value	*value = pop();
527fdf1f88bSGabor Kovesdan 
528fdf1f88bSGabor Kovesdan 	if (value != NULL) {
529fdf1f88bSGabor Kovesdan 		switch (value->type) {
530fdf1f88bSGabor Kovesdan 		case BCODE_NONE:
531fdf1f88bSGabor Kovesdan 			break;
532fdf1f88bSGabor Kovesdan 		case BCODE_NUMBER:
533fdf1f88bSGabor Kovesdan 			normalize(value->u.num, 0);
534fdf1f88bSGabor Kovesdan 			print_ascii(stdout, value->u.num);
535fdf1f88bSGabor Kovesdan 			fflush(stdout);
536fdf1f88bSGabor Kovesdan 			break;
537fdf1f88bSGabor Kovesdan 		case BCODE_STRING:
538fdf1f88bSGabor Kovesdan 			fputs(value->u.string, stdout);
539fdf1f88bSGabor Kovesdan 			fflush(stdout);
540fdf1f88bSGabor Kovesdan 			break;
541fdf1f88bSGabor Kovesdan 		}
542fdf1f88bSGabor Kovesdan 		stack_free_value(value);
543fdf1f88bSGabor Kovesdan 	}
544fdf1f88bSGabor Kovesdan }
545fdf1f88bSGabor Kovesdan 
546fdf1f88bSGabor Kovesdan static void
547fdf1f88bSGabor Kovesdan pop_printn(void)
548fdf1f88bSGabor Kovesdan {
549fdf1f88bSGabor Kovesdan 	struct value	*value = pop();
550fdf1f88bSGabor Kovesdan 
551fdf1f88bSGabor Kovesdan 	if (value != NULL) {
552fdf1f88bSGabor Kovesdan 		print_value(stdout, value, "", bmachine.obase);
553fdf1f88bSGabor Kovesdan 		fflush(stdout);
554fdf1f88bSGabor Kovesdan 		stack_free_value(value);
555fdf1f88bSGabor Kovesdan 	}
556fdf1f88bSGabor Kovesdan }
557fdf1f88bSGabor Kovesdan 
558fdf1f88bSGabor Kovesdan static __inline void
559fdf1f88bSGabor Kovesdan dup(void)
560fdf1f88bSGabor Kovesdan {
561fdf1f88bSGabor Kovesdan 
562fdf1f88bSGabor Kovesdan 	stack_dup(&bmachine.stack);
563fdf1f88bSGabor Kovesdan }
564fdf1f88bSGabor Kovesdan 
565fdf1f88bSGabor Kovesdan static void
566fdf1f88bSGabor Kovesdan swap(void)
567fdf1f88bSGabor Kovesdan {
568fdf1f88bSGabor Kovesdan 
569fdf1f88bSGabor Kovesdan 	stack_swap(&bmachine.stack);
570fdf1f88bSGabor Kovesdan }
571fdf1f88bSGabor Kovesdan 
572fdf1f88bSGabor Kovesdan static void
573fdf1f88bSGabor Kovesdan drop(void)
574fdf1f88bSGabor Kovesdan {
575fdf1f88bSGabor Kovesdan 	struct value	*v = pop();
576fdf1f88bSGabor Kovesdan 	if (v != NULL)
577fdf1f88bSGabor Kovesdan 		stack_free_value(v);
578fdf1f88bSGabor Kovesdan }
579fdf1f88bSGabor Kovesdan 
580fdf1f88bSGabor Kovesdan static void
581fdf1f88bSGabor Kovesdan get_scale(void)
582fdf1f88bSGabor Kovesdan {
583fdf1f88bSGabor Kovesdan 	struct number	*n;
584fdf1f88bSGabor Kovesdan 
585fdf1f88bSGabor Kovesdan 	n = new_number();
586fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(n->number, bmachine.scale));
587fdf1f88bSGabor Kovesdan 	push_number(n);
588fdf1f88bSGabor Kovesdan }
589fdf1f88bSGabor Kovesdan 
590fdf1f88bSGabor Kovesdan static void
591fdf1f88bSGabor Kovesdan set_scale(void)
592fdf1f88bSGabor Kovesdan {
593fdf1f88bSGabor Kovesdan 	struct number	*n;
594fdf1f88bSGabor Kovesdan 	u_long		 scale;
595fdf1f88bSGabor Kovesdan 
596fdf1f88bSGabor Kovesdan 	n = pop_number();
597fdf1f88bSGabor Kovesdan 	if (n != NULL) {
598fdf1f88bSGabor Kovesdan 		if (BN_cmp(n->number, &zero) < 0)
599fdf1f88bSGabor Kovesdan 			warnx("scale must be a nonnegative number");
600fdf1f88bSGabor Kovesdan 		else {
601fdf1f88bSGabor Kovesdan 			scale = get_ulong(n);
602fdf1f88bSGabor Kovesdan 			if (scale != BN_MASK2 && scale <= UINT_MAX)
603fdf1f88bSGabor Kovesdan 				bmachine.scale = (u_int)scale;
604fdf1f88bSGabor Kovesdan 			else
605fdf1f88bSGabor Kovesdan 				warnx("scale too large");
606fdf1f88bSGabor Kovesdan 			}
607fdf1f88bSGabor Kovesdan 		free_number(n);
608fdf1f88bSGabor Kovesdan 	}
609fdf1f88bSGabor Kovesdan }
610fdf1f88bSGabor Kovesdan 
611fdf1f88bSGabor Kovesdan static void
612fdf1f88bSGabor Kovesdan get_obase(void)
613fdf1f88bSGabor Kovesdan {
614fdf1f88bSGabor Kovesdan 	struct number	*n;
615fdf1f88bSGabor Kovesdan 
616fdf1f88bSGabor Kovesdan 	n = new_number();
617fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(n->number, bmachine.obase));
618fdf1f88bSGabor Kovesdan 	push_number(n);
619fdf1f88bSGabor Kovesdan }
620fdf1f88bSGabor Kovesdan 
621fdf1f88bSGabor Kovesdan static void
622fdf1f88bSGabor Kovesdan set_obase(void)
623fdf1f88bSGabor Kovesdan {
624fdf1f88bSGabor Kovesdan 	struct number	*n;
625fdf1f88bSGabor Kovesdan 	u_long		 base;
626fdf1f88bSGabor Kovesdan 
627fdf1f88bSGabor Kovesdan 	n = pop_number();
628fdf1f88bSGabor Kovesdan 	if (n != NULL) {
629fdf1f88bSGabor Kovesdan 		base = get_ulong(n);
630fdf1f88bSGabor Kovesdan 		if (base != BN_MASK2 && base > 1 && base <= UINT_MAX)
631fdf1f88bSGabor Kovesdan 			bmachine.obase = (u_int)base;
632fdf1f88bSGabor Kovesdan 		else
633fdf1f88bSGabor Kovesdan 			warnx("output base must be a number greater than 1");
634fdf1f88bSGabor Kovesdan 		free_number(n);
635fdf1f88bSGabor Kovesdan 	}
636fdf1f88bSGabor Kovesdan }
637fdf1f88bSGabor Kovesdan 
638fdf1f88bSGabor Kovesdan static void
639fdf1f88bSGabor Kovesdan get_ibase(void)
640fdf1f88bSGabor Kovesdan {
641fdf1f88bSGabor Kovesdan 	struct number	*n;
642fdf1f88bSGabor Kovesdan 
643fdf1f88bSGabor Kovesdan 	n = new_number();
644fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(n->number, bmachine.ibase));
645fdf1f88bSGabor Kovesdan 	push_number(n);
646fdf1f88bSGabor Kovesdan }
647fdf1f88bSGabor Kovesdan 
648fdf1f88bSGabor Kovesdan static void
649fdf1f88bSGabor Kovesdan set_ibase(void)
650fdf1f88bSGabor Kovesdan {
651fdf1f88bSGabor Kovesdan 	struct number	*n;
652fdf1f88bSGabor Kovesdan 	u_long		 base;
653fdf1f88bSGabor Kovesdan 
654fdf1f88bSGabor Kovesdan 	n = pop_number();
655fdf1f88bSGabor Kovesdan 	if (n != NULL) {
656fdf1f88bSGabor Kovesdan 		base = get_ulong(n);
657fdf1f88bSGabor Kovesdan 		if (base != BN_MASK2 && 2 <= base && base <= 16)
658fdf1f88bSGabor Kovesdan 			bmachine.ibase = (u_int)base;
659fdf1f88bSGabor Kovesdan 		else
660fdf1f88bSGabor Kovesdan 			warnx("input base must be a number between 2 and 16 "
661fdf1f88bSGabor Kovesdan 			    "(inclusive)");
662fdf1f88bSGabor Kovesdan 		free_number(n);
663fdf1f88bSGabor Kovesdan 	}
664fdf1f88bSGabor Kovesdan }
665fdf1f88bSGabor Kovesdan 
666fdf1f88bSGabor Kovesdan static void
667fdf1f88bSGabor Kovesdan stackdepth(void)
668fdf1f88bSGabor Kovesdan {
669fdf1f88bSGabor Kovesdan 	size_t		 i;
670fdf1f88bSGabor Kovesdan 	struct number	*n;
671fdf1f88bSGabor Kovesdan 
672fdf1f88bSGabor Kovesdan 	i = stack_size(&bmachine.stack);
673fdf1f88bSGabor Kovesdan 	n = new_number();
674fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(n->number, i));
675fdf1f88bSGabor Kovesdan 	push_number(n);
676fdf1f88bSGabor Kovesdan }
677fdf1f88bSGabor Kovesdan 
678fdf1f88bSGabor Kovesdan static void
679fdf1f88bSGabor Kovesdan push_scale(void)
680fdf1f88bSGabor Kovesdan {
681fdf1f88bSGabor Kovesdan 	struct value	*value;
682fdf1f88bSGabor Kovesdan 	u_int		 scale = 0;
683fdf1f88bSGabor Kovesdan 	struct number	*n;
684fdf1f88bSGabor Kovesdan 
685fdf1f88bSGabor Kovesdan 
686fdf1f88bSGabor Kovesdan 	value = pop();
687fdf1f88bSGabor Kovesdan 	if (value != NULL) {
688fdf1f88bSGabor Kovesdan 		switch (value->type) {
689fdf1f88bSGabor Kovesdan 		case BCODE_NONE:
690fdf1f88bSGabor Kovesdan 			return;
691fdf1f88bSGabor Kovesdan 		case BCODE_NUMBER:
692fdf1f88bSGabor Kovesdan 			scale = value->u.num->scale;
693fdf1f88bSGabor Kovesdan 			break;
694fdf1f88bSGabor Kovesdan 		case BCODE_STRING:
695fdf1f88bSGabor Kovesdan 			break;
696fdf1f88bSGabor Kovesdan 		}
697fdf1f88bSGabor Kovesdan 		stack_free_value(value);
698fdf1f88bSGabor Kovesdan 		n = new_number();
699fdf1f88bSGabor Kovesdan 		bn_check(BN_set_word(n->number, scale));
700fdf1f88bSGabor Kovesdan 		push_number(n);
701fdf1f88bSGabor Kovesdan 	}
702fdf1f88bSGabor Kovesdan }
703fdf1f88bSGabor Kovesdan 
704fdf1f88bSGabor Kovesdan static u_int
705fdf1f88bSGabor Kovesdan count_digits(const struct number *n)
706fdf1f88bSGabor Kovesdan {
707fdf1f88bSGabor Kovesdan 	struct number	*int_part, *fract_part;
708fdf1f88bSGabor Kovesdan 	u_int		 i;
709fdf1f88bSGabor Kovesdan 
710fdf1f88bSGabor Kovesdan 	if (BN_is_zero(n->number))
711fdf1f88bSGabor Kovesdan 		return (1);
712fdf1f88bSGabor Kovesdan 
713fdf1f88bSGabor Kovesdan 	int_part = new_number();
714fdf1f88bSGabor Kovesdan 	fract_part = new_number();
715fdf1f88bSGabor Kovesdan 	fract_part->scale = n->scale;
716fdf1f88bSGabor Kovesdan 	split_number(n, int_part->number, fract_part->number);
717fdf1f88bSGabor Kovesdan 
718fdf1f88bSGabor Kovesdan 	i = 0;
719fdf1f88bSGabor Kovesdan 	while (!BN_is_zero(int_part->number)) {
720fdf1f88bSGabor Kovesdan 		BN_div_word(int_part->number, 10);
721fdf1f88bSGabor Kovesdan 		i++;
722fdf1f88bSGabor Kovesdan 	}
723fdf1f88bSGabor Kovesdan 	free_number(int_part);
724fdf1f88bSGabor Kovesdan 	free_number(fract_part);
725fdf1f88bSGabor Kovesdan 	return (i + n->scale);
726fdf1f88bSGabor Kovesdan }
727fdf1f88bSGabor Kovesdan 
728fdf1f88bSGabor Kovesdan static void
729fdf1f88bSGabor Kovesdan num_digits(void)
730fdf1f88bSGabor Kovesdan {
731fdf1f88bSGabor Kovesdan 	struct value	*value;
732fdf1f88bSGabor Kovesdan 	size_t		 digits;
733fdf1f88bSGabor Kovesdan 	struct number	*n = NULL;
734fdf1f88bSGabor Kovesdan 
735fdf1f88bSGabor Kovesdan 	value = pop();
736fdf1f88bSGabor Kovesdan 	if (value != NULL) {
737fdf1f88bSGabor Kovesdan 		switch (value->type) {
738fdf1f88bSGabor Kovesdan 		case BCODE_NONE:
739fdf1f88bSGabor Kovesdan 			return;
740fdf1f88bSGabor Kovesdan 		case BCODE_NUMBER:
741fdf1f88bSGabor Kovesdan 			digits = count_digits(value->u.num);
742fdf1f88bSGabor Kovesdan 			n = new_number();
743fdf1f88bSGabor Kovesdan 			bn_check(BN_set_word(n->number, digits));
744fdf1f88bSGabor Kovesdan 			break;
745fdf1f88bSGabor Kovesdan 		case BCODE_STRING:
746fdf1f88bSGabor Kovesdan 			digits = strlen(value->u.string);
747fdf1f88bSGabor Kovesdan 			n = new_number();
748fdf1f88bSGabor Kovesdan 			bn_check(BN_set_word(n->number, digits));
749fdf1f88bSGabor Kovesdan 			break;
750fdf1f88bSGabor Kovesdan 		}
751fdf1f88bSGabor Kovesdan 		stack_free_value(value);
752fdf1f88bSGabor Kovesdan 		push_number(n);
753fdf1f88bSGabor Kovesdan 	}
754fdf1f88bSGabor Kovesdan }
755fdf1f88bSGabor Kovesdan 
756fdf1f88bSGabor Kovesdan static void
757fdf1f88bSGabor Kovesdan to_ascii(void)
758fdf1f88bSGabor Kovesdan {
759fdf1f88bSGabor Kovesdan 	char		 str[2];
760fdf1f88bSGabor Kovesdan 	struct value	*value;
761fdf1f88bSGabor Kovesdan 	struct number	*n;
762fdf1f88bSGabor Kovesdan 
763fdf1f88bSGabor Kovesdan 	value = pop();
764fdf1f88bSGabor Kovesdan 	if (value != NULL) {
765fdf1f88bSGabor Kovesdan 		str[1] = '\0';
766fdf1f88bSGabor Kovesdan 		switch (value->type) {
767fdf1f88bSGabor Kovesdan 		case BCODE_NONE:
768fdf1f88bSGabor Kovesdan 			return;
769fdf1f88bSGabor Kovesdan 		case BCODE_NUMBER:
770fdf1f88bSGabor Kovesdan 			n = value->u.num;
771fdf1f88bSGabor Kovesdan 			normalize(n, 0);
772fdf1f88bSGabor Kovesdan 			if (BN_num_bits(n->number) > 8)
773fdf1f88bSGabor Kovesdan 				bn_check(BN_mask_bits(n->number, 8));
774fdf1f88bSGabor Kovesdan 			str[0] = (char)BN_get_word(n->number);
775fdf1f88bSGabor Kovesdan 			break;
776fdf1f88bSGabor Kovesdan 		case BCODE_STRING:
777fdf1f88bSGabor Kovesdan 			str[0] = value->u.string[0];
778fdf1f88bSGabor Kovesdan 			break;
779fdf1f88bSGabor Kovesdan 		}
780fdf1f88bSGabor Kovesdan 		stack_free_value(value);
781fdf1f88bSGabor Kovesdan 		push_string(bstrdup(str));
782fdf1f88bSGabor Kovesdan 	}
783fdf1f88bSGabor Kovesdan }
784fdf1f88bSGabor Kovesdan 
785fdf1f88bSGabor Kovesdan static int
786fdf1f88bSGabor Kovesdan readreg(void)
787fdf1f88bSGabor Kovesdan {
788fdf1f88bSGabor Kovesdan 	int	 idx, ch1, ch2;
789fdf1f88bSGabor Kovesdan 
790fdf1f88bSGabor Kovesdan 	idx = readch();
791fdf1f88bSGabor Kovesdan 	if (idx == 0xff && bmachine.extended_regs) {
792fdf1f88bSGabor Kovesdan 		ch1 = readch();
793fdf1f88bSGabor Kovesdan 		ch2 = readch();
794fdf1f88bSGabor Kovesdan 		if (ch1 == EOF || ch2 == EOF) {
795fdf1f88bSGabor Kovesdan 			warnx("unexpected eof");
796fdf1f88bSGabor Kovesdan 			idx = -1;
797fdf1f88bSGabor Kovesdan 		} else
798fdf1f88bSGabor Kovesdan 			idx = (ch1 << 8) + ch2 + UCHAR_MAX + 1;
799fdf1f88bSGabor Kovesdan 	}
800fdf1f88bSGabor Kovesdan 	if (idx < 0 || (unsigned)idx >= bmachine.reg_array_size) {
801fdf1f88bSGabor Kovesdan 		warnx("internal error: reg num = %d", idx);
802fdf1f88bSGabor Kovesdan 		idx = -1;
803fdf1f88bSGabor Kovesdan 	}
804fdf1f88bSGabor Kovesdan 	return (idx);
805fdf1f88bSGabor Kovesdan }
806fdf1f88bSGabor Kovesdan 
807fdf1f88bSGabor Kovesdan static void
808fdf1f88bSGabor Kovesdan load(void)
809fdf1f88bSGabor Kovesdan {
810fdf1f88bSGabor Kovesdan 	int		 idx;
811fdf1f88bSGabor Kovesdan 	struct value	*v, copy;
812fdf1f88bSGabor Kovesdan 	struct number	*n;
813fdf1f88bSGabor Kovesdan 
814fdf1f88bSGabor Kovesdan 	idx = readreg();
815fdf1f88bSGabor Kovesdan 	if (idx >= 0) {
816fdf1f88bSGabor Kovesdan 		v = stack_tos(&bmachine.reg[idx]);
817fdf1f88bSGabor Kovesdan 		if (v == NULL) {
818fdf1f88bSGabor Kovesdan 			n = new_number();
819fdf1f88bSGabor Kovesdan 			bn_check(BN_zero(n->number));
820fdf1f88bSGabor Kovesdan 			push_number(n);
821fdf1f88bSGabor Kovesdan 		} else
822fdf1f88bSGabor Kovesdan 			push(stack_dup_value(v, &copy));
823fdf1f88bSGabor Kovesdan 	}
824fdf1f88bSGabor Kovesdan }
825fdf1f88bSGabor Kovesdan 
826fdf1f88bSGabor Kovesdan static void
827fdf1f88bSGabor Kovesdan store(void)
828fdf1f88bSGabor Kovesdan {
829fdf1f88bSGabor Kovesdan 	int		 idx;
830fdf1f88bSGabor Kovesdan 	struct value	*val;
831fdf1f88bSGabor Kovesdan 
832fdf1f88bSGabor Kovesdan 	idx = readreg();
833fdf1f88bSGabor Kovesdan 	if (idx >= 0) {
834fdf1f88bSGabor Kovesdan 		val = pop();
835fdf1f88bSGabor Kovesdan 		if (val == NULL) {
836fdf1f88bSGabor Kovesdan 			return;
837fdf1f88bSGabor Kovesdan 		}
838fdf1f88bSGabor Kovesdan 		stack_set_tos(&bmachine.reg[idx], val);
839fdf1f88bSGabor Kovesdan 	}
840fdf1f88bSGabor Kovesdan }
841fdf1f88bSGabor Kovesdan 
842fdf1f88bSGabor Kovesdan static void
843fdf1f88bSGabor Kovesdan load_stack(void)
844fdf1f88bSGabor Kovesdan {
845fdf1f88bSGabor Kovesdan 	int		 idx;
846fdf1f88bSGabor Kovesdan 	struct stack	*stack;
847fdf1f88bSGabor Kovesdan 	struct value	*value;
848fdf1f88bSGabor Kovesdan 
849fdf1f88bSGabor Kovesdan 	idx = readreg();
850fdf1f88bSGabor Kovesdan 	if (idx >= 0) {
851fdf1f88bSGabor Kovesdan 		stack = &bmachine.reg[idx];
852fdf1f88bSGabor Kovesdan 		value = NULL;
853fdf1f88bSGabor Kovesdan 		if (stack_size(stack) > 0) {
854fdf1f88bSGabor Kovesdan 			value = stack_pop(stack);
855fdf1f88bSGabor Kovesdan 		}
856fdf1f88bSGabor Kovesdan 		if (value != NULL)
857fdf1f88bSGabor Kovesdan 			push(value);
858fdf1f88bSGabor Kovesdan 		else
859fdf1f88bSGabor Kovesdan 			warnx("stack register '%c' (0%o) is empty",
860fdf1f88bSGabor Kovesdan 			    idx, idx);
861fdf1f88bSGabor Kovesdan 	}
862fdf1f88bSGabor Kovesdan }
863fdf1f88bSGabor Kovesdan 
864fdf1f88bSGabor Kovesdan static void
865fdf1f88bSGabor Kovesdan store_stack(void)
866fdf1f88bSGabor Kovesdan {
867fdf1f88bSGabor Kovesdan 	int		 idx;
868fdf1f88bSGabor Kovesdan 	struct value	*value;
869fdf1f88bSGabor Kovesdan 
870fdf1f88bSGabor Kovesdan 	idx = readreg();
871fdf1f88bSGabor Kovesdan 	if (idx >= 0) {
872fdf1f88bSGabor Kovesdan 		value = pop();
873fdf1f88bSGabor Kovesdan 		if (value == NULL)
874fdf1f88bSGabor Kovesdan 			return;
875fdf1f88bSGabor Kovesdan 		stack_push(&bmachine.reg[idx], value);
876fdf1f88bSGabor Kovesdan 	}
877fdf1f88bSGabor Kovesdan }
878fdf1f88bSGabor Kovesdan 
879fdf1f88bSGabor Kovesdan static void
880fdf1f88bSGabor Kovesdan load_array(void)
881fdf1f88bSGabor Kovesdan {
882fdf1f88bSGabor Kovesdan 	int			 reg;
883fdf1f88bSGabor Kovesdan 	struct number		*inumber, *n;
884fdf1f88bSGabor Kovesdan 	u_long			 idx;
885fdf1f88bSGabor Kovesdan 	struct stack		*stack;
886fdf1f88bSGabor Kovesdan 	struct value		*v, copy;
887fdf1f88bSGabor Kovesdan 
888fdf1f88bSGabor Kovesdan 	reg = readreg();
889fdf1f88bSGabor Kovesdan 	if (reg >= 0) {
890fdf1f88bSGabor Kovesdan 		inumber = pop_number();
891fdf1f88bSGabor Kovesdan 		if (inumber == NULL)
892fdf1f88bSGabor Kovesdan 			return;
893fdf1f88bSGabor Kovesdan 		idx = get_ulong(inumber);
894fdf1f88bSGabor Kovesdan 		if (BN_cmp(inumber->number, &zero) < 0)
895fdf1f88bSGabor Kovesdan 			warnx("negative idx");
896fdf1f88bSGabor Kovesdan 		else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX)
897fdf1f88bSGabor Kovesdan 			warnx("idx too big");
898fdf1f88bSGabor Kovesdan 		else {
899fdf1f88bSGabor Kovesdan 			stack = &bmachine.reg[reg];
900fdf1f88bSGabor Kovesdan 			v = frame_retrieve(stack, idx);
901fdf1f88bSGabor Kovesdan 			if (v == NULL || v->type == BCODE_NONE) {
902fdf1f88bSGabor Kovesdan 				n = new_number();
903fdf1f88bSGabor Kovesdan 				bn_check(BN_zero(n->number));
904fdf1f88bSGabor Kovesdan 				push_number(n);
905fdf1f88bSGabor Kovesdan 			}
906fdf1f88bSGabor Kovesdan 			else
907fdf1f88bSGabor Kovesdan 				push(stack_dup_value(v, &copy));
908fdf1f88bSGabor Kovesdan 		}
909fdf1f88bSGabor Kovesdan 		free_number(inumber);
910fdf1f88bSGabor Kovesdan 	}
911fdf1f88bSGabor Kovesdan }
912fdf1f88bSGabor Kovesdan 
913fdf1f88bSGabor Kovesdan static void
914fdf1f88bSGabor Kovesdan store_array(void)
915fdf1f88bSGabor Kovesdan {
916fdf1f88bSGabor Kovesdan 	int			 reg;
917fdf1f88bSGabor Kovesdan 	struct number		*inumber;
918fdf1f88bSGabor Kovesdan 	u_long			 idx;
919fdf1f88bSGabor Kovesdan 	struct value		*value;
920fdf1f88bSGabor Kovesdan 	struct stack		*stack;
921fdf1f88bSGabor Kovesdan 
922fdf1f88bSGabor Kovesdan 	reg = readreg();
923fdf1f88bSGabor Kovesdan 	if (reg >= 0) {
924fdf1f88bSGabor Kovesdan 		inumber = pop_number();
925fdf1f88bSGabor Kovesdan 		if (inumber == NULL)
926fdf1f88bSGabor Kovesdan 			return;
927fdf1f88bSGabor Kovesdan 		value = pop();
928fdf1f88bSGabor Kovesdan 		if (value == NULL) {
929fdf1f88bSGabor Kovesdan 			free_number(inumber);
930fdf1f88bSGabor Kovesdan 			return;
931fdf1f88bSGabor Kovesdan 		}
932fdf1f88bSGabor Kovesdan 		idx = get_ulong(inumber);
933fdf1f88bSGabor Kovesdan 		if (BN_cmp(inumber->number, &zero) < 0) {
934fdf1f88bSGabor Kovesdan 			warnx("negative idx");
935fdf1f88bSGabor Kovesdan 			stack_free_value(value);
936fdf1f88bSGabor Kovesdan 		} else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) {
937fdf1f88bSGabor Kovesdan 			warnx("idx too big");
938fdf1f88bSGabor Kovesdan 			stack_free_value(value);
939fdf1f88bSGabor Kovesdan 		} else {
940fdf1f88bSGabor Kovesdan 			stack = &bmachine.reg[reg];
941fdf1f88bSGabor Kovesdan 			frame_assign(stack, idx, value);
942fdf1f88bSGabor Kovesdan 		}
943fdf1f88bSGabor Kovesdan 		free_number(inumber);
944fdf1f88bSGabor Kovesdan 	}
945fdf1f88bSGabor Kovesdan }
946fdf1f88bSGabor Kovesdan 
947fdf1f88bSGabor Kovesdan static void
948fdf1f88bSGabor Kovesdan push_line(void)
949fdf1f88bSGabor Kovesdan {
950fdf1f88bSGabor Kovesdan 
951fdf1f88bSGabor Kovesdan 	push_string(read_string(&bmachine.readstack[bmachine.readsp]));
952fdf1f88bSGabor Kovesdan }
953fdf1f88bSGabor Kovesdan 
954fdf1f88bSGabor Kovesdan static void
955fdf1f88bSGabor Kovesdan comment(void)
956fdf1f88bSGabor Kovesdan {
957fdf1f88bSGabor Kovesdan 
958fdf1f88bSGabor Kovesdan 	free(readline());
959fdf1f88bSGabor Kovesdan }
960fdf1f88bSGabor Kovesdan 
961fdf1f88bSGabor Kovesdan static void
962fdf1f88bSGabor Kovesdan bexec(char *line)
963fdf1f88bSGabor Kovesdan {
964fdf1f88bSGabor Kovesdan 
965fdf1f88bSGabor Kovesdan 	system(line);
966fdf1f88bSGabor Kovesdan 	free(line);
967fdf1f88bSGabor Kovesdan }
968fdf1f88bSGabor Kovesdan 
969fdf1f88bSGabor Kovesdan static void
970fdf1f88bSGabor Kovesdan badd(void)
971fdf1f88bSGabor Kovesdan {
972fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
973fdf1f88bSGabor Kovesdan 	struct number	*r;
974fdf1f88bSGabor Kovesdan 
975fdf1f88bSGabor Kovesdan 	a = pop_number();
976fdf1f88bSGabor Kovesdan 	if (a == NULL) {
977fdf1f88bSGabor Kovesdan 		return;
978fdf1f88bSGabor Kovesdan 	}
979fdf1f88bSGabor Kovesdan 	b = pop_number();
980fdf1f88bSGabor Kovesdan 	if (b == NULL) {
981fdf1f88bSGabor Kovesdan 		push_number(a);
982fdf1f88bSGabor Kovesdan 		return;
983fdf1f88bSGabor Kovesdan 	}
984fdf1f88bSGabor Kovesdan 
985fdf1f88bSGabor Kovesdan 	r = new_number();
986fdf1f88bSGabor Kovesdan 	r->scale = max(a->scale, b->scale);
987fdf1f88bSGabor Kovesdan 	if (r->scale > a->scale)
988fdf1f88bSGabor Kovesdan 		normalize(a, r->scale);
989fdf1f88bSGabor Kovesdan 	else if (r->scale > b->scale)
990fdf1f88bSGabor Kovesdan 		normalize(b, r->scale);
991fdf1f88bSGabor Kovesdan 	bn_check(BN_add(r->number, a->number, b->number));
992fdf1f88bSGabor Kovesdan 	push_number(r);
993fdf1f88bSGabor Kovesdan 	free_number(a);
994fdf1f88bSGabor Kovesdan 	free_number(b);
995fdf1f88bSGabor Kovesdan }
996fdf1f88bSGabor Kovesdan 
997fdf1f88bSGabor Kovesdan static void
998fdf1f88bSGabor Kovesdan bsub(void)
999fdf1f88bSGabor Kovesdan {
1000fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
1001fdf1f88bSGabor Kovesdan 	struct number	*r;
1002fdf1f88bSGabor Kovesdan 
1003fdf1f88bSGabor Kovesdan 	a = pop_number();
1004fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1005fdf1f88bSGabor Kovesdan 		return;
1006fdf1f88bSGabor Kovesdan 	}
1007fdf1f88bSGabor Kovesdan 	b = pop_number();
1008fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1009fdf1f88bSGabor Kovesdan 		push_number(a);
1010fdf1f88bSGabor Kovesdan 		return;
1011fdf1f88bSGabor Kovesdan 	}
1012fdf1f88bSGabor Kovesdan 
1013fdf1f88bSGabor Kovesdan 	r = new_number();
1014fdf1f88bSGabor Kovesdan 
1015fdf1f88bSGabor Kovesdan 	r->scale = max(a->scale, b->scale);
1016fdf1f88bSGabor Kovesdan 	if (r->scale > a->scale)
1017fdf1f88bSGabor Kovesdan 		normalize(a, r->scale);
1018fdf1f88bSGabor Kovesdan 	else if (r->scale > b->scale)
1019fdf1f88bSGabor Kovesdan 		normalize(b, r->scale);
1020fdf1f88bSGabor Kovesdan 	bn_check(BN_sub(r->number, b->number, a->number));
1021fdf1f88bSGabor Kovesdan 	push_number(r);
1022fdf1f88bSGabor Kovesdan 	free_number(a);
1023fdf1f88bSGabor Kovesdan 	free_number(b);
1024fdf1f88bSGabor Kovesdan }
1025fdf1f88bSGabor Kovesdan 
1026fdf1f88bSGabor Kovesdan void
1027fdf1f88bSGabor Kovesdan bmul_number(struct number *r, struct number *a, struct number *b)
1028fdf1f88bSGabor Kovesdan {
1029fdf1f88bSGabor Kovesdan 	BN_CTX		*ctx;
1030fdf1f88bSGabor Kovesdan 
1031fdf1f88bSGabor Kovesdan 	/* Create copies of the scales, since r might be equal to a or b */
1032fdf1f88bSGabor Kovesdan 	u_int ascale = a->scale;
1033fdf1f88bSGabor Kovesdan 	u_int bscale = b->scale;
1034fdf1f88bSGabor Kovesdan 	u_int rscale = ascale + bscale;
1035fdf1f88bSGabor Kovesdan 
1036fdf1f88bSGabor Kovesdan 	ctx = BN_CTX_new();
1037fdf1f88bSGabor Kovesdan 	bn_checkp(ctx);
1038fdf1f88bSGabor Kovesdan 	bn_check(BN_mul(r->number, a->number, b->number, ctx));
1039fdf1f88bSGabor Kovesdan 	BN_CTX_free(ctx);
1040fdf1f88bSGabor Kovesdan 
1041fdf1f88bSGabor Kovesdan 	if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) {
1042fdf1f88bSGabor Kovesdan 		r->scale = rscale;
1043fdf1f88bSGabor Kovesdan 		normalize(r, max(bmachine.scale, max(ascale, bscale)));
1044fdf1f88bSGabor Kovesdan 	} else
1045fdf1f88bSGabor Kovesdan 		r->scale = rscale;
1046fdf1f88bSGabor Kovesdan }
1047fdf1f88bSGabor Kovesdan 
1048fdf1f88bSGabor Kovesdan static void
1049fdf1f88bSGabor Kovesdan bmul(void)
1050fdf1f88bSGabor Kovesdan {
1051fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
1052fdf1f88bSGabor Kovesdan 	struct number	*r;
1053fdf1f88bSGabor Kovesdan 
1054fdf1f88bSGabor Kovesdan 	a = pop_number();
1055fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1056fdf1f88bSGabor Kovesdan 		return;
1057fdf1f88bSGabor Kovesdan 	}
1058fdf1f88bSGabor Kovesdan 	b = pop_number();
1059fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1060fdf1f88bSGabor Kovesdan 		push_number(a);
1061fdf1f88bSGabor Kovesdan 		return;
1062fdf1f88bSGabor Kovesdan 	}
1063fdf1f88bSGabor Kovesdan 
1064fdf1f88bSGabor Kovesdan 	r = new_number();
1065fdf1f88bSGabor Kovesdan 	bmul_number(r, a, b);
1066fdf1f88bSGabor Kovesdan 
1067fdf1f88bSGabor Kovesdan 	push_number(r);
1068fdf1f88bSGabor Kovesdan 	free_number(a);
1069fdf1f88bSGabor Kovesdan 	free_number(b);
1070fdf1f88bSGabor Kovesdan }
1071fdf1f88bSGabor Kovesdan 
1072fdf1f88bSGabor Kovesdan static void
1073fdf1f88bSGabor Kovesdan bdiv(void)
1074fdf1f88bSGabor Kovesdan {
1075fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
1076fdf1f88bSGabor Kovesdan 	struct number	*r;
1077fdf1f88bSGabor Kovesdan 	u_int		 scale;
1078fdf1f88bSGabor Kovesdan 	BN_CTX		*ctx;
1079fdf1f88bSGabor Kovesdan 
1080fdf1f88bSGabor Kovesdan 	a = pop_number();
1081fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1082fdf1f88bSGabor Kovesdan 		return;
1083fdf1f88bSGabor Kovesdan 	}
1084fdf1f88bSGabor Kovesdan 	b = pop_number();
1085fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1086fdf1f88bSGabor Kovesdan 		push_number(a);
1087fdf1f88bSGabor Kovesdan 		return;
1088fdf1f88bSGabor Kovesdan 	}
1089fdf1f88bSGabor Kovesdan 
1090fdf1f88bSGabor Kovesdan 	r = new_number();
1091fdf1f88bSGabor Kovesdan 	r->scale = bmachine.scale;
1092fdf1f88bSGabor Kovesdan 	scale = max(a->scale, b->scale);
1093fdf1f88bSGabor Kovesdan 
1094fdf1f88bSGabor Kovesdan 	if (BN_is_zero(a->number))
1095fdf1f88bSGabor Kovesdan 		warnx("divide by zero");
1096fdf1f88bSGabor Kovesdan 	else {
1097fdf1f88bSGabor Kovesdan 		normalize(a, scale);
1098fdf1f88bSGabor Kovesdan 		normalize(b, scale + r->scale);
1099fdf1f88bSGabor Kovesdan 
1100fdf1f88bSGabor Kovesdan 		ctx = BN_CTX_new();
1101fdf1f88bSGabor Kovesdan 		bn_checkp(ctx);
1102fdf1f88bSGabor Kovesdan 		bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
1103fdf1f88bSGabor Kovesdan 		BN_CTX_free(ctx);
1104fdf1f88bSGabor Kovesdan 	}
1105fdf1f88bSGabor Kovesdan 	push_number(r);
1106fdf1f88bSGabor Kovesdan 	free_number(a);
1107fdf1f88bSGabor Kovesdan 	free_number(b);
1108fdf1f88bSGabor Kovesdan }
1109fdf1f88bSGabor Kovesdan 
1110fdf1f88bSGabor Kovesdan static void
1111fdf1f88bSGabor Kovesdan bmod(void)
1112fdf1f88bSGabor Kovesdan {
1113fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
1114fdf1f88bSGabor Kovesdan 	struct number	*r;
1115fdf1f88bSGabor Kovesdan 	u_int		 scale;
1116fdf1f88bSGabor Kovesdan 	BN_CTX		*ctx;
1117fdf1f88bSGabor Kovesdan 
1118fdf1f88bSGabor Kovesdan 	a = pop_number();
1119fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1120fdf1f88bSGabor Kovesdan 		return;
1121fdf1f88bSGabor Kovesdan 	}
1122fdf1f88bSGabor Kovesdan 	b = pop_number();
1123fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1124fdf1f88bSGabor Kovesdan 		push_number(a);
1125fdf1f88bSGabor Kovesdan 		return;
1126fdf1f88bSGabor Kovesdan 	}
1127fdf1f88bSGabor Kovesdan 
1128fdf1f88bSGabor Kovesdan 	r = new_number();
1129fdf1f88bSGabor Kovesdan 	scale = max(a->scale, b->scale);
1130fdf1f88bSGabor Kovesdan 	r->scale = max(b->scale, a->scale + bmachine.scale);
1131fdf1f88bSGabor Kovesdan 
1132fdf1f88bSGabor Kovesdan 	if (BN_is_zero(a->number))
1133fdf1f88bSGabor Kovesdan 		warnx("remainder by zero");
1134fdf1f88bSGabor Kovesdan 	else {
1135fdf1f88bSGabor Kovesdan 		normalize(a, scale);
1136fdf1f88bSGabor Kovesdan 		normalize(b, scale + bmachine.scale);
1137fdf1f88bSGabor Kovesdan 
1138fdf1f88bSGabor Kovesdan 		ctx = BN_CTX_new();
1139fdf1f88bSGabor Kovesdan 		bn_checkp(ctx);
1140fdf1f88bSGabor Kovesdan 		bn_check(BN_mod(r->number, b->number, a->number, ctx));
1141fdf1f88bSGabor Kovesdan 		BN_CTX_free(ctx);
1142fdf1f88bSGabor Kovesdan 	}
1143fdf1f88bSGabor Kovesdan 	push_number(r);
1144fdf1f88bSGabor Kovesdan 	free_number(a);
1145fdf1f88bSGabor Kovesdan 	free_number(b);
1146fdf1f88bSGabor Kovesdan }
1147fdf1f88bSGabor Kovesdan 
1148fdf1f88bSGabor Kovesdan static void
1149fdf1f88bSGabor Kovesdan bdivmod(void)
1150fdf1f88bSGabor Kovesdan {
1151fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
1152fdf1f88bSGabor Kovesdan 	struct number	*rdiv, *rmod;
1153fdf1f88bSGabor Kovesdan 	u_int		 scale;
1154fdf1f88bSGabor Kovesdan 	BN_CTX		*ctx;
1155fdf1f88bSGabor Kovesdan 
1156fdf1f88bSGabor Kovesdan 	a = pop_number();
1157fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1158fdf1f88bSGabor Kovesdan 		return;
1159fdf1f88bSGabor Kovesdan 	}
1160fdf1f88bSGabor Kovesdan 	b = pop_number();
1161fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1162fdf1f88bSGabor Kovesdan 		push_number(a);
1163fdf1f88bSGabor Kovesdan 		return;
1164fdf1f88bSGabor Kovesdan 	}
1165fdf1f88bSGabor Kovesdan 
1166fdf1f88bSGabor Kovesdan 	rdiv = new_number();
1167fdf1f88bSGabor Kovesdan 	rmod = new_number();
1168fdf1f88bSGabor Kovesdan 	rdiv->scale = bmachine.scale;
1169fdf1f88bSGabor Kovesdan 	rmod->scale = max(b->scale, a->scale + bmachine.scale);
1170fdf1f88bSGabor Kovesdan 	scale = max(a->scale, b->scale);
1171fdf1f88bSGabor Kovesdan 
1172fdf1f88bSGabor Kovesdan 	if (BN_is_zero(a->number))
1173fdf1f88bSGabor Kovesdan 		warnx("divide by zero");
1174fdf1f88bSGabor Kovesdan 	else {
1175fdf1f88bSGabor Kovesdan 		normalize(a, scale);
1176fdf1f88bSGabor Kovesdan 		normalize(b, scale + bmachine.scale);
1177fdf1f88bSGabor Kovesdan 
1178fdf1f88bSGabor Kovesdan 		ctx = BN_CTX_new();
1179fdf1f88bSGabor Kovesdan 		bn_checkp(ctx);
1180fdf1f88bSGabor Kovesdan 		bn_check(BN_div(rdiv->number, rmod->number,
1181fdf1f88bSGabor Kovesdan 		    b->number, a->number, ctx));
1182fdf1f88bSGabor Kovesdan 		BN_CTX_free(ctx);
1183fdf1f88bSGabor Kovesdan 	}
1184fdf1f88bSGabor Kovesdan 	push_number(rdiv);
1185fdf1f88bSGabor Kovesdan 	push_number(rmod);
1186fdf1f88bSGabor Kovesdan 	free_number(a);
1187fdf1f88bSGabor Kovesdan 	free_number(b);
1188fdf1f88bSGabor Kovesdan }
1189fdf1f88bSGabor Kovesdan 
1190fdf1f88bSGabor Kovesdan static void
1191fdf1f88bSGabor Kovesdan bexp(void)
1192fdf1f88bSGabor Kovesdan {
1193fdf1f88bSGabor Kovesdan 	struct number	*a, *p;
1194fdf1f88bSGabor Kovesdan 	struct number	*r;
1195fdf1f88bSGabor Kovesdan 	bool		 neg;
1196fdf1f88bSGabor Kovesdan 	u_int		 scale;
1197fdf1f88bSGabor Kovesdan 
1198fdf1f88bSGabor Kovesdan 	p = pop_number();
1199fdf1f88bSGabor Kovesdan 	if (p == NULL) {
1200fdf1f88bSGabor Kovesdan 		return;
1201fdf1f88bSGabor Kovesdan 	}
1202fdf1f88bSGabor Kovesdan 	a = pop_number();
1203fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1204fdf1f88bSGabor Kovesdan 		push_number(p);
1205fdf1f88bSGabor Kovesdan 		return;
1206fdf1f88bSGabor Kovesdan 	}
1207fdf1f88bSGabor Kovesdan 
1208fdf1f88bSGabor Kovesdan 	if (p->scale != 0)
1209fdf1f88bSGabor Kovesdan 		warnx("Runtime warning: non-zero scale in exponent");
1210fdf1f88bSGabor Kovesdan 	normalize(p, 0);
1211fdf1f88bSGabor Kovesdan 
1212fdf1f88bSGabor Kovesdan 	neg = false;
1213fdf1f88bSGabor Kovesdan 	if (BN_cmp(p->number, &zero) < 0) {
1214fdf1f88bSGabor Kovesdan 		neg = true;
1215fdf1f88bSGabor Kovesdan 		negate(p);
1216fdf1f88bSGabor Kovesdan 		scale = bmachine.scale;
1217fdf1f88bSGabor Kovesdan 	} else {
1218fdf1f88bSGabor Kovesdan 		/* Posix bc says min(a.scale * b, max(a.scale, scale) */
1219fdf1f88bSGabor Kovesdan 		u_long	 b;
1220fdf1f88bSGabor Kovesdan 		u_int	 m;
1221fdf1f88bSGabor Kovesdan 
1222fdf1f88bSGabor Kovesdan 		b = BN_get_word(p->number);
1223fdf1f88bSGabor Kovesdan 		m = max(a->scale, bmachine.scale);
1224fdf1f88bSGabor Kovesdan 		scale = a->scale * (u_int)b;
1225fdf1f88bSGabor Kovesdan 		if (scale > m || (a->scale > 0 && (b == BN_MASK2 ||
1226fdf1f88bSGabor Kovesdan 		    b > UINT_MAX)))
1227fdf1f88bSGabor Kovesdan 			scale = m;
1228fdf1f88bSGabor Kovesdan 	}
1229fdf1f88bSGabor Kovesdan 
1230fdf1f88bSGabor Kovesdan 	if (BN_is_zero(p->number)) {
1231fdf1f88bSGabor Kovesdan 		r = new_number();
1232fdf1f88bSGabor Kovesdan 		bn_check(BN_one(r->number));
1233fdf1f88bSGabor Kovesdan 		normalize(r, scale);
1234fdf1f88bSGabor Kovesdan 	} else {
1235fdf1f88bSGabor Kovesdan 		while (!BN_is_bit_set(p->number, 0)) {
1236fdf1f88bSGabor Kovesdan 			bmul_number(a, a, a);
1237fdf1f88bSGabor Kovesdan 			bn_check(BN_rshift1(p->number, p->number));
1238fdf1f88bSGabor Kovesdan 		}
1239fdf1f88bSGabor Kovesdan 
1240fdf1f88bSGabor Kovesdan 		r = dup_number(a);
1241fdf1f88bSGabor Kovesdan 		normalize(r, scale);
1242fdf1f88bSGabor Kovesdan 		bn_check(BN_rshift1(p->number, p->number));
1243fdf1f88bSGabor Kovesdan 
1244fdf1f88bSGabor Kovesdan 		while (!BN_is_zero(p->number)) {
1245fdf1f88bSGabor Kovesdan 			bmul_number(a, a, a);
1246fdf1f88bSGabor Kovesdan 			if (BN_is_bit_set(p->number, 0))
1247fdf1f88bSGabor Kovesdan 				bmul_number(r, r, a);
1248fdf1f88bSGabor Kovesdan 			bn_check(BN_rshift1(p->number, p->number));
1249fdf1f88bSGabor Kovesdan 		}
1250fdf1f88bSGabor Kovesdan 
1251fdf1f88bSGabor Kovesdan 		if (neg) {
1252fdf1f88bSGabor Kovesdan 			BN_CTX	*ctx;
1253fdf1f88bSGabor Kovesdan 			BIGNUM	*one;
1254fdf1f88bSGabor Kovesdan 
1255fdf1f88bSGabor Kovesdan 			one = BN_new();
1256fdf1f88bSGabor Kovesdan 			bn_checkp(one);
1257fdf1f88bSGabor Kovesdan 			bn_check(BN_one(one));
1258fdf1f88bSGabor Kovesdan 			ctx = BN_CTX_new();
1259fdf1f88bSGabor Kovesdan 			bn_checkp(ctx);
1260fdf1f88bSGabor Kovesdan 			scale_number(one, r->scale + scale);
1261fdf1f88bSGabor Kovesdan 			normalize(r, scale);
1262fdf1f88bSGabor Kovesdan 			bn_check(BN_div(r->number, NULL, one, r->number, ctx));
1263fdf1f88bSGabor Kovesdan 			BN_free(one);
1264fdf1f88bSGabor Kovesdan 			BN_CTX_free(ctx);
1265fdf1f88bSGabor Kovesdan 		} else
1266fdf1f88bSGabor Kovesdan 			normalize(r, scale);
1267fdf1f88bSGabor Kovesdan 	}
1268fdf1f88bSGabor Kovesdan 	push_number(r);
1269fdf1f88bSGabor Kovesdan 	free_number(a);
1270fdf1f88bSGabor Kovesdan 	free_number(p);
1271fdf1f88bSGabor Kovesdan }
1272fdf1f88bSGabor Kovesdan 
1273fdf1f88bSGabor Kovesdan static bool
1274fdf1f88bSGabor Kovesdan bsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount)
1275fdf1f88bSGabor Kovesdan {
1276fdf1f88bSGabor Kovesdan 	BIGNUM	*r;
1277fdf1f88bSGabor Kovesdan 	bool	 ret;
1278fdf1f88bSGabor Kovesdan 
1279fdf1f88bSGabor Kovesdan 	r = BN_new();
1280fdf1f88bSGabor Kovesdan 	bn_checkp(r);
1281fdf1f88bSGabor Kovesdan 	bn_check(BN_sub(r, x, y));
1282fdf1f88bSGabor Kovesdan 	if (BN_is_one(r))
1283fdf1f88bSGabor Kovesdan 		(*onecount)++;
1284fdf1f88bSGabor Kovesdan 	ret = BN_is_zero(r);
1285fdf1f88bSGabor Kovesdan 	BN_free(r);
1286fdf1f88bSGabor Kovesdan 	return (ret || *onecount > 1);
1287fdf1f88bSGabor Kovesdan }
1288fdf1f88bSGabor Kovesdan 
1289fdf1f88bSGabor Kovesdan static void
1290fdf1f88bSGabor Kovesdan bsqrt(void)
1291fdf1f88bSGabor Kovesdan {
1292fdf1f88bSGabor Kovesdan 	struct number	*n;
1293fdf1f88bSGabor Kovesdan 	struct number	*r;
1294fdf1f88bSGabor Kovesdan 	BIGNUM		*x, *y;
1295fdf1f88bSGabor Kovesdan 	u_int		 scale, onecount;
1296fdf1f88bSGabor Kovesdan 	BN_CTX		*ctx;
1297fdf1f88bSGabor Kovesdan 
1298fdf1f88bSGabor Kovesdan 	onecount = 0;
1299fdf1f88bSGabor Kovesdan 	n = pop_number();
1300fdf1f88bSGabor Kovesdan 	if (n == NULL) {
1301fdf1f88bSGabor Kovesdan 		return;
1302fdf1f88bSGabor Kovesdan 	}
1303fdf1f88bSGabor Kovesdan 	if (BN_is_zero(n->number)) {
1304fdf1f88bSGabor Kovesdan 		r = new_number();
1305fdf1f88bSGabor Kovesdan 		push_number(r);
1306fdf1f88bSGabor Kovesdan 	} else if (BN_cmp(n->number, &zero) < 0)
1307fdf1f88bSGabor Kovesdan 		warnx("square root of negative number");
1308fdf1f88bSGabor Kovesdan 	else {
1309fdf1f88bSGabor Kovesdan 		scale = max(bmachine.scale, n->scale);
1310fdf1f88bSGabor Kovesdan 		normalize(n, 2*scale);
1311fdf1f88bSGabor Kovesdan 		x = BN_dup(n->number);
1312fdf1f88bSGabor Kovesdan 		bn_checkp(x);
1313fdf1f88bSGabor Kovesdan 		bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
1314fdf1f88bSGabor Kovesdan 		y = BN_new();
1315fdf1f88bSGabor Kovesdan 		bn_checkp(y);
1316fdf1f88bSGabor Kovesdan 		ctx = BN_CTX_new();
1317fdf1f88bSGabor Kovesdan 		bn_checkp(ctx);
1318fdf1f88bSGabor Kovesdan 		for (;;) {
1319fdf1f88bSGabor Kovesdan 			bn_checkp(BN_copy(y, x));
1320fdf1f88bSGabor Kovesdan 			bn_check(BN_div(x, NULL, n->number, x, ctx));
1321fdf1f88bSGabor Kovesdan 			bn_check(BN_add(x, x, y));
1322fdf1f88bSGabor Kovesdan 			bn_check(BN_rshift1(x, x));
1323fdf1f88bSGabor Kovesdan 			if (bsqrt_stop(x, y, &onecount))
1324fdf1f88bSGabor Kovesdan 				break;
1325fdf1f88bSGabor Kovesdan 		}
1326fdf1f88bSGabor Kovesdan 		r = bmalloc(sizeof(*r));
1327fdf1f88bSGabor Kovesdan 		r->scale = scale;
1328fdf1f88bSGabor Kovesdan 		r->number = y;
1329fdf1f88bSGabor Kovesdan 		BN_free(x);
1330fdf1f88bSGabor Kovesdan 		BN_CTX_free(ctx);
1331fdf1f88bSGabor Kovesdan 		push_number(r);
1332fdf1f88bSGabor Kovesdan 	}
1333fdf1f88bSGabor Kovesdan 
1334fdf1f88bSGabor Kovesdan 	free_number(n);
1335fdf1f88bSGabor Kovesdan }
1336fdf1f88bSGabor Kovesdan 
1337fdf1f88bSGabor Kovesdan static void
1338fdf1f88bSGabor Kovesdan not(void)
1339fdf1f88bSGabor Kovesdan {
1340fdf1f88bSGabor Kovesdan 	struct number	*a;
1341fdf1f88bSGabor Kovesdan 
1342fdf1f88bSGabor Kovesdan 	a = pop_number();
1343fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1344fdf1f88bSGabor Kovesdan 		return;
1345fdf1f88bSGabor Kovesdan 	}
1346fdf1f88bSGabor Kovesdan 	a->scale = 0;
1347fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1));
1348fdf1f88bSGabor Kovesdan 	push_number(a);
1349fdf1f88bSGabor Kovesdan }
1350fdf1f88bSGabor Kovesdan 
1351fdf1f88bSGabor Kovesdan static void
1352fdf1f88bSGabor Kovesdan equal(void)
1353fdf1f88bSGabor Kovesdan {
1354fdf1f88bSGabor Kovesdan 
1355fdf1f88bSGabor Kovesdan 	compare(BCODE_EQUAL);
1356fdf1f88bSGabor Kovesdan }
1357fdf1f88bSGabor Kovesdan 
1358fdf1f88bSGabor Kovesdan static void
1359fdf1f88bSGabor Kovesdan equal_numbers(void)
1360fdf1f88bSGabor Kovesdan {
1361fdf1f88bSGabor Kovesdan 	struct number	*a, *b, *r;
1362fdf1f88bSGabor Kovesdan 
1363fdf1f88bSGabor Kovesdan 	a = pop_number();
1364fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1365fdf1f88bSGabor Kovesdan 		return;
1366fdf1f88bSGabor Kovesdan 	}
1367fdf1f88bSGabor Kovesdan 	b = pop_number();
1368fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1369fdf1f88bSGabor Kovesdan 		push_number(a);
1370fdf1f88bSGabor Kovesdan 		return;
1371fdf1f88bSGabor Kovesdan 	}
1372fdf1f88bSGabor Kovesdan 	r = new_number();
1373fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(r->number,
1374fdf1f88bSGabor Kovesdan 	    compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0));
1375fdf1f88bSGabor Kovesdan 	push_number(r);
1376fdf1f88bSGabor Kovesdan }
1377fdf1f88bSGabor Kovesdan 
1378fdf1f88bSGabor Kovesdan static void
1379fdf1f88bSGabor Kovesdan less_numbers(void)
1380fdf1f88bSGabor Kovesdan {
1381fdf1f88bSGabor Kovesdan 	struct number	*a, *b, *r;
1382fdf1f88bSGabor Kovesdan 
1383fdf1f88bSGabor Kovesdan 	a = pop_number();
1384fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1385fdf1f88bSGabor Kovesdan 		return;
1386fdf1f88bSGabor Kovesdan 	}
1387fdf1f88bSGabor Kovesdan 	b = pop_number();
1388fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1389fdf1f88bSGabor Kovesdan 		push_number(a);
1390fdf1f88bSGabor Kovesdan 		return;
1391fdf1f88bSGabor Kovesdan 	}
1392fdf1f88bSGabor Kovesdan 	r = new_number();
1393fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(r->number,
1394fdf1f88bSGabor Kovesdan 	    compare_numbers(BCODE_LESS, a, b) ? 1 : 0));
1395fdf1f88bSGabor Kovesdan 	push_number(r);
1396fdf1f88bSGabor Kovesdan }
1397fdf1f88bSGabor Kovesdan 
1398fdf1f88bSGabor Kovesdan static void
1399fdf1f88bSGabor Kovesdan lesseq_numbers(void)
1400fdf1f88bSGabor Kovesdan {
1401fdf1f88bSGabor Kovesdan 	struct number	*a, *b, *r;
1402fdf1f88bSGabor Kovesdan 
1403fdf1f88bSGabor Kovesdan 	a = pop_number();
1404fdf1f88bSGabor Kovesdan 	if (a == NULL) {
1405fdf1f88bSGabor Kovesdan 		return;
1406fdf1f88bSGabor Kovesdan 	}
1407fdf1f88bSGabor Kovesdan 	b = pop_number();
1408fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1409fdf1f88bSGabor Kovesdan 		push_number(a);
1410fdf1f88bSGabor Kovesdan 		return;
1411fdf1f88bSGabor Kovesdan 	}
1412fdf1f88bSGabor Kovesdan 	r = new_number();
1413fdf1f88bSGabor Kovesdan 	bn_check(BN_set_word(r->number,
1414fdf1f88bSGabor Kovesdan 	    compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0));
1415fdf1f88bSGabor Kovesdan 	push_number(r);
1416fdf1f88bSGabor Kovesdan }
1417fdf1f88bSGabor Kovesdan 
1418fdf1f88bSGabor Kovesdan static void
1419fdf1f88bSGabor Kovesdan not_equal(void)
1420fdf1f88bSGabor Kovesdan {
1421fdf1f88bSGabor Kovesdan 
1422fdf1f88bSGabor Kovesdan 	compare(BCODE_NOT_EQUAL);
1423fdf1f88bSGabor Kovesdan }
1424fdf1f88bSGabor Kovesdan 
1425fdf1f88bSGabor Kovesdan static void
1426fdf1f88bSGabor Kovesdan less(void)
1427fdf1f88bSGabor Kovesdan {
1428fdf1f88bSGabor Kovesdan 
1429fdf1f88bSGabor Kovesdan 	compare(BCODE_LESS);
1430fdf1f88bSGabor Kovesdan }
1431fdf1f88bSGabor Kovesdan 
1432fdf1f88bSGabor Kovesdan static void
1433fdf1f88bSGabor Kovesdan not_compare(void)
1434fdf1f88bSGabor Kovesdan {
1435fdf1f88bSGabor Kovesdan 	switch (readch()) {
1436fdf1f88bSGabor Kovesdan 	case '<':
1437fdf1f88bSGabor Kovesdan 		not_less();
1438fdf1f88bSGabor Kovesdan 		break;
1439fdf1f88bSGabor Kovesdan 	case '>':
1440fdf1f88bSGabor Kovesdan 		not_greater();
1441fdf1f88bSGabor Kovesdan 		break;
1442fdf1f88bSGabor Kovesdan 	case '=':
1443fdf1f88bSGabor Kovesdan 		not_equal();
1444fdf1f88bSGabor Kovesdan 		break;
1445fdf1f88bSGabor Kovesdan 	default:
1446fdf1f88bSGabor Kovesdan 		unreadch();
1447fdf1f88bSGabor Kovesdan 		bexec(readline());
1448fdf1f88bSGabor Kovesdan 		break;
1449fdf1f88bSGabor Kovesdan 	}
1450fdf1f88bSGabor Kovesdan }
1451fdf1f88bSGabor Kovesdan 
1452fdf1f88bSGabor Kovesdan static void
1453fdf1f88bSGabor Kovesdan not_less(void)
1454fdf1f88bSGabor Kovesdan {
1455fdf1f88bSGabor Kovesdan 
1456fdf1f88bSGabor Kovesdan 	compare(BCODE_NOT_LESS);
1457fdf1f88bSGabor Kovesdan }
1458fdf1f88bSGabor Kovesdan 
1459fdf1f88bSGabor Kovesdan static void
1460fdf1f88bSGabor Kovesdan greater(void)
1461fdf1f88bSGabor Kovesdan {
1462fdf1f88bSGabor Kovesdan 
1463fdf1f88bSGabor Kovesdan 	compare(BCODE_GREATER);
1464fdf1f88bSGabor Kovesdan }
1465fdf1f88bSGabor Kovesdan 
1466fdf1f88bSGabor Kovesdan static void
1467fdf1f88bSGabor Kovesdan not_greater(void)
1468fdf1f88bSGabor Kovesdan {
1469fdf1f88bSGabor Kovesdan 
1470fdf1f88bSGabor Kovesdan 	compare(BCODE_NOT_GREATER);
1471fdf1f88bSGabor Kovesdan }
1472fdf1f88bSGabor Kovesdan 
1473fdf1f88bSGabor Kovesdan static bool
1474fdf1f88bSGabor Kovesdan compare_numbers(enum bcode_compare type, struct number *a, struct number *b)
1475fdf1f88bSGabor Kovesdan {
1476fdf1f88bSGabor Kovesdan 	u_int	 scale;
1477fdf1f88bSGabor Kovesdan 	int	 cmp;
1478fdf1f88bSGabor Kovesdan 
1479fdf1f88bSGabor Kovesdan 	scale = max(a->scale, b->scale);
1480fdf1f88bSGabor Kovesdan 
1481fdf1f88bSGabor Kovesdan 	if (scale > a->scale)
1482fdf1f88bSGabor Kovesdan 		normalize(a, scale);
1483fdf1f88bSGabor Kovesdan 	else if (scale > b->scale)
1484fdf1f88bSGabor Kovesdan 		normalize(b, scale);
1485fdf1f88bSGabor Kovesdan 
1486fdf1f88bSGabor Kovesdan 	cmp = BN_cmp(a->number, b->number);
1487fdf1f88bSGabor Kovesdan 
1488fdf1f88bSGabor Kovesdan 	free_number(a);
1489fdf1f88bSGabor Kovesdan 	free_number(b);
1490fdf1f88bSGabor Kovesdan 
1491fdf1f88bSGabor Kovesdan 	switch (type) {
1492fdf1f88bSGabor Kovesdan 	case BCODE_EQUAL:
1493fdf1f88bSGabor Kovesdan 		return (cmp == 0);
1494fdf1f88bSGabor Kovesdan 	case BCODE_NOT_EQUAL:
1495fdf1f88bSGabor Kovesdan 		return (cmp != 0);
1496fdf1f88bSGabor Kovesdan 	case BCODE_LESS:
1497fdf1f88bSGabor Kovesdan 		return (cmp < 0);
1498fdf1f88bSGabor Kovesdan 	case BCODE_NOT_LESS:
1499fdf1f88bSGabor Kovesdan 		return (cmp >= 0);
1500fdf1f88bSGabor Kovesdan 	case BCODE_GREATER:
1501fdf1f88bSGabor Kovesdan 		return (cmp > 0);
1502fdf1f88bSGabor Kovesdan 	case BCODE_NOT_GREATER:
1503fdf1f88bSGabor Kovesdan 		return (cmp <= 0);
1504fdf1f88bSGabor Kovesdan 	}
1505fdf1f88bSGabor Kovesdan 	return (false);
1506fdf1f88bSGabor Kovesdan }
1507fdf1f88bSGabor Kovesdan 
1508fdf1f88bSGabor Kovesdan static void
1509fdf1f88bSGabor Kovesdan compare(enum bcode_compare type)
1510fdf1f88bSGabor Kovesdan {
1511fdf1f88bSGabor Kovesdan 	int		 idx, elseidx;
1512fdf1f88bSGabor Kovesdan 	struct number	*a, *b;
1513fdf1f88bSGabor Kovesdan 	bool		 ok;
1514fdf1f88bSGabor Kovesdan 	struct value	*v;
1515fdf1f88bSGabor Kovesdan 
1516fdf1f88bSGabor Kovesdan 	elseidx = NO_ELSE;
1517fdf1f88bSGabor Kovesdan 	idx = readreg();
1518fdf1f88bSGabor Kovesdan 	if (readch() == 'e')
1519fdf1f88bSGabor Kovesdan 		elseidx = readreg();
1520fdf1f88bSGabor Kovesdan 	else
1521fdf1f88bSGabor Kovesdan 		unreadch();
1522fdf1f88bSGabor Kovesdan 
1523fdf1f88bSGabor Kovesdan 	a = pop_number();
1524fdf1f88bSGabor Kovesdan 	if (a == NULL)
1525fdf1f88bSGabor Kovesdan 		return;
1526fdf1f88bSGabor Kovesdan 	b = pop_number();
1527fdf1f88bSGabor Kovesdan 	if (b == NULL) {
1528fdf1f88bSGabor Kovesdan 		push_number(a);
1529fdf1f88bSGabor Kovesdan 		return;
1530fdf1f88bSGabor Kovesdan 	}
1531fdf1f88bSGabor Kovesdan 
1532fdf1f88bSGabor Kovesdan 	ok = compare_numbers(type, a, b);
1533fdf1f88bSGabor Kovesdan 
1534fdf1f88bSGabor Kovesdan 	if (!ok && elseidx != NO_ELSE)
1535fdf1f88bSGabor Kovesdan 		idx = elseidx;
1536fdf1f88bSGabor Kovesdan 
1537fdf1f88bSGabor Kovesdan 	if (idx >= 0 && (ok || (!ok && elseidx != NO_ELSE))) {
1538fdf1f88bSGabor Kovesdan 		v = stack_tos(&bmachine.reg[idx]);
1539fdf1f88bSGabor Kovesdan 		if (v == NULL)
1540fdf1f88bSGabor Kovesdan 			warnx("register '%c' (0%o) is empty", idx, idx);
1541fdf1f88bSGabor Kovesdan 		else {
1542fdf1f88bSGabor Kovesdan 			switch(v->type) {
1543fdf1f88bSGabor Kovesdan 			case BCODE_NONE:
1544fdf1f88bSGabor Kovesdan 				warnx("register '%c' (0%o) is empty", idx, idx);
1545fdf1f88bSGabor Kovesdan 				break;
1546fdf1f88bSGabor Kovesdan 			case BCODE_NUMBER:
1547fdf1f88bSGabor Kovesdan 				warn("eval called with non-string argument");
1548fdf1f88bSGabor Kovesdan 				break;
1549fdf1f88bSGabor Kovesdan 			case BCODE_STRING:
1550fdf1f88bSGabor Kovesdan 				eval_string(bstrdup(v->u.string));
1551fdf1f88bSGabor Kovesdan 				break;
1552fdf1f88bSGabor Kovesdan 			}
1553fdf1f88bSGabor Kovesdan 		}
1554fdf1f88bSGabor Kovesdan 	}
1555fdf1f88bSGabor Kovesdan }
1556fdf1f88bSGabor Kovesdan 
1557fdf1f88bSGabor Kovesdan 
1558fdf1f88bSGabor Kovesdan static void
1559fdf1f88bSGabor Kovesdan nop(void)
1560fdf1f88bSGabor Kovesdan {
1561fdf1f88bSGabor Kovesdan }
1562fdf1f88bSGabor Kovesdan 
1563fdf1f88bSGabor Kovesdan static void
1564fdf1f88bSGabor Kovesdan quit(void)
1565fdf1f88bSGabor Kovesdan {
1566fdf1f88bSGabor Kovesdan 	if (bmachine.readsp < 2)
1567fdf1f88bSGabor Kovesdan 		exit(0);
1568fdf1f88bSGabor Kovesdan 	src_free();
1569fdf1f88bSGabor Kovesdan 	bmachine.readsp--;
1570fdf1f88bSGabor Kovesdan 	src_free();
1571fdf1f88bSGabor Kovesdan 	bmachine.readsp--;
1572fdf1f88bSGabor Kovesdan }
1573fdf1f88bSGabor Kovesdan 
1574fdf1f88bSGabor Kovesdan static void
1575fdf1f88bSGabor Kovesdan quitN(void)
1576fdf1f88bSGabor Kovesdan {
1577fdf1f88bSGabor Kovesdan 	struct number	*n;
1578fdf1f88bSGabor Kovesdan 	u_long		 i;
1579fdf1f88bSGabor Kovesdan 
1580fdf1f88bSGabor Kovesdan 	n = pop_number();
1581fdf1f88bSGabor Kovesdan 	if (n == NULL)
1582fdf1f88bSGabor Kovesdan 		return;
1583fdf1f88bSGabor Kovesdan 	i = get_ulong(n);
1584fdf1f88bSGabor Kovesdan 	free_number(n);
1585fdf1f88bSGabor Kovesdan 	if (i == BN_MASK2 || i == 0)
1586fdf1f88bSGabor Kovesdan 		warnx("Q command requires a number >= 1");
1587fdf1f88bSGabor Kovesdan 	else if (bmachine.readsp < i)
1588fdf1f88bSGabor Kovesdan 		warnx("Q command argument exceeded string execution depth");
1589fdf1f88bSGabor Kovesdan 	else {
1590fdf1f88bSGabor Kovesdan 		while (i-- > 0) {
1591fdf1f88bSGabor Kovesdan 			src_free();
1592fdf1f88bSGabor Kovesdan 			bmachine.readsp--;
1593fdf1f88bSGabor Kovesdan 		}
1594fdf1f88bSGabor Kovesdan 	}
1595fdf1f88bSGabor Kovesdan }
1596fdf1f88bSGabor Kovesdan 
1597fdf1f88bSGabor Kovesdan static void
1598fdf1f88bSGabor Kovesdan skipN(void)
1599fdf1f88bSGabor Kovesdan {
1600fdf1f88bSGabor Kovesdan 	struct number	*n;
1601fdf1f88bSGabor Kovesdan 	u_long		 i;
1602fdf1f88bSGabor Kovesdan 
1603fdf1f88bSGabor Kovesdan 	n = pop_number();
1604fdf1f88bSGabor Kovesdan 	if (n == NULL)
1605fdf1f88bSGabor Kovesdan 		return;
1606fdf1f88bSGabor Kovesdan 	i = get_ulong(n);
1607fdf1f88bSGabor Kovesdan 	if (i == BN_MASK2)
1608fdf1f88bSGabor Kovesdan 		warnx("J command requires a number >= 0");
1609fdf1f88bSGabor Kovesdan 	else if (i > 0 && bmachine.readsp < i)
1610fdf1f88bSGabor Kovesdan 		warnx("J command argument exceeded string execution depth");
1611fdf1f88bSGabor Kovesdan 	else {
1612fdf1f88bSGabor Kovesdan 		while (i-- > 0) {
1613fdf1f88bSGabor Kovesdan 			src_free();
1614fdf1f88bSGabor Kovesdan 			bmachine.readsp--;
1615fdf1f88bSGabor Kovesdan 		}
1616fdf1f88bSGabor Kovesdan 		skip_until_mark();
1617fdf1f88bSGabor Kovesdan 	}
1618fdf1f88bSGabor Kovesdan }
1619fdf1f88bSGabor Kovesdan 
1620fdf1f88bSGabor Kovesdan static void
1621fdf1f88bSGabor Kovesdan skip_until_mark(void)
1622fdf1f88bSGabor Kovesdan {
1623fdf1f88bSGabor Kovesdan 
1624fdf1f88bSGabor Kovesdan 	for (;;) {
1625*4ef08904SGabor Kovesdan 		switch (readch()) {
1626fdf1f88bSGabor Kovesdan 		case 'M':
1627fdf1f88bSGabor Kovesdan 			return;
1628fdf1f88bSGabor Kovesdan 		case EOF:
1629fdf1f88bSGabor Kovesdan 			errx(1, "mark not found");
1630fdf1f88bSGabor Kovesdan 			return;
1631fdf1f88bSGabor Kovesdan 		case 'l':
1632fdf1f88bSGabor Kovesdan 		case 'L':
1633fdf1f88bSGabor Kovesdan 		case 's':
1634fdf1f88bSGabor Kovesdan 		case 'S':
1635fdf1f88bSGabor Kovesdan 		case ':':
1636fdf1f88bSGabor Kovesdan 		case ';':
1637fdf1f88bSGabor Kovesdan 		case '<':
1638fdf1f88bSGabor Kovesdan 		case '>':
1639fdf1f88bSGabor Kovesdan 		case '=':
1640fdf1f88bSGabor Kovesdan 			readreg();
1641fdf1f88bSGabor Kovesdan 			if (readch() == 'e')
1642fdf1f88bSGabor Kovesdan 				readreg();
1643fdf1f88bSGabor Kovesdan 			else
1644fdf1f88bSGabor Kovesdan 				unreadch();
1645fdf1f88bSGabor Kovesdan 			break;
1646fdf1f88bSGabor Kovesdan 		case '[':
1647fdf1f88bSGabor Kovesdan 			free(read_string(&bmachine.readstack[bmachine.readsp]));
1648fdf1f88bSGabor Kovesdan 			break;
1649fdf1f88bSGabor Kovesdan 		case '!':
1650*4ef08904SGabor Kovesdan 			switch (readch()) {
1651fdf1f88bSGabor Kovesdan 				case '<':
1652fdf1f88bSGabor Kovesdan 				case '>':
1653fdf1f88bSGabor Kovesdan 				case '=':
1654fdf1f88bSGabor Kovesdan 					readreg();
1655fdf1f88bSGabor Kovesdan 					if (readch() == 'e')
1656fdf1f88bSGabor Kovesdan 						readreg();
1657fdf1f88bSGabor Kovesdan 					else
1658fdf1f88bSGabor Kovesdan 						unreadch();
1659fdf1f88bSGabor Kovesdan 					break;
1660fdf1f88bSGabor Kovesdan 				default:
1661fdf1f88bSGabor Kovesdan 					free(readline());
1662fdf1f88bSGabor Kovesdan 					break;
1663fdf1f88bSGabor Kovesdan 			}
1664fdf1f88bSGabor Kovesdan 			break;
1665fdf1f88bSGabor Kovesdan 		default:
1666fdf1f88bSGabor Kovesdan 			break;
1667fdf1f88bSGabor Kovesdan 		}
1668fdf1f88bSGabor Kovesdan 	}
1669fdf1f88bSGabor Kovesdan }
1670fdf1f88bSGabor Kovesdan 
1671fdf1f88bSGabor Kovesdan static void
1672fdf1f88bSGabor Kovesdan parse_number(void)
1673fdf1f88bSGabor Kovesdan {
1674fdf1f88bSGabor Kovesdan 
1675fdf1f88bSGabor Kovesdan 	unreadch();
1676fdf1f88bSGabor Kovesdan 	push_number(readnumber(&bmachine.readstack[bmachine.readsp],
1677fdf1f88bSGabor Kovesdan 	    bmachine.ibase));
1678fdf1f88bSGabor Kovesdan }
1679fdf1f88bSGabor Kovesdan 
1680fdf1f88bSGabor Kovesdan static void
1681fdf1f88bSGabor Kovesdan unknown(void)
1682fdf1f88bSGabor Kovesdan {
1683fdf1f88bSGabor Kovesdan 	int ch = bmachine.readstack[bmachine.readsp].lastchar;
1684fdf1f88bSGabor Kovesdan 	warnx("%c (0%o) is unimplemented", ch, ch);
1685fdf1f88bSGabor Kovesdan }
1686fdf1f88bSGabor Kovesdan 
1687fdf1f88bSGabor Kovesdan static void
1688fdf1f88bSGabor Kovesdan eval_string(char *p)
1689fdf1f88bSGabor Kovesdan {
1690fdf1f88bSGabor Kovesdan 	int	 ch;
1691fdf1f88bSGabor Kovesdan 
1692fdf1f88bSGabor Kovesdan 	if (bmachine.readsp > 0) {
1693fdf1f88bSGabor Kovesdan 		/* Check for tail call. Do not recurse in that case. */
1694fdf1f88bSGabor Kovesdan 		ch = readch();
1695fdf1f88bSGabor Kovesdan 		if (ch == EOF) {
1696fdf1f88bSGabor Kovesdan 			src_free();
1697fdf1f88bSGabor Kovesdan 			src_setstring(&bmachine.readstack[bmachine.readsp], p);
1698fdf1f88bSGabor Kovesdan 			return;
1699fdf1f88bSGabor Kovesdan 		} else
1700fdf1f88bSGabor Kovesdan 			unreadch();
1701fdf1f88bSGabor Kovesdan 	}
1702fdf1f88bSGabor Kovesdan 	if (bmachine.readsp == bmachine.readstack_sz - 1) {
1703fdf1f88bSGabor Kovesdan 		size_t newsz = bmachine.readstack_sz * 2;
1704fdf1f88bSGabor Kovesdan 		struct source *stack;
1705fdf1f88bSGabor Kovesdan 		stack = realloc(bmachine.readstack, newsz *
1706fdf1f88bSGabor Kovesdan 		    sizeof(struct source));
1707fdf1f88bSGabor Kovesdan 		if (stack == NULL)
1708fdf1f88bSGabor Kovesdan 			err(1, "recursion too deep");
1709fdf1f88bSGabor Kovesdan 		bmachine.readstack_sz = newsz;
1710fdf1f88bSGabor Kovesdan 		bmachine.readstack = stack;
1711fdf1f88bSGabor Kovesdan 	}
1712fdf1f88bSGabor Kovesdan 	src_setstring(&bmachine.readstack[++bmachine.readsp], p);
1713fdf1f88bSGabor Kovesdan }
1714fdf1f88bSGabor Kovesdan 
1715fdf1f88bSGabor Kovesdan static void
1716fdf1f88bSGabor Kovesdan eval_line(void)
1717fdf1f88bSGabor Kovesdan {
1718fdf1f88bSGabor Kovesdan 	/* Always read from stdin */
1719fdf1f88bSGabor Kovesdan 	struct source	 in;
1720fdf1f88bSGabor Kovesdan 	char		*p;
1721fdf1f88bSGabor Kovesdan 
1722fdf1f88bSGabor Kovesdan 	clearerr(stdin);
1723fdf1f88bSGabor Kovesdan 	src_setstream(&in, stdin);
1724fdf1f88bSGabor Kovesdan 	p = (*in.vtable->readline)(&in);
1725fdf1f88bSGabor Kovesdan 	eval_string(p);
1726fdf1f88bSGabor Kovesdan }
1727fdf1f88bSGabor Kovesdan 
1728fdf1f88bSGabor Kovesdan static void
1729fdf1f88bSGabor Kovesdan eval_tos(void)
1730fdf1f88bSGabor Kovesdan {
1731fdf1f88bSGabor Kovesdan 	char	*p;
1732fdf1f88bSGabor Kovesdan 
1733fdf1f88bSGabor Kovesdan 	p = pop_string();
1734fdf1f88bSGabor Kovesdan 	if (p == NULL)
1735fdf1f88bSGabor Kovesdan 		return;
1736fdf1f88bSGabor Kovesdan 	eval_string(p);
1737fdf1f88bSGabor Kovesdan }
1738fdf1f88bSGabor Kovesdan 
1739fdf1f88bSGabor Kovesdan void
1740fdf1f88bSGabor Kovesdan eval(void)
1741fdf1f88bSGabor Kovesdan {
1742fdf1f88bSGabor Kovesdan 	int	 ch;
1743fdf1f88bSGabor Kovesdan 
1744fdf1f88bSGabor Kovesdan 	for (;;) {
1745fdf1f88bSGabor Kovesdan 		ch = readch();
1746fdf1f88bSGabor Kovesdan 		if (ch == EOF) {
1747fdf1f88bSGabor Kovesdan 			if (bmachine.readsp == 0)
1748fdf1f88bSGabor Kovesdan 				return;
1749fdf1f88bSGabor Kovesdan 			src_free();
1750fdf1f88bSGabor Kovesdan 			bmachine.readsp--;
1751fdf1f88bSGabor Kovesdan 			continue;
1752fdf1f88bSGabor Kovesdan 		}
1753fdf1f88bSGabor Kovesdan 		if (bmachine.interrupted) {
1754fdf1f88bSGabor Kovesdan 			if (bmachine.readsp > 0) {
1755fdf1f88bSGabor Kovesdan 				src_free();
1756fdf1f88bSGabor Kovesdan 				bmachine.readsp--;
1757fdf1f88bSGabor Kovesdan 				continue;
1758fdf1f88bSGabor Kovesdan 			} else
1759fdf1f88bSGabor Kovesdan 				bmachine.interrupted = false;
1760fdf1f88bSGabor Kovesdan 		}
1761fdf1f88bSGabor Kovesdan #ifdef DEBUGGING
1762fdf1f88bSGabor Kovesdan 		fprintf(stderr, "# %c\n", ch);
1763fdf1f88bSGabor Kovesdan 		stack_print(stderr, &bmachine.stack, "* ",
1764fdf1f88bSGabor Kovesdan 		    bmachine.obase);
1765fdf1f88bSGabor Kovesdan 		fprintf(stderr, "%zd =>\n", bmachine.readsp);
1766fdf1f88bSGabor Kovesdan #endif
1767fdf1f88bSGabor Kovesdan 
1768fdf1f88bSGabor Kovesdan 		if (0 <= ch && ch < (signed)UCHAR_MAX)
1769fdf1f88bSGabor Kovesdan 			(*jump_table[ch])();
1770fdf1f88bSGabor Kovesdan 		else
1771fdf1f88bSGabor Kovesdan 			warnx("internal error: opcode %d", ch);
1772fdf1f88bSGabor Kovesdan 
1773fdf1f88bSGabor Kovesdan #ifdef DEBUGGING
1774fdf1f88bSGabor Kovesdan 		stack_print(stderr, &bmachine.stack, "* ",
1775fdf1f88bSGabor Kovesdan 		    bmachine.obase);
1776fdf1f88bSGabor Kovesdan 		fprintf(stderr, "%zd ==\n", bmachine.readsp);
1777fdf1f88bSGabor Kovesdan #endif
1778fdf1f88bSGabor Kovesdan 	}
1779fdf1f88bSGabor Kovesdan }
1780