/* @(#)display.c 1.10 90/02/02 * * Display manipulation routines used by calctool. * * Copyright (c) Rich Burridge. * Sun Microsystems, Australia - All rights reserved. * * Basic algorithms, copyright (c) Ed Falk. * Sun Microsystems, Mountain View. * * Permission is given to distribute these sources, as long as the * copyright messages are not removed, and no monies are exchanged. * * No responsibility is taken for any errors or inaccuracies inherent * either to the comments or the code of this program, but if * reported to me then an attempt will be made to fix them. */ #include #include #include #include "calctool.h" #include "color.h" #include "extern.h" char_val(chr) char chr ; { if (chr >= '0' && chr <= '9') return(chr - '0') ; else if (chr >= 'a' && chr <= 'f') return(chr - 'a' + 10) ; else return(-1) ; } clear_display() { int i ; pointed = 0 ; toclear = 1 ; STRCPY(display, "0.") ; for (i = 0; i < accuracy; i++) STRNCAT(display, "0", 1) ; set_item(DISPLAYITEM, display) ; hyperbolic = inverse = 0 ; set_item(HYPITEM, " ") ; set_item(INVITEM, " ") ; disp_val = 0.0 ; } double convert_display() /* Convert input string into a double. */ { int exp, exp_sign, i, inum ; double val ; char *optr ; val = 0.0 ; exp = 0 ; optr = display ; while ((inum = char_val(*optr)) >= 0) { val = val * basevals[(int) base] + inum ; *optr++ ; } if (*optr == '.') for (i = 1; (inum = char_val(*++optr)) >= 0; i++) val += inum / powers[i][(int) base] ; while (*optr == ' ') optr++ ; if (*optr != '\0') { if (*optr == '-') exp_sign = -1 ; else exp_sign = 1 ; while ((inum = char_val(*++optr)) >= 0) exp = exp * basevals[(int) base] + inum ; } exp *= exp_sign ; if (key_exp) val *= pow((double) basevals[(int) base], (double) exp) ; return(val) ; } get_label(n) int n ; { if (tstate) switch (buttons[n].value) { case CCTRL('c') : case CCTRL('d') : case CCTRL('e') : case CCTRL('f') : case CCTRL('g') : case CCTRL('n') : case CCTRL('r') : case CCTRL('s') : case CCTRL('t') : SPRINTF(pstr, "^%c ", buttons[n].value + 96) ; break ; case CCTRL('h') : STRCPY(pstr, "bsp ") ; break ; case '\177' : STRCPY(pstr, "del ") ; break ; default : SPRINTF(pstr, "%c ", buttons[n].value) ; } else STRCPY(pstr, buttons[n].str) ; } initialise() { error = 0 ; /* Currently no display error. */ cur_op = '?' ; /* No arithmetic operator defined yet. */ old_cal_value = '?' ; result = 0.0 ; /* No previous result yet. */ last_input = 0.0 ; } char * make_fixed(number, cmax) /* Convert fixed number. */ double number ; /* Value to convert. */ int cmax ; /* Maximum characters to generate. */ { char *optr ; double val ; int ndig ; /* Total number of digits to generate. */ int ddig ; /* Number of digits to left of . */ int dval ; optr = fnum ; val = fabs(number) ; if (number < 0.0) *optr++ = '-' ; val += .5 / powers[accuracy][(int) base] ; if (val < 1.0) { ddig = 0 ; *optr++ = '0' ; cmax-- ; } else { for (ddig = 0; val >= 1.0; ddig++) val /= powers[1][(int) base] ; } ndig = MIN(ddig + accuracy, --cmax) ; while (ndig-- > 0) { if (ddig-- == 0) *optr++ = '.' ; val *= powers[1][(int) base] ; dval = val ; *optr++ = digits[dval] ; val -= (int) val ; } *optr++ = '\0' ; toclear = 1 ; pointed = 0 ; return(fnum) ; } char * make_number(number) /* Convert display value to current base. */ double number ; /* Value to convert. */ { double val ; /* Try to apply sanity checks to try to detect if the number to be * converted is not a valid number. These are based on the isnan and * isinf routines, which are only available on certain machines. */ if (number != number || (number*0 != 0)) /* Same as isnan & isinf. */ { STRCPY(display, "Error") ; error = 1 ; set_item(OPITEM, "CLR") ; return(display) ; } val = fabs(number) ; if (dtype == SCI || dtype == FIX && val != 0.0 && (val > max_fix[(int) base] || val < exp_p1[accuracy][(int) base])) return(make_scientific(number)) ; else return(make_fixed(number, MAX_DIGITS)) ; } char * make_scientific(number) /* Convert scientific number. */ double number ; /* Value to convert. */ { char fixed[MAX_DIGITS+1] ; char *optr ; double mant ; /* Mantissa */ double val ; int exp = 0 ; /* Exponent */ int i ; int eng = 0 ; /* Scientific not engineering value. */ double atmp ; optr = snum ; val = fabs(number) ; if (number < 0.0) *optr++ = '-' ; mant = val ; atmp = 1.0 / powers[10][(int) base] ; if (mant != 0.0) { while (mant >= powers[10][(int) base]) { exp += 10 ; mant *= atmp ; } while ((!eng && mant >= powers[1][(int) base]) || (eng && (mant >= powers[3][(int) base] || exp % 3 != 0))) { exp += 1 ; mant /= powers[1][(int) base] ; } while (mant < atmp) { exp -= 10 ; mant *= powers[10][(int) base] ; } while (mant < 1.0 || (eng && exp % 3 != 0)) { exp -= 1 ; mant *= powers[1][(int) base] ; } } STRCPY(fixed, make_fixed(mant, MAX_DIGITS-6)) ; for (i = 0; i < strlen(fixed); i++) *optr++ = fixed[i] ; *optr++ = 'e' ; if (exp < 0) { exp = -exp ; *optr++ = '-' ; } else *optr++ = '+' ; if ((*optr = digits[exp / ((int) powers[2][(int) base])]) != '0') optr++ ; exp %= (int) powers[2][(int) base] ; *optr++ = digits[exp / ((int) powers[1][(int) base])] ; exp %= (int) powers[1][(int) base] ; *optr++ = digits[exp] ; *optr++ = '\0' ; toclear = 1 ; pointed = 0 ; return(snum) ; } process_item(n) int n ; { int i,isvalid ; if (n < 0 || n > TITEMS) return ; current = buttons[n].value ; if (current == 'X') current = 'x' ; /* Reassign "extra" values. */ if (current == '*') current = 'x' ; if (current == '\015') current = '=' ; if (current == 'Q') current = 'q' ; if (error) { isvalid = 0 ; /* Must press a valid key first. */ for (i = 0; i < MAXVKEYS; i++) if (current == validkeys[i]) isvalid = 1 ; if (pending == '?') isvalid = 1 ; if (!isvalid) return ; error = 0 ; } if (pending) { for (n = 0; n < TITEMS; n++) if (pending == buttons[n].value) break ; } switch (buttons[n].opdisp) { case OP_SET : set_item(OPITEM, buttons[n].str) ; break ; case OP_CLEAR : if (error) set_item(OPITEM, "CLR") ; else set_item(OPITEM, "") ; } (*buttons[n].func)() ; } show_display(val) double val ; { if (!error) { STRCPY(display, make_number(val)) ; set_item(DISPLAYITEM, display) ; } }