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