[gnumeric] Criteria: implement pattern matching.



commit cfb430df770b90a2765ebfc3c036a5e092952d75
Author: Morten Welinder <terra gnome org>
Date:   Sat Jun 20 15:36:00 2009 -0400

    Criteria: implement pattern matching.

 ChangeLog                       |   11 ++++++
 NEWS                            |   28 +++++++++------
 plugins/fn-database/functions.c |    4 +-
 plugins/fn-math/functions.c     |    4 +-
 src/value.c                     |   72 ++++++++++++++++++++------------------
 src/value.h                     |   15 +++++---
 6 files changed, 78 insertions(+), 56 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a6985d2..81407a3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-06-20  Morten Welinder  <terra gnome org>
+
+	* src/value.c (criteria_test_match): New function.
+	(free_criteria): Free regexp if needed.
+	(criteria_inspect_values, criteria_test_equal,
+	criteria_test_unequal, criteria_test_less, criteria_test_greater,
+	criteria_test_less_or_equal, criteria_test_greater_or_equal): Take
+	GnmCriteria instead of y and date_conv.  All callers changed.
+	(parse_criteria): The no-operator case is criteria_test_match, not
+	criteria_test_equal.
+
 2009-06-20  Morten Welinder <terra gnome org>
 
 	* configure.in: Post-release bump.
diff --git a/NEWS b/NEWS
index 04de424..21f91ac 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,9 @@
 Gnumeric 1.9.10
 
