gcalctool r2094 - trunk/gcalctool



Author: rancell
Date: Sat May 17 03:08:32 2008
New Revision: 2094
URL: http://svn.gnome.org/viewvc/gcalctool?rev=2094&view=rev

Log:
Moved all display code into display.[ch]


Modified:
   trunk/gcalctool/calctool.c
   trunk/gcalctool/calctool.h
   trunk/gcalctool/ce_parser.c
   trunk/gcalctool/display.c
   trunk/gcalctool/display.h
   trunk/gcalctool/functions.c
   trunk/gcalctool/functions.h
   trunk/gcalctool/get.c
   trunk/gcalctool/gtk.c
   trunk/gcalctool/lr_parser.c
   trunk/gcalctool/lr_tokeniser.l
   trunk/gcalctool/mp.c
   trunk/gcalctool/mpmath.c
   trunk/gcalctool/mpmath.h
   trunk/gcalctool/ui.h
   trunk/gcalctool/unittest.c

Modified: trunk/gcalctool/calctool.c
==============================================================================
--- trunk/gcalctool/calctool.c	(original)
+++ trunk/gcalctool/calctool.c	Sat May 17 03:08:32 2008
@@ -31,6 +31,7 @@
 #include "display.h"
 #include "functions.h"
 #include "ui.h"
+#include "mpmath.h"
 
 time_t time();
 
@@ -715,8 +716,6 @@
     for (i = 0; i < MAX_REGISTERS; i++) {
         mpcim(&n, v->MPmvals[i]);
     }
-    
-    exp_clear();
 }
 
 
@@ -724,7 +723,6 @@
 main(int argc, char **argv)
 {
     char *ptr;
-    struct exprm_state *e;
     
     v = (Vars)  LINT_CAST(calloc(1, sizeof(struct calcVars)));
 
@@ -739,31 +737,26 @@
         v->appname = strdup(argv[0]);
     }
     
+    srand48((long) time((time_t *) 0));   /* Seed random number generator. */    
+    
+    v->radix = get_radix();    /* Locale specific radix string. */
+    v->tsep  = get_tsep();     /* Locale specific thousands separator. */
+    v->tsep_count = get_tsep_count();
+    
     init_state();
     
     get_options(argc, argv);   /* Get command line arguments. */
     ui_init(&argc, &argv);     /* Initialise UI */
     resources_init();          /* Initialise configuration */
-
-    v->radix = get_radix();    /* Locale specific radix string. */
-    v->tsep  = get_tsep();     /* Locale specific thousands separator. */
-    v->tsep_count = get_tsep_count();
+    display_init();
 
     init_text();               /* Setup text strings depending upon language. */
     read_resources();          /* Read resources from merged database. */
     ui_load();
 
-    srand48((long) time((time_t *) 0));   /* Seed random number generator. */
-
     do_clear();                /* Initialise and clear display. */
 
-    display_set_number(v->MPdisp_val);     /* Output in correct display mode. */
-
-    memset(&(v->h), 0, sizeof(struct exprm_state_history)); /* clear expression mode state history*/
-    e = get_state();
-    e->clear = 1;              /* Clear initial state as if clear was pressed */
-    
-    ui_start();                    /* Display the calculator. */
+    ui_start();                /* Display the calculator. */
     
     return(0);
 }

Modified: trunk/gcalctool/calctool.h
==============================================================================
--- trunk/gcalctool/calctool.h	(original)
+++ trunk/gcalctool/calctool.h	Sat May 17 03:08:32 2008
@@ -184,7 +184,6 @@
     int ans[MP_SIZE];      /* Previously calculated answer */
     char *expression;      /* Expression entered by user */
     int cursor;
-    int clear;             /* Clear command issued */
 };
 
 /* Circular list of Arithmetic Precedence Mode states*/ 

Modified: trunk/gcalctool/ce_parser.c
==============================================================================
--- trunk/gcalctool/ce_parser.c	(original)
+++ trunk/gcalctool/ce_parser.c	Sat May 17 03:08:32 2008
@@ -22,7 +22,6 @@
 #include "ce_parser.h"
 #include "limits.h"
 #include "calctool.h"
-#include "functions.h" /* FIXME: Needed for gc_strdup() */
 
 /* TODO: This file is almost identical to lr-parser. */
 
@@ -39,7 +38,7 @@
 
     if (strlen(expression)) {
         parser_state.i = 0;
-        parser_state.buff = gc_strdup(expression);
+        parser_state.buff = strdup(expression);
 		v->math_error = 0;
         ret = ceparse();
         free(parser_state.buff);

Modified: trunk/gcalctool/display.c
==============================================================================
--- trunk/gcalctool/display.c	(original)
+++ trunk/gcalctool/display.c	Sat May 17 03:08:32 2008
@@ -25,19 +25,57 @@
 
 #include "display.h"
 
-#include "mp.h"
 #include "mpmath.h"
 #include "functions.h"
 #include "ui.h"
+#include "ce_parser.h" // For ce_parse()
 
-static char digits[] = "0123456789ABCDEF";
+static gboolean
+exp_has_postfix(char *str, char *postfix)
+{
+    int len, plen;
+
+    if (!str) {
+        return FALSE;
+    }
+
+    assert(postfix);
+
+    len = strlen(str);
+    plen = strlen(postfix);
+
+    if (plen > len) {
+        return FALSE;
+    }
+
+    return strcasecmp(str + len - plen, postfix) == 0;
+}
+
+static char *
+str_replace(char *str, char *from, char *to)
+{
+    char output[MAXLINE];
+    int offset = 0;
+    char *c;
+    int flen = strlen(from);
+    int tlen = strlen(to);
+    
+    for (c = str; *c && offset < MAXLINE - 1; c++, offset++) {
+        if (strncasecmp(from, c, flen) == 0) {
+            SNPRINTF(output + offset, MAXLINE - offset, to);
+            c += flen - 1;
+            offset += tlen - 1;
+        } else {
+            output[offset] = *c;
+        }
+    }
 
-static double max_fix[MAXBASES] = {
-    1.298074214e+33,    /* Binary. */
-    2.037035976e+90,    /* Octal. */
-    1.000000000e+100,   /* Decimal */
-    2.582249878e+120    /* Hexadecimal. */
-};
+    if (offset >= MAXLINE)
+        offset = MAXLINE - 1;
+    output[offset] = '\0';
+    
+    return strdup(output);
+}
 
 /* Add in the thousand separators characters if required and if we are
  * currently in the decimal numeric base, use the "right" radix character.
@@ -135,33 +173,29 @@
 }
 
 
-static int
-char_val(char chr)
-{
-    if (chr >= '0' && chr <= '9') {
-        return(chr - '0');
-    } else if (chr >= 'a' && chr <= 'f') {
-        return(chr - 'a' + 10);
-    } else if (chr >= 'A' && chr <= 'F') {
-        return(chr - 'A' + 10);
-    } else {
-        return(-1);
-    }
-}
-
-
 void
 display_clear(int initialise)
 {
-    v->ltr.pointed = 0;
-    v->ltr.toclear = 1;
-    do_zero(v->MPdisp_val);
-    display_set_number(v->MPdisp_val);
-
-    if (initialise == TRUE) {
-        v->ltr.noparens   = 0;
-        ui_set_hyperbolic_state(FALSE);          /* Also clears v->hyperbolic. */
-        ui_set_inverse_state(FALSE);          /* Also clears v->inverse. */
+    switch(v->syntax) {
+    case NPA:
+        v->ltr.pointed = 0;
+        v->ltr.toclear = 1;
+        do_zero(v->MPdisp_val);
+        display_set_number(v->MPdisp_val);
+
+        if (initialise == TRUE) {
+            v->ltr.noparens   = 0;
+            ui_set_hyperbolic_state(FALSE);          /* Also clears v->hyperbolic. */
+            ui_set_inverse_state(FALSE);          /* Also clears v->inverse. */
+        }
+        break;
+
+    case EXPRS:
+        display_set_string("");
+        break;
+
+    default:
+        assert(0);
     }
 }
 
