[gnumeric] Cond format: fix "Starts with" and "Ends with".



commit 8e11e5b24085edfe1c66db8723dd19a814b0d6d9
Author: Morten Welinder <terra gnome org>
Date:   Fri Mar 21 10:51:09 2014 -0400

    Cond format: fix "Starts with" and "Ends with".
    
    These need to be case insensitive.

 ChangeLog              |    7 ++++
 NEWS                   |    1 +
 src/style-conditions.c |   88 ++++++++++++++++++++++++++----------------------
 3 files changed, 56 insertions(+), 40 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 5d2c687..e6d60e5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2014-03-21  Morten Welinder  <terra gnome org>
+
+       * src/style-conditions.c (generate_end_match): Use case
+       insensitive comparison.  Pull negation into the operator.
+       (gnm_style_cond_eval): "Start with..." and "Ends with..." are case
+       insensitive.
+
 2014-03-18  Morten Welinder  <terra gnome org>
 
        * src/gui-util.c (kill_popup_menu): One more try at really killing
diff --git a/NEWS b/NEWS
index e362099..ff4cc2e 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ Gnumeric 1.12.14
 Morten:
        * Plug leaks.
        * xlsx conditional format fixes.  [#726202]
+       * Fix semantics of conditional format operators.  [#726806]
 
 --------------------------------------------------------------------------
 Gnumeric 1.12.13
diff --git a/src/style-conditions.c b/src/style-conditions.c
index a28865e..438b9e3 100644
--- a/src/style-conditions.c
+++ b/src/style-conditions.c
@@ -243,7 +243,7 @@ gnm_style_cond_set_overlay (GnmStyleCond *cond, GnmStyle *overlay)
 }
 
 static GnmExpr const *
-generate_end_match (const char *endfunc, gboolean force,
+generate_end_match (const char *endfunc, gboolean force, gboolean negate,
                    GnmExprTop const *sexpr, GnmCellRef *cr)
 {
        GnmValue const *v = gnm_expr_get_constant (sexpr->expr);
@@ -263,12 +263,12 @@ generate_end_match (const char *endfunc, gboolean force,
        } else
                return NULL;
 
-       return gnm_expr_new_funcall2
-               (gnm_func_lookup_or_add_placeholder ("EXACT"),
-                gnm_expr_new_funcall2
+       return gnm_expr_new_binary
+               (gnm_expr_new_funcall2
                 (gnm_func_lookup_or_add_placeholder (endfunc),
                  gnm_expr_new_cellref (cr),
                  len_expr),
+                negate ? GNM_EXPR_OP_NOT_EQUAL : GNM_EXPR_OP_EQUAL,
                 gnm_expr_copy (sexpr->expr));
 }
 
@@ -333,27 +333,13 @@ gnm_style_cond_get_alternate_expr (GnmStyleCond const *cond)
        case GNM_STYLE_COND_NOT_BEGINS_WITH_STR:
                negate = TRUE; /* ...and fall through */
        case GNM_STYLE_COND_BEGINS_WITH_STR:
-               expr = generate_end_match ("LEFT", FALSE, sexpr, &self);
-               if (expr)
-                       break;
-
                /*
-                * We get here if sexpr is not a constant.  We are
-                * constrained by using only Excel functions and not
-                * evaluating the needle more than once.  The
-                * expression used here works, but FIND is more
-                * expensive that it ought to be.
+                * We are constrained by using only Excel functions and not
+                * evaluating the needle more than once.  We cannot fulfill
+                * that and end up computing the needle twice.
                 */
-               expr = gnm_expr_new_binary
-                       (gnm_expr_new_funcall2
-                        (gnm_func_lookup_or_add_placeholder ("IFERROR"),
-                         gnm_expr_new_funcall2
-                         (gnm_func_lookup_or_add_placeholder ("FIND"),
-                          gnm_expr_copy (sexpr->expr),
-                          gnm_expr_new_cellref (&self)),
-                         gnm_expr_new_constant (value_new_int (2))),
-                        GNM_EXPR_OP_EQUAL,
-                        gnm_expr_new_constant (value_new_int (1)));
+               expr = generate_end_match ("LEFT", TRUE, negate, sexpr, &self);
+               negate = FALSE;
                break;
 
        case GNM_STYLE_COND_NOT_ENDS_WITH_STR:
@@ -364,7 +350,8 @@ gnm_style_cond_get_alternate_expr (GnmStyleCond const *cond)
                 * evaluating the needle more than once.  We cannot fulfill
                 * that and end up computing the needle twice.
                 */
-               expr = generate_end_match ("RIGHT", TRUE, sexpr, &self);
+               expr = generate_end_match ("RIGHT", TRUE, negate, sexpr, &self);
+               negate = FALSE;
                break;
 
        default:
@@ -393,16 +380,17 @@ isself (GnmExpr const *expr)
 }
 
 static GnmExprTop const *
-decode_end_match (const char *endfunc, GnmExpr const *expr)
+decode_end_match (const char *endfunc, GnmExpr const *expr, gboolean *negated)
 {
        GnmExpr const *needle;
        GnmExpr const *expr2;
 
-       if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL &&
-           expr->func.argc == 2 &&
-           expr->func.func == gnm_func_lookup_or_add_placeholder ("EXACT") &&
-           (needle = expr->func.argv[1]) &&
-           (expr2 = expr->func.argv[0]) &&
+       *negated = (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_NOT_EQUAL);
+
+       if ((GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_EQUAL ||
+            GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_NOT_EQUAL) &&
+           (needle = expr->binary.value_b) &&
+           (expr2 = expr->binary.value_a) &&
            GNM_EXPR_GET_OPER (expr2) == GNM_EXPR_OP_FUNCALL &&
            expr2->func.argc == 2 &&
            expr2->func.func == gnm_func_lookup_or_add_placeholder (endfunc) &&
@@ -442,6 +430,7 @@ gnm_style_cond_canonicalize (GnmStyleCond *cond)
        GnmExprTop const *texpr;
        GnmValue const *v;
        gboolean negate = FALSE;
+       gboolean match_negated;
        GnmFunc const *iserror;
        GnmFunc const *iferror;
        GnmFunc const *find;
@@ -511,12 +500,12 @@ gnm_style_cond_canonicalize (GnmStyleCond *cond)
                newop = negate
                        ? GNM_STYLE_COND_NOT_BEGINS_WITH_STR
                        : GNM_STYLE_COND_BEGINS_WITH_STR;
-       } else if ((texpr = decode_end_match ("LEFT", expr))) {
-               newop = negate
+       } else if ((texpr = decode_end_match ("LEFT", expr, &match_negated))) {
+               newop = (negate ^ match_negated)
                        ? GNM_STYLE_COND_NOT_BEGINS_WITH_STR
                        : GNM_STYLE_COND_BEGINS_WITH_STR;
-       } else if ((texpr = decode_end_match ("RIGHT", expr))) {
-               newop = negate
+       } else if ((texpr = decode_end_match ("RIGHT", expr, &match_negated))) {
+               newop = (negate ^ match_negated)
                        ? GNM_STYLE_COND_NOT_ENDS_WITH_STR
                        : GNM_STYLE_COND_ENDS_WITH_STR;
        }
@@ -529,6 +518,29 @@ gnm_style_cond_canonicalize (GnmStyleCond *cond)
        }
 }
 
+static gboolean
+case_insensitive_has_fix (GnmValue const *vs, GnmValue const *vp,
+                         gboolean is_prefix)
+{
+       size_t plen = g_utf8_strlen (value_peek_string (vp), -1);
+       const char *s = value_peek_string (vs);
+       size_t slen = g_utf8_strlen (s, -1);
+       GnmValue *vs2;
+       gboolean res;
+
+       if (plen > slen)
+               return FALSE;
+
+       vs2 = value_new_string_nocopy
+               (is_prefix
+                ? g_strndup (s, g_utf8_offset_to_pointer (s, plen) - s)
+                : g_strdup (g_utf8_offset_to_pointer (s, slen - plen)));
+       res = (value_compare (vs2, vp, FALSE) == IS_EQUAL);
+       value_release (vs2);
+
+       return res;
+}
+
 
 static gboolean
 gnm_style_cond_eval (GnmStyleCond const *cond, GnmValue const *cv,
@@ -604,17 +616,13 @@ gnm_style_cond_eval (GnmStyleCond const *cond, GnmValue const *cv,
        case GNM_STYLE_COND_NOT_BEGINS_WITH_STR:
                negate = TRUE;  /* ...and fall through */
        case GNM_STYLE_COND_BEGINS_WITH_STR:
-               res = (cv &&
-                      g_str_has_prefix (value_peek_string (cv),
-                                        value_peek_string (val0)));
+               res = (cv && case_insensitive_has_fix (cv, val0, TRUE));
                break;
 
        case GNM_STYLE_COND_NOT_ENDS_WITH_STR:
                negate = TRUE;  /* ...and fall through */
        case GNM_STYLE_COND_ENDS_WITH_STR:
-               res = (cv &&
-                      g_str_has_suffix (value_peek_string (cv),
-                                        value_peek_string (val0)));
+               res = (cv && case_insensitive_has_fix (cv, val0, FALSE));
                break;
 
        case GNM_STYLE_COND_CUSTOM:


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