+Morten:
+	* Make SUMIF/COUNTIF and the D* functions understand pattern.
+	[#586215]
+
 --------------------------------------------------------------------------
 Gnumeric 1.9.9
 
@@ -12,18 +16,18 @@ Andreas:
 	* Remove distinction between label and filled rectangle.
 	* Add superscipt and subscript buttons. [#583327]
 	* Improve ODF import.
-	* Improve 2 factor ANOVA tool
-	* Improve Rank & Percentiles tool
-	* Improve Fourier transform tool
-	* New FOURIER function
-	* Added Tests for Independence and Homogeneity
-	* Make imported manual page breaks work
-	* Improve print area handling and export to ODF
-	* Some minor menu rearrangement
-	* Let the sort dialog guess whether there is a header
-	* Fix xls import of sheet labels [#586066]
-	* Fix html export [#586028]
-	* Avoid analysis tool crashes if required plugins are not loaded
+	* Improve 2 factor ANOVA tool.
+	* Improve Rank & Percentiles tool.
+	* Improve Fourier transform tool.
+	* New FOURIER function.
+	* Added Tests for Independence and Homogeneity.
+	* Make imported manual page breaks work.
+	* Improve print area handling and export to ODF.
+	* Some minor menu rearrangement.
+	* Let the sort dialog guess whether there is a header.
+	* Fix xls import of sheet labels.  [#586066]
+	* Fix html export.  [#586028]
+	* Avoid analysis tool crashes if required plugins are not loaded.
 
 Jody:
 	* GOString start of richtext and phonetic support.
diff --git a/plugins/fn-database/functions.c b/plugins/fn-database/functions.c
index 96c628c..369e9da 100644
--- a/plugins/fn-database/functions.c
+++ b/plugins/fn-database/functions.c
@@ -81,13 +81,13 @@ find_cells_that_match (Sheet *sheet, GnmValue const *database,
 			condition = current_criteria->conditions;
 
 			for (;condition != NULL ; condition = condition->next) {
-				GnmCriteria const *cond = condition->data;
+				GnmCriteria *cond = condition->data;
 				GnmCell *tmp = sheet_cell_get (sheet,
 					cond->column, row);
 				if (tmp != NULL)
 					gnm_cell_eval (tmp);
 				if (gnm_cell_is_empty (tmp) ||
-				    !cond->fun (tmp->value, cond->x, date_conv)) {
+				    !cond->fun (tmp->value, cond)) {
 					add_flag = FALSE;
 					break;
 				}
diff --git a/plugins/fn-math/functions.c b/plugins/fn-math/functions.c
index ab8ba5f..a406e8a 100644
--- a/plugins/fn-math/functions.c
+++ b/plugins/fn-math/functions.c
@@ -601,7 +601,7 @@ cb_countif (GnmCellIter const *iter, CountIfClosure *res)
 	if (!VALUE_IS_NUMBER (v) && !VALUE_IS_STRING (v))
 		return NULL;
 
-	if (!res->crit->fun (v, res->crit->x, res->crit->date_conv))
+	if (!res->crit->fun (v, res->crit))
 		return NULL;
 
 	res->count++;
@@ -693,7 +693,7 @@ cb_sumif (GnmCellIter const *iter, SumIfClosure *res)
 	if (!VALUE_IS_NUMBER (v) && !VALUE_IS_STRING (v))
 		return NULL;
 
-	if (!res->crit->fun (v, res->crit->x, res->crit->date_conv))
+	if (!res->crit->fun (v, res->crit))
 		return NULL;
 
 	if (NULL != res->target_sheet) {
diff --git a/src/value.c b/src/value.c
index 49c3108..fda9e94 100644
--- a/src/value.c
+++ b/src/value.c
@@ -1337,11 +1337,11 @@ value_set_fmt (GnmValue *v, GOFormat const *fmt)
 typedef enum { CRIT_NULL, CRIT_FLOAT, CRIT_BADFLOAT, CRIT_STRING } CritType;
 
 static CritType
-criteria_inspect_values (GnmValue const *x, GnmValue const *y,
-			 gnm_float *xr, gnm_float *yr,
-			 GODateConventions const *date_conv)
+criteria_inspect_values (GnmValue const *x, gnm_float *xr, gnm_float *yr,
+			 GnmCriteria *crit)
 {
 	GnmValue *vx;
+	GnmValue const *y = crit->x;
 
 	if (x == NULL || y == NULL)
 		return CRIT_NULL;
@@ -1355,7 +1355,7 @@ criteria_inspect_values (GnmValue const *x, GnmValue const *y,
 		return CRIT_FLOAT;
 	}
 
-	vx = format_match (value_peek_string (x), NULL, date_conv);
+	vx = format_match (value_peek_string (x), NULL, crit->date_conv);
 	if (!vx)
 		return CRIT_BADFLOAT;
 
@@ -1366,12 +1366,12 @@ criteria_inspect_values (GnmValue const *x, GnmValue const *y,
 
 
 static gboolean
-criteria_test_equal (GnmValue const *x, GnmValue const *y,
-		     GODateConventions const *date_conv)
+criteria_test_equal (GnmValue const *x, GnmCriteria *crit)
 {
 	gnm_float xf, yf;
+	GnmValue const *y = crit->x;
 
-	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	switch (criteria_inspect_values (x, &xf, &yf, crit)) {
 	default:
 		g_assert_not_reached ();
 	case CRIT_NULL:
@@ -1387,12 +1387,11 @@ criteria_test_equal (GnmValue const *x, GnmValue const *y,
 }
 
 static gboolean
-criteria_test_unequal (GnmValue const *x, GnmValue const *y,
-		       GODateConventions const *date_conv)
+criteria_test_unequal (GnmValue const *x, GnmCriteria *crit)
 {
 	gnm_float xf, yf;
 
-	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	switch (criteria_inspect_values (x, &xf, &yf, crit)) {
 	default:
 		g_assert_not_reached ();
 	case CRIT_NULL:
@@ -1403,17 +1402,16 @@ criteria_test_unequal (GnmValue const *x, GnmValue const *y,
 	case CRIT_STRING:
 		/* FIXME: _ascii_??? */
 		return g_ascii_strcasecmp (value_peek_string (x),
-					   value_peek_string (y)) != 0;
+					   value_peek_string (crit->x)) != 0;
 	}
 }
 
 static gboolean
-criteria_test_less (GnmValue const *x, GnmValue const *y,
-		    GODateConventions const *date_conv)
+criteria_test_less (GnmValue const *x, GnmCriteria *crit)
 {
 	gnm_float xf, yf;
 
-	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	switch (criteria_inspect_values (x, &xf, &yf, crit)) {
 	default:
 		g_assert_not_reached ();
 	case CRIT_NULL:
@@ -1426,12 +1424,11 @@ criteria_test_less (GnmValue const *x, GnmValue const *y,
 }
 
 static gboolean
-criteria_test_greater (GnmValue const *x, GnmValue const *y,
-		       GODateConventions const *date_conv)
+criteria_test_greater (GnmValue const *x, GnmCriteria *crit)
 {
 	gnm_float xf, yf;
 
-	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	switch (criteria_inspect_values (x, &xf, &yf, crit)) {
 	default:
 		g_assert_not_reached ();
 	case CRIT_NULL:
@@ -1444,12 +1441,11 @@ criteria_test_greater (GnmValue const *x, GnmValue const *y,
 }
 
 static gboolean
-criteria_test_less_or_equal (GnmValue const *x, GnmValue const *y,
-			     GODateConventions const *date_conv)
+criteria_test_less_or_equal (GnmValue const *x, GnmCriteria *crit)
 {
 	gnm_float xf, yf;
 
-	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	switch (criteria_inspect_values (x, &xf, &yf, crit)) {
 	default:
 		g_assert_not_reached ();
 	case CRIT_NULL:
@@ -1462,12 +1458,11 @@ criteria_test_less_or_equal (GnmValue const *x, GnmValue const *y,
 }
 
 static gboolean
-criteria_test_greater_or_equal (GnmValue const *x, GnmValue const *y,
-				GODateConventions const *date_conv)
+criteria_test_greater_or_equal (GnmValue const *x, GnmCriteria *crit)
 {
 	gnm_float xf, yf;
 
-	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	switch (criteria_inspect_values (x, &xf, &yf, crit)) {
 	default:
 		g_assert_not_reached ();
 	case CRIT_NULL:
@@ -1479,6 +1474,15 @@ criteria_test_greater_or_equal (GnmValue const *x, GnmValue const *y,
 	}
 }
 
+static gboolean
+criteria_test_match (GnmValue const *x, GnmCriteria *crit)
+{
+	if (!crit->has_rx)
+		return FALSE;
+
+	return go_regexec (&crit->rx, value_peek_string (x), 0, NULL, 0) == REG_OK;
+}
+
 /*
  * Finds a column index of a field.
  */
@@ -1536,6 +1540,8 @@ void
 free_criteria (GnmCriteria *criteria)
 {
 	value_release (criteria->x);
+	if (criteria->has_rx)
+		go_regfree (&criteria->rx);
 	g_free (criteria);
 }
 
@@ -1596,20 +1602,21 @@ parse_criteria (GnmValue const *crit_val, GODateConventions const *date_conv)
 		res->fun = criteria_test_greater_or_equal;
 		len = 2;
 	} else if (strncmp (criteria, "<>", 2) == 0) {
-		res->fun = (GnmCriteriaFunc) criteria_test_unequal;
+		res->fun = criteria_test_unequal;
 		len = 2;
 		res->iter_flags = CELL_ITER_ALL;
 	} else if (*criteria == '<') {
-		res->fun = (GnmCriteriaFunc) criteria_test_less;
+		res->fun = criteria_test_less;
 		len = 1;
 	} else if (*criteria == '=') {
-		res->fun = (GnmCriteriaFunc) criteria_test_equal;
+		res->fun = criteria_test_equal;
 		len = 1;
 	} else if (*criteria == '>') {
-		res->fun = (GnmCriteriaFunc) criteria_test_greater;
+		res->fun = criteria_test_greater;
 		len = 1;
 	} else {
-		res->fun = (GnmCriteriaFunc) criteria_test_equal;
+		res->fun = criteria_test_match;
+		res->has_rx = (gnm_regcomp_XL (&res->rx, criteria, 0, TRUE) == REG_OK);
 		len = 0;
 	}
 
@@ -1714,22 +1721,19 @@ find_rows_that_match (Sheet *sheet, int first_col, int first_row,
 	gboolean   add_flag;
 	char const *t1, *t2;
 	GnmCell   *test_cell;
-	GnmCriteria const *cond;
-	GODateConventions const *date_conv =
-		workbook_date_conv (sheet->workbook);
 
 	for (row = first_row; row <= last_row; row++) {
 		add_flag = TRUE;
-		for (crit_ptr = criterias; crit_ptr != NULL; crit_ptr = crit_ptr->next) {
+		for (crit_ptr = criterias; crit_ptr; crit_ptr = crit_ptr->next) {
 			add_flag = TRUE;
 			for (cond_ptr = ((GnmDBCriteria const *)crit_ptr->data)->conditions;
 			     cond_ptr != NULL ; cond_ptr = cond_ptr->next) {
-				cond = cond_ptr->data;
+				GnmCriteria *cond = cond_ptr->data;
 				test_cell = sheet_cell_get (sheet, cond->column, row);
 				if (test_cell != NULL) {
 					gnm_cell_eval (test_cell);
 					if (!gnm_cell_is_empty (test_cell) &&
-					    !cond->fun (test_cell->value, cond->x, date_conv)) {
+					    !cond->fun (test_cell->value, cond)) {
 						add_flag = FALSE;
 						break;
 					}
diff --git a/src/value.h b/src/value.h
index b570800..66bf54f 100644
--- a/src/value.h
+++ b/src/value.h
@@ -185,16 +185,19 @@ extern GnmValueErr const value_terminate_err;
 
 void value_array_set       (GnmValue *array, int col, int row, GnmValue *v);
 
+typedef struct _GnmCriteria GnmCriteria;
+
 /* FIXME: this stuff below ought to go elsewhere.  */
-typedef gboolean (*GnmCriteriaFunc) (GnmValue const *x, GnmValue const *y,
-				     GODateConventions const *date_conv);
-typedef struct {
+typedef gboolean (*GnmCriteriaFunc) (GnmValue const *x, GnmCriteria *crit);
+struct _GnmCriteria {
         GnmCriteriaFunc fun;
-        GnmValue  *x;
-        int	   column; /* absolute */
+        GnmValue *x;
+        int column; /* absolute */
 	CellIterFlags iter_flags;
 	GODateConventions const *date_conv;
-} GnmCriteria;
+	GORegexp rx;
+	gboolean has_rx;
+};
 
 typedef struct {
         int     row;	/* absolute */



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