[gcalctool] Don't truncate answers



commit aa0350eaa91b2975809dc88a13b70a49ece8180d
Author: Robin Sonefors <ozamosi flukkost nu>
Date:   Wed Oct 13 01:39:40 2010 +0200

    Don't truncate answers
    
    Originally implemented to get rid of garbage when string was truncated.
    This also means that if a number is too big it will get rounded, but it
    won't be off by orders of magnitudes.

 src/gcalccmd.c       |    5 +++--
 src/gcalctool.c      |    5 +++--
 src/math-buttons.c   |   13 ++++++++-----
 src/math-equation.c  |   20 ++++++++++++--------
 src/math-variables.c |    5 +++--
 src/mp-binary.c      |   15 ++++++++++-----
 src/mp-serializer.c  |   38 +++++++++++++++++++++-----------------
 src/mp-serializer.h  |    4 ++--
 src/mp.c             |    9 +++++++++
 src/unittest.c       |    5 +++--
 10 files changed, 74 insertions(+), 45 deletions(-)
---
diff --git a/src/gcalccmd.c b/src/gcalccmd.c
index e7a6509..eedd3b2 100644
--- a/src/gcalccmd.c
+++ b/src/gcalccmd.c
@@ -36,7 +36,7 @@ solve(const char *equation)
     int ret;
     MPEquationOptions options;
     MPNumber z;
-    char result_str[MAXLINE];
+    char *result_str;
     
     memset(&options, 0, sizeof(options));
     options.base = 10;
@@ -50,9 +50,10 @@ solve(const char *equation)
     else if (ret)        
         fprintf(stderr, "Error %d\n", ret);
     else {
-        mp_serializer_to_specific_string(&z, 10, 9, true, true, result_str, MAXLINE);
+        mp_serializer_to_specific_string(&z, 10, 9, true, true, &result_str);
         printf("%s\n", result_str);
     }
+    g_free(result_str);
 }
 
 
diff --git a/src/gcalctool.c b/src/gcalctool.c
index 1bb4f87..fa0e413 100644
--- a/src/gcalctool.c
+++ b/src/gcalctool.c
@@ -45,7 +45,7 @@ solve(const char *equation)
     MPEquationOptions options;
     MPErrorCode error;
     MPNumber result;
-    char result_str[1024];
+    char *result_str;
 
     memset(&options, 0, sizeof(options));
     options.base = 10;
@@ -62,8 +62,9 @@ solve(const char *equation)
         exit(1);
     }
     else {
-        mp_serializer_to_specific_string(&result, options.base, 9, true, true, result_str, 1024);
+        mp_serializer_to_specific_string(&result, options.base, 9, true, true, &result_str);
         printf("%s\n", result_str);
+        g_free(result_str);
         exit(0);
     }
 }
diff --git a/src/math-buttons.c b/src/math-buttons.c
index de82728..b0cd926 100644
--- a/src/math-buttons.c
+++ b/src/math-buttons.c
@@ -589,12 +589,12 @@ update_currency_label(MathButtons *buttons)
                          math_equation_get_source_currency(buttons->priv->equation),
                          math_equation_get_target_currency(buttons->priv->equation),
                          &value)) {
-        char input_text[1024], output_text[1024];
+        char *input_text, *output_text;
         const char *source_symbol, *target_symbol;
         int i;
 
-        mp_serializer_to_specific_string(&x, 10, 2, false, true, input_text, 1024);
-        mp_serializer_to_specific_string(&value, 10, 2, false, true, output_text, 1024);
+        mp_serializer_to_specific_string(&x, 10, 2, false, true, &input_text);
+        mp_serializer_to_specific_string(&value, 10, 2, false, true, &output_text);
 
         for (i = 0; strcmp(math_equation_get_source_currency(buttons->priv->equation), currency_names[i].short_name) != 0; i++);
         source_symbol = currency_names[i].symbol;
@@ -605,6 +605,8 @@ update_currency_label(MathButtons *buttons)
         label = g_strdup_printf(_("%s%s = %s%s"),
                                 source_symbol, input_text,
                                 target_symbol, output_text);
+        g_free(input_text);
+        g_free(output_text);
     }
     else
         label = g_strdup("");
