Remove unused UI routines
[gcalctool.git] / gcalctool / display.c
blob909a2e6a69747ea517439e14b613e12d5a8111d5
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 <string.h>
24 #include <assert.h>
26 #include "display.h"
28 #include "mp.h"
29 #include "mpmath.h"
30 #include "functions.h"
31 #include "ui.h"
33 static char digits[] = "0123456789ABCDEF";
35 static double max_fix[MAXBASES] = {
36 1.298074214e+33, /* Binary. */
37 2.037035976e+90, /* Octal. */
38 1.000000000e+100, /* Decimal */
39 2.582249878e+120 /* Hexadecimal. */
42 static char *make_eng_sci(int *, int);
44 /* Add in the thousand separators characters if required and if we are
45 * currently in the decimal numeric base, use the "right" radix character.
48 void
49 localize_number(char *dest, const char *src)
51 char tnum[MAX_LOCALIZED], *dstp;
53 if (!v->error && v->show_tsep && v->base == DEC) {
54 const char *radixp, *srcp;
55 int n, i;
56 size_t tsep_len;
58 /* Process the fractional part (if any). */
59 srcp = src + strlen(src) - 1;
60 dstp = tnum;
61 if ((radixp = strchr(src, '.')) != NULL) {
62 while (srcp != radixp) {
63 *dstp++ = *srcp--;
65 *dstp++ = *srcp--;
68 /* Process the integer part, add in thousand separators. */
69 tsep_len = strlen(v->tsep);
70 n = 0;
71 while (srcp >= src) {
72 *dstp++ = *srcp--;
73 n++;
74 if (n == 3 && srcp >= src && *srcp != '-') {
75 for (i = tsep_len - 1; i >= 0; i--) {
76 *dstp++ = v->tsep[i];
78 n = 0;
81 *dstp++ = '\0';
83 /* Move from scratch pad to fnum, reversing the character order. */
84 srcp = tnum + strlen(tnum) - 1;
85 dstp = dest;
86 while (srcp >= tnum) {
87 *dstp++ = *srcp--;
89 *dstp++ = '\0';
90 } else {
91 STRCPY(dest, src);
93 dstp = strchr(dest, '.');
94 if (dstp != NULL) {
95 size_t radix_len;
97 radix_len = strlen(v->radix);
98 if (radix_len != 1) {
99 memmove(dstp + radix_len, dstp + 1, strlen (dstp + 1) + 1);
101 MEMCPY(dstp, v->radix, radix_len);
106 static int
107 char_val(char chr)
109 if (chr >= '0' && chr <= '9') {
110 return(chr - '0');
111 } else if (chr >= 'a' && chr <= 'f') {
112 return(chr - 'a' + 10);
113 } else if (chr >= 'A' && chr <= 'F') {
114 return(chr - 'A' + 10);
115 } else {
116 return(-1);
121 void
122 clear_display(int initialise)
124 int i;
126 v->pointed = 0;
127 v->toclear = 1;
128 i = 0;
129 mpcim(&i, v->MPdisp_val);
130 STRNCPY(v->display, make_number(v->MPdisp_val, v->base, FALSE),
131 MAXLINE - 1);
132 ui_set_display(v->display, FALSE);
133 v->ghost_zero = 1;
135 if (initialise == TRUE) {
136 v->show_paren = 0;
137 v->numsptr = 0;
138 v->noparens = 0;
139 ui_set_hyperbolic_state(FALSE); /* Also clears v->hyperbolic. */
140 ui_set_inverse_state(FALSE); /* Also clears v->inverse. */
145 void
146 initialise()
148 /* TODO: perhaps this function should be renamed to reset. */
150 int i;
151 struct exprm_state *e;
153 v->error = 0; /* Currently no display error. */
154 v->cur_op = -1; /* No arithmetic operator defined yet. */
155 v->old_cal_value = -1;
156 i = 0;
157 mpcim(&i, v->MPresult); /* No previous result yet. */
158 mpcim(&i, v->MPdisp_val);
159 mpcim(&i, v->MPlast_input);
161 v->new_input = 1; /* Value zero is on calculator display */
163 e = get_state();
164 free(e->expression);
165 e->expression = NULL;
169 /* Convert MP number to fixed number string in the given base to the
170 * maximum number of digits specified.
173 char *
174 make_fixed(int *MPnumber, char *str, int base, int cmax, int toclear)
176 char half[4], *optr;
177 int MP1base[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MPval[MP_SIZE];
178 int ndig; /* Total number of digits to generate. */
179 int ddig; /* Number of digits to left of decimal sep. */
180 int dval, n;
182 optr = str;
183 mpabs(MPnumber, MPval);
184 n = 0;
185 mpcim(&n, MP1);
186 if (mplt(MPnumber, MP1)) {
187 *optr++ = '-';
190 mpcim(&basevals[base], MP1base);
192 mppwr(MP1base, &v->accuracy, MP1);
193 /* FIXME: string const. if MPstr_to_num can get it */
194 SPRINTF(half, "0.5");
195 MPstr_to_num(half, DEC, MP2);
196 mpdiv(MP2, MP1, MP1);
197 mpadd(MPval, MP1, MPval);
199 n = 1;
200 mpcim(&n, MP2);
201 if (mplt(MPval, MP2)) {
202 ddig = 0;
203 *optr++ = '0';
204 cmax--;
205 } else {
206 for (ddig = 0; mpge(MPval, MP2); ddig++) {
207 mpdiv(MPval, MP1base, MPval);
211 ndig = MIN(ddig + v->accuracy, --cmax);
213 while (ndig-- > 0) {
214 if (ddig-- == 0) {
215 *optr++ = '.';
217 mpmul(MPval, MP1base, MPval);
218 mpcmi(MPval, &dval);
220 if (dval > basevals[base]-1) {
221 dval = basevals[base]-1;
224 *optr++ = digits[dval];
225 dval = -dval;
226 mpaddi(MPval, &dval, MPval);
228 *optr++ = '\0';
229 if (toclear == TRUE) {
230 v->toclear = 1;
232 v->pointed = 0;
234 if (!v->show_zeroes && v->accuracy != 0) {
235 optr = str + strlen(str) - 1;
236 while (*optr == '0') {
237 optr--;
239 if (optr < str || *optr != '.') {
240 optr++;
242 *optr = '\0';
245 return(str);
249 /* Convert MP number to character string in the given base. */
251 char *
252 make_number(int *MPnumber, int base, int ignoreError)
254 double number, val;
256 /* NOTE: make_number can currently set v->error when converting to a double.
257 * This is to provide the same look&feel as V3 even though gcalctool
258 * now does internal arithmetic to "infinite" precision.
260 * XXX: Needs to be improved. Shouldn't need to convert to a double in
261 * order to do these tests.
264 mpcmd(MPnumber, &number);
265 val = fabs(number);
266 if (v->error && !ignoreError) {
267 return(_("Error"));
269 if ((v->dtype == ENG) ||
270 (v->dtype == SCI) ||
271 (v->dtype == FIX && val != 0.0 && (val > max_fix[base]))) {
272 return(make_eng_sci(MPnumber, base));
273 } else {
274 return(make_fixed(MPnumber, v->fnum, base, MAX_DIGITS, TRUE));
279 /* Convert engineering or scientific number in the given base. */
281 static char *
282 make_eng_sci(int *MPnumber, int base)
284 char half[4], fixed[MAX_DIGITS], *optr;
285 int MP1[MP_SIZE], MPatmp[MP_SIZE], MPval[MP_SIZE];
286 int MP1base[MP_SIZE], MP3base[MP_SIZE], MP10base[MP_SIZE];
287 int i, dval, len, n;
288 int MPmant[MP_SIZE]; /* Mantissa. */
289 int ddig; /* Number of digits in exponent. */
290 int eng = 0; /* Set if this is an engineering number. */
291 int exp = 0; /* Exponent */
293 if (v->dtype == ENG) {
294 eng = 1;
296 optr = v->snum;
297 mpabs(MPnumber, MPval);
298 n = 0;
299 mpcim(&n, MP1);
300 if (mplt(MPnumber, MP1)) {
301 *optr++ = '-';
303 mpstr(MPval, MPmant);
305 mpcim(&basevals[base], MP1base);
306 n = 3;
307 mppwr(MP1base, &n, MP3base);
309 n = 10;
310 mppwr(MP1base, &n, MP10base);
312 n = 1;
313 mpcim(&n, MP1);
314 mpdiv(MP1, MP10base, MPatmp);
316 n = 0;
317 mpcim(&n, MP1);
318 if (!mpeq(MPmant, MP1)) {
319 while (!eng && mpge(MPmant, MP10base)) {
320 exp += 10;
321 mpmul(MPmant, MPatmp, MPmant);
324 while ((!eng && mpge(MPmant, MP1base)) ||
325 (eng && (mpge(MPmant, MP3base) || exp % 3 != 0))) {
326 exp += 1;
327 mpdiv(MPmant, MP1base, MPmant);
330 while (!eng && mplt(MPmant, MPatmp)) {
331 exp -= 10;
332 mpmul(MPmant, MP10base, MPmant);
335 n = 1;
336 mpcim(&n, MP1);
337 while (mplt(MPmant, MP1) || (eng && exp % 3 != 0)) {
338 exp -= 1;
339 mpmul(MPmant, MP1base, MPmant);
343 STRCPY(fixed, make_fixed(MPmant, v->fnum, base, MAX_DIGITS-6, TRUE));
344 len = strlen(fixed);
345 for (i = 0; i < len; i++) {
346 *optr++ = fixed[i];
349 *optr++ = 'e';
351 if (exp < 0) {
352 exp = -exp;
353 *optr++ = '-';
354 } else {
355 *optr++ = '+';
358 SPRINTF(half, "0.5");
359 MPstr_to_num(half, DEC, MP1);
360 mpaddi(MP1, &exp, MPval);
361 n = 1;
362 mpcim(&n, MP1);
363 for (ddig = 0; mpge(MPval, MP1); ddig++) {
364 mpdiv(MPval, MP1base, MPval);
367 if (ddig == 0) {
368 *optr++ = '0';
371 while (ddig-- > 0) {
372 mpmul(MPval, MP1base, MPval);
373 mpcmi(MPval, &dval);
374 *optr++ = digits[dval];
375 dval = -dval;
376 mpaddi(MPval, &dval, MPval);
378 *optr++ = '\0';
379 v->toclear = 1;
380 v->pointed = 0;
382 return(v->snum);
386 /* Convert string into an MP number, in the given base
389 void
390 MPstr_to_num(char *str, enum base_type base, int *MPval)
392 char *optr;
393 int MP1[MP_SIZE], MP2[MP_SIZE], MPbase[MP_SIZE];
394 int i, inum;
395 int exp = 0;
396 int exp_sign = 1;
397 int negate = 0;
398 char *lnp = ui_get_localized_numeric_point();
399 assert(lnp);
401 i = 0;
402 mpcim(&i, MPval);
403 mpcim(&basevals[(int) base], MPbase);
405 optr = str;
407 /* Remove any initial spaces or tabs. */
408 while (*optr == ' ' || *optr == '\t') {
409 optr++;
412 /* Check if this is a negative number. */
413 if (*optr == '-') {
414 negate = 1;
415 optr++;
418 while ((inum = char_val(*optr)) >= 0) {
419 mpmul(MPval, MPbase, MPval);
420 mpaddi(MPval, &inum, MPval);
421 optr++;
424 if (*optr == '.' || *optr == *lnp) {
425 optr++;
426 for (i = 1; (inum = char_val(*optr)) >= 0; i++) {
427 mppwr(MPbase, &i, MP1);
428 mpcim(&inum, MP2);
429 mpdiv(MP2, MP1, MP1);
430 mpadd(MPval, MP1, MPval);
431 optr++;
435 while (*optr == ' ') {
436 optr++;
439 if (*optr != '\0') {
440 if (*optr == '-') {
441 exp_sign = -1;
444 while ((inum = char_val(*++optr)) >= 0) {
445 exp = exp * basevals[(int) base] + inum;
448 exp *= exp_sign;
450 if (v->key_exp) {
451 mppwr(MPbase, &exp, MP1);
452 mpmul(MPval, MP1, MPval);
455 if (negate == 1) {
456 mpneg(MPval, MPval);
461 /* Append the latest parenthesis char to the display item. */
463 void
464 paren_disp(int key)
466 int i, n;
467 char *text;
469 /* If the character is a Delete, clear the whole line, and exit parenthesis
470 * processing.
472 * If the character is a Back Space, remove the last character. If the last
473 * character was a left parenthesis, decrement the parentheses count. If
474 * the parentheses count is zero, exit parenthesis processing.
476 * Otherwise just append the character.
479 n = strlen(v->display);
480 text = buttons[key].symname;
481 switch (key) {
482 case -1:
483 case KEY_CLEAR:
484 v->noparens = v->numsptr = 0;
485 v->cur_op = -1;
486 i = 0;
487 mpcim(&i, v->MPdisp_val);
488 show_display(v->MPdisp_val);
489 return;
490 case KEY_BACKSPACE:
491 if (!n) {
492 return;
495 if (v->display[n-1] == ')') {
496 v->noparens++;
497 } else if (v->display[n-1] == '(') {
498 v->noparens--;
499 if (!v->noparens) {
500 v->numsptr = 0;
501 v->cur_op = -1;
502 show_display(v->MPdisp_val);
503 return;
505 } else if (v->display[n-1] == ')') v->noparens++;
506 v->display[n-1] = '\0';
507 break;
509 case KEY_START_BLOCK:
511 /* If this is the first left parenthesis being displayed and there is no
512 * current arithmetic operand, then the current display is initially cleared
513 * to avoid the confusion of showing something like "0(".
516 if (v->noparens == 1 && v->cur_op == -1) {
517 n = 0;
518 v->display[0] = '\0';
520 text = "(";
521 break;
523 case KEY_END_BLOCK:
524 text = ")";
525 break;
528 if (text) {
529 SNPRINTF(v->display+n, MAXLINE-n, "%s", text);
532 n = (n < MAX_DIGITS) ? 0 : n - MAX_DIGITS;
533 v->show_paren = 1; /* Hack to get ui_set_display to really display it. */
534 ui_set_display(&v->display[n], FALSE);
535 v->show_paren = 0;
539 void
540 process_item(struct button *button, int arg)
542 v->current = button->id;
544 if (v->error) {
545 /* Must press a valid key first. */
546 if (v->current != KEY_CLEAR) {
547 return;
549 ui_set_error_state(FALSE);
552 if (v->noparens > 0) {
553 do_paren();
554 return;
557 (*button->func)(arg);
561 void
562 show_display(int *MPval)
564 if (!v->error) {
565 STRNCPY(v->display, make_number(MPval, v->base, FALSE), MAXLINE - 1);
566 ui_set_display(v->display, FALSE);
571 /* In arithmetic precedence mode this routine should be called to redraw
572 * the display.
575 void
576 refresh_display()
578 char localized[MAX_LOCALIZED];
579 struct exprm_state *e;
581 switch (v->syntax) {
582 case NPA:
583 show_display(v->MPdisp_val);
584 break;
586 case EXPRS:
587 e = get_state();
589 if (e->expression && strlen(e->expression)) {
590 char *str = gc_strdup(e->expression);
591 char *ans = make_number(e->ans, v->base, TRUE);
593 localize_number(localized, ans);
594 str_replace(&str, "Ans", localized);
596 { /* Replace registers with values. */
597 char reg[3];
598 int n = '0';
599 int i;
601 for (i = 0; i < 10; i++) {
602 char *reg_val;
603 int MP_reg[MP_SIZE];
605 SNPRINTF(reg, 3, "R%c", n+i);
606 do_rcl_reg(i, MP_reg);
607 reg_val = make_number(MP_reg, v->base, FALSE);
608 str_replace(&str, reg, reg_val);
611 ui_set_display(str, FALSE);
612 free(str);
613 v->ghost_zero = 0;
614 } else {
615 int MP1[MP_SIZE];
617 do_zero(MP1);
618 show_display(MP1);
619 v->ghost_zero = 1;
621 break;
623 default:
624 assert(0);