@@ -178,297 +212,9 @@
   
     v->ltr.new_input = 1;             /* Value zero is on calculator display */
 
-    exp_clear();
-}
-
-
-/* Convert MP number to fixed number string in the given base to the
- * maximum number of digits specified.
- */
-
-void
-make_fixed(char *target, int target_len, int *MPnumber, int base, int cmax, int toclear)
-{
-    char half[MAXLINE], *optr;
-    int MP1base[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MPval[MP_SIZE];
-    int ndig;                   /* Total number of digits to generate. */
-    int ddig;                   /* Number of digits to left of decimal sep. */
-    int dval, n, i;
- 
-    optr = target;
-    mpabs(MPnumber, MPval);
-    do_zero(MP1);
-    if (mplt(MPnumber, MP1)) {
-        *optr++ = '-';
-    }
-
-    mpcim(&basevals[base], MP1base);
-
-    mppwr(MP1base, &v->accuracy, MP1);
-    /* FIXME: string const. if MPstr_to_num can get it */
-    SNPRINTF(half, MAXLINE, "0.5");
-    MPstr_to_num(half, DEC, MP2);
-    mpdiv(MP2, MP1, MP1);
-    mpadd(MPval, MP1, MPval);
-
-    n = 1;
-    mpcim(&n, MP2);
-    if (mplt(MPval, MP2)) {
-        ddig = 0;
-        *optr++ = '0';
-        cmax--;
-    } else {
-        for (ddig = 0; mpge(MPval, MP2); ddig++) {
-            mpdiv(MPval, MP1base, MPval);
-        }
-    }
- 
-    ndig = MIN(ddig + v->accuracy, --cmax);
-
-    while (ndig-- > 0) {
-        if (ddig-- == 0) {
-            for (i = 0; i < strlen(v->radix); i++)
-                *optr++ = v->radix[i];
-        }
-        mpmul(MPval, MP1base, MPval);
-        mpcmi(MPval, &dval);
-
-        if (dval > basevals[base]-1) {
-            dval = basevals[base]-1;
-        }
-
-        *optr++ = digits[dval];
-        dval = -dval;
-        mpaddi(MPval, &dval, MPval);
-    }    
-    *optr++ = '\0';
-    if (toclear == TRUE) {
-        v->ltr.toclear = 1;
-    }
-    v->ltr.pointed = 0;
-
-    /* Strip off trailing zeroes */
-    if (!v->show_zeroes) {
-        for (i = strlen(target) - 1; i > 1 && target[i] == '0'; i--) {
-            target[i] = '\0';
-        }
-        
-        /* If no fractional part discard radix */
-        if (strlen(target) >= strlen(v->radix) && strcmp(target + strlen(target) - strlen(v->radix), v->radix) == 0) {
-            target[strlen(target) - strlen(v->radix)] = '\0';
-        }
-    }
+    display_clear(TRUE);
 }
 
-
-/* Convert engineering or scientific number in the given base. */
-
-void
-make_eng_sci(char *target, int target_len, int *MPnumber, int base)
-{
-    char half[MAXLINE], fixed[MAX_DIGITS], *optr;
-    int MP1[MP_SIZE], MPatmp[MP_SIZE], MPval[MP_SIZE];
-    int MP1base[MP_SIZE], MP3base[MP_SIZE], MP10base[MP_SIZE];
-    int i, dval, len, n;
-    int MPmant[MP_SIZE];        /* Mantissa. */
-    int ddig;                   /* Number of digits in exponent. */
-    int eng = 0;                /* Set if this is an engineering number. */
-    int exp = 0;                /* Exponent */
-    
-    if (v->dtype == ENG) {
-        eng = 1;
-    }
-    optr = target;
-    mpabs(MPnumber, MPval);
-    do_zero(MP1);
-    if (mplt(MPnumber, MP1)) {
-        *optr++ = '-';
-    }
-    mpstr(MPval, MPmant);
-
-    mpcim(&basevals[base], MP1base);
-    n = 3;
-    mppwr(MP1base, &n, MP3base);
-
-    n = 10;
-    mppwr(MP1base, &n, MP10base);
-
-    n = 1;
-    mpcim(&n, MP1);
-    mpdiv(MP1, MP10base, MPatmp);
-
-    do_zero(MP1);
-    if (!mpeq(MPmant, MP1)) {
-        while (!eng && mpge(MPmant, MP10base)) {
-            exp += 10;
-            mpmul(MPmant, MPatmp, MPmant);
-        }
- 
-        while ((!eng &&  mpge(MPmant, MP1base)) ||
-                (eng && (mpge(MPmant, MP3base) || exp % 3 != 0))) {
-            exp += 1;
-            mpdiv(MPmant, MP1base, MPmant);
-        }
- 
-        while (!eng && mplt(MPmant, MPatmp)) {
-            exp -= 10;
-            mpmul(MPmant, MP10base, MPmant);
-        }
- 
-        n = 1;
-        mpcim(&n, MP1);
-        while (mplt(MPmant, MP1) || (eng && exp % 3 != 0)) {
-            exp -= 1;
-            mpmul(MPmant, MP1base, MPmant);
-        }
-    }
- 
-    make_fixed(fixed, MAX_DIGITS, MPmant, base, MAX_DIGITS-6, TRUE);
-    len = strlen(fixed);
-    for (i = 0; i < len; i++) {
-        *optr++ = fixed[i];
-    }
- 
-    *optr++ = 'e';
- 
-    if (exp < 0) {
-        exp = -exp;
-        *optr++ = '-';
-    } else {
-        *optr++ = '+';
-    }
- 
-    SNPRINTF(half, MAXLINE, "0.5");
-    MPstr_to_num(half, DEC, MP1);
-    mpaddi(MP1, &exp, MPval);
-    n = 1;
-    mpcim(&n, MP1);
-    for (ddig = 0; mpge(MPval, MP1); ddig++) {
-        mpdiv(MPval, MP1base, MPval);
-    }
- 
-    if (ddig == 0) {
-        *optr++ = '0';
-    }
- 
-    while (ddig-- > 0) {
-        mpmul(MPval, MP1base, MPval);
-        mpcmi(MPval, &dval);
-        *optr++ = digits[dval];
-        dval = -dval;
-        mpaddi(MPval, &dval, MPval);
-    }
-    *optr++    = '\0';
-    v->ltr.toclear = 1;
-    v->ltr.pointed = 0;
-}
-
-
-/* Convert MP number to character string in the given base. */
-
-void
-make_number(char *target, int target_len, int *MPnumber, int base, int ignoreError)
-{
-    double number, val;
-    
-/*  NOTE: make_number can currently set v->error when converting to a double.
- *        This is to provide the same look&feel as V3 even though gcalctool
- *        now does internal arithmetic to "infinite" precision.
- *
- *  XXX:  Needs to be improved. Shouldn't need to convert to a double in
- *        order to do these tests.
- */
-
-    mpcmd(MPnumber, &number);
-    val = fabs(number);
-    if (v->error && !ignoreError) {
-        STRNCPY(target, _("Error"), target_len - 1);
-        return;
-	}
-    if ((v->dtype == ENG) ||
-        (v->dtype == SCI) ||
-        (v->dtype == FIX && val != 0.0 && (val > max_fix[base]))) {
-        make_eng_sci(target, target_len, MPnumber, base);
-    } else {
-        make_fixed(target, target_len, MPnumber, base, MAX_DIGITS, TRUE);
-    }
-}
-
-
-/* Convert string into an MP number, in the given base
- */
-
-void
-MPstr_to_num(char *str, enum base_type base, int *MPval)
-{
-    char *optr;
-    int MP1[MP_SIZE], MP2[MP_SIZE], MPbase[MP_SIZE];
-    int i, inum;
-    int exp      = 0;
-    int exp_sign = 1;
-    int negate = 0;
-    char *lnp = ui_get_localized_numeric_point();
-    assert(lnp);
-
-    do_zero(MPval);
-    mpcim(&basevals[(int) base], MPbase);
-
-    optr = str;
-
-    /* Remove any initial spaces or tabs. */
-    while (*optr == ' ' || *optr == '\t') {
-        optr++;
-    }
-
-    /* Check if this is a negative number. */
-    if (*optr == '-') {
-        negate = 1;
-        optr++;
-    }
-
-    while ((inum = char_val(*optr)) >= 0) {
-        mpmul(MPval, MPbase, MPval);
-        mpaddi(MPval, &inum, MPval);
-        optr++;
-    }
-
-    if (*optr == '.' || *optr == *lnp) {
-        optr++;
-        for (i = 1; (inum = char_val(*optr)) >= 0; i++) {
-            mppwr(MPbase, &i, MP1);
-            mpcim(&inum, MP2);
-            mpdiv(MP2, MP1, MP1);
-            mpadd(MPval, MP1, MPval);
-        optr++;
-        }
-    }
-
-    while (*optr == ' ') {
-        optr++;
-    }
- 
-    if (*optr != '\0') {
-        if (*optr == '-') {
-            exp_sign = -1;
-        }
- 
-        while ((inum = char_val(*++optr)) >= 0) {
-            exp = exp * basevals[(int) base] + inum;
-        }
-    }
-    exp *= exp_sign;
-
-    if (v->ltr.key_exp) {
-        mppwr(MPbase, &exp, MP1);
-        mpmul(MPval, MP1, MPval);
-    }
-
-    if (negate == 1) {
-        mpneg(MPval, MPval);
-    }
-}
-
-
 /* Append the latest parenthesis char to the display item. */
 
 void
@@ -554,9 +300,208 @@
 void
 display_set_string(char *value)
 {
-    if(value != v->display)
-        STRNCPY(value, v->display, MAX_DIGITS - 1);
-    ui_set_display(v->display, -1);
+    struct exprm_state *e;
+    
+    switch(v->syntax) {
+    case NPA:
+        if(value != v->display)
+            STRNCPY(value, v->display, MAX_DIGITS - 1);
+        ui_set_display(v->display, -1);
+        break;
+
+    case EXPRS:
+        e = get_state();
+        free(e->expression);
+        e->expression = strdup(value);
+        break;
+
+    default:
+        assert(0);
+    }
+}
+
+void
+display_set_error(const char *message)
+{
+    ui_set_statusbar(message, "gtk-dialog-error");
+}
+
+static void
+copy_state(struct exprm_state *dst, struct exprm_state *src)
+{
+    MEMCPY(dst, src, sizeof(struct exprm_state));
+    dst->expression = strdup(src->expression);
+}
+
+static void
+update_undo_redo_button_sensitivity(void)
+{
+    int undo = 0;
+    int redo = 0;
+
+    if (v->h.current != v->h.end) {
+        redo = 1;
+    }
+
+    if (v->h.current != v->h.begin) {
+        undo = 1;
+    }
+
+    ui_set_undo_enabled(undo, redo);
+}
+
+void display_clear_stack(void)
+{
+    int i = v->h.begin;
+    while (i != v->h.end) {
+        if (i != v->h.current) {
+            free(v->h.e[i].expression);
+            v->h.e[i].expression = NULL;
+        }
+        i = ((i + 1) % UNDO_HISTORY_LENGTH);
+    }
+    v->h.begin = v->h.end = v->h.current;
+    update_undo_redo_button_sensitivity();   
+}
+
+void display_push(void)
+{
+    int c;
+
+    if (v->h.current != v->h.end) {
+        int i = v->h.current;
+
+        do {
+            i = ((i + 1) % UNDO_HISTORY_LENGTH);
+            free(v->h.e[i].expression);
+            v->h.e[i].expression = strdup("Ans");
+        } while (i != v->h.end);
+    }
+
+    v->h.end = v->h.current;
+
+    c = v->h.current;
+    v->h.end = v->h.current = ((v->h.current + 1) % UNDO_HISTORY_LENGTH);
+    if (v->h.current == v->h.begin) {
+        free(v->h.e[v->h.begin].expression);
+        v->h.e[v->h.begin].expression = NULL;
+        v->h.begin = ((v->h.begin + 1) % UNDO_HISTORY_LENGTH);
+    }
+
+    copy_state(&(v->h.e[v->h.current]), &(v->h.e[c]));
+    update_undo_redo_button_sensitivity();   
+}
+
+void display_pop(void)
+{
+    struct exprm_state *e;
+    
+    if (v->h.current != v->h.begin) {
+        v->h.current = ((v->h.current - 1) % UNDO_HISTORY_LENGTH);
+        ui_set_statusbar("", "");
+    } else {
+        ui_set_statusbar(_("No undo history"), "gtk-dialog-warning");
+    }
+    update_undo_redo_button_sensitivity();
+    
+    e = get_state();
+    display_refresh(e->cursor);
+}
+
+void
+display_unpop(void)
+{
+    if (v->h.current != v->h.end) {
+        v->h.current = ((v->h.current + 1) % UNDO_HISTORY_LENGTH);
+        ui_set_statusbar("", "");
+    } else {
+        ui_set_statusbar(_("No redo steps"), "gtk-dialog-warning");
+    }
+    update_undo_redo_button_sensitivity();
+}
+
+int
+display_insert(const char *text, int cursor)
+{
+    char buf[MAXLINE], *display;
+    struct exprm_state *e = get_state();
+    
+    if (cursor < 0) {
+        SNPRINTF(buf, MAXLINE, "%s%s", e->expression, text);
+    } else {
+        display = ui_get_display();
+        SNPRINTF(buf, MAXLINE, "%.*s%s%s", cursor, display, text, display + cursor);
+        cursor += strlen(text);
+    }
+    display_set_string(buf);
+    
+    return cursor;
+}
+
+int
+display_backspace(int cursor)
+{
+    char buf[MAXLINE] = "", buf2[MAXLINE], *t;
+    struct exprm_state *e = get_state();
+    int i, MP_reg[MP_SIZE];
+
+    /* If cursor is at end of the line then delete the last character preserving accuracy */
+    if (cursor < 0) {
+        if (exp_has_postfix(e->expression, "Ans")) {
+            make_number(buf, MAXLINE, e->ans, v->base, FALSE);
+            t = str_replace(e->expression, "Ans", buf);
+            free(e->expression);
+            e->expression = t;
+        } else {
+            for (i = 0; i < 10; i++) {
+                SNPRINTF(buf, MAXLINE, "R%d", i);
+                if (exp_has_postfix(e->expression, buf)) {
+                    do_rcl_reg(i, MP_reg);
+                    make_number(buf2, MAXLINE, MP_reg, v->base, FALSE);
+                    /* Remove "Rx" postfix and replace with backspaced number */
+                    SNPRINTF(buf, MAXLINE, "%.*s%s", strlen(e->expression) - 2, e->expression - 3, buf2);
+                    display_set_string(buf);
+                    return cursor - 1;
+                }
+            }
+        }
+
+        SNPRINTF(buf, MAXLINE, "%.*s", strlen(e->expression) - 1, e->expression);
+    } else if (cursor > 0) {
+        t = ui_get_display();
+        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor - 1, t, t + cursor);
+    } else {
+        return cursor; /* At the start of the line */
+    }
+
+    display_set_string(buf);
+    return cursor - 1;
+}
+
+int
+display_delete(int cursor)
+{
+    char buf[MAXLINE] = "", *display;
+    
+    if (cursor >= 0) {
+        display = ui_get_display();
+        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor, display, display + cursor + 1);
+        display_set_string(buf);
+    }
+
+    return cursor;
+}
+
+int
+display_surround(const char *prefix, const char *suffix, int cursor)
+{
+    struct exprm_state *e = get_state();
+    char buffer[MAXLINE];
+    
+    SNPRINTF(buffer, MAXLINE, "%s%s%s", prefix, e->expression, suffix);
+    display_set_string(buffer);
+    
+    return cursor;
 }
 
 /* In arithmetic precedence mode this routine should be called to redraw 
@@ -577,12 +522,12 @@
 
         case EXPRS:
             e = get_state();
-            if (e->expression[0] == '\0') {
+            if (display_is_empty()) {
                 do_zero(MP_reg);
                 make_number(x, MAX_LOCALIZED, MP_reg, v->base, FALSE);
                 str = x;
             } else {           
-                str = gc_strdup(e->expression);
+                str = strdup(e->expression);
             }
         
             /* Substitute answer register */
