GnuCash  5.6-150-g038405b370+
gnc-engine-guile.cpp
1 /********************************************************************\
2  * gnc-engine-guile.cpp -- engine helper functions for guile *
3  * Copyright (C) 2000 Linas Vepstas <linas@linas.org> *
4  * Copyright (C) 2001 Linux Developers Group, Inc. *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \********************************************************************/
24 
25 #include <config.h>
26 
27 #include "swig-runtime.h"
28 #include <libguile.h>
29 #include <cstring>
30 
31 #include "Account.h"
32 #include "engine-helpers.h"
33 #include "gnc-engine-guile.h"
34 #include "gnc-date.h"
35 #include "gnc-engine.h"
36 #include "gnc-session.h"
37 #include "guile-mappings.h"
38 #include "gnc-guile-utils.h"
39 #include <qof.h>
40 #include <qofbookslots.h>
41 
42 #ifndef HAVE_STRPTIME
43 # include "strptime.h"
44 #endif
45 
50 #include "qofquery-p.h"
51 #include "qofquerycore-p.h"
52 
53 #define FUNC_NAME G_STRFUNC
54 
55 static QofLogModule log_module = GNC_MOD_ENGINE;
56 
57 
58 GDate gnc_time64_to_GDate(SCM x)
59 {
60  time64 time = scm_to_int64 (x);
61  return time64_to_gdate(time);
62 }
63 
64 SCM
65 gnc_guid2scm(GncGUID guid)
66 {
67  char string[GUID_ENCODING_LENGTH + 1];
68 
69  if (!guid_to_string_buff(&guid, string))
70  return SCM_BOOL_F;
71 
72  return scm_from_utf8_string(string);
73 }
74 
75 GncGUID
76 gnc_scm2guid(SCM guid_scm)
77 {
78  GncGUID guid;
79  gchar * str;
80 
81  if (!scm_is_string(guid_scm)
82  || (GUID_ENCODING_LENGTH != scm_c_string_length (guid_scm)))
83  {
84  return *guid_null();
85  }
86  str = gnc_scm_to_utf8_string (guid_scm);
87  string_to_guid(str, &guid);
88  g_free (str);
89  return guid;
90 }
91 
92 int
93 gnc_guid_p(SCM guid_scm)
94 {
95  GncGUID guid;
96  gchar * str;
97  int return_int;
98 
99  if (!scm_is_string(guid_scm))
100  return FALSE;
101 
102  if (GUID_ENCODING_LENGTH != scm_c_string_length (guid_scm))
103  {
104  return FALSE;
105  }
106  str = gnc_scm_to_utf8_string (guid_scm);
107  return_int = string_to_guid(str, &guid);
108  g_free (str);
109  return return_int;
110 }
111 
112 
113 /********************************************************************
114  * type converters for query API
115  ********************************************************************/
116 
117 /* The query scm representation is a list of pairs, where the
118  * car of each pair is one of the following symbols:
119  *
120  * Symbol cdr
121  * 'terms list of OR terms
122  * 'primary-sort scm rep of sort_type_t
123  * 'secondary-sort scm rep of sort_type_t
124  * 'tertiary-sort scm rep of sort_type_t
125  * 'primary-increasing boolean
126  * 'secondary-increasing boolean
127  * 'tertiary-increasing boolean
128  * 'max-splits integer
129  *
130  * Each OR term is a list of AND terms.
131  * Each AND term is a list of one of the following forms:
132  *
133  * ('pd-amount pr-type sense-bool amt-match-how amt-match-sign amount)
134  * ('pd-account pr-type sense-bool acct-match-how list-of-account-guids)
135  * ('pd-string pr-type sense-bool case-sense-bool use-regexp-bool string)
136  * ('pd-cleared pr-type sense-bool cleared-field)
137  * ('pd-balance pr-type sense-bool balance-field)
138  */
139 
140 typedef enum
141 {
142  gnc_QUERY_v1 = 1,
143  gnc_QUERY_v2
144 } query_version_t;
145 
146 /* QofCompareFunc */
147 
148 static QofQueryCompare
149 gnc_query_scm2compare (SCM how_scm)
150 {
151  return static_cast<QofQueryCompare>(scm_to_int(how_scm));
152 }
153 
154 /* QofStringMatch */
155 static QofStringMatch
156 gnc_query_scm2string (SCM how_scm)
157 {
158  return static_cast<QofStringMatch>(scm_to_int(how_scm));
159 }
160 
161 /* QofDateMatch */
162 static QofDateMatch
163 gnc_query_scm2date (SCM how_scm)
164 {
165  return static_cast<QofDateMatch>(scm_to_int(how_scm));
166 }
167 
168 /* QofNumericMatch */
169 static QofNumericMatch
170 gnc_query_scm2numericop (SCM how_scm)
171 {
172  return static_cast<QofNumericMatch>(scm_to_int(how_scm));
173 }
174 
175 /* QofGuidMatch */
176 static QofGuidMatch
177 gnc_query_scm2guid (SCM how_scm)
178 {
179  return static_cast<QofGuidMatch>(scm_to_int(how_scm));
180 }
181 
182 /* QofCharMatch */
183 static QofCharMatch
184 gnc_query_scm2char (SCM how_scm)
185 {
186  return static_cast<QofCharMatch>(scm_to_int(how_scm));
187 }
188 
189 static QofGuidMatch
190 gnc_scm2acct_match_how (SCM how_scm)
191 {
192  QofGuidMatch res;
193  gchar *how = gnc_scm_symbol_to_locale_string (how_scm);
194 
195  if (!g_strcmp0 (how, "acct-match-all"))
196  res = QOF_GUID_MATCH_ALL;
197  else if (!g_strcmp0 (how, "acct-match-any"))
198  res = QOF_GUID_MATCH_ANY;
199  else if (!g_strcmp0 (how, "acct-match-none"))
200  res = QOF_GUID_MATCH_NONE;
201  else
202  {
203  PINFO ("invalid account match: %s", how);
204  res = QOF_GUID_MATCH_NULL;
205  }
206 
207  g_free (how);
208  return res;
209 }
210 
211 static QofQueryCompare
212 gnc_scm2amt_match_how (SCM how_scm)
213 {
214  QofQueryCompare res;
215  gchar *how = gnc_scm_symbol_to_locale_string (how_scm);
216 
217  if (!g_strcmp0 (how, "amt-match-atleast"))
218  res = QOF_COMPARE_GTE;
219  else if (!g_strcmp0 (how, "amt-match-atmost"))
220  res = QOF_COMPARE_LTE;
221  else if (!g_strcmp0 (how, "amt-match-exactly"))
222  res = QOF_COMPARE_EQUAL;
223  else
224  {
225  PINFO ("invalid amount match: %s", how);
226  res = QOF_COMPARE_EQUAL;
227  }
228 
229  g_free (how);
230  return res;
231 }
232 
233 static int
234 gnc_scm2bitfield (SCM field_scm)
235 {
236  int field = 0;
237 
238  if (!scm_is_list (field_scm))
239  return 0;
240 
241  while (!scm_is_null (field_scm))
242  {
243  SCM scm;
244  int bit;
245 
246  scm = SCM_CAR (field_scm);
247  field_scm = SCM_CDR (field_scm);
248 
249  bit = scm_to_int(scm);
250  field |= bit;
251  }
252 
253  return field;
254 }
255 
256 static cleared_match_t
257 gnc_scm2cleared_match_how (SCM how_scm)
258 {
259  return static_cast<cleared_match_t>(gnc_scm2bitfield (how_scm));
260 }
261 
262 static gboolean
263 gnc_scm2balance_match_how (SCM how_scm, gboolean *resp)
264 {
265  gchar *how;
266 
267  if (!scm_is_list (how_scm))
268  return FALSE;
269 
270  if (scm_is_null (how_scm))
271  return FALSE;
272 
273  /* Only allow a single-entry list */
274  if (!scm_is_null (SCM_CDR (how_scm)))
275  return FALSE;
276 
277  how = gnc_scm_symbol_to_locale_string (SCM_CAR(how_scm));
278 
279  if (!g_strcmp0 (how, "balance-match-balanced"))
280  *resp = TRUE;
281  else
282  *resp = FALSE;
283 
284  g_free (how);
285  return TRUE;
286 }
287 
288 static SCM
289 gnc_guid_glist2scm (const GList *account_guids)
290 {
291  SCM guids = SCM_EOL;
292  const GList *node;
293 
294  for (node = account_guids; node; node = node->next)
295  {
296  auto guid = static_cast<GncGUID*>(node->data);
297 
298  if (guid)
299  guids = scm_cons (gnc_guid2scm (*guid), guids);
300  }
301 
302  return scm_reverse (guids);
303 }
304 
305 static GList *
306 gnc_scm2guid_glist (SCM guids_scm)
307 {
308  GList *guids = nullptr;
309 
310  if (!scm_is_list (guids_scm))
311  return nullptr;
312 
313  while (!scm_is_null (guids_scm))
314  {
315  SCM guid_scm = SCM_CAR (guids_scm);
316  GncGUID *guid = nullptr;
317 
318  if (guid_scm != SCM_BOOL_F)
319  {
320  guid = guid_malloc ();
321  *guid = gnc_scm2guid (guid_scm);
322  }
323 
324  guids = g_list_prepend (guids, guid);
325 
326  guids_scm = SCM_CDR (guids_scm);
327  }
328 
329  return g_list_reverse (guids);
330 }
331 
332 static inline void
333 gnc_guid_glist_free (GList *guids)
334 {
335  g_list_free_full (guids, (GDestroyNotify)guid_free);
336 }
337 
338 static SCM
339 gnc_query_numeric2scm (gnc_numeric val)
340 {
341  return scm_cons (scm_from_int64 (val.num),
342  scm_from_int64 (val.denom));
343 }
344 
345 static gboolean
346 gnc_query_numeric_p (SCM pair)
347 {
348  return (scm_is_pair (pair));
349 }
350 
351 static gnc_numeric
352 gnc_query_scm2numeric (SCM pair)
353 {
354  SCM denom;
355  SCM num;
356 
357  num = SCM_CAR (pair);
358  denom = SCM_CDR (pair);
359 
360  return gnc_numeric_create (scm_to_int64 (num),
361  scm_to_int64 (denom));
362 }
363 
364 static SCM
365 gnc_query_path2scm (const GSList *path)
366 {
367  SCM path_scm = SCM_EOL;
368  const GSList *node;
369 
370  for (node = path; node; node = node->next)
371  {
372  auto key = static_cast<const char *>(node->data);
373 
374  if (key)
375  path_scm = scm_cons (scm_from_utf8_string (key), path_scm);
376  }
377 
378  return scm_reverse (path_scm);
379 }
380 
381 GSList *
382 gnc_query_scm2path (SCM path_scm)
383 {
384  GSList *path = nullptr;
385 
386  if (!scm_is_list (path_scm))
387  return nullptr;
388 
389  for (; !scm_is_null (path_scm); path_scm = scm_cdr (path_scm))
390  {
391  SCM key_scm = SCM_CAR (path_scm);
392 
393  if (!scm_is_string (key_scm))
394  break;
395 
396  auto key = gnc_scm_to_utf8_string(key_scm);
397  path = g_slist_prepend (path, (gpointer)qof_string_cache_insert(key));
398  g_free (key);
399  }
400 
401  return g_slist_reverse (path);
402 }
403 
404 static void
405 gnc_query_path_free (GSList *path)
406 {
407  g_slist_free_full (path, (GDestroyNotify)qof_string_cache_remove);
408 }
409 
410 
411 static SCM
412 gnc_queryterm2scm (const QofQueryTerm *qt)
413 {
414  SCM qt_scm = SCM_EOL;
415  QofQueryPredData *pd = nullptr;
416 
417  qt_scm = scm_cons (gnc_query_path2scm (qof_query_term_get_param_path (qt)),
418  qt_scm);
419  qt_scm = scm_cons (SCM_BOOL (qof_query_term_is_inverted (qt)), qt_scm);
420 
421  pd = qof_query_term_get_pred_data (qt);
422  qt_scm = scm_cons (scm_from_locale_symbol (pd->type_name), qt_scm);
423  qt_scm = scm_cons (scm_from_long (pd->how), qt_scm);
424 
425  if (!g_strcmp0 (pd->type_name, QOF_TYPE_STRING))
426  {
427  auto pdata = (query_string_t) pd;
428 
429  qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
430  qt_scm = scm_cons (SCM_BOOL (pdata->is_regex), qt_scm);
431  qt_scm = scm_cons (pdata->matchstring ? scm_from_utf8_string (pdata->matchstring) : SCM_BOOL_F, qt_scm);
432 
433  }
434  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_DATE))
435  {
436  auto pdata = (query_date_t) pd;
437 
438  qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
439  qt_scm = scm_cons (scm_from_int64 (pdata->date), qt_scm);
440 
441  }
442  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_NUMERIC))
443  {
444  auto pdata = (query_numeric_t) pd;
445 
446  qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
447  qt_scm = scm_cons (gnc_query_numeric2scm (pdata->amount), qt_scm);
448 
449  }
450  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_GUID))
451  {
452  auto pdata = (query_guid_t) pd;
453 
454  qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
455  qt_scm = scm_cons (gnc_guid_glist2scm (pdata->guids), qt_scm);
456 
457  }
458  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_INT64))
459  {
460  auto pdata = (query_int64_t) pd;
461 
462  qt_scm = scm_cons (scm_from_int64 (pdata->val), qt_scm);
463 
464  }
465  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_DOUBLE))
466  {
467  auto pdata = (query_double_t) pd;
468 
469  qt_scm = scm_cons (scm_from_double (pdata->val), qt_scm);
470 
471  }
472  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_BOOLEAN))
473  {
474  auto pdata = (query_boolean_t) pd;
475 
476  qt_scm = scm_cons (SCM_BOOL (pdata->val), qt_scm);
477 
478  }
479  else if (!g_strcmp0 (pd->type_name, QOF_TYPE_CHAR))
480  {
481  auto pdata = (query_char_t) pd;
482 
483  qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
484  qt_scm = scm_cons (pdata->char_list ? scm_from_utf8_string (pdata->char_list) : SCM_BOOL_F, qt_scm);
485 
486  }
487  else
488  {
489  PWARN ("query core type %s not supported", pd->type_name);
490  return SCM_BOOL_F;
491  }
492 
493  return scm_reverse (qt_scm);
494 }
495 
496 static QofQuery *
497 gnc_scm2query_term_query_v2 (SCM qt_scm)
498 {
499  QofQuery *q = nullptr;
500  QofQueryPredData *pd = nullptr;
501  SCM scm;
502  gchar *type = nullptr;
503  GSList *path = nullptr;
504  gboolean inverted = FALSE;
505  QofQueryCompare compare_how;
506 
507  if (!scm_is_list (qt_scm) || scm_is_null (qt_scm))
508  return nullptr;
509 
510  do
511  {
512  /* param path */
513  scm = SCM_CAR (qt_scm);
514  qt_scm = SCM_CDR (qt_scm);
515  if (!scm_is_list (scm))
516  break;
517  path = gnc_query_scm2path (scm);
518 
519  /* inverted */
520  scm = SCM_CAR (qt_scm);
521  qt_scm = SCM_CDR (qt_scm);
522  if (!scm_is_bool (scm))
523  break;
524  inverted = scm_is_true (scm);
525 
526  /* type */
527  scm = SCM_CAR (qt_scm);
528  qt_scm = SCM_CDR (qt_scm);
529  if (!scm_is_symbol (scm))
530  break;
531  type = gnc_scm_symbol_to_locale_string (scm);
532 
533  /* QofCompareFunc */
534  scm = SCM_CAR (qt_scm);
535  qt_scm = SCM_CDR (qt_scm);
536  if (scm_is_null (scm))
537  break;
538  compare_how = gnc_query_scm2compare (scm);
539 
540  /* Now compute the predicate */
541 
542  if (!g_strcmp0 (type, QOF_TYPE_STRING))
543  {
544  QofStringMatch options;
545  gboolean is_regex;
546  gchar *matchstring;
547 
548  scm = SCM_CAR (qt_scm);
549  qt_scm = SCM_CDR (qt_scm);
550  if (scm_is_null (scm)) break;
551  options = gnc_query_scm2string (scm);
552 
553  scm = SCM_CAR (qt_scm);
554  qt_scm = SCM_CDR (qt_scm);
555  if (!scm_is_bool (scm)) break;
556  is_regex = scm_is_true (scm);
557 
558  scm = SCM_CAR (qt_scm);
559  if (!scm_is_string (scm)) break;
560 
561  matchstring = gnc_scm_to_utf8_string (scm);
562 
563  pd = qof_query_string_predicate (compare_how, matchstring,
564  options, is_regex);
565  g_free (matchstring);
566  }
567  else if (!g_strcmp0 (type, QOF_TYPE_DATE))
568  {
569  QofDateMatch options;
570  time64 date;
571 
572  scm = SCM_CAR (qt_scm);
573  qt_scm = SCM_CDR (qt_scm);
574  if (scm_is_null (scm))
575  break;
576  options = gnc_query_scm2date (scm);
577 
578  scm = SCM_CAR (qt_scm);
579  if (scm_is_null (scm))
580  break;
581  date = scm_to_int64 (scm);
582 
583  pd = qof_query_date_predicate (compare_how, options, date);
584 
585  }
586  else if (!g_strcmp0 (type, QOF_TYPE_NUMERIC))
587  {
588  QofNumericMatch options;
589  gnc_numeric val;
590 
591  scm = SCM_CAR (qt_scm);
592  qt_scm = SCM_CDR (qt_scm);
593  if (scm_is_null (scm))
594  break;
595  options = gnc_query_scm2numericop (scm);
596 
597  scm = SCM_CAR (qt_scm);
598  if (!gnc_query_numeric_p (scm))
599  break;
600  val = gnc_query_scm2numeric (scm);
601 
602  pd = qof_query_numeric_predicate (compare_how, options, val);
603 
604  }
605  else if (!g_strcmp0 (type, QOF_TYPE_GUID))
606  {
607  QofGuidMatch options;
608  GList *guids;
609 
610  scm = SCM_CAR (qt_scm);
611  qt_scm = SCM_CDR (qt_scm);
612  if (scm_is_null (scm))
613  break;
614  options = gnc_query_scm2guid (scm);
615 
616  scm = SCM_CAR (qt_scm);
617  if (!scm_is_list (scm))
618  break;
619  guids = gnc_scm2guid_glist (scm);
620 
621  pd = qof_query_guid_predicate (options, guids);
622 
623  gnc_guid_glist_free (guids);
624 
625  }
626  else if (!g_strcmp0 (type, QOF_TYPE_INT64))
627  {
628  gint64 val;
629 
630  scm = SCM_CAR (qt_scm);
631  if (scm_is_null (scm))
632  break;
633  val = scm_to_int64 (scm);
634 
635  pd = qof_query_int64_predicate (compare_how, val);
636 
637  }
638  else if (!g_strcmp0 (type, QOF_TYPE_DOUBLE))
639  {
640  double val;
641 
642  scm = SCM_CAR (qt_scm);
643  if (!scm_is_number (scm))
644  break;
645  val = scm_to_double (scm);
646 
647  pd = qof_query_double_predicate (compare_how, val);
648 
649  }
650  else if (!g_strcmp0 (type, QOF_TYPE_BOOLEAN))
651  {
652  gboolean val;
653 
654  scm = SCM_CAR (qt_scm);
655  if (!scm_is_bool (scm))
656  break;
657  val = scm_is_true (scm);
658 
659  pd = qof_query_boolean_predicate (compare_how, val);
660 
661  }
662  else if (!g_strcmp0 (type, QOF_TYPE_CHAR))
663  {
664  QofCharMatch options;
665  gchar *char_list;
666 
667  scm = SCM_CAR (qt_scm);
668  qt_scm = SCM_CDR (qt_scm);
669  if (scm_is_null (scm))
670  break;
671  options = gnc_query_scm2char (scm);
672 
673  scm = SCM_CAR (qt_scm);
674  if (!scm_is_string (scm))
675  break;
676  char_list = gnc_scm_to_utf8_string (scm);
677 
678  pd = qof_query_char_predicate (options, char_list);
679  g_free (char_list);
680  }
681  else
682  {
683  PWARN ("query core type %s not supported", type);
684  break;
685  }
686 
687  g_free (type);
688 
689  }
690  while (FALSE);
691 
692  if (pd)
693  {
694  q = qof_query_create ();
695  qof_query_add_term (q, path, pd, QOF_QUERY_OR);
696  if (inverted)
697  {
698  QofQuery *outq = qof_query_invert (q);
699  qof_query_destroy (q);
700  q = outq;
701  }
702  }
703  else
704  {
705  gnc_query_path_free (path);
706  }
707 
708  return q;
709 }
710 
711 static QofQuery *
712 gnc_scm2query_term_query_v1 (SCM query_term_scm)
713 {
714  gboolean ok = FALSE;
715  gchar * pd_type = nullptr;
716  gchar * pr_type = nullptr;
717  gboolean sense = FALSE;
718  QofQuery *q = nullptr;
719  SCM scm;
720 
721  if (!scm_is_list (query_term_scm) ||
722  scm_is_null (query_term_scm))
723  {
724  PINFO ("null term");
725  return nullptr;
726  }
727 
728  do
729  {
730  /* pd_type */
731  scm = SCM_CAR (query_term_scm);
732  query_term_scm = SCM_CDR (query_term_scm);
733  pd_type = gnc_scm_symbol_to_locale_string (scm);
734 
735  /* pr_type */
736  if (scm_is_null (query_term_scm))
737  {
738  PINFO ("null pr_type");
739  break;
740  }
741  scm = SCM_CAR (query_term_scm);
742  query_term_scm = SCM_CDR (query_term_scm);
743  pr_type = gnc_scm_symbol_to_locale_string (scm);
744 
745  /* sense */
746  if (scm_is_null (query_term_scm))
747  {
748  PINFO ("null sense");
749  break;
750  }
751  scm = SCM_CAR (query_term_scm);
752  query_term_scm = SCM_CDR (query_term_scm);
753  sense = scm_is_true (scm);
754 
755  q = qof_query_create_for(GNC_ID_SPLIT);
756 
757  if (!g_strcmp0 (pd_type, "pd-date"))
758  {
759  gboolean use_start;
760  gboolean use_end;
761  time64 start;
762  time64 end;
763 
764  /* use_start */
765  if (scm_is_null (query_term_scm))
766  {
767  PINFO ("null use_start");
768  break;
769  }
770 
771  scm = SCM_CAR (query_term_scm);
772  query_term_scm = SCM_CDR (query_term_scm);
773  use_start = scm_is_true (scm);
774 
775  /* start */
776  if (scm_is_null (query_term_scm))
777  break;
778 
779  scm = SCM_CAR (query_term_scm);
780  query_term_scm = SCM_CDR (query_term_scm);
781  start = scm_to_int64 (scm);
782 
783  /* use_end */
784  if (scm_is_null (query_term_scm))
785  break;
786 
787  scm = SCM_CAR (query_term_scm);
788  query_term_scm = SCM_CDR (query_term_scm);
789  use_end = scm_is_true (scm);
790 
791  /* end */
792  if (scm_is_null (query_term_scm))
793  break;
794 
795  scm = SCM_CAR (query_term_scm);
796  end = scm_to_int64 (scm);
797 
798  xaccQueryAddDateMatchTT (q, use_start, start, use_end, end, QOF_QUERY_OR);
799 
800  ok = TRUE;
801 
802  }
803  else if (!g_strcmp0 (pd_type, "pd-amount"))
804  {
805  QofQueryCompare how;
806  QofNumericMatch amt_sgn;
807  gnc_numeric val;
808 
809  /* how */
810  if (scm_is_null (query_term_scm))
811  break;
812  scm = SCM_CAR (query_term_scm);
813  query_term_scm = SCM_CDR (query_term_scm);
814  how = gnc_scm2amt_match_how (scm);
815 
816  /* amt_sgn */
817  if (scm_is_null (query_term_scm))
818  break;
819  scm = SCM_CAR (query_term_scm);
820  query_term_scm = SCM_CDR (query_term_scm);
821  amt_sgn = gnc_query_scm2numericop (scm);
822 
823  /* amount */
824  if (scm_is_null (query_term_scm))
825  break;
826  scm = SCM_CAR (query_term_scm);
827  val = gnc_numeric_create (scm_to_int64(scm_numerator(scm)),
828  scm_to_int64(scm_denominator(scm)));
829 
830  if (!g_strcmp0 (pr_type, "pr-price"))
831  {
832  xaccQueryAddSharePriceMatch (q, val, how, QOF_QUERY_OR);
833  ok = TRUE;
834 
835  }
836  else if (!g_strcmp0 (pr_type, "pr-shares"))
837  {
838  xaccQueryAddSharesMatch (q, val, how, QOF_QUERY_OR);
839  ok = TRUE;
840 
841  }
842  else if (!g_strcmp0 (pr_type, "pr-value"))
843  {
844  xaccQueryAddValueMatch (q, val, amt_sgn, how, QOF_QUERY_OR);
845  ok = TRUE;
846 
847  }
848  else
849  {
850  PINFO ("unknown amount predicate: %s", pr_type);
851  }
852 
853  }
854  else if (!g_strcmp0 (pd_type, "pd-account"))
855  {
856  QofGuidMatch how;
857  GList *account_guids;
858 
859  /* how */
860  if (scm_is_null (query_term_scm))
861  {
862  PINFO ("pd-account: null how");
863  break;
864  }
865 
866  scm = SCM_CAR (query_term_scm);
867  query_term_scm = SCM_CDR (query_term_scm);
868  how = gnc_scm2acct_match_how (scm);
869 
870  /* account guids */
871  if (scm_is_null (query_term_scm))
872  {
873  PINFO ("pd-account: null guids");
874  break;
875  }
876 
877  scm = SCM_CAR (query_term_scm);
878 
879  account_guids = gnc_scm2guid_glist (scm);
880 
881  xaccQueryAddAccountGUIDMatch (q, account_guids, how, QOF_QUERY_OR);
882 
883  gnc_guid_glist_free (account_guids);
884 
885  ok = TRUE;
886 
887  }
888  else if (!g_strcmp0 (pd_type, "pd-string"))
889  {
890  gboolean case_sens;
891  gboolean use_regexp;
892  gchar *matchstring;
893 
894  /* case_sens */
895  if (scm_is_null (query_term_scm))
896  break;
897 
898  scm = SCM_CAR (query_term_scm);
899  query_term_scm = SCM_CDR (query_term_scm);
900  case_sens = scm_is_true (scm);
901 
902  /* use_regexp */
903  if (scm_is_null (query_term_scm))
904  break;
905 
906  scm = SCM_CAR (query_term_scm);
907  query_term_scm = SCM_CDR (query_term_scm);
908  use_regexp = scm_is_true (scm);
909 
910  /* matchstring */
911  if (scm_is_null (query_term_scm))
912  break;
913 
914  scm = SCM_CAR (query_term_scm);
915  matchstring = gnc_scm_to_utf8_string (scm);
916 
917  if (!g_strcmp0 (pr_type, "pr-action"))
918  {
919  xaccQueryAddActionMatch (q, matchstring, case_sens, use_regexp,
920  QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
921  ok = TRUE;
922 
923  }
924  else if (!g_strcmp0 (pr_type, "pr-desc"))
925  {
926  xaccQueryAddDescriptionMatch (q, matchstring, case_sens,
927  use_regexp, QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
928  ok = TRUE;
929 
930  }
931  else if (!g_strcmp0 (pr_type, "pr-memo"))
932  {
933  xaccQueryAddMemoMatch (q, matchstring, case_sens, use_regexp,
934  QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
935  ok = TRUE;
936 
937  }
938  else if (!g_strcmp0 (pr_type, "pr-num"))
939  {
940  xaccQueryAddNumberMatch (q, matchstring, case_sens, use_regexp,
941  QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
942  ok = TRUE;
943 
944  }
945  else
946  {
947  PINFO ("Unknown string predicate: %s", pr_type);
948  }
949  g_free (matchstring);
950 
951  }
952  else if (!g_strcmp0 (pd_type, "pd-cleared"))
953  {
954  cleared_match_t how;
955 
956  /* how */
957  if (scm_is_null (query_term_scm))
958  break;
959 
960  scm = SCM_CAR (query_term_scm);
961  how = gnc_scm2cleared_match_how (scm);
962 
963  xaccQueryAddClearedMatch (q, how, QOF_QUERY_OR);
964  ok = TRUE;
965 
966  }
967  else if (!g_strcmp0 (pd_type, "pd-balance"))
968  {
969  gboolean how;
970 
971  /* how */
972  if (scm_is_null (query_term_scm))
973  break;
974 
975  scm = SCM_CAR (query_term_scm);
976  if (gnc_scm2balance_match_how (scm, &how) == FALSE)
977  break;
978 
979  xaccQueryAddBalanceMatch (q, static_cast<QofQueryCompare>(how), QOF_QUERY_OR);
980  ok = TRUE;
981 
982  }
983  else if (!g_strcmp0 (pd_type, "pd-guid"))
984  {
985  GncGUID guid;
986  QofIdType id_type;
987 
988  /* guid */
989  if (scm_is_null (query_term_scm))
990  break;
991 
992  scm = SCM_CAR (query_term_scm);
993  query_term_scm = SCM_CDR (query_term_scm);
994  guid = gnc_scm2guid (scm);
995 
996  /* id type */
997  scm = SCM_CAR (query_term_scm);
998  id_type = (QofIdType) gnc_scm_to_utf8_string (scm);
999 
1000  xaccQueryAddGUIDMatch (q, &guid, id_type, QOF_QUERY_OR);
1001  g_free ((void *) id_type);
1002  ok = TRUE;
1003 
1004  }
1005  else
1006  {
1007  PINFO ("Unknown Predicate: %s", pd_type);
1008  }
1009 
1010  g_free (pd_type);
1011  g_free (pr_type);
1012 
1013  }
1014  while (FALSE);
1015 
1016  if (ok)
1017  {
1018  QofQuery *out_q;
1019 
1020  if (sense)
1021  out_q = q;
1022  else
1023  {
1024  out_q = qof_query_invert (q);
1025  qof_query_destroy (q);
1026  }
1027 
1028  return out_q;
1029  }
1030 
1031  qof_query_destroy (q);
1032  return nullptr;
1033 }
1034 
1035 static QofQuery *
1036 gnc_scm2query_term_query (SCM query_term_scm, query_version_t vers)
1037 {
1038  switch (vers)
1039  {
1040  case gnc_QUERY_v1:
1041  return gnc_scm2query_term_query_v1 (query_term_scm);
1042  case gnc_QUERY_v2:
1043  return gnc_scm2query_term_query_v2 (query_term_scm);
1044  default:
1045  return nullptr;
1046  }
1047 }
1048 
1049 static SCM
1050 gnc_query_terms2scm (const GList *terms)
1051 {
1052  SCM or_terms = SCM_EOL;
1053  const GList *or_node;
1054 
1055  for (or_node = terms; or_node; or_node = or_node->next)
1056  {
1057  SCM and_terms = SCM_EOL;
1058  GList *and_node;
1059 
1060  for (and_node = static_cast<GList*>(or_node->data); and_node; and_node = and_node->next)
1061  {
1062  auto qt = static_cast<QofQueryTerm*>(and_node->data);
1063  SCM qt_scm;
1064 
1065  qt_scm = gnc_queryterm2scm (qt);
1066 
1067  and_terms = scm_cons (qt_scm, and_terms);
1068  }
1069 
1070  and_terms = scm_reverse (and_terms);
1071 
1072  or_terms = scm_cons (and_terms, or_terms);
1073  }
1074 
1075  return scm_reverse (or_terms);
1076 }
1077 
1078 static QofQuery *
1079 gnc_scm2query_and_terms (SCM and_terms, query_version_t vers)
1080 {
1081  QofQuery *q = nullptr;
1082 
1083  if (!scm_is_list (and_terms))
1084  return nullptr;
1085 
1086  while (!scm_is_null (and_terms))
1087  {
1088  SCM term;
1089 
1090  term = SCM_CAR (and_terms);
1091  and_terms = SCM_CDR (and_terms);
1092 
1093  if (!q)
1094  q = gnc_scm2query_term_query (term, vers);
1095  else
1096  {
1097  QofQuery *q_and;
1098  QofQuery *q_new;
1099 
1100  q_and = gnc_scm2query_term_query (term, vers);
1101 
1102  if (q_and)
1103  {
1104  q_new = qof_query_merge (q, q_and, QOF_QUERY_AND);
1105  qof_query_destroy (q_and);
1106 
1107  if (q_new)
1108  {
1109  qof_query_destroy (q);
1110  q = q_new;
1111  }
1112  }
1113  }
1114  }
1115 
1116  return q;
1117 }
1118 
1119 static QofQuery *
1120 gnc_scm2query_or_terms (SCM or_terms, query_version_t vers)
1121 {
1122  QofQuery *q = nullptr;
1123 
1124  if (!scm_is_list (or_terms))
1125  return nullptr;
1126 
1127  q = qof_query_create_for(GNC_ID_SPLIT);
1128 
1129  while (!scm_is_null (or_terms))
1130  {
1131  SCM and_terms;
1132 
1133  and_terms = SCM_CAR (or_terms);
1134  or_terms = SCM_CDR (or_terms);
1135 
1136  if (!q)
1137  q = gnc_scm2query_and_terms (and_terms, vers);
1138  else
1139  {
1140  QofQuery *q_or;
1141  QofQuery *q_new;
1142 
1143  q_or = gnc_scm2query_and_terms (and_terms, vers);
1144 
1145  if (q_or)
1146  {
1147  q_new = qof_query_merge (q, q_or, QOF_QUERY_OR);
1148  qof_query_destroy (q_or);
1149 
1150  if (q_new)
1151  {
1152  qof_query_destroy (q);
1153  q = q_new;
1154  }
1155  }
1156  }
1157  }
1158 
1159  return q;
1160 }
1161 
1162 static SCM
1163 gnc_query_sort2scm (const QofQuerySort *qs)
1164 {
1165  SCM sort_scm = SCM_EOL;
1166  GSList *path;
1167 
1168  path = qof_query_sort_get_param_path (qs);
1169  if (path == nullptr)
1170  return SCM_BOOL_F;
1171 
1172  sort_scm = scm_cons (gnc_query_path2scm (path), sort_scm);
1173  sort_scm = scm_cons (scm_from_int (qof_query_sort_get_sort_options (qs)), sort_scm);
1174  sort_scm = scm_cons (SCM_BOOL (qof_query_sort_get_increasing (qs)), sort_scm);
1175 
1176  return scm_reverse (sort_scm);
1177 }
1178 
1179 static gboolean
1180 gnc_query_scm2sort (SCM sort_scm, GSList **path, gint *options, gboolean *inc)
1181 {
1182  SCM val;
1183  GSList *p;
1184  gint o;
1185  gboolean i;
1186 
1187  g_return_val_if_fail (path && options && inc, FALSE);
1188  g_return_val_if_fail (*path == nullptr, FALSE);
1189 
1190  /* This is ok -- it means we have an empty sort. Don't do anything */
1191  if (scm_is_bool (sort_scm))
1192  return TRUE;
1193 
1194  /* Ok, this had better be a list */
1195  if (!scm_is_list (sort_scm))
1196  return FALSE;
1197 
1198  /* Parse the path, options, and increasing */
1199  val = SCM_CAR (sort_scm);
1200  sort_scm = SCM_CDR (sort_scm);
1201  if (!scm_is_list (val))
1202  return FALSE;
1203  p = gnc_query_scm2path (val);
1204 
1205  /* options */
1206  val = SCM_CAR (sort_scm);
1207  sort_scm = SCM_CDR (sort_scm);
1208  if (!scm_is_number (val))
1209  {
1210  gnc_query_path_free (p);
1211  return FALSE;
1212  }
1213  o = scm_to_int (val);
1214 
1215  /* increasing */
1216  val = SCM_CAR (sort_scm);
1217  sort_scm = SCM_CDR (sort_scm);
1218  if (!scm_is_bool (val))
1219  {
1220  gnc_query_path_free (p);
1221  return FALSE;
1222  }
1223  i = scm_is_true (val);
1224 
1225  /* EOL */
1226  if (!scm_is_null (sort_scm))
1227  {
1228  gnc_query_path_free (p);
1229  return FALSE;
1230  }
1231  *path = p;
1232  *options = o;
1233  *inc = i;
1234 
1235  return TRUE;
1236 }
1237 
1238 SCM
1239 gnc_query2scm (QofQuery *q)
1240 {
1241  SCM query_scm = SCM_EOL;
1242  SCM pair;
1243  QofQuerySort *s1, *s2, *s3;
1244 
1245  if (!q) return SCM_BOOL_F;
1246 
1247  /* terms */
1248  pair = scm_cons (gnc_query_terms2scm (qof_query_get_terms (q)), SCM_EOL);
1249  pair = scm_cons (scm_from_locale_symbol ("terms"), pair);
1250  query_scm = scm_cons (pair, query_scm);
1251 
1252  /* search-for */
1253  pair = scm_cons (scm_from_locale_symbol (qof_query_get_search_for (q)), SCM_EOL);
1254  pair = scm_cons (scm_from_locale_symbol ("search-for"), pair);
1255  query_scm = scm_cons (pair, query_scm);
1256 
1257  /* sorts... */
1258  qof_query_get_sorts (q, &s1, &s2, &s3);
1259 
1260  /* primary-sort */
1261  pair = scm_cons (gnc_query_sort2scm (s1), SCM_EOL);
1262  pair = scm_cons (scm_from_locale_symbol ("primary-sort"), pair);
1263  query_scm = scm_cons (pair, query_scm);
1264 
1265  /* secondary-sort */
1266  pair = scm_cons (gnc_query_sort2scm (s2), SCM_EOL);
1267  pair = scm_cons (scm_from_locale_symbol ("secondary-sort"), pair);
1268  query_scm = scm_cons (pair, query_scm);
1269 
1270  /* tertiary-sort */
1271  pair = scm_cons (gnc_query_sort2scm (s3), SCM_EOL);
1272  pair = scm_cons (scm_from_locale_symbol ("tertiary-sort"), pair);
1273  query_scm = scm_cons (pair, query_scm);
1274 
1275  /* max results */
1276  pair = scm_cons (scm_from_int (qof_query_get_max_results (q)), SCM_EOL);
1277  pair = scm_cons (scm_from_locale_symbol ("max-results"), pair);
1278  query_scm = scm_cons (pair, query_scm);
1279 
1280  /* Reverse this list; tag it as 'query-v2' */
1281  pair = scm_reverse (query_scm);
1282  return scm_cons (scm_from_locale_symbol ("query-v2"), pair);
1283 }
1284 
1285 static GSList *
1286 gnc_query_sort_to_list (const gchar * symbol)
1287 {
1288  GSList *path = nullptr;
1289 
1290  if (!symbol)
1291  return nullptr;
1292 
1293  if (!g_strcmp0 (symbol, "by-none"))
1294  {
1295  path = nullptr;
1296  }
1297  else if (!g_strcmp0 (symbol, "by-standard"))
1298  {
1299  path = g_slist_prepend (path, (gpointer) QUERY_DEFAULT_SORT);
1300 
1301  }
1302  else if (!g_strcmp0 (symbol, "by-date") ||
1303  !g_strcmp0 (symbol, "by-date-rounded"))
1304  {
1305  path = g_slist_prepend (path, (gpointer) TRANS_DATE_POSTED);
1306  path = g_slist_prepend (path, (gpointer) SPLIT_TRANS);
1307 
1308  }
1309  else if (!g_strcmp0 (symbol, "by-date-entered") ||
1310  !g_strcmp0 (symbol, "by-date-entered-rounded"))
1311  {
1312  path = g_slist_prepend (path, (gpointer) TRANS_DATE_ENTERED);
1313  path = g_slist_prepend (path, (gpointer) SPLIT_TRANS);
1314 
1315  }
1316  else if (!g_strcmp0 (symbol, "by-date-reconciled") ||
1317  !g_strcmp0 (symbol, "by-date-reconciled-rounded"))
1318  {
1319  path = g_slist_prepend (path, (gpointer) SPLIT_DATE_RECONCILED);
1320 
1321  }
1322  else if (!g_strcmp0 (symbol, "by-num"))
1323  {
1324  path = g_slist_prepend (path, (gpointer) TRANS_NUM);
1325  path = g_slist_prepend (path, (gpointer) SPLIT_TRANS);
1326 
1327  }
1328  else if (!g_strcmp0 (symbol, "by-amount"))
1329  {
1330  path = g_slist_prepend (path, (gpointer) SPLIT_VALUE);
1331 
1332  }
1333  else if (!g_strcmp0 (symbol, "by-memo"))
1334  {
1335  path = g_slist_prepend (path, (gpointer) SPLIT_MEMO);
1336 
1337  }
1338  else if (!g_strcmp0 (symbol, "by-desc"))
1339  {
1340  path = g_slist_prepend (path, (gpointer) TRANS_DESCRIPTION);
1341  path = g_slist_prepend (path, (gpointer) SPLIT_TRANS);
1342 
1343  }
1344  else if (!g_strcmp0 (symbol, "by-reconcile"))
1345  {
1346  path = g_slist_prepend (path, (gpointer) SPLIT_RECONCILE);
1347 
1348  }
1349  else if (!g_strcmp0 (symbol, "by-account-full-name"))
1350  {
1351  path = g_slist_prepend (path, (gpointer) SPLIT_ACCT_FULLNAME);
1352 
1353  }
1354  else if (!g_strcmp0 (symbol, "by-account-code"))
1355  {
1356  path = g_slist_prepend (path, (gpointer) ACCOUNT_CODE_);
1357  path = g_slist_prepend (path, (gpointer) SPLIT_ACCOUNT);
1358 
1359  }
1360  else if (!g_strcmp0 (symbol, "by-corr-account-full-name"))
1361  {
1362  path = g_slist_prepend (path, (gpointer) SPLIT_CORR_ACCT_NAME);
1363 
1364  }
1365  else if (!g_strcmp0 (symbol, "by-corr-account-code"))
1366  {
1367  path = g_slist_prepend (path, (gpointer) SPLIT_CORR_ACCT_CODE);
1368 
1369  }
1370  else
1371  {
1372  PERR ("Unknown sort-type, %s", symbol);
1373  }
1374 
1375  return path;
1376 }
1377 
1378 static QofQuery *
1379 gnc_scm2query_v1 (SCM query_scm)
1380 {
1381  QofQuery *q = nullptr;
1382  gboolean ok = TRUE;
1383  gchar * primary_sort = nullptr;
1384  gchar * secondary_sort = nullptr;
1385  gchar * tertiary_sort = nullptr;
1386  gboolean primary_increasing = TRUE;
1387  gboolean secondary_increasing = TRUE;
1388  gboolean tertiary_increasing = TRUE;
1389  int max_splits = -1;
1390 
1391  while (!scm_is_null (query_scm))
1392  {
1393  gchar *symbol;
1394  SCM sym_scm;
1395  SCM value;
1396  SCM pair;
1397 
1398  pair = SCM_CAR (query_scm);
1399  query_scm = SCM_CDR (query_scm);
1400 
1401  if (!scm_is_pair (pair))
1402  {
1403  PERR ("Not a Pair");
1404  ok = FALSE;
1405  break;
1406  }
1407 
1408  sym_scm = SCM_CAR (pair);
1409  value = SCM_CADR (pair);
1410 
1411  if (!scm_is_symbol (sym_scm))
1412  {
1413  PERR ("Not a symbol");
1414  ok = FALSE;
1415  break;
1416  }
1417 
1418  symbol = gnc_scm_symbol_to_locale_string (sym_scm);
1419  if (!symbol)
1420  {
1421  PERR ("No string found");
1422  ok = FALSE;
1423  break;
1424  }
1425 
1426  if (g_strcmp0 ("terms", symbol) == 0)
1427  {
1428  if (q)
1429  qof_query_destroy (q);
1430 
1431  q = gnc_scm2query_or_terms (value, gnc_QUERY_v1);
1432  if (!q)
1433  {
1434  PINFO ("invalid terms");
1435  ok = FALSE;
1436  break;
1437  }
1438 
1439  }
1440  else if (g_strcmp0 ("primary-sort", symbol) == 0)
1441  {
1442  if (!scm_is_symbol (value))
1443  {
1444  PINFO ("Invalid primary sort");
1445  ok = FALSE;
1446  break;
1447  }
1448 
1449  primary_sort = gnc_scm_symbol_to_locale_string (value);
1450 
1451  }
1452  else if (g_strcmp0 ("secondary-sort", symbol) == 0)
1453  {
1454  if (!scm_is_symbol (value))
1455  {
1456  PINFO ("Invalid secondary sort");
1457  ok = FALSE;
1458  break;
1459  }
1460 
1461  secondary_sort = gnc_scm_symbol_to_locale_string (value);
1462 
1463  }
1464  else if (g_strcmp0 ("tertiary-sort", symbol) == 0)
1465  {
1466  if (!scm_is_symbol (value))
1467  {
1468  PINFO ("Invalid tertiary sort");
1469  ok = FALSE;
1470  break;
1471  }
1472 
1473  tertiary_sort = gnc_scm_symbol_to_locale_string (value);
1474 
1475  }
1476  else if (g_strcmp0 ("primary-increasing", symbol) == 0)
1477  {
1478  primary_increasing = scm_is_true (value);
1479 
1480  }
1481  else if (g_strcmp0 ("secondary-increasing", symbol) == 0)
1482  {
1483  secondary_increasing = scm_is_true (value);
1484 
1485  }
1486  else if (g_strcmp0 ("tertiary-increasing", symbol) == 0)
1487  {
1488  tertiary_increasing = scm_is_true (value);
1489 
1490  }
1491  else if (g_strcmp0 ("max-splits", symbol) == 0)
1492  {
1493  if (!scm_is_number (value))
1494  {
1495  PERR ("invalid max-splits");
1496  ok = FALSE;
1497  break;
1498  }
1499 
1500  max_splits = scm_to_int (value);
1501 
1502  }
1503  else
1504  {
1505  PERR ("Unknown symbol: %s", symbol);
1506  ok = FALSE;
1507  break;
1508  }
1509 
1510  g_free (symbol);
1511  }
1512 
1513  if (ok)
1514  {
1515  GSList *s1, *s2, *s3;
1516  s1 = gnc_query_sort_to_list (primary_sort);
1517  s2 = gnc_query_sort_to_list (secondary_sort);
1518  s3 = gnc_query_sort_to_list (tertiary_sort);
1519 
1520  qof_query_set_sort_order (q, s1, s2, s3);
1521  qof_query_set_sort_increasing (q, primary_increasing, secondary_increasing,
1522  tertiary_increasing);
1523  qof_query_set_max_results (q, max_splits);
1524  }
1525  else
1526  {
1527  qof_query_destroy (q);
1528  q = nullptr;
1529  }
1530 
1531  g_free (primary_sort);
1532  g_free (secondary_sort);
1533  g_free (tertiary_sort);
1534 
1535  return q;
1536 }
1537 
1538 static QofQuery *
1539 gnc_scm2query_v2 (SCM query_scm)
1540 {
1541  QofQuery *q = nullptr;
1542  gboolean ok = TRUE;
1543  gchar * search_for = nullptr;
1544  GSList *sp1 = nullptr, *sp2 = nullptr, *sp3 = nullptr;
1545  gint so1 = 0, so2 = 0, so3 = 0;
1546  gboolean si1 = TRUE, si2 = TRUE, si3 = TRUE;
1547  int max_results = -1;
1548 
1549  while (!scm_is_null (query_scm))
1550  {
1551  gchar *symbol;
1552  SCM sym_scm;
1553  SCM value;
1554  SCM pair;
1555 
1556  pair = SCM_CAR (query_scm);
1557  query_scm = SCM_CDR (query_scm);
1558 
1559  if (!scm_is_pair (pair))
1560  {
1561  ok = FALSE;
1562  break;
1563  }
1564 
1565  sym_scm = SCM_CAR (pair);
1566  value = SCM_CADR (pair);
1567 
1568  if (!scm_is_symbol (sym_scm))
1569  {
1570  ok = FALSE;
1571  break;
1572  }
1573 
1574  symbol = gnc_scm_symbol_to_locale_string (sym_scm);
1575  if (!symbol)
1576  {
1577  ok = FALSE;
1578  break;
1579  }
1580 
1581  if (!g_strcmp0 ("terms", symbol))
1582  {
1583  if (q)
1584  qof_query_destroy (q);
1585 
1586  q = gnc_scm2query_or_terms (value, gnc_QUERY_v2);
1587  if (!q)
1588  {
1589  ok = FALSE;
1590  break;
1591  }
1592 
1593  }
1594  else if (!g_strcmp0 ("search-for", symbol))
1595  {
1596  if (!scm_is_symbol (value))
1597  {
1598  ok = FALSE;
1599  break;
1600  }
1601  search_for = gnc_scm_symbol_to_locale_string (value);
1602 
1603  }
1604  else if (g_strcmp0 ("primary-sort", symbol) == 0)
1605  {
1606  if (! gnc_query_scm2sort (value, &sp1, &so1, &si1))
1607  {
1608  ok = FALSE;
1609  break;
1610  }
1611 
1612  }
1613  else if (!g_strcmp0 ("secondary-sort", symbol))
1614  {
1615  if (! gnc_query_scm2sort (value, &sp2, &so2, &si2))
1616  {
1617  ok = FALSE;
1618  break;
1619  }
1620 
1621  }
1622  else if (!g_strcmp0 ("tertiary-sort", symbol))
1623  {
1624  if (! gnc_query_scm2sort (value, &sp3, &so3, &si3))
1625  {
1626  ok = FALSE;
1627  break;
1628  }
1629 
1630  }
1631  else if (!g_strcmp0 ("max-results", symbol))
1632  {
1633  if (!scm_is_number (value))
1634  {
1635  ok = FALSE;
1636  break;
1637  }
1638 
1639  max_results = scm_to_int (value);
1640 
1641  }
1642  else
1643  {
1644  ok = FALSE;
1645  break;
1646  }
1647 
1648  g_free (symbol);
1649  }
1650 
1651  if (ok && search_for)
1652  {
1653  qof_query_search_for (q, search_for);
1654  qof_query_set_sort_order (q, sp1, sp2, sp3);
1655  qof_query_set_sort_options (q, so1, so2, so3);
1656  qof_query_set_sort_increasing (q, si1, si2, si3);
1657  qof_query_set_max_results (q, max_results);
1658  }
1659  else
1660  {
1661  qof_query_destroy (q);
1662  q = nullptr;
1663  }
1664 
1665  g_free (search_for);
1666 
1667  return q;
1668 }
1669 
1670 QofQuery *
1671 gnc_scm2query (SCM query_scm)
1672 {
1673  SCM q_type;
1674  gchar *type;
1675  QofQuery *q = nullptr;
1676 
1677  /* Not a list or nullptr? No need to go further */
1678  if (!scm_is_list (query_scm) || scm_is_null (query_scm))
1679  return nullptr;
1680 
1681  /* Grab the 'type' (for v2 and above) */
1682  q_type = SCM_CAR (query_scm);
1683 
1684  if (!scm_is_symbol (q_type))
1685  {
1686  if (scm_is_pair (q_type))
1687  {
1688  /* Version-1 queries are just a list */
1689  return gnc_scm2query_v1 (query_scm);
1690  }
1691  else
1692  {
1693  return nullptr;
1694  }
1695  }
1696 
1697  /* Ok, the LHS is the version and the RHS is the actual query list */
1698  type = gnc_scm_symbol_to_locale_string (q_type);
1699  if (!type)
1700  return nullptr;
1701 
1702  if (!g_strcmp0 (type, "query-v2"))
1703  q = gnc_scm2query_v2 (SCM_CDR (query_scm));
1704 
1705  g_free (type);
1706  return q;
1707 }
1708 
1709 gnc_numeric
1710 gnc_scm_to_numeric(SCM gncnum)
1711 {
1712  SCM num, denom;
1713 
1714  /* Not a number. */
1715  if (!scm_is_number (gncnum))
1717 
1718  num = scm_numerator (gncnum);
1719  denom = scm_denominator (gncnum);
1720 
1721  /* scm overflows 64-bit numbers */
1722  if (!scm_is_signed_integer (num, INT64_MIN, INT64_MAX) ||
1723  !scm_is_signed_integer (denom, INT64_MIN, INT64_MAX))
1725 
1726  return gnc_numeric_create (scm_to_int64 (num), scm_to_int64 (denom));
1727 }
1728 
1729 SCM
1730 gnc_numeric_to_scm(gnc_numeric arg)
1731 {
1732  return gnc_numeric_check (arg) ? SCM_BOOL_F :
1733  scm_divide (scm_from_int64 (arg.num), scm_from_int64 (arg.denom));
1734 }
1735 
1736 static SCM
1737 gnc_generic_to_scm(const void *cx, const gchar *type_str)
1738 {
1739  swig_type_info * stype = nullptr;
1740  void *x = (void*) cx;
1741 
1742  if (!x) return SCM_BOOL_F;
1743  stype = SWIG_TypeQuery(type_str);
1744 
1745  if (!stype)
1746  {
1747  PERR("Unknown SWIG Type: %s ", type_str);
1748  return SCM_BOOL_F;
1749  }
1750 
1751  return SWIG_NewPointerObj(x, stype, 0);
1752 }
1753 
1754 static void *
1755 gnc_scm_to_generic(SCM scm, const gchar *type_str)
1756 {
1757  swig_type_info * stype = nullptr;
1758 
1759  stype = SWIG_TypeQuery(type_str);
1760  if (!stype)
1761  {
1762  PERR("Unknown SWIG Type: %s ", type_str);
1763  return nullptr;
1764  }
1765 
1766  if (!SWIG_IsPointerOfType(scm, stype))
1767  return nullptr;
1768 
1769  return SWIG_MustGetPtr(scm, stype, 1, 0);
1770 }
1771 
1772 gnc_commodity *
1773 gnc_scm_to_commodity(SCM scm)
1774 {
1775  return static_cast<gnc_commodity*>(gnc_scm_to_generic(scm, "_p_gnc_commodity"));
1776 }
1777 
1778 SCM
1779 gnc_commodity_to_scm (const gnc_commodity *commodity)
1780 {
1781  return gnc_generic_to_scm(commodity, "_p_gnc_commodity");
1782 }
1783 
1784 SCM
1785 gnc_book_to_scm (const QofBook *book)
1786 {
1787  return gnc_generic_to_scm(book, "_p_QofBook");
1788 }
1789 
1790 static swig_type_info *
1791 get_acct_type ()
1792 {
1793  static swig_type_info * account_type = nullptr;
1794 
1795  if (!account_type)
1796  account_type = SWIG_TypeQuery("_p_Account");
1797 
1798  return account_type;
1799 }
1800 
1801 GncAccountValue * gnc_scm_to_account_value_ptr (SCM valuearg)
1802 {
1803  GncAccountValue *res;
1804  Account *acc = nullptr;
1805  gnc_numeric value;
1806  swig_type_info * account_type = get_acct_type();
1807  SCM val;
1808 
1809  /* Get the account */
1810  val = SCM_CAR (valuearg);
1811  if (!SWIG_IsPointerOfType (val, account_type))
1812  return nullptr;
1813 
1814  acc = static_cast<Account*>(SWIG_MustGetPtr(val, account_type, 1, 0));
1815 
1816  /* Get the value */
1817  val = SCM_CDR (valuearg);
1818  value = gnc_scm_to_numeric (val);
1819 
1820  /* Build and return the object */
1821  res = g_new0 (GncAccountValue, 1);
1822  res->account = acc;
1823  res->value = value;
1824  return res;
1825 }
1826 
1827 SCM gnc_account_value_ptr_to_scm (GncAccountValue *av)
1828 {
1829  swig_type_info * account_type = get_acct_type();
1830  gnc_commodity * com;
1831  gnc_numeric val;
1832 
1833  if (!av) return SCM_BOOL_F;
1834 
1835  com = xaccAccountGetCommodity (av->account);
1836  val = gnc_numeric_convert (av->value, gnc_commodity_get_fraction (com),
1838 
1839  return scm_cons (SWIG_NewPointerObj(av->account, account_type, 0),
1840  gnc_numeric_to_scm (val));
1841 }
1842 
1843 typedef struct
1844 {
1845  SCM proc;
1846  int num_args;
1847 } GncScmDangler;
1848 
1849 
1850 static void
1851 delete_scm_hook (gpointer data)
1852 {
1853  auto scm = static_cast<GncScmDangler*>(data);
1854  scm_gc_unprotect_object(scm->proc);
1855  g_free(scm);
1856 }
1857 
1858 static void
1859 scm_hook_cb (gpointer data, GncScmDangler *scm)
1860 {
1861  ENTER("data %p, cbarg %p", data, scm);
1862 
1863  if (scm->num_args == 0)
1864  scm_call_0 (scm->proc);
1865  else
1866  {
1867  // XXX: FIXME: We really should make sure this is a session!!! */
1868  scm_call_1 (scm->proc,
1869  SWIG_NewPointerObj(data, SWIG_TypeQuery("_p_QofSession"), 0));
1870  }
1871 
1872  LEAVE("");
1873 }
1874 
1875 void
1876 gnc_hook_add_scm_dangler (const gchar *name, SCM proc)
1877 {
1878  GncScmDangler *scm;
1879  int num_args;
1880 
1881  ENTER("list %s, proc ???", name);
1882  num_args = gnc_hook_num_args(name);
1883  g_return_if_fail(num_args >= 0);
1884  scm = g_new0(GncScmDangler, 1);
1885  scm_gc_protect_object(proc);
1886  scm->proc = proc;
1887  scm->num_args = num_args;
1888  gnc_hook_add_dangler(name, (GFunc)scm_hook_cb,
1889  (GDestroyNotify) delete_scm_hook, scm);
1890  LEAVE("");
1891 }
1892 
1893 time64
1894 gnc_parse_time_to_time64 (const gchar *s, const gchar *format)
1895 {
1896  struct tm tm{};
1897 
1898  g_return_val_if_fail(s && format, -1);
1899 
1900  if (!strptime(s, format, &tm))
1901  return -1;
1902 
1903  return gnc_mktime(&tm);
1904 }
1905 
void qof_query_add_term(QofQuery *q, QofQueryParamList *param_list, QofQueryPredData *pred_data, QofQueryOp op)
This is the general function that adds a new Query Term to a query.
Definition: qofquery.cpp:681
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Date and Time handling routines.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *params1, QofQueryParamList *params2, QofQueryParamList *params3)
When a query is run, the results are sorted before being returned.
Definition: qofquery.cpp:1249
STRUCTS.
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
GDate time64_to_gdate(time64 t)
Returns the GDate in which the time64 occurs.
Definition: gnc-date.cpp:1211
Intermediate result overflow.
Definition: gnc-numeric.h:225
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:173
QofStringMatch
List of known core query data-types...
Definition: qofquerycore.h:70
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
When a query is run, the results are sorted before being returned.
Definition: qofquery.cpp:1280
These expect a single object and expect the QofAccessFunc returns GncGUID*.
Definition: qofquerycore.h:113
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
const char * qof_string_cache_insert(const char *key)
You can use this function with g_hash_table_insert(), for the key (or value), as long as you use the ...
void qof_query_set_max_results(QofQuery *q, int n)
Set the maximum number of results that should be returned.
Definition: qofquery.cpp:1289
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:80
Account handling public routines.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
QofGuidMatch
Definition: qofquerycore.h:109
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition: guid.cpp:104
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code)
Create a gnc_numeric object that signals the error condition noted by error_code, rather than a numbe...
Argument is not a valid number.
Definition: gnc-numeric.h:224
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
Definition: gnc-date.cpp:218
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
Combine two queries together using the Boolean set (logical) operator &#39;op&#39;.
Definition: qofquery.cpp:1129
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
QofQuery * qof_query_invert(QofQuery *q)
Make a copy of the indicated query, inverting the sense of the search.
Definition: qofquery.cpp:1050
All type declarations for the whole Gnucash engine.
These expect a GList* of objects and calls the QofAccessFunc routine on each item in the list to obta...
Definition: qofquerycore.h:118
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3371
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
QofIdType qof_query_get_search_for(const QofQuery *q)
Return the type of data we&#39;re querying for.
Definition: qofquery.cpp:1380
QofDateMatch
Comparisons for QOF_TYPE_DATE The QOF_DATE_MATCH_DAY comparison rounds the two time values to mid-day...
Definition: qofquerycore.h:83
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition: qofquery.h:105
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
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
QofQuery * qof_query_create(void)
Create a new query.
Definition: qofquery.cpp:918
A Query.
Definition: qofquery.cpp:74
void qof_query_search_for(QofQuery *q, QofIdTypeConst obj_type)
Set the object type to be searched for.
Definition: qofquery.cpp:926
void qof_string_cache_remove(const char *key)
You can use this function as a destroy notifier for a GHashTable that uses common strings as keys (or...