@@ -1279,13 +1281,14 @@ delete_variable_cb(GtkWidget *widget, MathButtons *buttons)
 static GtkWidget *
 make_register_menu_item(MathButtons *buttons, const gchar *name, const MPNumber *value, gboolean can_modify, GCallback callback)
 {
-    gchar text[1024] = "", *mstr;
+    gchar *text, *mstr;
     GtkWidget *item, *label;
 
     if (value) {
         MpSerializer *serializer = math_equation_get_serializer(buttons->priv->equation);
-        mp_serializer_to_standard_string(serializer, value, text, 1024);
+        mp_serializer_to_standard_string(serializer, value, &text);
         mstr = g_strdup_printf("<span weight=\"bold\">%s</span> = %s", name, text);
+        g_free(text);
     }
     else
         mstr = g_strdup_printf("<span weight=\"bold\">%s</span>", name);
diff --git a/src/math-equation.c b/src/math-equation.c
index 66ec07b..d2a0808 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -147,13 +147,13 @@ reformat_ans(MathEquation *equation)
         return;
 
     gchar *orig_ans_text;
-    gchar ans_text[MAX_DIGITS];
+    gchar *ans_text;
     GtkTextIter ans_start, ans_end;
 
     gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &ans_start, equation->priv->ans_start);
     gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &ans_end, equation->priv->ans_end);
     orig_ans_text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(equation), &ans_start, &ans_end, FALSE);
-    mp_serializer_to_standard_string(equation->priv->serializer, &equation->priv->state.ans, ans_text, MAX_DIGITS);
+    mp_serializer_to_standard_string(equation->priv->serializer, &equation->priv->state.ans, &ans_text);
     if (strcmp(orig_ans_text, ans_text) != 0) {
         gint start;
 
@@ -175,6 +175,7 @@ reformat_ans(MathEquation *equation)
     gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &ans_start, equation->priv->ans_start);
     gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &ans_end, equation->priv->ans_end);
     g_free(orig_ans_text);
+    g_free(ans_text);
 }
 
 static void
@@ -714,11 +715,11 @@ math_equation_set(MathEquation *equation, const gchar *text)
 void
 math_equation_set_number(MathEquation *equation, const MPNumber *x)
 {
-    char text[MAX_DIGITS];
+    char *text;
     GtkTextIter start, end;
 
     /* Show the number in the user chosen format */
-    mp_serializer_to_standard_string(equation->priv->serializer, x, text, MAX_DIGITS);
+    mp_serializer_to_standard_string(equation->priv->serializer, x, &text);
     gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), text, -1);
     mp_set_from_mp(x, &equation->priv->state.ans);
 
@@ -728,6 +729,7 @@ math_equation_set_number(MathEquation *equation, const MPNumber *x)
     equation->priv->ans_start = gtk_text_buffer_create_mark(GTK_TEXT_BUFFER(equation), NULL, &start, FALSE);
     equation->priv->ans_end = gtk_text_buffer_create_mark(GTK_TEXT_BUFFER(equation), NULL, &end, TRUE);
     gtk_text_buffer_apply_tag(GTK_TEXT_BUFFER(equation), equation->priv->ans_tag, &start, &end);
+    g_free(text);
 }
 
 
@@ -787,9 +789,10 @@ math_equation_insert_numeric_point(MathEquation *equation)
 void
 math_equation_insert_number(MathEquation *equation, const MPNumber *x)
 {
-    char text[MAX_DIGITS];
-    mp_serializer_to_standard_string(equation->priv->serializer, x, text, MAX_DIGITS);
+    char *text;
+    mp_serializer_to_standard_string(equation->priv->serializer, x, &text);
     math_equation_insert(equation, text);
+    g_free(text);
 }
 
 