@@ -609,7 +554,26 @@
     }
 }
 
-gboolean display_is_result(void)
+gboolean
+display_is_empty(void)
+{
+    struct exprm_state *e;
+
+    switch (v->syntax) {
+        case NPA:
+            return v->ltr.toclear;
+
+        case EXPRS:
+            e = get_state();
+            return strcmp(e->expression, "") == 0;
+        
+        default:
+            assert(FALSE);
+    }
+}
+
+gboolean
+display_is_result(void)
 {
     struct exprm_state *e;
 
@@ -634,3 +598,52 @@
     
     return FALSE;
 }
+
+gboolean
+display_is_usable_number(int MPnum[MP_SIZE])
+{
+    struct exprm_state *e = get_state();
+    if (display_is_empty()) {
+        return ce_parse("0", MPnum);
+    } else {
+        return ce_parse(e->expression, MPnum);
+    }
+}
+
+void
+display_init(void)
+{
+    int i;
+
+    memset(&(v->h), 0, sizeof(struct exprm_state_history)); /* clear expression mode state history */
+    for (i = 0; i < UNDO_HISTORY_LENGTH; i++)
+        v->h.e[i].expression = strdup("");
+}
+
+int
+display_solve(int *result)
+{
+    struct exprm_state *e;
+    char *c;
+    GString *clean;
+    int errorCode;
+
+    e = get_state();    
+
+    /* Remove thousands separators and use english radix */
+    clean = g_string_sized_new(strlen(e->expression));
+    for (c = e->expression; *c; c++) {
+        if (strncmp(c, v->tsep, strlen(v->tsep)) == 0) {
+            c += strlen(v->tsep) - 1;
+        } else if (strncmp(c, v->radix, strlen(v->radix)) == 0) {
+            g_string_append_c(clean, '.');
+            c += strlen(v->radix) - 1;
+        } else {
+            g_string_append_c(clean, *c);
+        }
+    }
+    errorCode = ce_parse(clean->str, result);
+    g_string_free(clean, TRUE);
+    
+    return errorCode;
+}

