more simplification, got gtk.c under 3k lines
[gcalctool.git] / gcalctool / functions.c
blob05dd411c52f4d9e9cc23a214223c25da371384cb
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("");
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);
874 ui_make_registers();
875 break;
877 case EXPRS:
878 e = get_state();
879 ret = usable_num(MP);
881 if (ret) {
882 ui_set_statusbar(_("No sane value to convert"),
883 "gtk-dialog-error");
884 } else if (!v->ghost_zero) {
885 mpstr(MP, e->ans);
886 exp_replace("Ans");
888 v->base = b;
889 set_resource(R_BASE, Rbstr[(int) v->base]);
890 ui_set_base(v->base);
891 ui_make_registers();
892 clear_undo_history();
893 break;
895 default:
896 assert(0);
899 refresh_display();
903 void
904 do_constant(int index)
906 int *MPval;
907 struct exprm_state *e;
909 assert(index >= 0);
910 assert(index <= 9);
912 switch (v->syntax) {
913 case NPA:
914 MPval = v->MPcon_vals[index];
915 mpstr(MPval, v->MPdisp_val);
916 break;
918 case EXPRS:
919 e = get_state();
920 do_expression();
921 break;
923 default:
924 assert(0);
927 v->new_input = 1;
928 syntaxdep_show_display();
932 void
933 do_delete() /* Remove the last numeric character typed. */
935 size_t len;
937 len = strlen(v->display);
938 if (len > 0) {
939 v->display[len-1] = '\0';
942 /* If we were entering a scientific number, and we have backspaced over
943 * the exponent sign, then this reverts to entering a fixed point number.
946 if (v->key_exp && !(strchr(v->display, '+'))) {
947 v->key_exp = 0;
948 v->display[strlen(v->display)-1] = '\0';
951 /* If we've backspaced over the numeric point, clear the pointed flag. */
953 if (v->pointed && !(strchr(v->display, '.'))) {
954 v->pointed = 0;
957 ui_set_display(v->display);
958 MPstr_to_num(v->display, v->base, v->MPdisp_val);
960 if (v->dtype == FIX) {
961 STRCPY(v->fnum, v->display);
962 ui_set_display(v->fnum);
967 void
968 do_exchange(int index) /* Exchange display with memory register. */
970 int MPtemp[MP_SIZE];
971 int MPexpr[MP_SIZE];
972 struct exprm_state *e;
973 int ret;
974 int n;
976 switch (v->syntax) {
977 case NPA:
978 mpstr(v->MPdisp_val, MPtemp);
979 mpstr(v->MPmvals[index], v->MPdisp_val);
980 mpstr(MPtemp, v->MPmvals[index]);
981 ui_make_registers();
982 break;
984 case EXPRS:
985 e = get_state();
986 ret = usable_num(MPexpr);
987 n = e->value;
989 if (ret) {
990 ui_set_statusbar(_("No sane value to store"),
991 "gtk-dialog-error");
992 } else {
993 mpstr(v->MPmvals[n], MPtemp);
994 mpstr(MPexpr, v->MPmvals[n]);
995 mpstr(MPtemp, e->ans);
996 exp_replace("Ans");
997 refresh_display();
998 ui_make_registers();
1000 break;
1002 default:
1003 assert(0);
1006 v->new_input = 1;
1007 syntaxdep_show_display();
1012 void
1013 do_expno() /* Get exponential number. */
1015 v->pointed = (strchr(v->display, '.') != NULL);
1016 if (!v->new_input) {
1017 STRCPY(v->display, "1.0 +");
1018 v->new_input = v->pointed = 1;
1019 } else if (!v->pointed) {
1020 STRNCAT(v->display, ". +", 3);
1021 v->pointed = 1;
1022 } else if (!v->key_exp) {
1023 STRNCAT(v->display, " +", 2);
1025 v->toclear = 0;
1026 v->key_exp = 1;
1027 v->exp_posn = strchr(v->display, '+');
1028 ui_set_display(v->display);
1029 MPstr_to_num(v->display, v->base, v->MPdisp_val);
1033 /* Calculate the factorial of MPval. */
1035 void
1036 do_factorial(int *MPval, int *MPres)
1038 double val;
1039 int i, MPa[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE];
1041 /* NOTE: do_factorial, on each iteration of the loop, will attempt to
1042 * convert the current result to a double. If v->error is set,
1043 * then we've overflowed. This is to provide the same look&feel
1044 * as V3.
1046 * XXX: Needs to be improved. Shouldn't need to convert to a double in
1047 * order to check this.
1050 mpstr(MPval, MPa);
1051 mpcmim(MPval, MP1);
1052 i = 0;
1053 mpcim(&i, MP2);
1054 if (mpeq(MPval, MP1) && mpge(MPval, MP2)) { /* Only positive integers. */
1055 i = 1;
1056 if (mpeq(MP1, MP2)) { /* Special case for 0! */
1057 mpcim(&i, MPres);
1058 return;
1060 mpcim(&i, MPa);
1061 mpcmi(MP1, &i);
1062 if (!i) {
1063 matherr((struct exception *) NULL);
1064 } else {
1065 while (i > 0) {
1066 mpmuli(MPa, &i, MPa);
1067 mpcmd(MPa, &val);
1068 if (v->error) {
1069 mperr();
1070 return;
1072 i--;
1075 } else {
1076 matherr((struct exception *) NULL);
1078 mpstr(MPa, MPres);
1082 void
1083 do_function(int index) /* Perform a user defined function. */
1085 char *str;
1086 int ret;
1088 assert(index >= 0);
1089 assert(index <= 9);
1091 switch (v->syntax) {
1092 case NPA:
1093 str = v->fun_vals[index];
1094 assert(str);
1095 ret = lr_udf_parse(str);
1096 break;
1098 case EXPRS:
1099 str = v->fun_vals[index];
1100 assert(str);
1101 ret = ce_udf_parse(str);
1102 break;
1104 default:
1105 assert(0);
1108 if (!ret) {
1109 ui_set_statusbar("", "");
1110 } else {
1111 ui_set_statusbar(_("Malformed function"), "gtk-dialog-error");
1113 v->new_input = 1;
1117 static void
1118 do_immedfunc(int s[MP_SIZE], int t[MP_SIZE])
1120 int MP1[MP_SIZE];
1122 if (v->current == KEY_MASK_32) { /* &32 */
1123 calc_u32(s, t);
1124 } else if (v->current == KEY_MASK_16) { /* &16 */
1125 calc_u16(s, t);
1126 } else if (v->current == KEY_E_POW_X) { /* e^x */
1127 mpstr(s, MP1);
1128 mpexp(MP1, t);
1129 } else if (v->current == KEY_10_POW_X) { /* 10^x */
1130 calc_tenpowx(s, t);
1131 } else if (v->current == KEY_NATURAL_LOGARITHM) { /* Ln */
1132 mpstr(s, MP1);
1133 mpln(MP1, t);
1134 } else if (v->current == KEY_LOGARITHM) { /* Log */
1135 mplog10(s, t);
1136 } else if (v->current == KEY_RANDOM) { /* Rand */
1137 calc_rand(t);
1138 } else if (v->current == KEY_SQUARE_ROOT) { /* Sqrt */
1139 mpstr(s, MP1);
1140 mpsqrt(MP1, t);
1141 } else if (v->current == KEY_NOT) { /* NOT */
1142 calc_not(t, s);
1143 } else if (v->current == KEY_RECIPROCAL) { /* 1/x */
1144 calc_inv(s, t);
1145 } else if (v->current == KEY_FACTORIAL) { /* x! */
1146 do_factorial(s, MP1);
1147 mpstr(MP1, t);
1148 } else if (v->current == KEY_SQUARE) { /* x^2 */
1149 mpstr(s, MP1);
1150 mpmul(MP1, MP1, t);
1151 } else if (v->current == KEY_CHANGE_SIGN) { /* +/- */
1152 if (v->key_exp) {
1153 if (*v->exp_posn == '+') {
1154 *v->exp_posn = '-';
1155 } else {
1156 *v->exp_posn = '+';
1158 ui_set_display(v->display);
1159 MPstr_to_num(v->display, v->base, s);
1160 v->key_exp = 0;
1161 } else {
1162 mpneg(s, t);
1168 void
1169 do_immed()
1171 do_immedfunc(v->MPdisp_val, v->MPdisp_val);
1172 show_display(v->MPdisp_val);
1176 void
1177 do_mode(int toclear) /* Set special calculator mode. */
1179 set_resource(R_MODE, Rmstr[(int) v->modetype]);
1180 ui_set_mode(v->modetype);
1181 if (toclear) {
1182 do_clear();
1187 void
1188 do_number()
1190 int offset;
1192 if (v->toclear) {
1193 offset = 0;
1194 v->toclear = 0;
1195 } else {
1196 offset = strlen(v->display);
1198 if (offset < MAXLINE) {
1199 SNPRINTF(v->display+offset, MAXLINE-offset, "%s", buttons[v->current].symname);
1202 ui_set_display(v->display);
1203 MPstr_to_num(v->display, v->base, v->MPdisp_val);
1204 v->new_input = 1;
1208 void
1209 do_numtype(enum num_type n) /* Set number display type. */
1211 struct exprm_state *e;
1212 int ret, MP[MP_SIZE];
1214 v->dtype = n;
1215 set_resource(R_DISPLAY, Rdstr[(int) v->dtype]);
1217 switch (v->syntax) {
1218 case NPA:
1219 ui_make_registers();
1220 break;
1222 case EXPRS:
1223 e = get_state();
1224 ret = usable_num(MP);
1225 if (ret) {
1226 ui_set_statusbar(_("No sane value to convert"),
1227 "gtk-dialog-error");
1228 } else if (!v->ghost_zero) {
1229 mpstr(MP, e->ans);
1230 exp_replace("Ans");
1231 ui_make_registers();
1233 clear_undo_history();
1234 break;
1236 default:
1237 assert(0);
1240 refresh_display();
1244 void
1245 do_paren()
1247 ui_set_statusbar("", "");
1249 switch (v->current) {
1250 case KEY_START_BLOCK:
1251 if (v->noparens == 0) {
1252 if (v->cur_op == -1) {
1253 v->display[0] = 0;
1254 ui_set_statusbar(_("Cleared display, prefix without an operator is not allowed"), "");
1255 } else {
1256 paren_disp(v->cur_op);
1259 v->noparens++;
1260 break;
1262 case KEY_END_BLOCK:
1263 v->noparens--;
1264 if (!v->noparens) {
1265 int ret, i = 0;
1266 while (v->display[i++] != '(') {
1267 /* do nothing */;
1270 ret = lr_parse(&v->display[i], v->MPdisp_val);
1271 if (!ret) {
1272 show_display(v->MPdisp_val);
1273 return;
1274 } else {
1275 ui_set_statusbar(_("Malformed parenthesis expression"),
1276 "gtk-dialog-error");
1279 break;
1281 default:
1282 /* Queue event */
1283 break;
1285 paren_disp(v->current);
1289 void
1290 do_sto(int index)
1292 int ret;
1294 switch (v->syntax) {
1295 case NPA:
1296 mpstr(v->MPdisp_val, v->MPmvals[index]);
1297 break;
1299 case EXPRS:
1300 ret = usable_num(v->MPmvals[index]);
1301 if (ret) {
1302 ui_set_statusbar(_("No sane value to store"),
1303 "gtk-dialog-error");
1305 break;
1307 default:
1308 assert(0);
1311 ui_make_registers();
1315 /* Return: 0 = success, otherwise failed.
1317 * TODO: remove hardcoding from reg ranges.
1321 do_sto_reg(int reg, int value[MP_SIZE])
1323 if ((reg >= 0) && (reg <= 10)) {
1324 mpstr(value, v->MPmvals[reg]);
1325 return(0);
1326 } else {
1327 return(-EINVAL);
1332 void
1333 do_rcl(int index)
1335 switch (v->syntax) {
1336 case NPA:
1337 mpstr(v->MPmvals[index], v->MPdisp_val);
1338 break;
1340 case EXPRS:
1341 do_expression();
1342 break;
1344 default:
1345 assert(0);
1348 v->new_input = 1;
1349 syntaxdep_show_display();
1353 /* Return: 0 = success, otherwise failed.
1355 * TODO: remove hardcoding from reg ranges.
1359 do_rcl_reg(int reg, int value[MP_SIZE])
1361 if ((reg >= 0) && (reg <= 10)) {
1362 mpstr(v->MPmvals[reg], value);
1363 return(0);
1364 } else {
1365 return(-EINVAL);
1370 void
1371 syntaxdep_show_display()
1373 switch (v->syntax) {
1374 case NPA:
1375 show_display(v->MPdisp_val);
1376 break;
1378 case EXPRS:
1379 refresh_display();
1380 break;
1382 default:
1383 assert(0);
1388 void
1389 do_point() /* Handle numeric point. */
1391 if (!v->pointed) {
1392 if (v->toclear) {
1393 STRCPY(v->display, ".");
1394 v->toclear = 0;
1395 } else {
1396 STRCAT(v->display, ".");
1398 v->pointed = 1;
1400 ui_set_display(v->display);
1401 MPstr_to_num(v->display, v->base, v->MPdisp_val);
1405 static void
1406 do_portionfunc(int num[MP_SIZE])
1408 int MP1[MP_SIZE];
1410 if (v->current == KEY_ABSOLUTE_VALUE) { /* Abs */
1411 mpstr(num, MP1);
1412 mpabs(MP1, num);
1414 } else if (v->current == KEY_FRACTION) { /* Frac */
1415 mpstr(num, MP1);
1416 mpcmf(MP1, num);
1418 } else if (v->current == KEY_INTEGER) { /* Int */
1419 mpstr(num, MP1);
1420 mpcmim(MP1, num);
1425 void
1426 do_portion()
1428 do_portionfunc(v->MPdisp_val);
1429 show_display(v->MPdisp_val);
1433 void
1434 do_shift(int count) /* Perform bitwise shift on display value. */
1436 int n, ret;
1437 BOOLEAN temp;
1438 double dval;
1439 struct exprm_state *e;
1440 int MPtemp[MP_SIZE], MPval[MP_SIZE];
1442 switch (v->syntax) {
1443 case NPA:
1444 MPstr_to_num(v->display, v->base, MPtemp);
1445 mpcmd(MPtemp, &dval);
1446 temp = ibool(dval);
1448 if (count < 0) {
1449 temp = temp >> -count;
1450 } else {
1451 temp = temp << count;
1454 dval = setbool(temp);
1455 mpcdm(&dval, v->MPdisp_val);
1456 show_display(v->MPdisp_val);
1457 mpstr(v->MPdisp_val, v->MPlast_input);
1458 break;
1460 case EXPRS:
1461 e = get_state();
1462 n = e->value;
1463 ret = usable_num(MPval);
1464 if (ret || !is_integer(MPval)) {
1465 ui_set_statusbar(_("No sane value to do bitwise shift"),
1466 "gtk-dialog-error");
1467 break;
1470 calc_shift(MPval, e->ans, n);
1472 exp_replace("Ans");
1473 break;
1475 default:
1476 assert(0);
1479 v->new_input = 1;
1480 syntaxdep_show_display();
1484 void
1485 do_trigtype(enum trig_type t) /* Change the current trigonometric type. */
1487 v->ttype = t;
1488 set_resource(R_TRIG, Rtstr[(int) v->ttype]);
1489 switch (v->cur_op) {
1490 case KEY_SIN:
1491 case KEY_SINH:
1492 case KEY_ASIN:
1493 case KEY_ASINH:
1494 case KEY_COS:
1495 case KEY_COSH:
1496 case KEY_ACOS:
1497 case KEY_ACOSH:
1498 case KEY_TAN:
1499 case KEY_TANH:
1500 case KEY_ATAN:
1501 case KEY_ATANH:
1502 mpstr(v->MPtresults[(int) v->ttype], v->MPdisp_val);
1503 show_display(v->MPtresults[(int) v->ttype]);
1504 break;
1506 default:
1507 break;
1511 void
1512 show_error(char *message)
1514 ui_set_statusbar(message, "gtk-dialog-error");