1 /********************************************************************\
2  * QueryCore.c -- API for providing core Query data types           *
3  * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>                *
4  *                                                                  *
5  * This program is free software; you can redistribute it and/or    *
6  * modify it under the terms of the GNU General Public License as   *
7  * published by the Free Software Foundation; either version 2 of   *
8  * the License, or (at your option) any later version.              *
9  *                                                                  *
10  * This program is distributed in the hope that it will be useful,  *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
13  * GNU General Public License for more details.                     *
14  *                                                                  *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact:                        *
17  *                                                                  *
18  * Free Software Foundation           Voice:  +1-617-542-5942       *
19  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
20  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
21  *                                                                  *
22 \********************************************************************/
23 
24 #include "guid.hpp"
25 #include <config.h>
26 
27 #include <glib.h>
28 #include <stdlib.h>
29 
30 #include "qof.h"
31 #include "qofquerycore-p.h"
32 
33 static QofLogModule log_module = QOF_MOD_QUERY;
34 
35 /* A function to destroy a query predicate's pdata */
36 typedef void (*QueryPredDataFree) (QofQueryPredData *pdata);
37 
38 /* A function to copy a query's predicate data */
39 typedef QofQueryPredData *(*QueryPredicateCopyFunc) (const QofQueryPredData *pdata);
40 
41 /* A function to take the object, apply the getter->param_getfcn,
42  * and return a printable string.  Note that this QofParam->getfnc
43  * function should be returning a type equal to this core object type.
44  *
45  * Note that this string MUST be freed by the caller.
46  */
47 typedef char * (*QueryToString) (gpointer object, QofParam *getter);
48 
49 /* A function to test for equality of predicate data */
50 typedef gboolean (*QueryPredicateEqual) (const QofQueryPredData *p1,
51         const QofQueryPredData *p2);
52 
53 static QueryPredicateCopyFunc qof_query_copy_predicate (QofType type);
54 static QueryPredDataFree qof_query_predicate_free (QofType type);
55 
56 /* Core Type Predicate helpers */
57 typedef const char * (*query_string_getter) (gpointer, QofParam *);
58 static const char * query_string_type = QOF_TYPE_STRING;
59 
60 typedef time64 (*query_date_getter) (gpointer, QofParam *);
61 static const char * query_date_type = QOF_TYPE_DATE;
62 
63 typedef gnc_numeric (*query_numeric_getter) (gpointer, QofParam *);
64 static const char * query_numeric_type = QOF_TYPE_NUMERIC;
65 
66 typedef GList * (*query_glist_getter) (gpointer, QofParam *);
67 typedef const GncGUID * (*query_guid_getter) (gpointer, QofParam *);
68 static const char * query_guid_type = QOF_TYPE_GUID;
69 
70 typedef gint32 (*query_int32_getter) (gpointer, QofParam *);
71 static const char * query_int32_type = QOF_TYPE_INT32;
72 
73 typedef gint64 (*query_int64_getter) (gpointer, QofParam *);
74 static const char * query_int64_type = QOF_TYPE_INT64;
75 
76 typedef double (*query_double_getter) (gpointer, QofParam *);
77 static const char * query_double_type = QOF_TYPE_DOUBLE;
78 
79 typedef gboolean (*query_boolean_getter) (gpointer, QofParam *);
80 static const char * query_boolean_type = QOF_TYPE_BOOLEAN;
81 
82 typedef char (*query_char_getter) (gpointer, QofParam *);
83 static const char * query_char_type = QOF_TYPE_CHAR;
84 
85 typedef QofCollection * (*query_collect_getter) (gpointer, QofParam*);
86 static const char * query_collect_type = QOF_TYPE_COLLECT;
87 
88 typedef const GncGUID * (*query_choice_getter) (gpointer, QofParam *);
89 static const char * query_choice_type = QOF_TYPE_CHOICE;
90 
91 /* Tables for predicate storage and lookup */
92 static gboolean initialized = FALSE;
93 static GHashTable *predTable = NULL;
94 static GHashTable *cmpTable = NULL;
95 static GHashTable *copyTable = NULL;
96 static GHashTable *freeTable = NULL;
97 static GHashTable *toStringTable = NULL;
98 static GHashTable *predEqualTable = NULL;
99 
100 #define COMPARE_ERROR -3
101 #define PREDICATE_ERROR -2
102 
103 #define VERIFY_PDATA(str) { \
104         g_return_if_fail (pd != NULL); \
105         g_return_if_fail (pd->type_name == str || \
106                         !g_strcmp0 (str, pd->type_name)); \
107 }
108 #define VERIFY_PDATA_R(str) { \
109         g_return_val_if_fail (pd != NULL, NULL); \
110         g_return_val_if_fail (pd->type_name == str || \
111                                 !g_strcmp0 (str, pd->type_name), \
112                                 NULL); \
113 }
114 #define VERIFY_PREDICATE(str) { \
115         g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \
116         g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \
117         g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \
118         g_return_val_if_fail (pd->type_name == str || \
119                                 !g_strcmp0 (str, pd->type_name), \
120                                 PREDICATE_ERROR); \
121 }
122 
123 /* *******************************************************************/
124 /* TYPE-HANDLING FUNCTIONS */
125 
126 /* QOF_TYPE_STRING */
127 
128 static int
string_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)129 string_match_predicate (gpointer object,
130                         QofParam *getter,
131                         QofQueryPredData *pd)
132 {
133     query_string_t pdata = (query_string_t) pd;
134     const char *s;
135     int ret = 0;
136 
137     VERIFY_PREDICATE (query_string_type);
138 
139     s = ((query_string_getter)getter->param_getfcn) (object, getter);
140 
141     if (!s) s = "";
142 
143     if (pdata->is_regex)
144     {
145         regmatch_t match;
146         if (!regexec (&pdata->compiled, s, 1, &match, 0))
147             ret = 1;
148     }
149     else
150     {
151         if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE)
152         {
153             if (pd->how == QOF_COMPARE_CONTAINS || pd->how == QOF_COMPARE_NCONTAINS)
154             {
155                 if (qof_utf8_substr_nocase (s, pdata->matchstring)) //uses strstr
156                     ret = 1;
157             }
158             else
159             {
160                  if (safe_strcasecmp (s, pdata->matchstring) == 0) //uses collate
161                     ret = 1;
162             }
163         }
164         else
165         {
166             if (pd->how == QOF_COMPARE_CONTAINS || pd->how == QOF_COMPARE_NCONTAINS)
167             {
168                 if (strstr (s, pdata->matchstring))
169                     ret = 1;
170             }
171             else
172             {
173                 if (g_strcmp0 (s, pdata->matchstring) == 0)
174                     ret = 1;
175             }
176         }
177     }
178 
179     switch (pd->how)
180     {
181     case QOF_COMPARE_CONTAINS:
182         return ret;
183     case QOF_COMPARE_NCONTAINS:
184         return !ret;
185     case QOF_COMPARE_EQUAL:
186         return ret;
187     case QOF_COMPARE_NEQ:
188         return !ret;
189     default:
190         PWARN ("bad match type: %d", pd->how);
191         return 0;
192     }
193 }
194 
195 static int
string_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)196 string_compare_func (gpointer a, gpointer b, gint options,
197                      QofParam *getter)
198 {
199     const char *s1, *s2;
200     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
201 
202     s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
203     s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
204 
205     if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
206         return safe_strcasecmp (s1, s2);
207 
208     return g_strcmp0 (s1, s2);
209 }
210 
211 int
qof_string_number_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)212 qof_string_number_compare_func (gpointer a, gpointer b, gint options,
213                                 QofParam *getter)
214 {
215     const char *s1, *s2;
216     char *sr1, *sr2;
217     long i1, i2;
218     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
219 
220     s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
221     s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
222 
223     // Deal with NULL strings
224     if (s1 == s2)  return 0;
225     if (!s1 && s2) return -1;
226     if (s1 && !s2) return 1;
227 
228     // Convert to integers and test
229     i1 = strtol(s1, &sr1, 10);
230     i2 = strtol(s2, &sr2, 10);
231     if (i1 < i2)  return -1;
232     if (i1 > i2)  return 1;
233 
234     // If the integers match, then test the REST of the string as text.
235     if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
236         return safe_strcasecmp (sr1, sr2);
237 
238     return g_strcmp0 (sr1, sr2);
239 }
240 
241 static void
string_free_pdata(QofQueryPredData * pd)242 string_free_pdata (QofQueryPredData *pd)
243 {
244     query_string_t pdata = (query_string_t) pd;
245 
246     VERIFY_PDATA (query_string_type);
247 
248     if (pdata->is_regex)
249         regfree (&pdata->compiled);
250 
251     g_free (pdata->matchstring);
252     g_free (pdata);
253 }
254 
255 static QofQueryPredData *
string_copy_predicate(const QofQueryPredData * pd)256 string_copy_predicate (const QofQueryPredData *pd)
257 {
258     const query_string_t pdata = (const query_string_t) pd;
259 
260     VERIFY_PDATA_R (query_string_type);
261 
262     return qof_query_string_predicate (pd->how, pdata->matchstring,
263                                        pdata->options,
264                                        pdata->is_regex);
265 }
266 
267 static gboolean
string_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)268 string_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
269 {
270     const query_string_t pd1 = (const query_string_t) p1;
271     const query_string_t pd2 = (const query_string_t) p2;
272 
273     if (pd1->options != pd2->options) return FALSE;
274     if (pd1->is_regex != pd2->is_regex) return FALSE;
275     return (g_strcmp0 (pd1->matchstring, pd2->matchstring) == 0);
276 }
277 
278 QofQueryPredData *
qof_query_string_predicate(QofQueryCompare how,const char * str,QofStringMatch options,gboolean is_regex)279 qof_query_string_predicate (QofQueryCompare how,
280                             const char *str, QofStringMatch options,
281                             gboolean is_regex)
282 {
283     query_string_t pdata;
284 
285     g_return_val_if_fail (str, NULL);
286 //    g_return_val_if_fail (*str != '\0', NULL);
287     g_return_val_if_fail (how == QOF_COMPARE_CONTAINS || how == QOF_COMPARE_NCONTAINS ||
288                           how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, NULL);
289 
290     pdata = g_new0 (query_string_def, 1);
291     pdata->pd.type_name = query_string_type;
292     pdata->pd.how = how;
293     pdata->options = options;
294     pdata->matchstring = g_strdup (str);
295 
296     if (is_regex)
297     {
298         int rc;
299         int flags = REG_EXTENDED;
300         if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
301             flags |= REG_ICASE;
302 
303         rc = regcomp(&pdata->compiled, str, flags);
304         if (rc)
305         {
306             g_free(pdata->matchstring);
307             g_free(pdata);
308             return NULL;
309         }
310         pdata->is_regex = TRUE;
311     }
312 
313     return ((QofQueryPredData*)pdata);
314 }
315 
316 static char *
string_to_string(gpointer object,QofParam * getter)317 string_to_string (gpointer object, QofParam *getter)
318 {
319     const char *res;
320     res = ((query_string_getter)getter->param_getfcn)(object, getter);
321     if (res)
322         return g_strdup (res);
323     return NULL;
324 }
325 
326 /* QOF_TYPE_DATE =================================================== */
327 
328 static int
date_compare(time64 ta,time64 tb,QofDateMatch options)329 date_compare (time64 ta, time64 tb, QofDateMatch options)
330 {
331 
332     if (options == QOF_DATE_MATCH_DAY)
333     {
334         ta = time64CanonicalDayTime (ta);
335         tb = time64CanonicalDayTime (tb);
336     }
337 
338     if (ta < tb)
339         return -1;
340     if (ta > tb)
341         return 1;
342 
343     return 0;
344 }
345 
346 static int
date_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)347 date_match_predicate (gpointer object, QofParam *getter,
348                       QofQueryPredData *pd)
349 {
350     query_date_t pdata = (query_date_t)pd;
351     time64 objtime;
352     int compare;
353 
354     VERIFY_PREDICATE (query_date_type);
355 
356     objtime = ((query_date_getter)getter->param_getfcn) (object, getter);
357     compare = date_compare (objtime, pdata->date, pdata->options);
358 
359     switch (pd->how)
360     {
361     case QOF_COMPARE_LT:
362         return (compare < 0);
363     case QOF_COMPARE_LTE:
364         return (compare <= 0);
365     case QOF_COMPARE_EQUAL:
366         return (compare == 0);
367     case QOF_COMPARE_GT:
368         return (compare > 0);
369     case QOF_COMPARE_GTE:
370         return (compare >= 0);
371     case QOF_COMPARE_NEQ:
372         return (compare != 0);
373     default:
374         PWARN ("bad match type: %d", pd->how);
375         return 0;
376     }
377 }
378 
379 static int
date_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)380 date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
381 {
382     time64 ta, tb;
383 
384     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
385 
386     ta = ((query_date_getter)getter->param_getfcn) (a, getter);
387     tb = ((query_date_getter)getter->param_getfcn) (b, getter);
388 
389     return date_compare (ta, tb, static_cast<QofDateMatch>(options));
390 }
391 
392 static void
date_free_pdata(QofQueryPredData * pd)393 date_free_pdata (QofQueryPredData *pd)
394 {
395     query_date_t pdata = (query_date_t)pd;
396 
397     VERIFY_PDATA (query_date_type);
398 
399     g_free (pdata);
400 }
401 
402 static QofQueryPredData *
date_copy_predicate(const QofQueryPredData * pd)403 date_copy_predicate (const QofQueryPredData *pd)
404 {
405     const query_date_t pdata = (const query_date_t)pd;
406 
407     VERIFY_PDATA_R (query_date_type);
408 
409     return qof_query_date_predicate (pd->how, pdata->options, pdata->date);
410 }
411 
412 static gboolean
date_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)413 date_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
414 {
415     const query_date_t pd1 = (const query_date_t) p1;
416     const query_date_t pd2 = (const query_date_t) p2;
417 
418     if (pd1->options != pd2->options) return FALSE;
419     return (pd1->date == pd2->date);
420 }
421 
422 QofQueryPredData *
qof_query_date_predicate(QofQueryCompare how,QofDateMatch options,time64 date)423 qof_query_date_predicate (QofQueryCompare how,
424                           QofDateMatch options, time64 date)
425 {
426     query_date_t pdata;
427 
428     pdata = g_new0 (query_date_def, 1);
429     pdata->pd.type_name = query_date_type;
430     pdata->pd.how = how;
431     pdata->options = options;
432     pdata->date = date;
433     return ((QofQueryPredData*)pdata);
434 }
435 
436 gboolean
qof_query_date_predicate_get_date(const QofQueryPredData * pd,time64 * date)437 qof_query_date_predicate_get_date (const QofQueryPredData *pd, time64 *date)
438 {
439     const query_date_t pdata = (const query_date_t)pd;
440 
441     if (pdata->pd.type_name != query_date_type)
442         return FALSE;
443     *date = pdata->date;
444     return TRUE;
445 }
446 
447 static char *
date_to_string(gpointer object,QofParam * getter)448 date_to_string (gpointer object, QofParam *getter)
449 {
450     time64 tt = ((query_date_getter)getter->param_getfcn)(object, getter);
451 
452     if (tt != INT64_MAX)
453         return qof_print_date (tt);
454 
455     return NULL;
456 }
457 
458 /* QOF_TYPE_NUMERIC ================================================= */
459 
460 static int
numeric_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)461 numeric_match_predicate (gpointer object, QofParam *getter,
462                          QofQueryPredData* pd)
463 {
464     query_numeric_t pdata = (query_numeric_t)pd;
465     gnc_numeric obj_val;
466     int compare;
467 
468     VERIFY_PREDICATE (query_numeric_type);
469 
470     obj_val = ((query_numeric_getter)getter->param_getfcn) (object, getter);
471 
472     switch (pdata->options)
473     {
474     case QOF_NUMERIC_MATCH_CREDIT:
475         if (gnc_numeric_positive_p (obj_val)) return 0;
476         break;
477     case QOF_NUMERIC_MATCH_DEBIT:
478         if (gnc_numeric_negative_p (obj_val)) return 0;
479         break;
480     default:
481         break;
482     }
483 
484     /* Amounts are considered to be 'equal' if they match to
485      * four decimal places. (epsilon=1/10000) */
486     if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ)
487     {
488         gnc_numeric cmp_val = gnc_numeric_create (1, 10000);
489         compare =
490             (gnc_numeric_compare (gnc_numeric_abs
491                                   (gnc_numeric_sub (gnc_numeric_abs (obj_val),
492                                           gnc_numeric_abs (pdata->amount),
493                                           100000, GNC_HOW_RND_ROUND_HALF_UP)),
494                                   cmp_val) < 0);
495     }
496     else
497         compare = gnc_numeric_compare (gnc_numeric_abs (obj_val), pdata->amount);
498 
499     switch (pd->how)
500     {
501     case QOF_COMPARE_LT:
502         return (compare < 0);
503     case QOF_COMPARE_LTE:
504         return (compare <= 0);
505     case QOF_COMPARE_EQUAL:
506         return compare;
507     case QOF_COMPARE_GT:
508         return (compare > 0);
509     case QOF_COMPARE_GTE:
510         return (compare >= 0);
511     case QOF_COMPARE_NEQ:
512         return !compare;
513     default:
514         PWARN ("bad match type: %d", pd->how);
515         return 0;
516     }
517 }
518 
519 static int
numeric_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)520 numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
521 {
522     gnc_numeric va, vb;
523 
524     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
525 
526     va = ((query_numeric_getter)getter->param_getfcn) (a, getter);
527     vb = ((query_numeric_getter)getter->param_getfcn) (b, getter);
528 
529     return gnc_numeric_compare (va, vb);
530 }
531 
532 static void
numeric_free_pdata(QofQueryPredData * pd)533 numeric_free_pdata (QofQueryPredData* pd)
534 {
535     query_numeric_t pdata = (query_numeric_t)pd;
536     VERIFY_PDATA (query_numeric_type);
537     g_free (pdata);
538 }
539 
540 static QofQueryPredData *
numeric_copy_predicate(const QofQueryPredData * pd)541 numeric_copy_predicate (const QofQueryPredData *pd)
542 {
543     const query_numeric_t pdata = (const query_numeric_t)pd;
544     VERIFY_PDATA_R (query_numeric_type);
545     return qof_query_numeric_predicate (pd->how, pdata->options, pdata->amount);
546 }
547 
548 static gboolean
numeric_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)549 numeric_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
550 {
551     const query_numeric_t pd1 = (const query_numeric_t) p1;
552     const query_numeric_t pd2 = (const query_numeric_t) p2;
553 
554     if (pd1->options != pd2->options) return FALSE;
555     return gnc_numeric_equal (pd1->amount, pd2->amount);
556 }
557 
558 QofQueryPredData *
qof_query_numeric_predicate(QofQueryCompare how,QofNumericMatch options,gnc_numeric value)559 qof_query_numeric_predicate (QofQueryCompare how,
560                              QofNumericMatch options,
561                              gnc_numeric value)
562 {
563     query_numeric_t pdata;
564     pdata = g_new0 (query_numeric_def, 1);
565     pdata->pd.type_name = query_numeric_type;
566     pdata->pd.how = how;
567     pdata->options = options;
568     pdata->amount = value;
569     return ((QofQueryPredData*)pdata);
570 }
571 
572 static char *
numeric_to_string(gpointer object,QofParam * getter)573 numeric_to_string (gpointer object, QofParam *getter)
574 {
575     gnc_numeric num;
576     num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
577 
578     return gnc_numeric_to_string (num);
579 }
580 
581 static char *
debcred_to_string(gpointer object,QofParam * getter)582 debcred_to_string (gpointer object, QofParam *getter)
583 {
584     gnc_numeric num;
585     num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
586 
587     return gnc_numeric_to_string (num);
588 }
589 
590 /* QOF_TYPE_GUID =================================================== */
591 
592 static int
guid_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)593 guid_match_predicate (gpointer object, QofParam *getter,
594                       QofQueryPredData *pd)
595 {
596     query_guid_t pdata = (query_guid_t)pd;
597     GList *node, *o_list;
598     const GncGUID *guid = NULL;
599 
600     VERIFY_PREDICATE (query_guid_type);
601 
602     switch (pdata->options)
603     {
604 
605     case QOF_GUID_MATCH_ALL:
606         /* object is a GList of objects; param_getfcn must be called on each one.
607          * See if every guid in the predicate is accounted-for in the
608          * object list
609          */
610 
611         for (node = pdata->guids; node; node = node->next)
612         {
613             /* See if this GncGUID matches the object's guid */
614             for (o_list = static_cast<GList*>(object); o_list;
615 		 o_list = static_cast<GList*>(o_list->next))
616             {
617                 guid = ((query_guid_getter)getter->param_getfcn) (o_list->data, getter);
618                 if (guid_equal (static_cast<GncGUID*>(node->data), guid))
619                     break;
620             }
621 
622             /*
623              * If o_list is NULL, we've walked the whole list without finding
624              * a match.  Therefore break out now, the match has failed.
625              */
626             if (o_list == NULL)
627                 break;
628         }
629 
630         /*
631          * The match is complete.  If node == NULL then we've successfully
632          * found a match for all the guids in the predicate.  Return
633          * appropriately below.
634          */
635 
636         break;
637 
638     case QOF_GUID_MATCH_LIST_ANY:
639         /* object is a single object, getter returns a GList* of GncGUID*
640          *
641          * See if any GncGUID* in the returned list matches any guid in the
642          * predicate match list.
643          */
644 
645         o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
646 
647         for (node = o_list; node; node = node->next)
648         {
649             GList *node2;
650 
651             /* Search the predicate data for a match */
652             for (node2 = pdata->guids; node2; node2 = node2->next)
653             {
654                 if (guid_equal (static_cast<GncGUID*>(node->data),
655 				static_cast<GncGUID*>(node2->data)))
656                     break;
657             }
658 
659             /* Check to see if we found a match.  If so, break now */
660             if (node2 != NULL)
661                 break;
662         }
663 
664         g_list_free(o_list);
665 
666         /* yea, node may point to an invalid location, but that's ok.
667          * we're not _USING_ the value, just checking that it's non-NULL
668          */
669 
670         break;
671 
672     default:
673         /* object is a single object, getter returns a GncGUID*
674          *
675          * See if the guid is in the list
676          */
677 
678         guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
679         for (node = pdata->guids; node; node = node->next)
680         {
681             if (guid_equal (static_cast<GncGUID*>(node->data), guid))
682                 break;
683         }
684     }
685 
686     switch (pdata->options)
687     {
688     case QOF_GUID_MATCH_ANY:
689     case QOF_GUID_MATCH_LIST_ANY:
690         return (node != NULL);
691         break;
692     case QOF_GUID_MATCH_NONE:
693     case QOF_GUID_MATCH_ALL:
694         return (node == NULL);
695         break;
696     case QOF_GUID_MATCH_NULL:
697         return ((guid == NULL) || guid_equal(guid, guid_null()));
698         break;
699     default:
700         PWARN ("bad match type");
701         return 0;
702     }
703 }
704 
705 static void
guid_free_pdata(QofQueryPredData * pd)706 guid_free_pdata (QofQueryPredData *pd)
707 {
708     query_guid_t pdata = (query_guid_t)pd;
709     GList *node;
710     VERIFY_PDATA (query_guid_type);
711     for (node = pdata->guids; node; node = node->next)
712     {
713         guid_free (static_cast<GncGUID*>(node->data));
714     }
715     g_list_free (pdata->guids);
716     g_free (pdata);
717 }
718 
719 static QofQueryPredData *
guid_copy_predicate(const QofQueryPredData * pd)720 guid_copy_predicate (const QofQueryPredData *pd)
721 {
722     const query_guid_t pdata = (const query_guid_t)pd;
723     VERIFY_PDATA_R (query_guid_type);
724     return qof_query_guid_predicate (pdata->options, pdata->guids);
725 }
726 
727 static gboolean
guid_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)728 guid_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
729 {
730     const query_guid_t pd1 = (const query_guid_t) p1;
731     const query_guid_t pd2 = (const query_guid_t) p2;
732     GList *l1 = pd1->guids, *l2 = pd2->guids;
733 
734     if (pd1->options != pd2->options) return FALSE;
735     for (; l1 || l2; l1 = l1->next, l2 = l2->next)
736     {
737         if (!l1 || !l2)
738             return FALSE;
739         if (!guid_equal (static_cast<GncGUID*>(l1->data),
740 			 static_cast<GncGUID*>(l2->data)))
741             return FALSE;
742     }
743     return TRUE;
744 }
745 
746 QofQueryPredData *
qof_query_guid_predicate(QofGuidMatch options,GList * guid_list)747 qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
748 {
749     query_guid_t pdata;
750     GList *node;
751 
752     /* An empty list of guids is only valid when testing for a null GUID value */
753     if (!guid_list)
754         g_return_val_if_fail (options == QOF_GUID_MATCH_NULL, NULL);
755 
756     pdata = g_new0 (query_guid_def, 1);
757     pdata->pd.how = QOF_COMPARE_EQUAL;
758     pdata->pd.type_name = query_guid_type;
759     pdata->options = options;
760 
761     pdata->guids = g_list_copy (guid_list);
762     for (node = pdata->guids; node; node = node->next)
763     {
764         GncGUID *guid = guid_malloc ();
765         *guid = *((GncGUID *)node->data);
766         node->data = guid;
767     }
768     return ((QofQueryPredData*)pdata);
769 }
770 
771 /* ================================================================ */
772 /* QOF_TYPE_INT32 */
773 
774 static int
int32_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)775 int32_match_predicate (gpointer object, QofParam *getter,
776                        QofQueryPredData *pd)
777 {
778     gint32 val;
779     query_int32_t pdata = (query_int32_t)pd;
780 
781     VERIFY_PREDICATE (query_int32_type);
782 
783     val = ((query_int32_getter)getter->param_getfcn) (object, getter);
784 
785     switch (pd->how)
786     {
787     case QOF_COMPARE_LT:
788         return (val < pdata->val);
789     case QOF_COMPARE_LTE:
790         return (val <= pdata->val);
791     case QOF_COMPARE_EQUAL:
792         return (val == pdata->val);
793     case QOF_COMPARE_GT:
794         return (val > pdata->val);
795     case QOF_COMPARE_GTE:
796         return (val >= pdata->val);
797     case QOF_COMPARE_NEQ:
798         return (val != pdata->val);
799     default:
800         PWARN ("bad match type: %d", pd->how);
801         return 0;
802     }
803 }
804 
805 static int
int32_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)806 int32_compare_func (gpointer a, gpointer b, gint options,
807                     QofParam *getter)
808 {
809     gint32 v1, v2;
810     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
811 
812     v1 = ((query_int32_getter)getter->param_getfcn)(a, getter);
813     v2 = ((query_int32_getter)getter->param_getfcn)(b, getter);
814 
815     if (v1 < v2) return -1;
816     if (v1 > v2) return 1;
817     return 0;
818 }
819 
820 static void
int32_free_pdata(QofQueryPredData * pd)821 int32_free_pdata (QofQueryPredData *pd)
822 {
823     query_int32_t pdata = (query_int32_t)pd;
824     VERIFY_PDATA (query_int32_type);
825     g_free (pdata);
826 }
827 
828 static QofQueryPredData *
int32_copy_predicate(const QofQueryPredData * pd)829 int32_copy_predicate (const QofQueryPredData *pd)
830 {
831     const query_int32_t pdata = (const query_int32_t)pd;
832     VERIFY_PDATA_R (query_int32_type);
833     return qof_query_int32_predicate (pd->how, pdata->val);
834 }
835 
836 static gboolean
int32_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)837 int32_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
838 {
839     const query_int32_t pd1 = (const query_int32_t) p1;
840     const query_int32_t pd2 = (const query_int32_t) p2;
841 
842     return (pd1->val == pd2->val);
843 }
844 
845 QofQueryPredData *
qof_query_int32_predicate(QofQueryCompare how,gint32 val)846 qof_query_int32_predicate (QofQueryCompare how, gint32 val)
847 {
848     query_int32_t pdata = g_new0 (query_int32_def, 1);
849     pdata->pd.type_name = query_int32_type;
850     pdata->pd.how = how;
851     pdata->val = val;
852     return ((QofQueryPredData*)pdata);
853 }
854 
855 static char *
int32_to_string(gpointer object,QofParam * getter)856 int32_to_string (gpointer object, QofParam *getter)
857 {
858     gint32 num = ((query_int32_getter)getter->param_getfcn)(object, getter);
859 
860     return g_strdup_printf ("%d", num);
861 }
862 
863 /* ================================================================ */
864 /* QOF_TYPE_INT64 */
865 
866 static int
int64_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)867 int64_match_predicate (gpointer object, QofParam *getter,
868                        QofQueryPredData *pd)
869 {
870     gint64 val;
871     query_int64_t pdata = (query_int64_t)pd;
872 
873     VERIFY_PREDICATE (query_int64_type);
874 
875     val = ((query_int64_getter)getter->param_getfcn) (object, getter);
876 
877     switch (pd->how)
878     {
879     case QOF_COMPARE_LT:
880         return (val < pdata->val);
881     case QOF_COMPARE_LTE:
882         return (val <= pdata->val);
883     case QOF_COMPARE_EQUAL:
884         return (val == pdata->val);
885     case QOF_COMPARE_GT:
886         return (val > pdata->val);
887     case QOF_COMPARE_GTE:
888         return (val >= pdata->val);
889     case QOF_COMPARE_NEQ:
890         return (val != pdata->val);
891     default:
892         PWARN ("bad match type: %d", pd->how);
893         return 0;
894     }
895 }
896 
897 static int
int64_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)898 int64_compare_func (gpointer a, gpointer b, gint options,
899                     QofParam *getter)
900 {
901     gint64 v1, v2;
902     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
903 
904     v1 = ((query_int64_getter)getter->param_getfcn)(a, getter);
905     v2 = ((query_int64_getter)getter->param_getfcn)(b, getter);
906 
907     if (v1 < v2) return -1;
908     if (v1 > v2) return 1;
909     return 0;
910 }
911 
912 static void
int64_free_pdata(QofQueryPredData * pd)913 int64_free_pdata (QofQueryPredData *pd)
914 {
915     query_int64_t pdata = (query_int64_t)pd;
916     VERIFY_PDATA (query_int64_type);
917     g_free (pdata);
918 }
919 
920 static QofQueryPredData *
int64_copy_predicate(const QofQueryPredData * pd)921 int64_copy_predicate (const QofQueryPredData *pd)
922 {
923     const query_int64_t pdata = (const query_int64_t)pd;
924     VERIFY_PDATA_R (query_int64_type);
925     return qof_query_int64_predicate (pd->how, pdata->val);
926 }
927 
928 static gboolean
int64_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)929 int64_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
930 {
931     const query_int64_t pd1 = (const query_int64_t) p1;
932     const query_int64_t pd2 = (const query_int64_t) p2;
933 
934     return (pd1->val == pd2->val);
935 }
936 
937 QofQueryPredData *
qof_query_int64_predicate(QofQueryCompare how,gint64 val)938 qof_query_int64_predicate (QofQueryCompare how, gint64 val)
939 {
940     query_int64_t pdata = g_new0 (query_int64_def, 1);
941     pdata->pd.type_name = query_int64_type;
942     pdata->pd.how = how;
943     pdata->val = val;
944     return ((QofQueryPredData*)pdata);
945 }
946 
947 static char *
int64_to_string(gpointer object,QofParam * getter)948 int64_to_string (gpointer object, QofParam *getter)
949 {
950     gint64 num = ((query_int64_getter)getter->param_getfcn)(object, getter);
951 
952     return g_strdup_printf ("%" G_GINT64_FORMAT, num);
953 }
954 
955 /* ================================================================ */
956 /* QOF_TYPE_DOUBLE */
957 
958 static int
double_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)959 double_match_predicate (gpointer object, QofParam *getter,
960                         QofQueryPredData *pd)
961 {
962     double val;
963     query_double_t pdata = (query_double_t)pd;
964 
965     VERIFY_PREDICATE (query_double_type);
966 
967     val = ((query_double_getter)getter->param_getfcn) (object, getter);
968 
969     switch (pd->how)
970     {
971     case QOF_COMPARE_LT:
972         return (val < pdata->val);
973     case QOF_COMPARE_LTE:
974         return (val <= pdata->val);
975     case QOF_COMPARE_EQUAL:
976         return (val == pdata->val);
977     case QOF_COMPARE_GT:
978         return (val > pdata->val);
979     case QOF_COMPARE_GTE:
980         return (val >= pdata->val);
981     case QOF_COMPARE_NEQ:
982         return (val != pdata->val);
983     default:
984         PWARN ("bad match type: %d", pd->how);
985         return 0;
986     }
987 }
988 
989 static int
double_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)990 double_compare_func (gpointer a, gpointer b, gint options,
991                      QofParam *getter)
992 {
993     double v1, v2;
994     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
995 
996     v1 = ((query_double_getter)getter->param_getfcn) (a, getter);
997     v2 = ((query_double_getter)getter->param_getfcn) (b, getter);
998 
999     if (v1 < v2) return -1;
1000     if (v1 > v2) return 1;
1001     return 0;
1002 }
1003 
1004 static void
double_free_pdata(QofQueryPredData * pd)1005 double_free_pdata (QofQueryPredData *pd)
1006 {
1007     query_double_t pdata = (query_double_t)pd;
1008     VERIFY_PDATA (query_double_type);
1009     g_free (pdata);
1010 }
1011 
1012 static QofQueryPredData *
double_copy_predicate(const QofQueryPredData * pd)1013 double_copy_predicate (const QofQueryPredData *pd)
1014 {
1015     const query_double_t pdata = (const query_double_t)pd;
1016     VERIFY_PDATA_R (query_double_type);
1017     return qof_query_double_predicate (pd->how, pdata->val);
1018 }
1019 
1020 static gboolean
double_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)1021 double_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1022 {
1023     const query_double_t pd1 = (const query_double_t) p1;
1024     const query_double_t pd2 = (const query_double_t) p2;
1025 
1026     return (pd1->val == pd2->val);
1027 }
1028 
1029 QofQueryPredData *
qof_query_double_predicate(QofQueryCompare how,double val)1030 qof_query_double_predicate (QofQueryCompare how, double val)
1031 {
1032     query_double_t pdata = g_new0 (query_double_def, 1);
1033     pdata->pd.type_name = query_double_type;
1034     pdata->pd.how = how;
1035     pdata->val = val;
1036     return ((QofQueryPredData*)pdata);
1037 }
1038 
1039 static char *
double_to_string(gpointer object,QofParam * getter)1040 double_to_string (gpointer object, QofParam *getter)
1041 {
1042     double num = ((query_double_getter)getter->param_getfcn)(object, getter);
1043 
1044     return g_strdup_printf ("%f", num);
1045 }
1046 
1047 /* QOF_TYPE_BOOLEAN =================================================== */
1048 
1049 static int
boolean_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1050 boolean_match_predicate (gpointer object, QofParam *getter,
1051                          QofQueryPredData *pd)
1052 {
1053     gboolean val;
1054     query_boolean_t pdata = (query_boolean_t)pd;
1055 
1056     VERIFY_PREDICATE (query_boolean_type);
1057 
1058     val = ((query_boolean_getter)getter->param_getfcn) (object, getter);
1059 
1060     switch (pd->how)
1061     {
1062     case QOF_COMPARE_EQUAL:
1063         return (val == pdata->val);
1064     case  QOF_COMPARE_NEQ:
1065         return (val != pdata->val);
1066     default:
1067         PWARN ("bad match type: %d", pd->how);
1068         return 0;
1069     }
1070 }
1071 
1072 static int
boolean_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)1073 boolean_compare_func (gpointer a, gpointer b, gint options,
1074                       QofParam *getter)
1075 {
1076     gboolean va, vb;
1077     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
1078     va = ((query_boolean_getter)getter->param_getfcn) (a, getter);
1079     vb = ((query_boolean_getter)getter->param_getfcn) (b, getter);
1080     if (!va && vb) return -1;
1081     if (va && !vb) return 1;
1082     return 0;
1083 }
1084 
1085 static void
boolean_free_pdata(QofQueryPredData * pd)1086 boolean_free_pdata (QofQueryPredData *pd)
1087 {
1088     query_boolean_t pdata = (query_boolean_t)pd;
1089     VERIFY_PDATA (query_boolean_type);
1090     g_free (pdata);
1091 }
1092 
1093 static QofQueryPredData *
boolean_copy_predicate(const QofQueryPredData * pd)1094 boolean_copy_predicate (const QofQueryPredData *pd)
1095 {
1096     const query_boolean_t pdata = (const query_boolean_t)pd;
1097     VERIFY_PDATA_R (query_boolean_type);
1098     return qof_query_boolean_predicate (pd->how, pdata->val);
1099 }
1100 
1101 static gboolean
boolean_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)1102 boolean_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1103 {
1104     const query_boolean_t pd1 = (const query_boolean_t) p1;
1105     const query_boolean_t pd2 = (const query_boolean_t) p2;
1106 
1107     return (pd1->val == pd2->val);
1108 }
1109 
1110 QofQueryPredData *
qof_query_boolean_predicate(QofQueryCompare how,gboolean val)1111 qof_query_boolean_predicate (QofQueryCompare how, gboolean val)
1112 {
1113     query_boolean_t pdata;
1114     g_return_val_if_fail (how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, NULL);
1115 
1116     pdata = g_new0 (query_boolean_def, 1);
1117     pdata->pd.type_name = query_boolean_type;
1118     pdata->pd.how = how;
1119     pdata->val = val;
1120     return ((QofQueryPredData*)pdata);
1121 }
1122 
1123 static char *
boolean_to_string(gpointer object,QofParam * getter)1124 boolean_to_string (gpointer object, QofParam *getter)
1125 {
1126     gboolean num = ((query_boolean_getter)getter->param_getfcn)(object, getter);
1127 
1128     return g_strdup_printf ("%s", (num ? "X" : ""));
1129 }
1130 
1131 /* QOF_TYPE_CHAR =================================================== */
1132 
1133 static int
char_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1134 char_match_predicate (gpointer object, QofParam *getter,
1135                       QofQueryPredData *pd)
1136 {
1137     char c;
1138     query_char_t pdata = (query_char_t)pd;
1139 
1140     VERIFY_PREDICATE (query_char_type);
1141 
1142     c = ((query_char_getter)getter->param_getfcn) (object, getter);
1143 
1144     switch (pdata->options)
1145     {
1146     case QOF_CHAR_MATCH_ANY:
1147         if (strchr (pdata->char_list, c)) return 1;
1148         return 0;
1149     case QOF_CHAR_MATCH_NONE:
1150         if (!strchr (pdata->char_list, c)) return 1;
1151         return 0;
1152     default:
1153         PWARN ("bad match type");
1154         return 0;
1155     }
1156 }
1157 
1158 static int
char_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)1159 char_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
1160 {
1161     char va, vb;
1162     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
1163     va = ((query_char_getter)getter->param_getfcn)(a, getter);
1164     vb = ((query_char_getter)getter->param_getfcn)(b, getter);
1165     return (va - vb);
1166 }
1167 
1168 static void
char_free_pdata(QofQueryPredData * pd)1169 char_free_pdata (QofQueryPredData *pd)
1170 {
1171     query_char_t pdata = (query_char_t)pd;
1172     VERIFY_PDATA (query_char_type);
1173     g_free (pdata->char_list);
1174     g_free (pdata);
1175 }
1176 
1177 static QofQueryPredData *
char_copy_predicate(const QofQueryPredData * pd)1178 char_copy_predicate (const QofQueryPredData *pd)
1179 {
1180     const query_char_t pdata = (const query_char_t)pd;
1181     VERIFY_PDATA_R (query_char_type);
1182     return qof_query_char_predicate (pdata->options, pdata->char_list);
1183 }
1184 
1185 static gboolean
char_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)1186 char_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1187 {
1188     const query_char_t pd1 = (const query_char_t) p1;
1189     const query_char_t pd2 = (const query_char_t) p2;
1190 
1191     if (pd1->options != pd2->options) return FALSE;
1192     return (g_strcmp0 (pd1->char_list, pd2->char_list) == 0);
1193 }
1194 
1195 QofQueryPredData *
qof_query_char_predicate(QofCharMatch options,const char * chars)1196 qof_query_char_predicate (QofCharMatch options, const char *chars)
1197 {
1198     query_char_t pdata;
1199     g_return_val_if_fail (chars, NULL);
1200     pdata = g_new0 (query_char_def, 1);
1201     pdata->pd.type_name = query_char_type;
1202     pdata->pd.how = QOF_COMPARE_EQUAL;
1203     pdata->options = options;
1204     pdata->char_list = g_strdup (chars);
1205     return ((QofQueryPredData*)pdata);
1206 }
1207 
1208 static char *
char_to_string(gpointer object,QofParam * getter)1209 char_to_string (gpointer object, QofParam *getter)
1210 {
1211     char num = ((query_char_getter)getter->param_getfcn)(object, getter);
1212 
1213     return g_strdup_printf ("%c", num);
1214 }
1215 
1216 /* QOF_TYPE_COLLECT =============================================== */
1217 
1218 static int
collect_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1219 collect_match_predicate (gpointer object, QofParam *getter,
1220                          QofQueryPredData *pd)
1221 {
1222     query_coll_t pdata;
1223     GList *node, *node2, *o_list;
1224     const GncGUID *guid;
1225 
1226     pdata = (query_coll_t)pd;
1227     VERIFY_PREDICATE (query_collect_type);
1228     guid = NULL;
1229     switch (pdata->options)
1230     {
1231     case QOF_GUID_MATCH_ALL :
1232     {
1233         for (node = pdata->guids; node; node = node->next)
1234         {
1235             for (o_list = static_cast<GList*>(object); o_list;
1236 		 o_list = static_cast<GList*>(o_list->next))
1237             {
1238                 guid = ((query_guid_getter)getter->param_getfcn)
1239                        (o_list->data, getter);
1240                 if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1241                 {
1242                     break;
1243                 }
1244             }
1245             if (o_list == NULL)
1246             {
1247                 break;
1248             }
1249         }
1250         break;
1251     }
1252     case QOF_GUID_MATCH_LIST_ANY :
1253     {
1254         o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
1255         for (node = o_list; node; node = node->next)
1256         {
1257             for (node2 = pdata->guids; node2; node2 = node2->next)
1258             {
1259                 if (guid_equal (static_cast<GncGUID*>(node->data),
1260 				static_cast<GncGUID*>(node2->data)))
1261                 {
1262                     break;
1263                 }
1264             }
1265             if (node2 != NULL)
1266             {
1267                 break;
1268             }
1269         }
1270         g_list_free(o_list);
1271         break;
1272     }
1273     default :
1274     {
1275         guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
1276         for (node = pdata->guids; node; node = node->next)
1277         {
1278             if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1279             {
1280                 break;
1281             }
1282         }
1283     }
1284     switch (pdata->options)
1285     {
1286     case QOF_GUID_MATCH_ANY :
1287     case QOF_GUID_MATCH_LIST_ANY :
1288     {
1289         return (node != NULL);
1290         break;
1291     }
1292     case QOF_GUID_MATCH_NONE :
1293     case QOF_GUID_MATCH_ALL :
1294     {
1295         return (node == NULL);
1296         break;
1297     }
1298     case QOF_GUID_MATCH_NULL :
1299     {
1300         return ((guid == NULL) || guid_equal(guid, guid_null()));
1301         break;
1302     }
1303     default :
1304     {
1305         PWARN ("bad match type");
1306         return 0;
1307     }
1308     }
1309     }
1310     return 0;
1311 }
1312 
1313 static int
collect_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)1314 collect_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
1315 {
1316     gint result;
1317     QofCollection *c1, *c2;
1318 
1319     c1 = ((query_collect_getter)getter->param_getfcn) (a, getter);
1320     c2 = ((query_collect_getter)getter->param_getfcn) (b, getter);
1321     result = qof_collection_compare(c1, c2);
1322     return result;
1323 }
1324 
1325 static void
collect_free_pdata(QofQueryPredData * pd)1326 collect_free_pdata (QofQueryPredData *pd)
1327 {
1328     query_coll_t pdata;
1329     GList *node;
1330 
1331     node = NULL;
1332     pdata = (query_coll_t) pd;
1333     VERIFY_PDATA (query_collect_type);
1334     for (node = pdata->guids; node; node = node->next)
1335     {
1336         guid_free (static_cast<GncGUID*>(node->data));
1337     }
1338     qof_collection_destroy(pdata->coll);
1339     g_list_free (pdata->guids);
1340     g_free (pdata);
1341 }
1342 
1343 static QofQueryPredData *
collect_copy_predicate(const QofQueryPredData * pd)1344 collect_copy_predicate (const QofQueryPredData *pd)
1345 {
1346     const query_coll_t pdata = (const query_coll_t) pd;
1347 
1348     VERIFY_PDATA_R (query_collect_type);
1349     return qof_query_collect_predicate (pdata->options, pdata->coll);
1350 }
1351 
1352 static gboolean
collect_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)1353 collect_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1354 {
1355     const query_coll_t pd1 = (const query_coll_t) p1;
1356     const query_coll_t pd2 = (const query_coll_t) p2;
1357     gint result;
1358 
1359     result = qof_collection_compare(pd1->coll, pd2->coll);
1360     if (result == 0)
1361     {
1362         return TRUE;
1363     }
1364     return FALSE;
1365 }
1366 
1367 static void
query_collect_cb(QofInstance * ent,gpointer user_data)1368 query_collect_cb(QofInstance* ent, gpointer user_data)
1369 {
1370     query_coll_t pdata;
1371     GncGUID *guid;
1372 
1373     guid = (GncGUID*)qof_entity_get_guid(ent);
1374     pdata = (query_coll_t)user_data;
1375     pdata->guids = g_list_append(pdata->guids, guid);
1376 }
1377 
1378 QofQueryPredData *
qof_query_collect_predicate(QofGuidMatch options,QofCollection * coll)1379 qof_query_collect_predicate (QofGuidMatch options, QofCollection *coll)
1380 {
1381     query_coll_t pdata;
1382 
1383     g_return_val_if_fail (coll, NULL);
1384     pdata = g_new0 (query_coll_def, 1);
1385     pdata->pd.type_name = query_collect_type;
1386     pdata->options = options;
1387     qof_collection_foreach(coll, query_collect_cb, pdata);
1388     if (NULL == pdata->guids)
1389     {
1390         return NULL;
1391     }
1392     return ((QofQueryPredData*)pdata);
1393 }
1394 
1395 /* QOF_TYPE_CHOICE */
1396 
1397 static int
choice_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1398 choice_match_predicate (gpointer object, QofParam *getter,
1399                         QofQueryPredData *pd)
1400 {
1401     query_choice_t pdata = (query_choice_t)pd;
1402     GList *node, *o_list;
1403     const GncGUID *guid = NULL;
1404 
1405     VERIFY_PREDICATE (query_choice_type);
1406 
1407     switch (pdata->options)
1408     {
1409 
1410     case QOF_GUID_MATCH_ALL:
1411         /* object is a GList of objects; param_getfcn must be called on each one.
1412          * See if every guid in the predicate is accounted-for in the
1413          * object list
1414          */
1415 
1416         for (node = pdata->guids; node; node = node->next)
1417         {
1418             /* See if this GncGUID matches the object's guid */
1419             for (o_list = static_cast<GList*>(object); o_list;
1420 		 o_list = static_cast<GList*>(o_list->next))
1421             {
1422                 guid = ((query_choice_getter)getter->param_getfcn) (o_list->data, getter);
1423                 if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1424                     break;
1425             }
1426 
1427             /*
1428              * If o_list is NULL, we've walked the whole list without finding
1429              * a match.  Therefore break out now, the match has failed.
1430              */
1431             if (o_list == NULL)
1432                 break;
1433         }
1434 
1435         /*
1436          * The match is complete.  If node == NULL then we've successfully
1437          * found a match for all the guids in the predicate.  Return
1438          * appropriately below.
1439          */
1440 
1441         break;
1442 
1443     case QOF_GUID_MATCH_LIST_ANY:
1444 
1445         o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
1446 
1447         for (node = o_list; node; node = node->next)
1448         {
1449             GList *node2;
1450 
1451             for (node2 = pdata->guids; node2; node2 = node2->next)
1452             {
1453                 if (guid_equal (static_cast<GncGUID*>(node->data),
1454 				static_cast<GncGUID*>(node2->data)))
1455                     break;
1456             }
1457 
1458             if (node2 != NULL)
1459                 break;
1460         }
1461 
1462         g_list_free(o_list);
1463 
1464         break;
1465 
1466     default:
1467         /* object is a single object, getter returns a GncGUID*
1468          *
1469          * See if the guid is in the list
1470          */
1471 
1472         guid = ((query_choice_getter)getter->param_getfcn) (object, getter);
1473         for (node = pdata->guids; node; node = node->next)
1474         {
1475             if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1476                 break;
1477         }
1478     }
1479 
1480     switch (pdata->options)
1481     {
1482     case QOF_GUID_MATCH_ANY:
1483     case QOF_GUID_MATCH_LIST_ANY:
1484         return (node != NULL);
1485         break;
1486     case QOF_GUID_MATCH_NONE:
1487     case QOF_GUID_MATCH_ALL:
1488         return (node == NULL);
1489         break;
1490     case QOF_GUID_MATCH_NULL:
1491         return ((guid == NULL) || guid_equal(guid, guid_null()));
1492         break;
1493     default:
1494         PWARN ("bad match type");
1495         return 0;
1496     }
1497 }
1498 
1499 static void
choice_free_pdata(QofQueryPredData * pd)1500 choice_free_pdata (QofQueryPredData *pd)
1501 {
1502     query_choice_t pdata = (query_choice_t)pd;
1503     GList *node;
1504     VERIFY_PDATA (query_choice_type);
1505     for (node = pdata->guids; node; node = node->next)
1506     {
1507         guid_free (static_cast<GncGUID*>(node->data));
1508     }
1509     g_list_free (pdata->guids);
1510     g_free (pdata);
1511 }
1512 
1513 static QofQueryPredData *
choice_copy_predicate(const QofQueryPredData * pd)1514 choice_copy_predicate (const QofQueryPredData *pd)
1515 {
1516     const query_choice_t pdata = (const query_choice_t)pd;
1517     VERIFY_PDATA_R (query_choice_type);
1518     return qof_query_choice_predicate (pdata->options, pdata->guids);
1519 }
1520 
1521 static gboolean
choice_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)1522 choice_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1523 {
1524     const query_choice_t pd1 = (const query_choice_t) p1;
1525     const query_choice_t pd2 = (const query_choice_t) p2;
1526     GList *l1 = pd1->guids, *l2 = pd2->guids;
1527 
1528     if (pd1->options != pd2->options) return FALSE;
1529     for (; l1 || l2; l1 = l1->next, l2 = l2->next)
1530     {
1531         if (!l1 || !l2)
1532             return FALSE;
1533         if (!guid_equal (static_cast<GncGUID*>(l1->data),
1534 			 static_cast<GncGUID*>(l2->data)))
1535             return FALSE;
1536     }
1537     return TRUE;
1538 }
1539 
1540 QofQueryPredData *
qof_query_choice_predicate(QofGuidMatch options,GList * guid_list)1541 qof_query_choice_predicate (QofGuidMatch options, GList *guid_list)
1542 {
1543     query_choice_t pdata;
1544     GList *node;
1545 
1546     if (NULL == guid_list) return NULL;
1547 
1548     pdata = g_new0 (query_choice_def, 1);
1549     pdata->pd.how = QOF_COMPARE_EQUAL;
1550     pdata->pd.type_name = query_choice_type;
1551     pdata->options = options;
1552 
1553     pdata->guids = g_list_copy (guid_list);
1554     for (node = pdata->guids; node; node = node->next)
1555     {
1556         GncGUID *guid = guid_malloc ();
1557         *guid = *((GncGUID *)node->data);
1558         node->data = guid;
1559     }
1560     return ((QofQueryPredData*)pdata);
1561 }
1562 
1563 
1564 /* initialization ================================================== */
1565 /** This function registers a new Core Object with the QofQuery
1566  * subsystem.  It maps the "core_name" object to the given
1567  * query_predicate, predicate_copy, and predicate_data_free functions.
1568  *
1569  * An example:
1570  * qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
1571  *                               string_compare_fcn, string_free_pdata,
1572  *                               string_print_fcn, pred_equal_fcn);
1573  */
1574 
1575 
1576 static void
qof_query_register_core_object(QofType core_name,QofQueryPredicateFunc pred,QofCompareFunc comp,QueryPredicateCopyFunc copy,QueryPredDataFree pd_free,QueryToString toString,QueryPredicateEqual pred_equal)1577 qof_query_register_core_object (QofType core_name,
1578                                 QofQueryPredicateFunc pred,
1579                                 QofCompareFunc comp,
1580                                 QueryPredicateCopyFunc copy,
1581                                 QueryPredDataFree pd_free,
1582                                 QueryToString toString,
1583                                 QueryPredicateEqual pred_equal)
1584 {
1585     g_return_if_fail (core_name);
1586     g_return_if_fail (*core_name != '\0');
1587 
1588     if (pred)
1589         g_hash_table_insert (predTable, (char *)core_name,
1590 			     reinterpret_cast<void*>(pred));
1591 
1592     if (comp)
1593         g_hash_table_insert (cmpTable, (char *)core_name,
1594 			     reinterpret_cast<void*>(comp));
1595 
1596     if (copy)
1597         g_hash_table_insert (copyTable, (char *)core_name,
1598 			     reinterpret_cast<void*>(copy));
1599 
1600     if (pd_free)
1601         g_hash_table_insert (freeTable, (char *)core_name,
1602 			     reinterpret_cast<void*>(pd_free));
1603 
1604     if (toString)
1605         g_hash_table_insert (toStringTable, (char *)core_name,
1606 			     reinterpret_cast<void*>(toString));
1607 
1608     if (pred_equal)
1609         g_hash_table_insert (predEqualTable, (char *)core_name,
1610 			     reinterpret_cast<void*>(pred_equal));
1611 }
1612 
init_tables(void)1613 static void init_tables (void)
1614 {
1615     unsigned int i;
1616     struct
1617     {
1618         QofType                name;
1619         QofQueryPredicateFunc  pred;
1620         QofCompareFunc         comp;
1621         QueryPredicateCopyFunc copy;
1622         QueryPredDataFree      pd_free;
1623         QueryToString          toString;
1624         QueryPredicateEqual    pred_equal;
1625     } knownTypes[] =
1626     {
1627         {
1628             QOF_TYPE_STRING, string_match_predicate, string_compare_func,
1629             string_copy_predicate, string_free_pdata, string_to_string,
1630             string_predicate_equal
1631         },
1632         {
1633             QOF_TYPE_DATE, date_match_predicate, date_compare_func,
1634             date_copy_predicate, date_free_pdata, date_to_string,
1635             date_predicate_equal
1636         },
1637         {
1638             QOF_TYPE_DEBCRED, numeric_match_predicate, numeric_compare_func,
1639             numeric_copy_predicate, numeric_free_pdata, debcred_to_string,
1640             numeric_predicate_equal
1641         },
1642         {
1643             QOF_TYPE_NUMERIC, numeric_match_predicate, numeric_compare_func,
1644             numeric_copy_predicate, numeric_free_pdata, numeric_to_string,
1645             numeric_predicate_equal
1646         },
1647         {
1648             QOF_TYPE_GUID, guid_match_predicate, NULL,
1649             guid_copy_predicate, guid_free_pdata, NULL,
1650             guid_predicate_equal
1651         },
1652         {
1653             QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
1654             int32_copy_predicate, int32_free_pdata, int32_to_string,
1655             int32_predicate_equal
1656         },
1657         {
1658             QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
1659             int64_copy_predicate, int64_free_pdata, int64_to_string,
1660             int64_predicate_equal
1661         },
1662         {
1663             QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
1664             double_copy_predicate, double_free_pdata, double_to_string,
1665             double_predicate_equal
1666         },
1667         {
1668             QOF_TYPE_BOOLEAN, boolean_match_predicate, boolean_compare_func,
1669             boolean_copy_predicate, boolean_free_pdata, boolean_to_string,
1670             boolean_predicate_equal
1671         },
1672         {
1673             QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
1674             char_copy_predicate, char_free_pdata, char_to_string,
1675             char_predicate_equal
1676         },
1677         {
1678             QOF_TYPE_COLLECT, collect_match_predicate, collect_compare_func,
1679             collect_copy_predicate, collect_free_pdata, NULL,
1680             collect_predicate_equal
1681         },
1682         {
1683             QOF_TYPE_CHOICE, choice_match_predicate, NULL,
1684             choice_copy_predicate, choice_free_pdata, NULL, choice_predicate_equal
1685         },
1686     };
1687 
1688     /* Register the known data types */
1689     for (i = 0; i < (sizeof(knownTypes) / sizeof(*knownTypes)); i++)
1690     {
1691         qof_query_register_core_object (knownTypes[i].name,
1692                                         knownTypes[i].pred,
1693                                         knownTypes[i].comp,
1694                                         knownTypes[i].copy,
1695                                         knownTypes[i].pd_free,
1696                                         knownTypes[i].toString,
1697                                         knownTypes[i].pred_equal);
1698     }
1699 }
1700 
1701 static QueryPredicateCopyFunc
qof_query_copy_predicate(QofType type)1702 qof_query_copy_predicate (QofType type)
1703 {
1704     QueryPredicateCopyFunc rc;
1705     g_return_val_if_fail (type, NULL);
1706     rc = reinterpret_cast<QueryPredicateCopyFunc>(g_hash_table_lookup (copyTable, type));
1707     return rc;
1708 }
1709 
1710 static QueryPredDataFree
qof_query_predicate_free(QofType type)1711 qof_query_predicate_free (QofType type)
1712 {
1713     g_return_val_if_fail (type, NULL);
1714     return reinterpret_cast<QueryPredDataFree>(g_hash_table_lookup (freeTable, type));
1715 }
1716 
1717 /********************************************************************/
1718 /* PUBLISHED API FUNCTIONS */
1719 
qof_query_core_init(void)1720 void qof_query_core_init (void)
1721 {
1722     /* Only let us initialize once */
1723     if (initialized) return;
1724     initialized = TRUE;
1725 
1726     /* Create the tables */
1727     predTable = g_hash_table_new (g_str_hash, g_str_equal);
1728     cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
1729     copyTable = g_hash_table_new (g_str_hash, g_str_equal);
1730     freeTable = g_hash_table_new (g_str_hash, g_str_equal);
1731     toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
1732     predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
1733 
1734     init_tables ();
1735 }
1736 
qof_query_core_shutdown(void)1737 void qof_query_core_shutdown (void)
1738 {
1739     if (!initialized) return;
1740     initialized = FALSE;
1741 
1742     g_hash_table_destroy (predTable);
1743     g_hash_table_destroy (cmpTable);
1744     g_hash_table_destroy (copyTable);
1745     g_hash_table_destroy (freeTable);
1746     g_hash_table_destroy (toStringTable);
1747     g_hash_table_destroy (predEqualTable);
1748 }
1749 
1750 QofQueryPredicateFunc
qof_query_core_get_predicate(QofType type)1751 qof_query_core_get_predicate (QofType type)
1752 {
1753     g_return_val_if_fail (type, NULL);
1754     return reinterpret_cast<QofQueryPredicateFunc>(g_hash_table_lookup (predTable, type));
1755 }
1756 
1757 QofCompareFunc
qof_query_core_get_compare(QofType type)1758 qof_query_core_get_compare (QofType type)
1759 {
1760     g_return_val_if_fail (type, NULL);
1761     return reinterpret_cast<QofCompareFunc>(g_hash_table_lookup (cmpTable, type));
1762 }
1763 
1764 void
qof_query_core_predicate_free(QofQueryPredData * pdata)1765 qof_query_core_predicate_free (QofQueryPredData *pdata)
1766 {
1767     QueryPredDataFree free_fcn;
1768 
1769     g_return_if_fail (pdata);
1770     g_return_if_fail (pdata->type_name);
1771 
1772     free_fcn = qof_query_predicate_free (pdata->type_name);
1773     free_fcn (pdata);
1774 }
1775 
1776 QofQueryPredData *
qof_query_core_predicate_copy(const QofQueryPredData * pdata)1777 qof_query_core_predicate_copy (const QofQueryPredData *pdata)
1778 {
1779     QueryPredicateCopyFunc copy;
1780 
1781     g_return_val_if_fail (pdata, NULL);
1782     g_return_val_if_fail (pdata->type_name, NULL);
1783 
1784     copy = qof_query_copy_predicate (pdata->type_name);
1785     return (copy (pdata));
1786 }
1787 
1788 char *
qof_query_core_to_string(QofType type,gpointer object,QofParam * getter)1789 qof_query_core_to_string (QofType type, gpointer object,
1790                           QofParam *getter)
1791 {
1792     QueryToString toString;
1793 
1794     g_return_val_if_fail (type, NULL);
1795     g_return_val_if_fail (object, NULL);
1796     g_return_val_if_fail (getter, NULL);
1797 
1798     toString = reinterpret_cast<QueryToString>(g_hash_table_lookup (toStringTable, type));
1799     g_return_val_if_fail (toString, NULL);
1800 
1801     return toString (object, getter);
1802 }
1803 
1804 gboolean
qof_query_core_predicate_equal(const QofQueryPredData * p1,const QofQueryPredData * p2)1805 qof_query_core_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1806 {
1807     QueryPredicateEqual pred_equal;
1808 
1809     if (p1 == p2) return TRUE;
1810     if (!p1 || !p2) return FALSE;
1811 
1812     if (p1->how != p2->how) return FALSE;
1813     if (g_strcmp0 (p1->type_name, p2->type_name)) return FALSE;
1814 
1815     pred_equal = reinterpret_cast<QueryPredicateEqual>(g_hash_table_lookup (predEqualTable, p1->type_name));
1816     g_return_val_if_fail (pred_equal, FALSE);
1817 
1818     return pred_equal (p1, p2);
1819 }
1820