Modified: trunk/gcalctool/display.h
==============================================================================
--- trunk/gcalctool/display.h	(original)
+++ trunk/gcalctool/display.h	Sat May 17 03:08:32 2008
@@ -24,17 +24,31 @@
 
 #include "calctool.h"
 
-void display_reset();
+void display_init(void);
+
+void display_reset(void);
 void localize_expression(char *, const char *, int, int *);
 void display_clear(int);
 void paren_disp(int);
 void display_refresh(int);
 void display_set_number(int *);
 void display_set_string(char *);
+void display_set_error(const char *);
+
+void display_clear_stack(void);
+void display_push(void);
+void display_pop(void);
+void display_unpop(void);
+
+int display_insert(const char *, int);
+int display_backspace(int cursor);
+int display_delete(int);
+int display_surround(const char *, const char *, int);
+
+gboolean display_is_empty(void);
 gboolean display_is_result(void);
+gboolean display_is_usable_number(int *);
 
-void MPstr_to_num(char *, enum base_type, int *);
-void make_fixed(char *, int, int *, int, int, int);
-void make_number(char *, int, int *, int, int);
+int display_solve(int *);
 
 #endif /* DISPLAY_H */

Modified: trunk/gcalctool/functions.c
==============================================================================
--- trunk/gcalctool/functions.c	(original)
+++ trunk/gcalctool/functions.c	Sat May 17 03:08:32 2008
@@ -36,26 +36,6 @@
 #include "lr_parser.h"
 #include "ui.h"
 
-char *
-gc_strdup(char *str)
-{
-    char *dup;
-    int len;
-
-    if (!str) {
-        return NULL;
-    }
-
-    len = strlen(str);
-    dup = malloc(len+1);
-    assert(dup);
-    memset(dup, 0, len+1);
-    strncpy(dup, str, len);
-
-    return(dup);
-}
-
-
 void
 make_exp(char *number, int t[MP_SIZE])
 {
@@ -67,7 +47,7 @@
     int MP_b[MP_SIZE];
 
     assert(number);
-    a = gc_strdup(number);
+    a = strdup(number);
     assert(a);
 
     for (i = 0; !((a[i] == 'e') || (a[i] == 'E')); i++) {
@@ -91,37 +71,10 @@
 }
 
 
-static void
-update_undo_redo_button_sensitivity(void)
-{
-    int undo = 0;
-    int redo = 0;
-
-    if (v->h.current != v->h.end) {
-        redo = 1;
-    }
-
-    if (v->h.current != v->h.begin) {
-        undo = 1;
-    }
-
-    ui_set_undo_enabled(undo, redo);
-}
-
-
 void
 clear_undo_history(void)
 {
-    int i = v->h.begin;
-    while (i != v->h.end) {
-        if (i != v->h.current) {
-            free(v->h.e[i].expression);
-            v->h.e[i].expression = NULL;
-        }
-        i = ((i + 1) % UNDO_HISTORY_LENGTH);
-    }
-    v->h.begin = v->h.end = v->h.current;
-    update_undo_redo_button_sensitivity();
+    display_clear_stack();
 }
 
 
@@ -132,77 +85,12 @@
 }
 
 
-static void
-copy_state(struct exprm_state *dst, struct exprm_state *src)
-{
-    MEMCPY(dst, src, sizeof(struct exprm_state));
-    dst->expression = gc_strdup(src->expression);
-}
-
-
-static void
-purge_redo_history(void)
-{
-    if (v->h.current != v->h.end) {
-        int i = v->h.current;
-
-        do {
-            i = ((i + 1) % UNDO_HISTORY_LENGTH);
-            free(v->h.e[i].expression);
-            v->h.e[i].expression = gc_strdup("Ans");
-        } while (i != v->h.end);
-    }
-
-    v->h.end = v->h.current;
-}
-
-
-static void
-new_state(void)
-{
-    int c;
-
-    purge_redo_history();
-
-    c = v->h.current;
-    v->h.end = v->h.current = ((v->h.current + 1) % UNDO_HISTORY_LENGTH);
-    if (v->h.current == v->h.begin) {
-        free(v->h.e[v->h.begin].expression);
-        v->h.e[v->h.begin].expression = NULL;
-        v->h.begin = ((v->h.begin + 1) % UNDO_HISTORY_LENGTH);
-    }
-
-    copy_state(&(v->h.e[v->h.current]), &(v->h.e[c]));
-    update_undo_redo_button_sensitivity();
-}
-
-
 void
 perform_undo(void)
 {
-    struct exprm_state *e;
-    
-    if (v->h.current != v->h.begin) {
-        v->h.current = ((v->h.current - 1) % UNDO_HISTORY_LENGTH);
-        ui_set_statusbar("", "");
-    } else {
-        ui_set_statusbar(_("No undo history"), "gtk-dialog-warning");
-    }
-    update_undo_redo_button_sensitivity();
-    
-    e = get_state();
-    display_refresh(e->cursor);
+    display_pop();
 }
 
-struct exprm_state *
-peek_previous_state(void)
-{
-    if (v->h.current != v->h.begin) {
-        return &(v->h.e[(v->h.current - 1) % UNDO_HISTORY_LENGTH]);
-    } else {
-        return NULL;
-    }
-}
 
 static int
 is_undo_step(void)
@@ -214,13 +102,7 @@
 void
 perform_redo(void)
 {
-    if (v->h.current != v->h.end) {
-        v->h.current = ((v->h.current + 1) % UNDO_HISTORY_LENGTH);
-        ui_set_statusbar("", "");
-    } else {
-        ui_set_statusbar(_("No redo steps"), "gtk-dialog-warning");
-    }
-    update_undo_redo_button_sensitivity();
+    display_unpop();
 }
 
 
