[gnumeric] Complex: improve parsing of complex numbers with embedded spaces.



commit 5333a4dff642241a24a279e5f62563fbe6b51acf
Author: Morten Welinder <terra gnome org>
Date:   Tue Apr 9 13:21:21 2013 -0400

    Complex: improve parsing of complex numbers with embedded spaces.

 ChangeLog     |    6 +++
 NEWS          |    1 +
 src/complex.c |  118 ++++++++++++++++++++++++++++++++++-----------------------
 3 files changed, 78 insertions(+), 47 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index dae4d1d..52d3305 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2013-04-09  Morten Welinder  <terra gnome org>
 
+       * src/complex.c (complex_from_string): Make this handle embedded
+       spaces systematically.
+       (is_unit_imaginary): Delete.
+
+2013-04-09  Morten Welinder  <terra gnome org>
+
        * src/complex.c (complex_pow): Use Goffice's copy.
 
 2013-04-05  Morten Welinder  <terra gnome org>
diff --git a/NEWS b/NEWS
index 4d722db..01f17fc 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,7 @@ Morten:
        * New function POCHHAMMER.
        * Fix import of IFERROR from xls.
        * Add test sheet for complex number parsing.
+       * Improve complex number parsing.
 
 --------------------------------------------------------------------------
 Gnumeric 1.12.1
diff --git a/src/complex.c b/src/complex.c
index d7c0e35..9ae8c8f 100644
--- a/src/complex.c
+++ b/src/complex.c
@@ -64,40 +64,55 @@ complex_to_string (complex_t const *src, char const *reformat,
 
 /* ------------------------------------------------------------------------- */
 
-static int
-is_unit_imaginary (char const *src, gnm_float *im, char *imunit)
-{
-       if (*src == '-') {
-               *im = -1.0;
-               src++;
-       } else {
-               *im = +1.0;
-               if (*src == '+') src++;
-       }
-
-       if ((*src == 'i' || *src == 'j') && src[1] == 0) {
-               *imunit = *src;
-               return 1;
-       } else
-               return 0;
-}
-
+#define EAT_SPACES(src_) do {                                  \
+       while (g_unichar_isspace (g_utf8_get_char (src_)))      \
+               src_ = g_utf8_next_char (src_);                 \
+} while (0)
+
+#define HANDLE_SIGN(src_,sign_) do {                           \
+       switch (*src_) {                                        \
+       case '+': sign_ = +1; src_++; EAT_SPACES (src_); break; \
+       case '-': sign_ = -1; src_++; EAT_SPACES (src_); break; \
+       default: sign_ = 0; break;                              \
+       }                                                       \
+} while (0)
+
+/**
+ * complex_from_string:
+ * @dst: return location
+ * @src: string to parse
+ * @imunit: (out): return location of imaginary unit.
+ *
+ * Returns: zero on success, -1 otherwise.
+ *
+ * This function differs from Excel's parsing in at least the following
+ * ways:
+ * (1) We allow spaces before the imaginary unit used with an impled "1".
+ * Therefore we allow "+ i".
+ * (2) We do not allow a thousands separator as in "1,000i".
+ */
 int
 complex_from_string (complex_t *dst, char const *src, char *imunit)
 {
        gnm_float x, y;
        char *end;
+       int sign;
+
+       EAT_SPACES (src);
+       HANDLE_SIGN (src, sign);
 
        /* Case: "i", "+i", "-i", ...  */
-       if (is_unit_imaginary (src, &dst->im, imunit)) {
-               dst->re = 0;
-               return 0;
+       if (*src == 'i' || *src == 'j') {
+               x = 1;
+       } else {
+               x = gnm_strto (src, &end);
+               if (src == end || errno == ERANGE)
+                       return -1;
+               src = end;
+               EAT_SPACES (src);
        }
-
-       x = gnm_strto (src, &end);
-       if (src == end || errno == ERANGE)
-               return -1;
-       src = end;
+       if (sign < 0)
+               x = 0 - x;
 
        /* Case: "42", "+42", "-42", ...  */
        if (*src == 0) {
@@ -106,32 +121,41 @@ complex_from_string (complex_t *dst, char const *src, char *imunit)
                return 0;
        }
 
-       /* Case: "42i", "+42i", "-42i", ...  */
-       if ((*src == 'i' || *src == 'j') && src[1] == 0) {
-               complex_init (dst, 0, x);
-               *imunit = *src;
-               return 0;
+       /* Case: "42i", "+42i", "-42i", "-i", "i", ...  */
+       if (*src == 'i' || *src == 'j') {
+               *imunit = *src++;
+               EAT_SPACES (src);
+               if (*src == 0) {
+                       complex_init (dst, 0, x);
+                       return 0;
+               } else
+                       return -1;
        }
 
-       if (*src != '-' && *src != '+')
+       HANDLE_SIGN (src, sign);
+       if (!sign)
                return -1;
 
-       /* Case: "42+i", "+42-i", "-42-i", ...  */
-       if (is_unit_imaginary (src, &dst->im, imunit)) {
-               dst->re = x;
-               return 0;
+       if (*src == 'i' || *src == 'j') {
+               y = 1;
+       } else {
+               y = gnm_strto (src, &end);
+               if (src == end || errno == ERANGE)
+                       return -1;
+               src = end;
+               EAT_SPACES (src);
        }
-
-       y = gnm_strto (src, &end);
-       if (src == end || errno == ERANGE)
-               return -1;
-       src = end;
-
-       /* Case: "42+12i", "+42-12i", "-42-12i", ...  */
-       if ((*src == 'i' || *src == 'j') && src[1] == 0) {
-               complex_init (dst, x, y);
-               *imunit = *src;
-               return 0;
+       if (sign < 0)
+               y = 0 - y;
+
+       /* Case: "42+12i", "+42-12i", "-42-12i", "-42+i", "+42-i", ...  */
+       if (*src == 'i' || *src == 'j') {
+               *imunit = *src++;
+               EAT_SPACES (src);
+               if (*src == 0) {
+                       complex_init (dst, x, y);
+                       return 0;
+               }
        }
 
        return -1;


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