@@ -1053,15 +1056,16 @@ math_equation_factorize(MathEquation *equation)
     text = g_string_new("");
 
     for (factor = factors; factor; factor = factor->next) {
-        gchar temp[MAX_DIGITS];
+        gchar *temp;
         MPNumber *n;
 
         n = factor->data;
-        mp_serializer_to_standard_string(equation->priv->serializer, n, temp, MAX_DIGITS);
+        mp_serializer_to_standard_string(equation->priv->serializer, n, &temp);
         g_string_append(text, temp);
         if (factor->next)
             g_string_append(text, "Ã?");
         g_slice_free(MPNumber, n);
+        g_free(temp);
     }
     g_list_free(factors);
 
diff --git a/src/math-variables.c b/src/math-variables.c
index 58a9815..77207b6 100644
--- a/src/math-variables.c
+++ b/src/math-variables.c
@@ -96,10 +96,11 @@ registers_save(MathVariables *variables)
     {
         gchar *name = key;
         MPNumber *value = val;
-        char number[1024];
+        char *number;
 
-        mp_serializer_to_specific_string(value, 10, 50, true, false, number, 1024);
+        mp_serializer_to_specific_string(value, 10, 50, true, false, &number);
         fprintf(f, "%s=%s\n", name, number);
+        g_free(number);
     }
     fclose(f);
 }
diff --git a/src/mp-binary.c b/src/mp-binary.c
index 6c8811c..f16470b 100644
--- a/src/mp-binary.c
+++ b/src/mp-binary.c
@@ -43,11 +43,11 @@ static int hex_to_int(char digit)
 static void
 mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, int), MPNumber *z, int wordlen)
 {
-    char text1[MAX_DIGITS], text2[MAX_DIGITS], text_out[MAX_DIGITS], text_out2[MAX_DIGITS];
+    char *text1, *text2, text_out[MAX_DIGITS], text_out2[MAX_DIGITS];
     int offset1, offset2, offset_out;
 
-    mp_serializer_to_specific_string(x, 16, 0, false, false, text1, MAX_DIGITS);
-    mp_serializer_to_specific_string(y, 16, 0, false, false, text2, MAX_DIGITS);
+    mp_serializer_to_specific_string(x, 16, 0, false, false, &text1);
+    mp_serializer_to_specific_string(y, 16, 0, false, false, &text2);
     offset1 = strlen(text1) - 1;
     offset2 = strlen(text2) - 1;
     offset_out = wordlen / 4 - 1;
@@ -56,6 +56,8 @@ mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, in
     }
     if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2)) {
         mperr("Overflow. Try a bigger word size");
+        g_free(text1);
+        g_free(text2);
         return;
     }
 
@@ -76,6 +78,8 @@ mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, in
 
     snprintf(text_out2, MAX_DIGITS, "%s", text_out);
     mp_set_from_string(text_out2, 16, z);
+    g_free(text1);
+    g_free(text2);
 }
 
 
@@ -153,15 +157,16 @@ mp_not(const MPNumber *x, int wordlen, MPNumber *z)
 void
 mp_mask(const MPNumber *x, int wordlen, MPNumber *z)
 {
-    char text[MAX_DIGITS];
+    char *text;
     size_t len, offset;
 
     /* Convert to a hexadecimal string and use last characters */
-    mp_serializer_to_specific_string(x, 16, 0, false, false, text, MAX_DIGITS);
+    mp_serializer_to_specific_string(x, 16, 0, false, false, &text);
     len = strlen(text);
     offset = wordlen / 4;
     offset = len > offset ? len - offset: 0;
     mp_set_from_string(text + offset, 16, z);
+    g_free(text);
 }
 
 