@@ -262,198 +144,17 @@
 }
 
 
-int
-exp_insert(char *text, int cursor)
-{
-    char buf[MAXLINE], *display;
-    struct exprm_state *e = get_state();
-    
-    if (cursor < 0) {
-        SNPRINTF(buf, MAXLINE, "%s%s", e->expression, text);
-    } else {
-        display = ui_get_display();
-        SNPRINTF(buf, MAXLINE, "%.*s%s%s", cursor, display, text, display + cursor);
-        cursor += strlen(text);
-    }
-    exp_replace(buf);
-    
-    return cursor;
-}
-
-
-void
-exp_clear(void)
-{
-    exp_replace("");
-}
-
-
-int
-usable_num(int MPnum[MP_SIZE])
-{
-    struct exprm_state *e = get_state();
-    if (e->expression[0] == '\0') {
-        return ce_parse("0", MPnum);
-    } else {
-        return ce_parse(e->expression, MPnum);
-    }
-}
-
-
-static int
-exp_has_postfix(char *str, char *postfix)
-{
-    int len, plen;
-
-    if (!str) {
-        return(0);
-    }
-
-    assert(postfix);
-
-    len = strlen(str);
-    plen = strlen(postfix);
-
-    if (plen > len) {
-        return(0);
-    }
-
-    if (!strcasecmp(str + len - plen, postfix)) {
-        return(1);
-    } else {
-        return(0);
-    }
-}
-
-
-static int
-exp_backspace(int cursor)
-{
-    char buf[MAXLINE] = "", buf2[MAXLINE], *t;
-    struct exprm_state *e = get_state();
-    int i, MP_reg[MP_SIZE];
-
-    /* If cursor is at end of the line then delete the last character preserving accuracy */
-    if (cursor < 0) {
-        if (exp_has_postfix(e->expression, "Ans")) {
-            make_number(buf, MAXLINE, e->ans, v->base, FALSE);
-            t = str_replace(e->expression, "Ans", buf);
-            free(e->expression);
-            e->expression = t;
-        } else {
-            for (i = 0; i < 10; i++) {
-                SNPRINTF(buf, MAXLINE, "R%d", i);
-                if (exp_has_postfix(e->expression, buf)) {
-                    do_rcl_reg(i, MP_reg);
-                    make_number(buf2, MAXLINE, MP_reg, v->base, FALSE);
-                    /* Remove "Rx" postfix and replace with backspaced number */
-                    SNPRINTF(buf, MAXLINE, "%.*s%s", strlen(e->expression) - 2, e->expression - 3, buf2);
-                    exp_replace(buf);
-                    return cursor - 1;
-                }
-            }
-        }
-
-        SNPRINTF(buf, MAXLINE, "%.*s", strlen(e->expression) - 1, e->expression);
-    } else if (cursor > 0) {
-        t = ui_get_display();
-        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor - 1, t, t + cursor);
-    } else {
-        return cursor; /* At the start of the line */
-    }
-
-    exp_replace(buf);
-    return cursor - 1;
-}
-
-
-static int
-exp_delete(int cursor)
-{
-    char buf[MAXLINE] = "", *display;
-    
-    if (cursor >= 0) {
-        display = ui_get_display();
-        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor, display, display + cursor + 1);
-        exp_replace(buf);
-    }
-
-    return cursor;
-}
-
-
-void
-exp_replace(char *text)
-{
-    struct exprm_state *e;
-    e = get_state();
-    if (e->expression != NULL) {
-        free(e->expression);
-    }
-    e->expression = gc_strdup(text);
-}
-
-
 static void
 exp_negate(void)
 {
-    struct exprm_state *e = get_state();
-
-    /* Ending zero + parenthesis + minus */
-    int len = strlen(e->expression) + 4;
-    char *exp = malloc(len);
-
-    assert(exp);
-    if (snprintf(exp, len, "-(%s)", e->expression) < 0) {
-        assert(0);
-    }
-    free(e->expression);
-    e->expression = exp;
+    display_surround("-(", ")", 0); // FIXME: Cursor
 }
 
 
 static void
 exp_inv(void)
 {
-    struct exprm_state *e = get_state();
-
-    /* Ending zero + 1/ + parenthesis */
-    int len = strlen(e->expression) + 5;
-    char *exp = malloc(len);
-
-    assert(exp);
-    if (snprintf(exp, len, "1/(%s)", e->expression) < 0) {
-        assert(0);
-    }
-    free(e->expression);
-    e->expression = exp;
-}
-
-
-char *
-str_replace(char *str, char *from, char *to)
-{
-    char output[MAXLINE];
-    int offset = 0;
-    char *c;
-    int flen = strlen(from);
-    int tlen = strlen(to);
-    
-    for (c = str; *c && offset < MAXLINE - 1; c++, offset++) {
-        if (strncasecmp(from, c, flen) == 0) {
-            SNPRINTF(output + offset, MAXLINE - offset, to);
-            c += flen - 1;
-            offset += tlen - 1;
-        } else {
-            output[offset] = *c;
-        }
-    }
-
-    if (offset >= MAXLINE)
-        offset = MAXLINE - 1;
-    output[offset] = '\0';
-    
-    return strdup(output);
+    display_surround("1/(", ")", 0); // FIXME: Cursor
 }
 
 
