/********************************************************************
 *                                                                  *
 *      CRISP - Custom Reduced Instruction Set Programmers Editor   *
 *                                                                  *
 *      (C) Paul Fox, 1989                                          *
 *                                                                  *
 *                                                                  *
 *    Please See COPYLEFT notice.                                   *
 *                                                                  *
 ********************************************************************/
# include	"crisp.h"

/***********************************************************************
/*    A simple calculator useful for doing number base conversions.
/***********************************************************************/
# define	OP_STATE	1	/* User just typed an operator.	*/
# define	NUM_STATE	2	/* User is typing a number.	*/
# define	EQ_STATE	3	/* User just typed an =		*/

list mem = quote_list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
void
calc()
{	extern int window_offset, top_line;
	int	curbuf,
		curwin,
		buf,
		win,
		accumulator,
		yaccumulator,
		radix,
		calc_state;
	string	op;
	
	accumulator = yaccumulator = 0;
	radix = 10;
	op = "+";
	calc_state = OP_STATE;
	curbuf = inq_buffer();
	curwin = inq_window();
	buf = create_buffer("Calculator", NULL, 1);
	win = sized_window(11, 23, int_to_key(ALT_H) + " for Help");
	set_window(win);
	set_buffer(buf);
	attach_buffer(buf);
	
	insert("\n");
	insert("\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\n");
	insert("Hex \xf1 Oct \xf1 Dec \xf1 rec\n");
	insert("Not \xf1 And \xf1 oR  \xf1 sto\n");
	insert(" a  \xf1  b  \xf1  c  \xf1     \n");
	insert(" d  \xf1  e  \xf1  f  \xf1  %\n");
	insert(" 9  \xf1  8  \xf1  7  \xf1  /\n");
	insert(" 6  \xf1  5  \xf1  4  \xf1  *\n");
	insert(" 3  \xf1  2  \xf1  1  \xf1  -\n");
	insert(" 0  \xf1  =  \xf1 Sign\xf1  +\n");
	top_of_buffer();
	
	keyboard_push();
	keyboard_typeables();
	assign_to_key("<Esc>", "exit");
	assign_to_key("D", "calc_radix 10");
	assign_to_key("r", "calc_r_cmd");
	assign_to_key("s", "calc_s_cmd");
	assign_to_key("H", "calc_radix 16");
	assign_to_key("N", "calc_N_cmd");
	assign_to_key("O", "calc_radix 8");
	assign_to_key("S", "calc_S_cmd");
	assign_to_key("C", "calc_C_cmd");
	assign_to_key("<Alt-H>", "cshelp \"features\" \"Calculator (infix)\"");
	register_macro(REG_TYPED, "calc_typed");
	calc_display_acc();
	window_offset += 9;
	top_line += 2;
	process();
	window_offset -= 9;
	top_line -= 2;
	keyboard_pop();
	unregister_macro(REG_TYPED, "calc_typed");
	
	delete_buffer(buf);
	delete_window();
	
	set_buffer(curbuf);
	set_window(curwin);
	attach_buffer(curbuf);
	refresh();
}
void
calc_N_cmd()
{	extern int accumulator;
	accumulator = ~accumulator;
	calc_display_acc();
}
void
calc_S_cmd()
{	extern int accumulator;
	accumulator = -accumulator;
	calc_display_acc();
}
/**********************************************************************/
/*   Clear the accumulator.					      */
/**********************************************************************/
void
calc_C_cmd()
{	extern int accumulator, yaccumulator;
	extern string op;

	accumulator = yaccumulator = 0;
	op = "+";
	calc_display_acc();
}
void
calc_r_cmd()
{	extern int accumulator;
	int	i;

	message("Recall Memory - type a digit.");
	while ((i = read_char()) == -1)
		continue;
	if (i >= '0' && i <= '9') {
		accumulator = mem[i - '0'];
		calc_display_acc();
		}
	message("");
}
void
calc_s_cmd()
{	extern int accumulator;
	int	i;

	message("Store in Memory - type a digit.");
	while ((i = read_char()) == -1)
		continue;
	if (i >= '0' && i <= '9') {
		i -= '0';
		mem[i] = accumulator;
		message("%d stored in MEM%d", accumulator, i);
		}
}
void
calc_radix()
{	extern int radix, calc_state;

	get_parm(0, radix);
	calc_state = OP_STATE;
	calc_display_acc();
}
void
calc_display_acc()
{	extern int radix, accumulator;
	string str;
	
	top_of_buffer();
	delete_to_eol();
	switch (radix) {
	  case 8:	sprintf(str, "OCT %14o", accumulator);
	  case 10:	sprintf(str, "DEC %14d", accumulator);
	  case 16:	sprintf(str, "HEX %14x", accumulator);
	  }
	insert(str);
}
void
calc_typed()
{	extern int calc_state, accumulator, yaccumulator;
	extern int radix;
	extern	string op;
	string ch, str;
	int	i;
	
	prev_char();
	ch = read(1);
	delete_char();
	
	if (index("0123456789abcdef", ch)) {
		switch (calc_state) {
		  case OP_STATE:	accumulator = 0;
		  case EQ_STATE:
					yaccumulator = 0;
					accumulator = 0;
		  }
		if (index("abcdef", ch)) 
			sprintf(ch, "%d", index("abcdef", ch) + 9);
		accumulator = (accumulator * radix) + atoi(ch);
		calc_display_acc();
		calc_state = NUM_STATE;
		return;
		}
	if (index("+-*/%ARX=", ch)) {
		int old_acc;
		old_acc = accumulator;
		switch (op) {
		  case "+":	accumulator = yaccumulator + accumulator;
		  case "-":	accumulator = yaccumulator - accumulator;
		  case "*":	accumulator = yaccumulator * accumulator;
		  case "/":	accumulator = yaccumulator / accumulator;
		  case "%":	accumulator = yaccumulator % accumulator;
		  case "A":	accumulator = yaccumulator & accumulator;
		  case "R":	accumulator = yaccumulator | accumulator;
		  case "X":	accumulator = yaccumulator ^ accumulator;
		  }
		calc_display_acc();
		yaccumulator = accumulator;
		accumulator = old_acc;
		if (ch == "=")
			calc_state = EQ_STATE;
		else	{
			calc_state = OP_STATE;
			op = ch;
			}
		return;
		}
	i = atoi(ch, 0);
	switch (int_to_key(i)) {
	  case "<Backspace>":
		backspace();
		beginning_of_line();
		right(3);
		re_search(SF_UNIX, "[~ ]");
		str = trim (read());
		accumulator = atoi(str);
		calc_display_acc();
		return;
	  }
}