diff --git a/src/mp-serializer.c b/src/mp-serializer.c
index b397a57..1b9db1e 100644
--- a/src/mp-serializer.c
+++ b/src/mp-serializer.c
@@ -76,7 +76,11 @@ mp_cast_to_string_real(MpSerializer *serializer, const MPNumber *x, int base, bo
     mp_xpowy_integer(&temp, -(serializer->priv->accuracy+1), &temp);
     mp_multiply_integer(&temp, base, &temp);
     mp_divide_integer(&temp, 2, &temp);
-    mp_add(&number, &temp, &number);
+    mp_add(&number, &temp, &temp);
+
+    /* If trying to add rounding factor causes overflow, don't add it */
+    if (!mp_get_error())
+        mp_set_from_mp(&temp, &number);
 
     /* Split into integer and fractional component */
     mp_floor(&number, &integer_component);
@@ -158,12 +162,12 @@ mp_cast_to_string_real(MpSerializer *serializer, const MPNumber *x, int base, bo
 
 
 static void
-mp_cast_to_string(MpSerializer *serializer, const MPNumber *x, char *buffer, int buffer_length)
+mp_cast_to_string(MpSerializer *serializer, const MPNumber *x, char **buffer)
 {
     GString *string;
     MPNumber x_real;
 
-    string = g_string_sized_new(buffer_length);
+    string = g_string_sized_new(1024);
 
     mp_real_component(x, &x_real);
     mp_cast_to_string_real(serializer, &x_real, serializer->priv->base, false, string);
@@ -179,7 +183,7 @@ mp_cast_to_string(MpSerializer *serializer, const MPNumber *x, char *buffer, int
             force_sign = false;
         }
 
-        s = g_string_sized_new(buffer_length);
+        s = g_string_sized_new(1024);
         mp_cast_to_string_real(serializer, &x_im, 10, force_sign, s);
         if (strcmp(s->str, "0") == 0 || strcmp(s->str, "+0") == 0 || strcmp(s->str, "â??0") == 0) {
             /* Ignore */
@@ -204,22 +208,21 @@ mp_cast_to_string(MpSerializer *serializer, const MPNumber *x, char *buffer, int
         g_string_free(s, TRUE);
     }
 
-    // FIXME: Check for truncation
-    strncpy(buffer, string->str, buffer_length);
+    *buffer = g_strndup(string->str, string->len + 1);
     g_string_free(string, TRUE);
 }
 
 
 static void
-mp_cast_to_exponential_string(MpSerializer *serializer, const MPNumber *x, bool eng_format, char *buffer, int buffer_length)
+mp_cast_to_exponential_string(MpSerializer *serializer, const MPNumber *x, bool eng_format, char **buffer)
 {
-    char fixed[1024], *c;
+    char *fixed, *c;
     MPNumber t, z, base, base3, base10, base10inv, mantissa;
     int exponent = 0;
     GString *string;
     const char *super_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�"};
 
-    string = g_string_sized_new(buffer_length);
+    string = g_string_sized_new(1024);
 
     mp_abs(x, &z);
     if (mp_is_negative(x))
@@ -256,8 +259,9 @@ mp_cast_to_exponential_string(MpSerializer *serializer, const MPNumber *x, bool
         }
     }
 
-    mp_cast_to_string(serializer, &mantissa, fixed, 1024);
+    mp_cast_to_string(serializer, &mantissa, &fixed);
     g_string_append(string, fixed);
+    g_free(fixed);
     if (exponent != 0) {
         g_string_append_printf(string, "Ã?10"); // FIXME: Use the current base
         if (exponent < 0) {
@@ -269,29 +273,29 @@ mp_cast_to_exponential_string(MpSerializer *serializer, const MPNumber *x, bool
             g_string_append(string, super_digits[*c - '0']);
     }
 
-    strncpy(buffer, string->str, buffer_length);
+    *buffer = g_strndup(string->str, string->len + 1);
     g_string_free(string, TRUE);
 }
 
 
 void
-mp_serializer_to_standard_string(MpSerializer *serializer, const MPNumber *x, char *target, int target_len)
+mp_serializer_to_standard_string(MpSerializer *serializer, const MPNumber *x, char **target)
 {
     switch(serializer->priv->format) {
     case FIX:
-        mp_cast_to_string(serializer, x, target, target_len);
+        mp_cast_to_string(serializer, x, target);
         break;
     case SCI:
-        mp_cast_to_exponential_string(serializer, x, false, target, target_len);
+        mp_cast_to_exponential_string(serializer, x, false, target);
         break;
     case ENG:
-        mp_cast_to_exponential_string(serializer, x, true, target, target_len);
+        mp_cast_to_exponential_string(serializer, x, true, target);
         break;
     }
 }
 
 void
-mp_serializer_to_specific_string(const MPNumber *x, int base, int accuracy, bool trim_zeroes, bool localize, char *target, int target_len)
+mp_serializer_to_specific_string(const MPNumber *x, int base, int accuracy, bool trim_zeroes, bool localize, char **target)
 {
     MpSerializer *serializer = mp_serializer_new ();
     if (!localize) {
@@ -302,7 +306,7 @@ mp_serializer_to_specific_string(const MPNumber *x, int base, int accuracy, bool
     serializer->priv->base = base;
     serializer->priv->accuracy = accuracy;
     serializer->priv->show_zeroes = !trim_zeroes;
-    mp_serializer_to_standard_string(serializer, x, target, target_len);
+    mp_serializer_to_standard_string(serializer, x, target);
     g_object_unref(serializer);
 }
 
diff --git a/src/mp-serializer.h b/src/mp-serializer.h
index f815fa2..718ee1e 100644
--- a/src/mp-serializer.h
+++ b/src/mp-serializer.h
@@ -50,8 +50,8 @@ typedef enum {
 GType mp_serializer_get_type(void);
 MpSerializer *mp_serializer_new(void);
 
-void mp_serializer_to_standard_string(MpSerializer *serializer, const MPNumber *z, char *target, int target_len);
-void mp_serializer_to_specific_string(const MPNumber *z, int base, int accuracy, bool trim_zeroes, bool localize, char *target, int target_len);
+void mp_serializer_to_standard_string(MpSerializer *serializer, const MPNumber *z, char **target);
+void mp_serializer_to_specific_string(const MPNumber *z, int base, int accuracy, bool trim_zeroes, bool localize, char **target);
 bool mp_serializer_from_string(MpSerializer *serializer, const char *str, MPNumber *z);
 
 const gchar* mp_serializer_get_thousands_separator_text(MpSerializer *serializer);
diff --git a/src/mp.c b/src/mp.c
index 0e46b35..798b1b0 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -293,6 +293,15 @@ mp_add_real(const MPNumber *x, int y_sign, const MPNumber *y, MPNumber *z)
         z->fraction[MP_T + i] = 0;
 
     if (sign_prod >= 0) {
+        /* This is probably insufficient overflow detection, but it makes us
+         * not crash at least.
+         */
+        if (MP_T + 3 < med) {
+            mperr(_("Overflow: the result couldn't be calculated"));
+            mp_set_from_integer(0, z);
+            return;
+        }
+
         /* HERE DO ADDITION, EXPONENT(Y) >= EXPONENT(X) */
         for (i = MP_T + 3; i >= MP_T; i--)
             z->fraction[i] = small_fraction[i - med];
diff --git a/src/unittest.c b/src/unittest.c
index 30de463..8701218 100644
--- a/src/unittest.c
+++ b/src/unittest.c
@@ -79,18 +79,19 @@ test(char *expression, char *expected, int expected_error)
 {
     MPErrorCode error;
     MPNumber result;
-    char result_str[1024] = "";
 
     error = mp_equation_parse(expression, &options, &result, NULL);
 
     if(error == 0) {
-        mp_serializer_to_specific_string(&result, options.base, 9, true, false, result_str, 1024);
+        char *result_str;
+        mp_serializer_to_specific_string(&result, options.base, 9, true, false, &result_str);
         if(expected_error != 0)
             fail("'%s' -> %s, expected error %s", expression, result_str, error_code_to_string(expected_error));
         else if(strcmp(result_str, expected) != 0)
             fail("'%s' -> '%s', expected '%s'", expression, result_str, expected);
         else
             pass("'%s' -> '%s'", expression, result_str);
+        g_free(result_str);
     }
     else {
         if(error == expected_error)



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