@@ -461,29 +162,26 @@
 do_expression(int function, int arg, int cursor)
 {
     char buf[MAXLINE];
-    struct exprm_state *e, *ex;
+    struct exprm_state *e;
     
-    new_state();
+    display_push();
     e = get_state();
-    ex = peek_previous_state();
 
     e->cursor = cursor;
-    e->clear = 0;
 
     ui_set_statusbar("", "");
 
     /* Starting a number after a calculation clears the display */
-    if (strcmp(e->expression, "Ans") == 0) {
+    if (display_is_result()) {
         if (buttons[function].flags & NUMBER) {
-            exp_replace("");
+            display_set_string("");
         }
     }
 
     switch (buttons[function].id) {
         case KEY_CLEAR:
         case KEY_CLEAR_ENTRY:
-            e->clear = 1;
-            exp_clear();
+            display_clear(FALSE);
             ui_set_error_state(FALSE);
             MPstr_to_num("0", DEC, e->ans);
             break;
@@ -511,20 +209,20 @@
 
         case KEY_RECALL:
             SNPRINTF(buf, MAXLINE, "R%d", arg);
-            cursor = exp_insert(buf, cursor);
+            cursor = display_insert(buf, cursor);
             break;
 
         case KEY_CONSTANT:
             make_number(buf, MAXLINE, v->MPcon_vals[arg], v->base, FALSE);
-            cursor = exp_insert(buf, cursor);
+            cursor = display_insert(buf, cursor);
             break;
 
         case KEY_BACKSPACE:
-            cursor = exp_backspace(cursor);
+            cursor = display_backspace(cursor);
             break;
         
         case KEY_DELETE:
-            cursor = exp_delete(cursor);
+            cursor = display_delete(cursor);
             break;
 
         case KEY_CHANGE_SIGN:
@@ -542,7 +240,7 @@
              * this result */
             /* TODO: Work out why two undo steps are required and why
              * the cursor must be taken from the first undo */
-            if (strcmp(e->expression, "Ans") == 0) {
+            if (display_is_result()) {
                 perform_undo();
                 e = get_state();
                 cursor = e->cursor;
@@ -551,35 +249,20 @@
                 }
 
             /* Do nothing */                
-            } else if (e->expression[0] == '\0') {
+            } else if (display_is_empty()) {
                 ;
                 
             /* Solve the equation */
             } else {
                 int MPval[MP_SIZE];
-                char *c, *message = NULL;
-                GString *clean;
                 int result;
+                const char *message = NULL;
                 
-                /* Remove thousands separators and use english radix */
-                clean = g_string_sized_new(strlen(e->expression));
-                for (c = e->expression; *c; c++) {
-                    if (strncmp(c, v->tsep, strlen(v->tsep)) == 0) {
-                        c += strlen(v->tsep) - 1;
-                    } else if (strncmp(c, v->radix, strlen(v->radix)) == 0) {
-                        g_string_append_c(clean, '.');
-                        c += strlen(v->radix) - 1;
-                    } else {
-                        g_string_append_c(clean, *c);
-                    }
-                }
-                result = ce_parse(clean->str, MPval);
-                g_string_free(clean, TRUE);
-                
+                result = display_solve(MPval);
                 switch (result) {
                     case 0:
                         mpstr(MPval, e->ans);
-                        exp_replace("Ans");
+                        display_set_string("Ans");
                         cursor = -1;
                         break;
 
@@ -613,33 +296,20 @@
             break;
 
         case KEY_NUMERIC_POINT:
-            cursor = exp_insert(ui_get_localized_numeric_point(), cursor);
+            cursor = display_insert(v->radix, cursor);
             break;
 
         default:
             /* If display is a number then perform functions on that number */
-            if ((buttons[function].flags & (PREFIXOP | FUNC))
-                && !strcmp(e->expression, "Ans")
-                && !(ex && ex->clear)) {
-                SNPRINTF(buf, MAXLINE, "%s(%s)",
-                         buttons[function].symname,
-                         e->expression);
-                exp_replace(buf);
-            } else if ((((buttons[function].id == KEY_ADD) 
-                         || (buttons[function].id == KEY_SUBTRACT))
-                        && !strcmp(e->expression, "Ans")
-                        && (ex && ex->clear))) {
-                exp_replace(buttons[function].symname);
+            if (buttons[function].flags & (PREFIXOP | FUNC) && display_is_result()) {
+                SNPRINTF(buf, MAXLINE, "%s(", buttons[function].symname);
+                display_surround(buf, ")", 0); // FIXME: Cursor
             } else {
                 if (buttons[function].flags & FUNC) {
                     SNPRINTF(buf, MAXLINE, "%s(", buttons[function].symname);
-                    if (!ex || ex->clear) {
-                        exp_replace(buf);
-                    } else {
-                        cursor = exp_insert(buf, cursor);
-                    }
+                    cursor = display_insert(buf, cursor);
                 } else {
-                    cursor = exp_insert(buttons[function].symname, cursor);
+                    cursor = display_insert(buttons[function].symname, cursor);
                 }
             }
             break;
@@ -924,14 +594,14 @@
 
         case EXPRS:
             e = get_state();
-            ret = usable_num(MP);
+            ret = display_is_usable_number(MP);
 
             if (ret) {
                 ui_set_statusbar(_("No sane value to convert"),
                                  "gtk-dialog-error");
             } else {
                 mpstr(MP, e->ans);
-                exp_replace("Ans");
+                display_set_string("Ans");
             }
             v->base = b;
             set_resource(R_BASE, Rbstr[(int) v->base]);
@@ -1025,14 +695,14 @@
         case EXPRS:
             e = get_state();
 
-            if (usable_num(MPexpr)) {
+            if (display_is_usable_number(MPexpr)) {
                 ui_set_statusbar(_("No sane value to store"),
                                  "gtk-dialog-error");
             } else {
                 mpstr(v->MPmvals[index], MPtemp);
                 mpstr(MPexpr, v->MPmvals[index]);
                 mpstr(MPtemp, e->ans);
-                exp_replace("Ans");
+                display_set_string("Ans");
                 display_refresh(-1);
                 ui_make_registers();
             }
@@ -1278,13 +948,13 @@
 
         case EXPRS:
             e = get_state();
-            ret = usable_num(MP);
+            ret = display_is_usable_number(MP);
             if (ret) {
                 ui_set_statusbar(_("No sane value to convert"),
                                  "gtk-dialog-error");
             } else {
                 mpstr(MP, e->ans);
-                exp_replace("Ans");
+                display_set_string("Ans");
                 ui_make_registers();
             }
             clear_undo_history();
@@ -1352,7 +1022,7 @@
             break;
 
         case EXPRS:
-            if (usable_num(v->MPmvals[index])) {
+            if (display_is_usable_number(v->MPmvals[index])) {
                 ui_set_statusbar(_("No sane value to store"),
                                  "gtk-dialog-error");
             }
@@ -1504,7 +1174,7 @@
 
         case EXPRS:
             e = get_state();
-            if (usable_num(MPval) || !is_integer(MPval)) {
+            if (display_is_usable_number(MPval) || !is_integer(MPval)) {
                 ui_set_statusbar(_("No sane value to do bitwise shift"),
                                  "gtk-dialog-error");
                 break;
@@ -1512,7 +1182,7 @@
 
             calc_shift(MPval, e->ans, count);
 
-            exp_replace("Ans");
+            display_set_string("Ans");
             break;
 
         default:
@@ -1522,10 +1192,3 @@
     v->ltr.new_input = 1;
     syntaxdep_show_display();
 }
-
-
-void
-show_error(char *message)
-{
-    ui_set_statusbar(message, "gtk-dialog-error");
-}

Modified: trunk/gcalctool/functions.h
==============================================================================
--- trunk/gcalctool/functions.h	(original)
+++ trunk/gcalctool/functions.h	Sat May 17 03:08:32 2008
@@ -24,16 +24,9 @@
 
 #include "calctool.h"
 
-void show_error(char *);
-char *str_replace(char *, char *, char *);
 void syntaxdep_show_display(void);
-char *gc_strdup(char *str);
-int usable_num(int MPnum[MP_SIZE]);
 
 void make_exp(char *number, int t[MP_SIZE]);
-int exp_insert(char *text, int);
-void exp_replace(char *text);
-void exp_clear(void);
 
 struct exprm_state *get_state(void);
 

Modified: trunk/gcalctool/get.c
==============================================================================
--- trunk/gcalctool/get.c	(original)
+++ trunk/gcalctool/get.c	Sat May 17 03:08:32 2008
@@ -33,8 +33,7 @@
 #include <gconf/gconf-client.h>
 
 #include "get.h"
-#include "display.h"
-#include "mp.h"
+#include "mpmath.h"
 
 #define EQUAL(a, b)    (strlen(a)==strlen(b)) & !strcmp(a, b) 
 

Modified: trunk/gcalctool/gtk.c
==============================================================================
--- trunk/gcalctool/gtk.c	(original)
+++ trunk/gcalctool/gtk.c	Sat May 17 03:08:32 2008
@@ -452,9 +452,6 @@
     GtkWidget *disp[MAXDISPMODES];     /* Numeric display mode. */
     GtkWidget *trig[MAXTRIGMODES];     /* Trigonometric mode. */
 
-    //FIXME: Obsolete?
-    char *lnp;                    /* Localized numerical point (UTF8 format) */
-    
     char *shelf;                       /* PUT selection shelf contents. */   
 
     gboolean warn_change_mode;    /* Should we warn user when changing modes? */
@@ -491,7 +488,7 @@
         case EXPRS:
             e = get_state();
             MPstr_to_num("0", DEC, e->ans);
-            exp_clear();
+            display_clear(FALSE);
             display_set_number(e->ans);
             break;
         
@@ -870,7 +867,7 @@
 
 
 void 
-ui_set_statusbar(gchar *text, const gchar *imagename)
+ui_set_statusbar(const gchar *text, const gchar *imagename)
 {
     GtkImage *image = GTK_IMAGE(X->status_image);
 
@@ -919,7 +916,7 @@
             break;
 
         case EXPRS: 
-            if (usable_num(MP) || !is_integer(MP)) {
+            if (display_is_usable_number(MP) || !is_integer(MP)) {
                 gtk_widget_set_sensitive(X->bit_panel, FALSE);
                 return;
             }
@@ -1045,17 +1042,6 @@
 }
 
 
-char *
-ui_get_localized_numeric_point(void)
-{
-    const char *decimal_point;
-
-    decimal_point = localeconv()->decimal_point;
-
-    return (g_locale_to_utf8(decimal_point, -1, NULL, NULL, NULL));
-}
-
-
 void
 ui_set_base(enum base_type base)
 {
@@ -1738,7 +1724,7 @@
             MPstr_to_num(v->display, v->base, MP1);
             break;
         case EXPRS: {
-            int ret = usable_num(e->ans);
+            int ret = display_is_usable_number(e->ans);
             assert(!ret);
             mpstr(e->ans, MP1);
         }
@@ -1766,7 +1752,7 @@
             break;
         case EXPRS:
             mpcdm(&number, e->ans);
-            exp_replace("Ans");
+            display_set_string("Ans");
             display_refresh(-1);
             break;
         default:
@@ -1913,7 +1899,7 @@
 
     outbuf[g_unichar_to_utf8(ch, outbuf)] = '\0';
 
-    return (strcmp(outbuf, X->lnp) == 0);
+    return (strcmp(outbuf, v->radix) == 0);
 }
 
 
@@ -2202,7 +2188,7 @@
             break;
     
         case EXPRS:
-            exp_insert((char *) text, get_cursor()); // FIXME: Move out of gtk.c
+            display_insert((char *) text, get_cursor()); // FIXME: Move out of gtk.c
             display_refresh(-1);
             break;
     
@@ -2865,7 +2851,6 @@
         
     gtk_init(argc, argv);
 
-    X->lnp = ui_get_localized_numeric_point();
     X->shelf      = NULL;      /* No selection for shelf initially. */
 
     gtk_rc_get_default_files();

Modified: trunk/gcalctool/lr_parser.c
==============================================================================
--- trunk/gcalctool/lr_parser.c	(original)
+++ trunk/gcalctool/lr_parser.c	Sat May 17 03:08:32 2008
@@ -22,7 +22,6 @@
 #include "lr_parser.h"
 #include "limits.h"
 #include "calctool.h"
-#include "functions.h" /* FIXME: Needed for gc_strdup() */
 
 /* TODO: This file is almost identical to ce-parser. */
 
@@ -39,7 +38,7 @@
 
     if (strlen(expression)) {
         parser_state.i = 0;
-        parser_state.buff = gc_strdup(expression);
+        parser_state.buff = strdup(expression);
         ret = lrparse();
         free(parser_state.buff);
     }

Modified: trunk/gcalctool/lr_tokeniser.l
==============================================================================
--- trunk/gcalctool/lr_tokeniser.l	(original)
+++ trunk/gcalctool/lr_tokeniser.l	Sat May 17 03:08:32 2008
@@ -27,8 +27,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include "calctool.h"
-#include "display.h"
-#include "functions.h" /* FIXME: Needed for gc_strdup() */
+#include "mpmath.h"
 #include "lr_parser.h"
 #include "lr_parser.tab.h"
 %}

Modified: trunk/gcalctool/mp.c
==============================================================================
--- trunk/gcalctool/mp.c	(original)
+++ trunk/gcalctool/mp.c	Sat May 17 03:08:32 2008
@@ -40,9 +40,9 @@
 #include <stdio.h>
 
 #include "mp.h"
+#include "mpmath.h"
 #include "calctool.h"
 #include "display.h"
-#include "functions.h" /* FIXME: Only for show_error() */
 
 #define C_abs(x)    ((x) >= 0 ? (x) : -(x))
 #define dabs(x)     (double) C_abs(x)
@@ -3361,7 +3361,7 @@
     else goto L70;
 
 L10:
-    show_error(_("Negative X and non-integer Y not supported"));
+    display_set_error(_("Negative X and non-integer Y not supported"));
     goto L50;
 
 /* HERE X IS ZERO, RETURN ZERO IF Y POSITIVE, OTHERWISE ERROR */

Modified: trunk/gcalctool/mpmath.c
==============================================================================
--- trunk/gcalctool/mpmath.c	(original)
+++ trunk/gcalctool/mpmath.c	Sat May 17 03:08:32 2008
@@ -21,9 +21,15 @@
 #include <errno.h>
 
 #include "mpmath.h"
-#include "mp.h"
-#include "calctool.h"
-#include "display.h" /* FIXME: Needed to MPstr_to_num() */
+
+static char digits[] = "0123456789ABCDEF";
+
+static double max_fix[MAXBASES] = {
+    1.298074214e+33,    /* Binary. */
+    2.037035976e+90,    /* Octal. */
+    1.000000000e+100,   /* Decimal */
+    2.582249878e+120    /* Hexadecimal. */
+};
 
 BOOLEAN
 ibool(double x)
@@ -784,7 +790,7 @@
 {    
     int MP1[MP_SIZE];
     if (!is_integer(MPnum)) {
-	return 0;
+        return 0;
     }
     mpabs(MPnum, MP1);
     return mpeq(MPnum, MP1);
@@ -862,3 +868,303 @@
 
     return(0);
 }
+
+/* Convert MP number to fixed number string in the given base to the
+ * maximum number of digits specified.
+ */
+
+void
+make_fixed(char *target, int target_len, int *MPnumber, int base, int cmax, int toclear)
+{
+    char half[MAXLINE], *optr;
+    int MP1base[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MPval[MP_SIZE];
+    int ndig;                   /* Total number of digits to generate. */
+    int ddig;                   /* Number of digits to left of decimal sep. */
+    int dval, n, i;
+ 
+    optr = target;
+    mpabs(MPnumber, MPval);
+    do_zero(MP1);
+    if (mplt(MPnumber, MP1)) {
+        *optr++ = '-';
+    }
+
+    mpcim(&basevals[base], MP1base);
+
+    mppwr(MP1base, &v->accuracy, MP1);
+    /* FIXME: string const. if MPstr_to_num can get it */
+    SNPRINTF(half, MAXLINE, "0.5");
+    MPstr_to_num(half, DEC, MP2);
+    mpdiv(MP2, MP1, MP1);
+    mpadd(MPval, MP1, MPval);
+
+    n = 1;
+    mpcim(&n, MP2);
+    if (mplt(MPval, MP2)) {
+        ddig = 0;
+        *optr++ = '0';
+        cmax--;
+    } else {
+        for (ddig = 0; mpge(MPval, MP2); ddig++) {
+            mpdiv(MPval, MP1base, MPval);
+        }
+    }
+ 
+    ndig = MIN(ddig + v->accuracy, --cmax);
+
+    while (ndig-- > 0) {
+        if (ddig-- == 0) {
+            for (i = 0; i < strlen(v->radix); i++)
+                *optr++ = v->radix[i];
+        }
+        mpmul(MPval, MP1base, MPval);
+        mpcmi(MPval, &dval);
+
+        if (dval > basevals[base]-1) {
+            dval = basevals[base]-1;
+        }
+
+        *optr++ = digits[dval];
+        dval = -dval;
+        mpaddi(MPval, &dval, MPval);
+    }    
+    *optr++ = '\0';
+    if (toclear == TRUE) {
+        v->ltr.toclear = 1;
+    }
+    v->ltr.pointed = 0;
+
+    /* Strip off trailing zeroes */
+    if (!v->show_zeroes) {
+        for (i = strlen(target) - 1; i > 1 && target[i] == '0'; i--) {
+            target[i] = '\0';
+        }
+        
+        /* If no fractional part discard radix */
+        if (strlen(target) >= strlen(v->radix) && strcmp(target + strlen(target) - strlen(v->radix), v->radix) == 0) {
+            target[strlen(target) - strlen(v->radix)] = '\0';
+        }
+    }
+}
+
+
+/* Convert engineering or scientific number in the given base. */
+
+void
+make_eng_sci(char *target, int target_len, int *MPnumber, int base)
+{
+    char half[MAXLINE], fixed[MAX_DIGITS], *optr;
+    int MP1[MP_SIZE], MPatmp[MP_SIZE], MPval[MP_SIZE];
+    int MP1base[MP_SIZE], MP3base[MP_SIZE], MP10base[MP_SIZE];
+    int i, dval, len, n;
+    int MPmant[MP_SIZE];        /* Mantissa. */
+    int ddig;                   /* Number of digits in exponent. */
+    int eng = 0;                /* Set if this is an engineering number. */
+    int exp = 0;                /* Exponent */
+    
+    if (v->dtype == ENG) {
+        eng = 1;
+    }
+    optr = target;
+    mpabs(MPnumber, MPval);
+    do_zero(MP1);
+    if (mplt(MPnumber, MP1)) {
+        *optr++ = '-';
+    }
+    mpstr(MPval, MPmant);
+
+    mpcim(&basevals[base], MP1base);
+    n = 3;
+    mppwr(MP1base, &n, MP3base);
+
+    n = 10;
+    mppwr(MP1base, &n, MP10base);
+
+    n = 1;
+    mpcim(&n, MP1);
+    mpdiv(MP1, MP10base, MPatmp);
+
+    do_zero(MP1);
+    if (!mpeq(MPmant, MP1)) {
+        while (!eng && mpge(MPmant, MP10base)) {
+            exp += 10;
+            mpmul(MPmant, MPatmp, MPmant);
+        }
+ 
+        while ((!eng &&  mpge(MPmant, MP1base)) ||
+                (eng && (mpge(MPmant, MP3base) || exp % 3 != 0))) {
+            exp += 1;
+            mpdiv(MPmant, MP1base, MPmant);
+        }
+ 
+        while (!eng && mplt(MPmant, MPatmp)) {
+            exp -= 10;
+            mpmul(MPmant, MP10base, MPmant);
+        }
+ 
+        n = 1;
+        mpcim(&n, MP1);
+        while (mplt(MPmant, MP1) || (eng && exp % 3 != 0)) {
+            exp -= 1;
+            mpmul(MPmant, MP1base, MPmant);
+        }
+    }
+ 
+    make_fixed(fixed, MAX_DIGITS, MPmant, base, MAX_DIGITS-6, TRUE);
+    len = strlen(fixed);
+    for (i = 0; i < len; i++) {
+        *optr++ = fixed[i];
+    }
+ 
+    *optr++ = 'e';
+ 
+    if (exp < 0) {
+        exp = -exp;
+        *optr++ = '-';
+    } else {
+        *optr++ = '+';
+    }
+ 
+    SNPRINTF(half, MAXLINE, "0.5");
+    MPstr_to_num(half, DEC, MP1);
+    mpaddi(MP1, &exp, MPval);
+    n = 1;
+    mpcim(&n, MP1);
+    for (ddig = 0; mpge(MPval, MP1); ddig++) {
+        mpdiv(MPval, MP1base, MPval);
+    }
+ 
+    if (ddig == 0) {
+        *optr++ = '0';
+    }
+ 
+    while (ddig-- > 0) {
+        mpmul(MPval, MP1base, MPval);
+        mpcmi(MPval, &dval);
+        *optr++ = digits[dval];
+        dval = -dval;
+        mpaddi(MPval, &dval, MPval);
+    }
+    *optr++    = '\0';
+    v->ltr.toclear = 1;
+    v->ltr.pointed = 0;
+}
+
+
+/* Convert MP number to character string in the given base. */
+
+void
+make_number(char *target, int target_len, int *MPnumber, int base, int ignoreError)
+{
+    double number, val;
+    
+/*  NOTE: make_number can currently set v->error when converting to a double.
+ *        This is to provide the same look&feel as V3 even though gcalctool
+ *        now does internal arithmetic to "infinite" precision.
+ *
+ *  XXX:  Needs to be improved. Shouldn't need to convert to a double in
+ *        order to do these tests.
+ */
+
+    mpcmd(MPnumber, &number);
+    val = fabs(number);
+    if (v->error && !ignoreError) {
+        STRNCPY(target, _("Error"), target_len - 1);
+        return;
+	}
+    if ((v->dtype == ENG) ||
+        (v->dtype == SCI) ||
+        (v->dtype == FIX && val != 0.0 && (val > max_fix[base]))) {
+        make_eng_sci(target, target_len, MPnumber, base);
+    } else {
+        make_fixed(target, target_len, MPnumber, base, MAX_DIGITS, TRUE);
+    }
+}
+
+
+static int
+char_val(char chr)
+{
+    if (chr >= '0' && chr <= '9') {
+        return(chr - '0');
+    } else if (chr >= 'a' && chr <= 'f') {
+        return(chr - 'a' + 10);
+    } else if (chr >= 'A' && chr <= 'F') {
+        return(chr - 'A' + 10);
+    } else {
+        return(-1);
+    }
+}
+
+
+/* Convert string into an MP number, in the given base
+ */
+
+void
+MPstr_to_num(char *str, enum base_type base, int *MPval)
+{
+    char *optr;
+    int MP1[MP_SIZE], MP2[MP_SIZE], MPbase[MP_SIZE];
+    int i, inum;
+    int exp      = 0;
+    int exp_sign = 1;
+    int negate = 0;
+
+    do_zero(MPval);
+    mpcim(&basevals[(int) base], MPbase);
+
+    optr = str;
+
+    /* Remove any initial spaces or tabs. */
+    while (*optr == ' ' || *optr == '\t') {
+        optr++;
+    }
+
+    /* Check if this is a negative number. */
+    if (*optr == '-') {
+        negate = 1;
+        optr++;
+    }
+
+    while ((inum = char_val(*optr)) >= 0) {
+        mpmul(MPval, MPbase, MPval);
+        mpaddi(MPval, &inum, MPval);
+        optr++;
+    }
+
+    if (*optr == '.' || *optr == *v->radix) {
+        optr++;
+        for (i = 1; (inum = char_val(*optr)) >= 0; i++) {
+            mppwr(MPbase, &i, MP1);
+            mpcim(&inum, MP2);
+            mpdiv(MP2, MP1, MP1);
+            mpadd(MPval, MP1, MPval);
+        optr++;
+        }
+    }
+
+    while (*optr == ' ') {
+        optr++;
+    }
+ 
+    if (*optr != '\0') {
+        if (*optr == '-') {
+            exp_sign = -1;
+        }
+ 
+        while ((inum = char_val(*++optr)) >= 0) {
+            exp = exp * basevals[(int) base] + inum;
+        }
+    }
+    exp *= exp_sign;
+
+    if (v->ltr.key_exp) {
+        mppwr(MPbase, &exp, MP1);
+        mpmul(MPval, MP1, MPval);
+    }
+
+    if (negate == 1) {
+        mpneg(MPval, MPval);
+    }
+}
+

Modified: trunk/gcalctool/mpmath.h
==============================================================================
--- trunk/gcalctool/mpmath.h	(original)
+++ trunk/gcalctool/mpmath.h	Sat May 17 03:08:32 2008
@@ -23,6 +23,7 @@
 #define MPMATH_H
 
 #include "mp.h"
+#include "calctool.h"
 
 typedef unsigned long  BOOLEAN;
 
@@ -76,4 +77,8 @@
 int
 is_natural(int MPnum[MP_SIZE]);
 
+void MPstr_to_num(char *, enum base_type, int *);
+void make_fixed(char *, int, int *, int, int, int);
+void make_number(char *, int, int *, int, int);
+
 #endif /*MPMATH_H*/

Modified: trunk/gcalctool/ui.h
==============================================================================
--- trunk/gcalctool/ui.h	(original)
+++ trunk/gcalctool/ui.h	Sat May 17 03:08:32 2008
@@ -48,9 +48,8 @@
 void ui_set_show_trailing_zeroes(gboolean);
 
 void ui_set_error_state(gboolean);
-void ui_set_statusbar(gchar *, const gchar *);
+void ui_set_statusbar(const gchar *, const gchar *);
 
 void ui_beep(void);
-char *ui_get_localized_numeric_point(void);
 
 #endif /* UI_H */

Modified: trunk/gcalctool/unittest.c
==============================================================================
--- trunk/gcalctool/unittest.c	(original)
+++ trunk/gcalctool/unittest.c	Sat May 17 03:08:32 2008
@@ -21,6 +21,7 @@
 
 #include "unittest.h"
 
+#include "mpmath.h"
 #include "display.h"
 #include "functions.h"
 #include "calctool.h"



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]