1 /*
2  * Calcoo: c_main.c
3  *
4  * Copyright (C) 2001, 2002, 2003 Alexei Kaminski
5  *
6  * creates and initializes cpu
7  *
8  * also handles "clear all" and RPN toggles
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <math.h>
14 #include <float.h>
15 
16 #include "codes.h"
17 #include "const.h"
18 #include "defaults.h"
19 #include "cpu.h"
20 #include "c_headers.h"
21 #include "io_headers.h"
22 #include "aux_headers.h"
23 
24 t_calcoo_cpu *cpu;
25 
26 void reset_stack(void);
27 
init_cpu(void)28 void init_cpu(void)
29 /* mallocs and initializes cpu variables;
30  * runs once, after calcoo is started */
31 {
32 	int i;
33 
34 	cpu = (t_calcoo_cpu*) malloc (sizeof(t_calcoo_cpu));
35 	if(cpu == NULL)
36 		error_occured("malloc in init_cpu() failed", TRUE);
37 	cpu->d = (t_cpu_display*) malloc (sizeof(t_cpu_display));
38 	if(cpu->d == NULL)
39 		error_occured("malloc in init_cpu() failed", TRUE);
40 
41 	cpu->stack_head = NULL;
42 
43 	for(i = 0; i < NUMBER_OF_MEMS; i++)
44 	{
45 		cpu->mem[i] = 0.0;
46 		cpu->mem_d[i] =
47 			(t_cpu_display*) malloc (sizeof(t_cpu_display));
48 	}
49 	for(i = 0; i < NUMBER_OF_REG_DISPLAYS; i++)
50 	{
51 		cpu->reg_d[i] =
52 			(t_cpu_display*) malloc (sizeof(t_cpu_display));
53 		if(cpu->reg_d[i] == NULL)
54 			error_occured("malloc in init_cpu() failed", TRUE);
55 
56 		cpu->op_d[i] = (t_cpu_operation_display*)
57 			malloc (sizeof(t_cpu_operation_display));
58 		if(cpu->op_d[i] == NULL)
59 			error_occured("malloc in init_cpu() failed", TRUE);
60 	}
61 
62 	reset_registers();
63 	cpu->prescribed_format = DEFAULT_DISPLAY_FORMAT;
64 	cpu->curr_mem = 0;
65 	cpu->rpn_mode = FALSE ; /* It is a kluge. We need it to have proper
66 		* (to display nothing) initialization of the operation
67 		* displays. The reason is that cpu->rpn_mode is used in
68 		* cpu_to_output(), and if it turns out to be set to TRUE
69 		* after having been malloc'ed, cpu_to_output() does not
70 		* reset operation displays. If these displays contain
71 		* some garbage after having been malloc'ed, it will lead to
72 		* weird stuff displayed in the operation displays in the
73 		* algebraic mode from after initialization until the next
74 		* call to cpu_to_output */
75 
76 	if (MAXIMIZE_PRECISION)
77 		cpu->precision = pow(10, -floor(fabs(log10(DBL_EPSILON))) + 1);
78 	        /* "+1" is just in case, to underestimate precision;
79 		 * as for -floor(fabs()), it is just me being paranoid,
80 		 * since I am not sure wether the behavior of floor()
81 		 * of a negative number is universal */
82 	else
83 		cpu->precision = pow(10, -INPUT_LENGTH - 1);
84         /* it is going to be used in evaluation of
85 	 * trigonometric functions to get sin PI == 0
86 	 * rather than 10^-17 and also in subtraction/addition
87 	 * to have 100.1 - 100 - 0.1 == 0 rather than 1e-15 */
88 
89 	cpu_to_output();
90 	init_undo_stack();
91   	refresh_body();
92 }
93 
aftermath(void)94 void aftermath(void)
95 {
96 	cpu_to_output();
97 	save_for_undo();
98 	refresh_body();
99 }
100 
reset_registers(void)101 void reset_registers(void)
102 /* the function called by the "C" button" */
103 {
104 	cpu->x = 0.0;
105 	cpu->y = 0.0;
106 	cpu->z = 0.0;
107 	cpu->t = 0.0;
108 
109 	cpu->op = CODE_NO_OPERATION;
110 	cpu->number_of_parens = 0;
111 
112 	reset_stack();
113 	cpu->last_action = ACTION_CLEAR;
114 	cpu->x_overflow = FALSE;
115 
116 	cpu->d->input_field = INPUT_FIELD_INT;
117 	cpu->d->sign = SIGN_PLUS;
118 	cpu->d->exp_sign = SIGN_PLUS;
119 	cpu->d->format = FORMAT_FIX;
120 	cpu->d->display_overflow = FALSE;
121 	cpu->d->n_int = 0;
122 	cpu->d->n_frac = 0;
123 }
124 
reset_stack(void)125 void reset_stack(void)
126 {
127 	t_stack_element *to_remove;
128 
129 	while (cpu->stack_head != NULL)
130 	{
131 		to_remove = cpu->stack_head;
132 		cpu->stack_head = cpu->stack_head->next;
133 		free(to_remove);
134 	}
135 }
136 
call_set_rpn_mode(int a)137 void call_set_rpn_mode(int a)
138 {
139 	double tmp;
140 
141 	if (a != cpu->rpn_mode)
142 	{
143 		if (cpu->last_action == ACTION_INPUT)
144 			input_to_x();
145 		tmp = cpu->x;
146 		reset_undo_stack();
147 		reset_registers();
148 		cpu->x = tmp;
149 
150 		if (a)
151 		{
152 			cpu->rpn_mode = TRUE;
153 		} else {
154 			cpu->rpn_mode = FALSE;
155 		} /* why not just "cpu->rpn_mode = a;"? I don't remember why */
156 
157 		cpu_to_output();
158 		save_for_undo();
159 		refresh_body();
160 	}
161 }
162 
call_get_rpn_mode(void)163 int call_get_rpn_mode(void)
164 {
165 	return cpu->rpn_mode;
166 }
167 
call_set_enter_mode(int new_mode)168 void call_set_enter_mode(int new_mode)
169 {
170 	cpu->enter_mode = new_mode;
171 }
172 
call_get_enter_mode(void)173 int call_get_enter_mode(void)
174 {
175 	return cpu->enter_mode;
176 }
177 
call_set_rounding_mode(int a)178 void call_set_rounding_mode(int a)
179 {
180 	if (cpu->last_action == ACTION_INPUT) {
181 		input_to_x();
182 		cpu->last_action = ACTION_ENTER;
183 	}
184 
185 	if (a > 0 )
186 	{
187 		cpu->rounding = TRUE;
188 		cpu->digits_to_keep = a;
189 	} else {
190 		cpu->rounding = FALSE;
191 		cpu->digits_to_keep = -a;
192 	}
193 	cpu_to_output();
194 	refresh_body();
195 }
196 
call_get_rounding_mode(void)197 int call_get_rounding_mode(void)
198 {
199 	if (cpu->rounding)
200 		return cpu->digits_to_keep;
201 	else
202 		return -cpu->digits_to_keep;
203 }
204 
call_set_trunc_zeros_mode(int a)205 void call_set_trunc_zeros_mode(int a)
206 {
207 	if(cpu->rounding){
208 		if (cpu->last_action == ACTION_INPUT) {
209 			input_to_x();
210 			cpu->last_action = ACTION_ENTER;
211 		}
212 
213 		cpu->trunc_zeros = a;
214 		cpu_to_output();
215 		refresh_body();
216 	} else {
217 		/* to ensure proper loading of options */
218 		cpu->trunc_zeros = a;
219 	}
220 }
221 
call_get_trunc_zeros_mode(void)222 int call_get_trunc_zeros_mode(void)
223 {
224 	return cpu->trunc_zeros;
225 }
226 
227 
call_set_stack_mode(int new_mode)228 void call_set_stack_mode(int new_mode)
229 {
230 	cpu->stack_mode = new_mode;
231 	if (new_mode == STACK_MODE_XYZT)
232 		reset_stack(); /* resets stack only beyond T */
233 }
234 
call_get_stack_mode(void)235 int call_get_stack_mode(void)
236 {
237 	return cpu->stack_mode;
238 }
239 
call_get_angle_units(void)240 int call_get_angle_units(void)
241 {
242 	return cpu->angle_units;
243 }
244 
call_change_angle_units(void)245 void call_change_angle_units(void)
246 {
247 	if (cpu->angle_units == CODE_DEG)
248 		cpu->angle_units = CODE_RAD;
249 	else
250 		cpu->angle_units = CODE_DEG;
251 
252 	save_for_undo();
253 	refresh_body();
254 }
255 
call_set_angle_units(int a)256 void call_set_angle_units(int a)
257 {
258 	cpu->angle_units = a;
259 	refresh_body();
260 }
261 
262