Remove unused UI routines
[gcalctool.git] / gcalctool / functions.c
blobdcbbf013d6ae3ef4a43952a4942681ca6f499cd3
2 /* $Header$
4 * Copyright (c) 1987-2007 Sun Microsystems, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "functions.h"
31 #include "get.h"
32 #include "mp.h"
33 #include "mpmath.h"
34 #include "display.h"
35 #include "ce_parser.h"
36 #include "lr_parser.h"
37 #include "ui.h"
39 char *
40 gc_strdup(char *str)
42 char *dup;
43 int len;
45 if (!str) {
46 return NULL;
49 len = strlen(str);
50 dup = malloc(len+1);
51 assert(dup);
52 memset(dup, 0, len+1);
53 strncpy(dup, str, len);
55 return(dup);
59 void
60 make_exp(char *number, int t[MP_SIZE])
62 int i;
63 char *a = NULL;
64 char *b = NULL;
66 int MP_a[MP_SIZE];
67 int MP_b[MP_SIZE];
69 assert(number);
70 a = gc_strdup(number);
71 assert(a);
73 for (i = 0; !((a[i] == 'e') || (a[i] == 'E')); i++) {
74 assert(a[i]);
77 a[i] = 0;
78 b = &a[i+2];
80 MPstr_to_num(a, v->base, MP_a);
81 MPstr_to_num(b, v->base, MP_b);
82 if (a[i+1] == '-') {
83 int MP_c[MP_SIZE];
84 mpneg(MP_b, MP_c);
85 calc_xtimestenpowx(MP_a, MP_c, t);
86 } else {
87 calc_xtimestenpowx(MP_a, MP_b, t);
90 free(a);
94 static void
95 update_undo_redo_button_sensitivity(void)
97 int undo = 0;
98 int redo = 0;
100 if (v->h.current != v->h.end) {
101 redo = 1;
104 if (v->h.current != v->h.begin) {
105 undo = 1;
108 ui_set_undo_enabled(undo, redo);
112 void
113 clear_undo_history(void)
115 int i = v->h.begin;
116 while (i != v->h.end) {
117 if (i != v->h.current) {
118 free(v->h.e[i].expression);
119 v->h.e[i].expression = NULL;
121 i = ((i + 1) % UNDO_HISTORY_LENGTH);
123 v->h.begin = v->h.end = v->h.current;
124 update_undo_redo_button_sensitivity();
128 struct exprm_state *
129 get_state(void)
131 return &(v->h.e[v->h.current]);
135 static void
136 copy_state(struct exprm_state *dst, struct exprm_state *src)
138 MEMCPY(dst, src, sizeof(struct exprm_state));
139 dst->expression = gc_strdup(src->expression);
143 static void
144 purge_redo_history(void)
146 if (v->h.current != v->h.end) {
147 int i = v->h.current;
149 do {
150 i = ((i + 1) % UNDO_HISTORY_LENGTH);
151 free(v->h.e[i].expression);
152 v->h.e[i].expression = NULL;
153 } while (i != v->h.end);
156 v->h.end = v->h.current;
160 void
161 new_state(void)
163 int c;
165 purge_redo_history();
167 c = v->h.current;
168 v->h.end = v->h.current = ((v->h.current + 1) % UNDO_HISTORY_LENGTH);
169 if (v->h.current == v->h.begin) {
170 free(v->h.e[v->h.begin].expression);
171 v->h.e[v->h.begin].expression = NULL;
172 v->h.begin = ((v->h.begin + 1) % UNDO_HISTORY_LENGTH);
175 copy_state(&(v->h.e[v->h.current]), &(v->h.e[c]));
176 update_undo_redo_button_sensitivity();
180 void
181 perform_undo(void)
183 if (v->h.current != v->h.begin) {
184 v->h.current = ((v->h.current - 1) % UNDO_HISTORY_LENGTH);
185 ui_set_statusbar("", "");
186 } else {
187 ui_set_statusbar("No undo history", "gtk-dialog-warning");
189 update_undo_redo_button_sensitivity();
193 static int
194 is_undo_step()
196 return(v->h.current != v->h.begin);
200 void
201 perform_redo(void)
203 if (v->h.current != v->h.end) {
204 v->h.current = ((v->h.current + 1) % UNDO_HISTORY_LENGTH);
205 ui_set_statusbar("", "");
206 } else {
207 ui_set_statusbar("No redo steps", "gtk-dialog-warning");
209 update_undo_redo_button_sensitivity();
213 void
214 do_accuracy(int value) /* Set display accuracy. */
216 v->accuracy = value;
217 set_int_resource(R_ACCURACY, v->accuracy);
218 ui_set_accuracy(v->accuracy);
219 ui_make_registers();
220 clear_undo_history();
221 syntaxdep_show_display();
225 void
226 do_business() /* Perform special business mode calculations. */
228 if (v->current == KEY_FINC_CTRM) {
229 calc_ctrm(v->MPdisp_val);
230 } else if (v->current == KEY_FINC_DDB) {
231 calc_ddb(v->MPdisp_val);
232 } else if (v->current == KEY_FINC_FV) {
233 calc_fv(v->MPdisp_val);
234 } else if (v->current == KEY_FINC_PMT) {
235 calc_pmt(v->MPdisp_val);
236 } else if (v->current == KEY_FINC_PV) {
237 calc_pv(v->MPdisp_val);
238 } else if (v->current == KEY_FINC_RATE) {
239 calc_rate(v->MPdisp_val);
240 } else if (v->current == KEY_FINC_SLN) {
241 calc_sln(v->MPdisp_val);
242 } else if (v->current == KEY_FINC_SYD) {
243 calc_syd(v->MPdisp_val);
244 } else if (v->current == KEY_FINC_TERM) {
245 calc_term(v->MPdisp_val);
247 show_display(v->MPdisp_val);
251 void
252 exp_append(char *text)
254 char *buf;
255 int orig_len, dest_len;
256 struct exprm_state *e;
258 if (!text) {
259 return;
262 e = get_state();
264 orig_len = (e->expression) ? strlen(e->expression) : 0;
265 dest_len = orig_len + strlen(text) +1;
266 buf = malloc(dest_len);
267 assert(buf);
268 if (e->expression) {
269 if (snprintf(buf, dest_len, "%s%s", e->expression, text) < 0) {
270 assert(0);
272 } else {
273 STRCPY(buf, text);
275 free(e->expression);
276 e->expression = buf;
280 void
281 exp_del()
283 struct exprm_state *e = get_state();
284 free(e->expression);
285 e->expression = NULL;
289 int
290 usable_num(int MPnum[MP_SIZE])
292 int ret = 0;
294 struct exprm_state *e = get_state();
296 if (e->expression) {
297 ret = ce_parse(e->expression, MPnum);
298 } else {
299 do_zero(MPnum);
302 return ret;
306 static void
307 exp_del_char(char **expr, int amount)
309 char *e = NULL;
310 int len;
312 assert(expr);
313 assert(amount >= 0);
315 if (!*expr) {
316 return;
318 len = strlen(*expr);
319 len = len - amount;
320 if (len >= 0) {
321 e = malloc(len+1);
322 assert(e);
323 SNPRINTF(e, len+1, "%s", *expr);
326 free(*expr);
327 *expr = e;
331 void
332 exp_replace(char *text)
334 struct exprm_state *e = get_state();
335 free(e->expression);
336 e->expression = NULL;
337 exp_append(text);
341 static void
342 exp_negate()
344 struct exprm_state *e = get_state();
346 if (e->expression) {
347 /* Ending zero + parenthesis + minus */
348 int len = strlen(e->expression) + 4;
349 char *exp = malloc(len);
351 assert(exp);
352 if (snprintf(exp, len, "-(%s)", e->expression) < 0) {
353 assert(0);
355 free(e->expression);
356 e->expression = exp;
361 static void
362 exp_inv()
364 struct exprm_state *e = get_state();
366 if (e->expression) {
367 /* Ending zero + 1/ + parenthesis */
368 int len = strlen(e->expression) + 5;
369 char *exp = malloc(len);
371 assert(exp);
372 if (snprintf(exp, len, "1/(%s)", e->expression) < 0) {
373 assert(0);
375 free(e->expression);
376 e->expression = exp;
381 static int
382 exp_has_postfix(char *str, char *postfix)
384 int len, plen;
386 if (!str) {
387 return(0);
390 assert(postfix);
392 len = strlen(str);
393 plen = strlen(postfix);
395 if (plen > len) {
396 return(0);
399 if (!strcasecmp(str + len - plen, postfix)) {
400 return(1);
401 } else {
402 return(0);
407 void
408 str_replace(char **str, char *from, char *to)
410 int i, flen, len;
412 assert(str);
413 assert(from);
414 assert(to);
416 if (!*str) {
417 return;
420 i = 0;
421 len = strlen(*str);
422 flen = strlen(from);
424 for (i = 0; len-i >= flen; i++) {
425 if (!strncasecmp(from, *str+i, flen)) {
426 char *print;
427 int j = i+flen;
428 char *prefix = malloc(i+1);
429 char *postfix = malloc(len-j+1);
431 assert(prefix && postfix);
432 memset(prefix, 0, i+1);
433 memset(postfix, 0, len-j+1);
434 MEMCPY(prefix, *str, i);
435 MEMCPY(postfix, *str+i+flen, len-j);
437 print = malloc(strlen(to)+i+len-j+1);
438 SPRINTF(print, "%s%s%s", prefix, to, postfix);
439 free(prefix);
440 free(postfix);
441 free(*str);
442 *str = print;
448 void
449 do_expression()
451 int i;
452 char buf[MAXLINE];
453 struct exprm_state *e;
455 e = get_state();
457 ui_set_statusbar("", "");
459 if (e->expression != NULL && strlen(e->expression) > 0) {
460 if (!strcmp(e->expression, "Ans")) {
461 if (e->button.flags & NUMBER) {
462 exp_del();
465 } else {
466 if (e->button.flags & POSTFIXOP) {
467 int MP1[MP_SIZE];
468 char *zero = NULL;
469 do_zero(MP1);
470 zero = make_number(MP1, v->base, FALSE);
471 exp_append(zero);
475 if ((e->button.flags & (PREFIXOP | FUNC))
476 && e->expression
477 && !strcmp(e->expression, "Ans")) {
478 SNPRINTF(buf, MAXLINE, "%s(Ans)", e->button.symname);
479 exp_replace(buf);
480 } else {
481 switch (e->button.id) {
482 case KEY_CLEAR:
483 case KEY_CLEAR_ENTRY:
484 exp_del();
485 ui_set_error_state(FALSE);
486 MPstr_to_num("0", DEC, e->ans);
487 break;
489 case KEY_SHIFT:
490 do_shift(e->value);
491 return;
493 case KEY_SET_ACCURACY:
494 do_accuracy(e->value);
495 return;
497 case KEY_FUNCTION:
498 do_function(e->value);
499 return;
501 case KEY_STORE:
502 do_sto(e->value);
503 return;
505 case KEY_EXCHANGE:
506 do_exchange(e->value);
507 return;
509 case KEY_RECALL:
510 SNPRINTF(buf, MAXLINE, "R%d", e->value);
511 exp_append(buf);
512 break;
514 case KEY_CONSTANT:
515 exp_append(make_number(v->MPcon_vals[e->value], v->base, FALSE));
516 break;
518 case KEY_BACKSPACE:
519 if (exp_has_postfix(e->expression, "Ans")) {
520 char *ans = make_number(e->ans, v->base, FALSE);
521 str_replace(&e->expression, "Ans", ans);
522 } else {
523 for (i = 0; i < 10; i++) {
524 SNPRINTF(buf, MAXLINE, "R%d", i);
525 if (exp_has_postfix(e->expression, buf)) {
526 int MP_reg[MP_SIZE];
527 char *reg_val;
529 do_rcl_reg(i, MP_reg);
530 reg_val = make_number(MP_reg, v->base, FALSE);
531 /* Remove "Rx" postfix. */
532 exp_del_char(&e->expression, 2);
533 exp_append(reg_val);
537 exp_del_char(&e->expression, 1);
538 break;
540 case KEY_CHANGE_SIGN:
541 exp_negate();
542 break;
544 case KEY_RECIPROCAL:
545 exp_inv();
546 break;
548 case KEY_CALCULATE:
549 if (e->expression) {
550 if (strcmp(e->expression, "Ans")) {
551 int MPval[MP_SIZE];
552 int ret = ce_parse(e->expression, MPval);
554 if (!ret) {
555 mpstr(MPval, e->ans);
556 exp_replace("Ans");
557 } else {
558 char *message = NULL;
560 switch (ret) {
561 case -PARSER_ERR_INVALID_BASE:
562 message = _("Invalid number for the current base");
563 break;
565 case -PARSER_ERR_TOO_LONG_NUMBER:
566 message = _("Too long number");
567 break;
569 case -PARSER_ERR_BITWISEOP:
570 message = _("Invalid bitwise operation parameter(s)");
571 break;
573 case -PARSER_ERR_MODULUSOP:
574 message = _("Invalid modulus operation parameter(s)");
575 break;
577 case -MPMATH_ERR:
578 message = _("Math operation error");
579 break;
581 default:
582 message = _("Malformed expression");
584 ui_set_statusbar(message, "gtk-dialog-error");
586 } else {
587 perform_undo();
588 if (is_undo_step()) {
589 perform_undo();
593 break;
595 case KEY_NUMERIC_POINT:
596 exp_append(ui_get_localized_numeric_point());
597 break;
599 default:
600 exp_append(e->button.symname);
601 if (e->button.flags & FUNC) {
602 exp_append("(");
604 break;
608 refresh_display();
612 void
613 do_calc() /* Perform arithmetic calculation and display result. */
615 double dval, dres;
616 int MP1[MP_SIZE], MP2[MP_SIZE];
618 if (v->current == KEY_CALCULATE &&
619 v->old_cal_value == KEY_CALCULATE) {
620 if (v->new_input) {
621 mpstr(v->MPlast_input, v->MPresult);
622 } else {
623 mpstr(v->MPlast_input, v->MPdisp_val);
627 if (v->current != KEY_CALCULATE &&
628 v->old_cal_value == KEY_CALCULATE) {
629 v->cur_op = -1;
632 switch (v->cur_op) {
633 case KEY_SIN:
634 case KEY_SINH:
635 case KEY_ASIN:
636 case KEY_ASINH:
637 case KEY_COS:
638 case KEY_COSH:
639 case KEY_ACOS:
640 case KEY_ACOSH:
641 case KEY_TAN:
642 case KEY_TANH:
643 case KEY_ATAN:
644 case KEY_ATANH:
645 case -1:
646 mpstr(v->MPdisp_val, v->MPresult);
647 break;
649 case KEY_ADD:
650 mpadd(v->MPresult, v->MPdisp_val, v->MPresult);
651 break;
653 case KEY_SUBTRACT:
654 mpsub(v->MPresult, v->MPdisp_val, v->MPresult);
655 break;
657 case KEY_MULTIPLY:
658 mpmul(v->MPresult, v->MPdisp_val, v->MPresult);
659 break;
661 case KEY_DIVIDE:
662 mpdiv(v->MPresult, v->MPdisp_val, v->MPresult);
663 break;
665 case KEY_MODULUS_DIVIDE:
666 mpcmim(v->MPresult, MP1);
667 mpcmim(v->MPdisp_val, MP2);
668 if (!mpeq(v->MPresult, MP1) || !mpeq(v->MPdisp_val, MP2)) {
669 doerr(_("Error, operands must be integers"));
672 mpdiv(v->MPresult, v->MPdisp_val, MP1);
673 mpcmim(MP1, MP1);
674 mpmul(MP1, v->MPdisp_val, MP2);
675 mpsub(v->MPresult, MP2, v->MPresult);
676 break;
678 case KEY_X_POW_Y:
679 calc_xpowy(v->MPresult, v->MPdisp_val, v->MPresult);
680 break;
682 case KEY_AND:
683 mpcmd(v->MPresult, &dres);
684 mpcmd(v->MPdisp_val, &dval);
685 dres = setbool(ibool(dres) & ibool(dval));
686 mpcdm(&dres, v->MPresult);
687 break;
689 case KEY_OR:
690 mpcmd(v->MPresult, &dres);
691 mpcmd(v->MPdisp_val, &dval);
692 dres = setbool(ibool(dres) | ibool(dval));
693 mpcdm(&dres, v->MPresult);
694 break;
696 case KEY_XOR:
697 mpcmd(v->MPresult, &dres);
698 mpcmd(v->MPdisp_val, &dval);
699 dres = setbool(ibool(dres) ^ ibool(dval));
700 mpcdm(&dres, v->MPresult);
701 break;
703 case KEY_XNOR:
704 mpcmd(v->MPresult, &dres);
705 mpcmd(v->MPdisp_val, &dval);
706 dres = setbool(~ibool(dres) ^ ibool(dval));
707 mpcdm(&dres, v->MPresult);
709 default:
710 break;
713 show_display(v->MPresult);
715 if (!(v->current == KEY_CALCULATE &&
716 v->old_cal_value == KEY_CALCULATE)) {
717 mpstr(v->MPdisp_val, v->MPlast_input);
720 mpstr(v->MPresult, v->MPdisp_val);
721 if (v->current != KEY_CALCULATE) {
722 v->cur_op = v->current;
724 v->old_cal_value = v->current;
725 v->new_input = v->key_exp = 0;
729 void
730 do_sin(void)
732 calc_trigfunc(sin_t, v->MPdisp_val, v->MPresult);
733 show_display(v->MPresult);
734 mpstr(v->MPresult, v->MPdisp_val);
738 void
739 do_sinh(void)
741 calc_trigfunc(sinh_t, v->MPdisp_val, v->MPresult);
742 show_display(v->MPresult);
743 mpstr(v->MPresult, v->MPdisp_val);
747 void
748 do_asin(void)
750 calc_trigfunc(asin_t, v->MPdisp_val, v->MPresult);
751 show_display(v->MPresult);
752 mpstr(v->MPresult, v->MPdisp_val);
756 void
757 do_asinh(void)
759 calc_trigfunc(asinh_t, v->MPdisp_val, v->MPresult);
760 show_display(v->MPresult);
761 mpstr(v->MPresult, v->MPdisp_val);
765 void
766 do_cos(void)
768 calc_trigfunc(cos_t, v->MPdisp_val, v->MPresult);
769 show_display(v->MPresult);
770 mpstr(v->MPresult, v->MPdisp_val);
774 void
775 do_cosh(void)
777 calc_trigfunc(cosh_t, v->MPdisp_val, v->MPresult);
778 show_display(v->MPresult);
779 mpstr(v->MPresult, v->MPdisp_val);
783 void
784 do_acos(void)
786 calc_trigfunc(acos_t, v->MPdisp_val, v->MPresult);
787 show_display(v->MPresult);
788 mpstr(v->MPresult, v->MPdisp_val);
792 void
793 do_acosh(void)
795 calc_trigfunc(acosh_t, v->MPdisp_val, v->MPresult);
796 show_display(v->MPresult);
797 mpstr(v->MPresult, v->MPdisp_val);
801 void
802 do_tan(void)
804 calc_trigfunc(tan_t, v->MPdisp_val, v->MPresult);
805 show_display(v->MPresult);
806 mpstr(v->MPresult, v->MPdisp_val);
810 void
811 do_tanh(void)
813 calc_trigfunc(tanh_t, v->MPdisp_val, v->MPresult);
814 show_display(v->MPresult);
815 mpstr(v->MPresult, v->MPdisp_val);
819 void
820 do_atan(void)
822 calc_trigfunc(atan_t, v->MPdisp_val, v->MPresult);
823 show_display(v->MPresult);
824 mpstr(v->MPresult, v->MPdisp_val);
828 void
829 do_atanh(void)
831 calc_trigfunc(atanh_t, v->MPdisp_val, v->MPresult);
832 show_display(v->MPresult);
833 mpstr(v->MPresult, v->MPdisp_val);
837 void
838 do_percent(void)
840 calc_percent(v->MPdisp_val, v->MPresult);
841 show_display(v->MPresult);
842 mpstr(v->MPresult, v->MPdisp_val);
846 void
847 do_clear() /* Clear the calculator display and re-initialise. */
849 clear_display(TRUE);
850 if (v->error) {
851 ui_set_display("", FALSE);
853 initialise();
857 void
858 do_clear_entry() /* Clear the calculator display. */
860 clear_display(FALSE);
863 void
864 do_base(enum base_type b) /* Change the current base setting. */
866 struct exprm_state *e;
867 int ret, MP[MP_SIZE];
869 switch (v->syntax) {
870 case NPA:
871 v->base = b;
872 set_resource(R_BASE, Rbstr[(int) v->base]);
873 ui_set_base(v->base);
875 if (v->rstate) {
876 ui_make_registers();
878 break;
880 case EXPRS:
881 e = get_state();
882 ret = usable_num(MP);
884 if (ret) {
885 ui_set_statusbar(_("No sane value to convert"),
886 "gtk-dialog-error");
887 } else if (!v->ghost_zero) {
888 mpstr(MP, e->ans);
889 exp_replace("Ans");
891 v->base = b;
892 set_resource(R_BASE, Rbstr[(int) v->base]);
893 ui_set_base(v->base);
894 ui_make_registers();
895 clear_undo_history();
896 break;
898 default:
899 assert(0);
902 refresh_display();
906 void
907 do_constant(int index)
909 int *MPval;
910 struct exprm_state *e;
912 assert(index >= 0);
913 assert(index <= 9);
915 switch (v->syntax) {
916 case NPA:
917 MPval = v->MPcon_vals[index];
918 mpstr(MPval, v->MPdisp_val);
919 break;
921 case EXPRS:
922 e = get_state();
923 do_expression();
924 break;
926 default:
927 assert(0);
930 v->new_input = 1;
931 syntaxdep_show_display();
935 void
936 do_delete() /* Remove the last numeric character typed. */
938 size_t len;
940 len = strlen(v->display);
941 if (len > 0) {
942 v->display[len-1] = '\0';
945 /* If we were entering a scientific number, and we have backspaced over
946 * the exponent sign, then this reverts to entering a fixed point number.
949 if (v->key_exp && !(strchr(v->display, '+'))) {
950 v->key_exp = 0;
951 v->display[strlen(v->display)-1] = '\0';
954 /* If we've backspaced over the numeric point, clear the pointed flag. */
956 if (v->pointed && !(strchr(v->display, '.'))) {
957 v->pointed = 0;
960 ui_set_display(v->display, TRUE);
961 MPstr_to_num(v->display, v->base, v->MPdisp_val);
963 if (v->dtype == FIX) {
964 STRCPY(v->fnum, v->display);
965 ui_set_display(v->fnum, FALSE);
970 void
971 do_exchange(int index) /* Exchange display with memory register. */
973 int MPtemp[MP_SIZE];
974 int MPexpr[MP_SIZE];
975 struct exprm_state *e;
976 int ret;
977 int n;
979 switch (v->syntax) {
980 case NPA:
981 mpstr(v->MPdisp_val, MPtemp);
982 mpstr(v->MPmvals[index], v->MPdisp_val);
983 mpstr(MPtemp, v->MPmvals[index]);
984 ui_make_registers();
985 break;
987 case EXPRS:
988 e = get_state();
989 ret = usable_num(MPexpr);
990 n = e->value;
992 if (ret) {
993 ui_set_statusbar(_("No sane value to store"),
994 "gtk-dialog-error");
995 } else {
996 mpstr(v->MPmvals[n], MPtemp);
997 mpstr(MPexpr, v->MPmvals[n]);
998 mpstr(MPtemp, e->ans);
999 exp_replace("Ans");
1000 refresh_display();
1001 ui_make_registers();
1003 break;
1005 default:
1006 assert(0);
1009 v->new_input = 1;
1010 syntaxdep_show_display();
1015 void
1016 do_expno() /* Get exponential number. */
1018 v->pointed = (strchr(v->display, '.') != NULL);
1019 if (!v->new_input) {
1020 STRCPY(v->display, "1.0 +");
1021 v->new_input = v->pointed = 1;
1022 } else if (!v->pointed) {
1023 STRNCAT(v->display, ". +", 3);
1024 v->pointed = 1;
1025 } else if (!v->key_exp) {
1026 STRNCAT(v->display, " +", 2);
1028 v->toclear = 0;
1029 v->key_exp = 1;
1030 v->exp_posn = strchr(v->display, '+');
1031 ui_set_display(v->display, FALSE);
1032 MPstr_to_num(v->display, v->base, v->MPdisp_val);
1036 /* Calculate the factorial of MPval. */
1038 void
1039 do_factorial(int *MPval, int *MPres)
1041 double val;
1042 int i, MPa[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE];
1044 /* NOTE: do_factorial, on each iteration of the loop, will attempt to
1045 * convert the current result to a double. If v->error is set,
1046 * then we've overflowed. This is to provide the same look&feel
1047 * as V3.
1049 * XXX: Needs to be improved. Shouldn't need to convert to a double in
1050 * order to check this.
1053 mpstr(MPval, MPa);
1054 mpcmim(MPval, MP1);
1055 i = 0;
1056 mpcim(&i, MP2);
1057 if (mpeq(MPval, MP1) && mpge(MPval, MP2)) { /* Only positive integers. */
1058 i = 1;
1059 if (mpeq(MP1, MP2)) { /* Special case for 0! */
1060 mpcim(&i, MPres);
1061 return;
1063 mpcim(&i, MPa);
1064 mpcmi(MP1, &i);
1065 if (!i) {
1066 matherr((struct exception *) NULL);
1067 } else {
1068 while (i > 0) {
1069 mpmuli(MPa, &i, MPa);
1070 mpcmd(MPa, &val);
1071 if (v->error) {
1072 mperr();
1073 return;
1075 i--;
1078 } else {
1079 matherr((struct exception *) NULL);
1081 mpstr(MPa, MPres);
1085 void
1086 do_function(int index) /* Perform a user defined function. */
1088 char *str;
1089 int ret;
1091 assert(index >= 0);
1092 assert(index <= 9);
1094 switch (v->syntax) {
1095 case NPA:
1096 str = v->fun_vals[index];
1097 assert(str);
1098 ret = lr_udf_parse(str);
1099 break;
1101 case EXPRS:
1102 str = v->fun_vals[index];
1103 assert(str);
1104 ret = ce_udf_parse(str);
1105 break;
1107 default:
1108 assert(0);
1111 if (!ret) {
1112 ui_set_statusbar("", "");
1113 } else {
1114 ui_set_statusbar(_("Malformed function"), "gtk-dialog-error");
1116 v->new_input = 1;
1120 static void
1121 do_immedfunc(int s[MP_SIZE], int t[MP_SIZE])
1123 int MP1[MP_SIZE];
1125 if (v->current == KEY_MASK_32) { /* &32 */
1126 calc_u32(s, t);
1127 } else if (v->current == KEY_MASK_16) { /* &16 */
1128 calc_u16(s, t);
1129 } else if (v->current == KEY_E_POW_X) { /* e^x */
1130 mpstr(s, MP1);
1131 mpexp(MP1, t);
1132 } else if (v->current == KEY_10_POW_X) { /* 10^x */
1133 calc_tenpowx(s, t);
1134 } else if (v->current == KEY_NATURAL_LOGARITHM) { /* Ln */
1135 mpstr(s, MP1);
1136 mpln(MP1, t);
1137 } else if (v->current == KEY_LOGARITHM) { /* Log */
1138 mplog10(s, t);
1139 } else if (v->current == KEY_RANDOM) { /* Rand */
1140 calc_rand(t);
1141 } else if (v->current == KEY_SQUARE_ROOT) { /* Sqrt */
1142 mpstr(s, MP1);
1143 mpsqrt(MP1, t);
1144 } else if (v->current == KEY_NOT) { /* NOT */
1145 calc_not(t, s);
1146 } else if (v->current == KEY_RECIPROCAL) { /* 1/x */
1147 calc_inv(s, t);
1148 } else if (v->current == KEY_FACTORIAL) { /* x! */
1149 do_factorial(s, MP1);
1150 mpstr(MP1, t);
1151 } else if (v->current == KEY_SQUARE) { /* x^2 */
1152 mpstr(s, MP1);
1153 mpmul(MP1, MP1, t);
1154 } else if (v->current == KEY_CHANGE_SIGN) { /* +/- */
1155 if (v->key_exp) {
1156 if (*v->exp_posn == '+') {
1157 *v->exp_posn = '-';
1158 } else {
1159 *v->exp_posn = '+';
1161 ui_set_display(v->display, FALSE);
1162 MPstr_to_num(v->display, v->base, s);
1163 v->key_exp = 0;
1164 } else {
1165 mpneg(s, t);
1171 void
1172 do_immed()
1174 do_immedfunc(v->MPdisp_val, v->MPdisp_val);
1175 show_display(v->MPdisp_val);
1179 void
1180 do_memory()
1182 set_boolean_resource(R_REGS, v->rstate == TRUE);
1183 ui_set_registers_visible(v->rstate);
1187 void
1188 do_mode(int toclear) /* Set special calculator mode. */
1190 set_resource(R_MODE, Rmstr[(int) v->modetype]);
1191 ui_set_mode(v->modetype);
1192 if (toclear) {
1193 do_clear();
1198 void
1199 do_number()
1201 int offset;
1203 if (v->toclear) {
1204 offset = 0;
1205 v->toclear = 0;
1206 } else {
1207 offset = strlen(v->display);
1209 if (offset < MAXLINE) {
1210 SNPRINTF(v->display+offset, MAXLINE-offset, "%s", buttons[v->current].symname);
1213 ui_set_display(v->display, TRUE);
1214 MPstr_to_num(v->display, v->base, v->MPdisp_val);
1215 v->new_input = 1;
1219 void
1220 do_numtype(enum num_type n) /* Set number display type. */
1222 struct exprm_state *e;
1223 int ret, MP[MP_SIZE];
1225 v->dtype = n;
1226 set_resource(R_DISPLAY, Rdstr[(int) v->dtype]);
1228 switch (v->syntax) {
1229 case NPA:
1230 if (v->rstate) {
1231 ui_make_registers();
1233 break;
1235 case EXPRS:
1236 e = get_state();
1237 ret = usable_num(MP);
1238 if (ret) {
1239 ui_set_statusbar(_("No sane value to convert"),
1240 "gtk-dialog-error");
1241 } else if (!v->ghost_zero) {
1242 mpstr(MP, e->ans);
1243 exp_replace("Ans");
1244 ui_make_registers();
1246 clear_undo_history();
1247 break;
1249 default:
1250 assert(0);
1253 refresh_display();
1257 void
1258 do_paren()
1260 ui_set_statusbar("", "");
1262 switch (v->current) {
1263 case KEY_START_BLOCK:
1264 if (v->noparens == 0) {
1265 if (v->cur_op == -1) {
1266 v->display[0] = 0;
1267 ui_set_statusbar(_("Cleared display, prefix without an operator is not allowed"), "");
1268 } else {
1269 paren_disp(v->cur_op);
1272 v->noparens++;
1273 break;
1275 case KEY_END_BLOCK:
1276 v->noparens--;
1277 if (!v->noparens) {
1278 int ret, i = 0;
1279 while (v->display[i++] != '(') {
1280 /* do nothing */;
1283 ret = lr_parse(&v->display[i], v->MPdisp_val);
1284 if (!ret) {
1285 show_display(v->MPdisp_val);
1286 return;
1287 } else {
1288 ui_set_statusbar(_("Malformed parenthesis expression"),
1289 "gtk-dialog-error");
1292 break;
1294 default:
1295 /* Queue event */
1296 break;
1298 paren_disp(v->current);
1302 void
1303 do_sto(int index)
1305 int ret;
1307 switch (v->syntax) {
1308 case NPA:
1309 mpstr(v->MPdisp_val, v->MPmvals[index]);
1310 break;
1312 case EXPRS:
1313 ret = usable_num(v->MPmvals[index]);
1314 if (ret) {
1315 ui_set_statusbar(_("No sane value to store"),
1316 "gtk-dialog-error");
1318 break;
1320 default:
1321 assert(0);
1324 ui_make_registers();
1328 /* Return: 0 = success, otherwise failed.
1330 * TODO: remove hardcoding from reg ranges.
1334 do_sto_reg(int reg, int value[MP_SIZE])
1336 if ((reg >= 0) && (reg <= 10)) {
1337 mpstr(value, v->MPmvals[reg]);
1338 return(0);
1339 } else {
1340 return(-EINVAL);
1345 void
1346 do_rcl(int index)
1348 switch (v->syntax) {
1349 case NPA:
1350 mpstr(v->MPmvals[index], v->MPdisp_val);
1351 break;
1353 case EXPRS:
1354 do_expression();
1355 break;
1357 default:
1358 assert(0);
1361 v->new_input = 1;
1362 syntaxdep_show_display();
1366 /* Return: 0 = success, otherwise failed.
1368 * TODO: remove hardcoding from reg ranges.
1372 do_rcl_reg(int reg, int value[MP_SIZE])
1374 if ((reg >= 0) && (reg <= 10)) {
1375 mpstr(v->MPmvals[reg], value);
1376 return(0);
1377 } else {
1378 return(-EINVAL);
1383 void
1384 syntaxdep_show_display()
1386 switch (v->syntax) {
1387 case NPA:
1388 show_display(v->MPdisp_val);
1389 break;
1391 case EXPRS:
1392 refresh_display();
1393 break;
1395 default:
1396 assert(0);
1401 void
1402 do_point() /* Handle numeric point. */
1404 if (!v->pointed) {
1405 if (v->toclear) {
1406 STRCPY(v->display, ".");
1407 v->toclear = 0;
1408 } else {
1409 STRCAT(v->display, ".");
1411 v->pointed = 1;
1413 ui_set_display(v->display, FALSE);
1414 MPstr_to_num(v->display, v->base, v->MPdisp_val);
1418 static void
1419 do_portionfunc(int num[MP_SIZE])
1421 int MP1[MP_SIZE];
1423 if (v->current == KEY_ABSOLUTE_VALUE) { /* Abs */
1424 mpstr(num, MP1);
1425 mpabs(MP1, num);
1427 } else if (v->current == KEY_FRACTION) { /* Frac */
1428 mpstr(num, MP1);
1429 mpcmf(MP1, num);
1431 } else if (v->current == KEY_INTEGER) { /* Int */
1432 mpstr(num, MP1);
1433 mpcmim(MP1, num);
1438 void
1439 do_portion()
1441 do_portionfunc(v->MPdisp_val);
1442 show_display(v->MPdisp_val);
1446 void
1447 do_shift(int count) /* Perform bitwise shift on display value. */
1449 int n, ret;
1450 BOOLEAN temp;
1451 double dval;
1452 struct exprm_state *e;
1453 int MPtemp[MP_SIZE], MPval[MP_SIZE];
1455 switch (v->syntax) {
1456 case NPA:
1457 MPstr_to_num(v->display, v->base, MPtemp);
1458 mpcmd(MPtemp, &dval);
1459 temp = ibool(dval);
1461 if (count < 0) {
1462 temp = temp >> -count;
1463 } else {
1464 temp = temp << count;
1467 dval = setbool(temp);
1468 mpcdm(&dval, v->MPdisp_val);
1469 show_display(v->MPdisp_val);
1470 mpstr(v->MPdisp_val, v->MPlast_input);
1471 break;
1473 case EXPRS:
1474 e = get_state();
1475 n = e->value;
1476 ret = usable_num(MPval);
1477 if (ret || !is_integer(MPval)) {
1478 ui_set_statusbar(_("No sane value to do bitwise shift"),
1479 "gtk-dialog-error");
1480 break;
1483 calc_shift(MPval, e->ans, n);
1485 exp_replace("Ans");
1486 break;
1488 default:
1489 assert(0);
1492 v->new_input = 1;
1493 syntaxdep_show_display();
1497 void
1498 do_trigtype(enum trig_type t) /* Change the current trigonometric type. */
1500 v->ttype = t;
1501 set_resource(R_TRIG, Rtstr[(int) v->ttype]);
1502 switch (v->cur_op) {
1503 case KEY_SIN:
1504 case KEY_SINH:
1505 case KEY_ASIN:
1506 case KEY_ASINH:
1507 case KEY_COS:
1508 case KEY_COSH:
1509 case KEY_ACOS:
1510 case KEY_ACOSH:
1511 case KEY_TAN:
1512 case KEY_TANH:
1513 case KEY_ATAN:
1514 case KEY_ATANH:
1515 mpstr(v->MPtresults[(int) v->ttype], v->MPdisp_val);
1516 show_display(v->MPtresults[(int) v->ttype]);
1517 break;
1519 default:
1520 break;
1524 void
1525 show_error(char *message)
1527 ui_set_statusbar(message, "gtk-dialog-error");