GnuCash c935c2f+
Loading...
Searching...
No Matches
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
55static QofLogModule log_module = GNC_MOD_ENGINE;
56
57
58GDate gnc_time64_to_GDate(SCM x)
59{
60 time64 time = scm_to_int64 (x);
61 return time64_to_gdate(time);
62}
63
64SCM
65gnc_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
76gnc_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
92int
93gnc_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
140typedef enum
141{
142 gnc_QUERY_v1 = 1,
143 gnc_QUERY_v2
144} query_version_t;
145
146/* QofCompareFunc */
147
148static QofQueryCompare
149gnc_query_scm2compare (SCM how_scm)
150{
151 return static_cast<QofQueryCompare>(scm_to_int(how_scm));
152}
153
154/* QofStringMatch */
155static QofStringMatch
156gnc_query_scm2string (SCM how_scm)
157{
158 return static_cast<QofStringMatch>(scm_to_int(how_scm));
159}
160
161/* QofDateMatch */
162static QofDateMatch
163gnc_query_scm2date (SCM how_scm)
164{
165 return static_cast<QofDateMatch>(scm_to_int(how_scm));
166}
167
168/* QofNumericMatch */
169static QofNumericMatch
170gnc_query_scm2numericop (SCM how_scm)
171{
172 return static_cast<QofNumericMatch>(scm_to_int(how_scm));
173}
174
175/* QofGuidMatch */
176static QofGuidMatch
177gnc_query_scm2guid (SCM how_scm)
178{
179 return static_cast<QofGuidMatch>(scm_to_int(how_scm));
180}
181
182/* QofCharMatch */
183static QofCharMatch
184gnc_query_scm2char (SCM how_scm)
185{
186 return static_cast<QofCharMatch>(scm_to_int(how_scm));
187}
188
189static QofGuidMatch
190gnc_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
211static QofQueryCompare
212gnc_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
233static int
234gnc_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
256static cleared_match_t
257gnc_scm2cleared_match_how (SCM how_scm)
258{
259 return static_cast<cleared_match_t>(gnc_scm2bitfield (how_scm));
260}
261
262static gboolean
263gnc_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
288static SCM
289gnc_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
305static GList *
306gnc_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
332static inline void
333gnc_guid_glist_free (GList *guids)
334{
335 g_list_free_full (guids, (GDestroyNotify)guid_free);
336}
337
338static SCM
339gnc_query_numeric2scm (gnc_numeric val)
340{
341 return scm_cons (scm_from_int64 (val.num),
342 scm_from_int64 (val.denom));
343}
344
345static gboolean
346gnc_query_numeric_p (SCM pair)
347{
348 return (scm_is_pair (pair));
349}
350
351static gnc_numeric
352gnc_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
364static SCM
365gnc_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
381GSList *
382gnc_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
404static void
405gnc_query_path_free (GSList *path)
406{
407 g_slist_free_full (path, (GDestroyNotify)qof_string_cache_remove);
408}
409
410
411static SCM
412gnc_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
496static QofQuery *
497gnc_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);
700 q = outq;
701 }
702 }
703 else
704 {
705 gnc_query_path_free (path);
706 }
707
708 return q;
709}
710
711static QofQuery *
712gnc_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);
1026 }
1027
1028 return out_q;
1029 }
1030
1032 return nullptr;
1033}
1034
1035static QofQuery *
1036gnc_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
1049static SCM
1050gnc_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
1078static QofQuery *
1079gnc_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 {
1110 q = q_new;
1111 }
1112 }
1113 }
1114 }
1115
1116 return q;
1117}
1118
1119static QofQuery *
1120gnc_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 {
1153 q = q_new;
1154 }
1155 }
1156 }
1157 }
1158
1159 return q;
1160}
1161
1162static SCM
1163gnc_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
1179static gboolean
1180gnc_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
1238SCM
1239gnc_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
1285static GSList *
1286gnc_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
1378static QofQuery *
1379gnc_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)
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 {
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
1538static QofQuery *
1539gnc_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)
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 {
1662 q = nullptr;
1663 }
1664
1665 g_free (search_for);
1666
1667 return q;
1668}
1669
1670QofQuery *
1671gnc_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
1709gnc_numeric
1710gnc_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
1729SCM
1730gnc_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
1736static swig_type_info*
1737get_swig_type (const gchar *type_str)
1738{
1739 auto type = SWIG_TypeQuery (type_str);
1740 if (!type)
1741 PERR("Unknown SWIG Type: %s ", type_str);
1742 return type;
1743}
1744
1745static SCM
1746gnc_generic_to_scm (const void *cx, swig_type_info* stype)
1747{
1748 void *x = (void*) cx;
1749 if (!x || !stype) return SCM_BOOL_F;
1750
1751 return SWIG_NewPointerObj(x, stype, 0);
1752}
1753
1754static void *
1755gnc_scm_to_generic (SCM scm, swig_type_info* stype)
1756{
1757 if (!stype || !SWIG_IsPointerOfType(scm, stype))
1758 return nullptr;
1759
1760 return SWIG_MustGetPtr(scm, stype, 1, 0);
1761}
1762
1763gnc_commodity *
1764gnc_scm_to_commodity(SCM scm)
1765{
1766 static auto stype = get_swig_type ("_p_gnc_commodity");
1767 return GNC_COMMODITY (gnc_scm_to_generic (scm, stype));
1768}
1769
1770SCM
1771gnc_commodity_to_scm (const gnc_commodity *commodity)
1772{
1773 static auto stype = get_swig_type ("_p_gnc_commodity");
1774 return gnc_generic_to_scm (commodity, stype);
1775}
1776
1777SCM
1778gnc_book_to_scm (const QofBook *book)
1779{
1780 static auto stype = get_swig_type ("_p_QofBook");
1781 return gnc_generic_to_scm (book, stype);
1782}
1783
1784SCM
1785gnc_split_to_scm (const Split *split)
1786{
1787 static auto stype = get_swig_type ("_p_Split");
1788 return gnc_generic_to_scm (split, stype);
1789}
1790
1791GncAccountValue * gnc_scm_to_account_value_ptr (SCM valuearg)
1792{
1793 GncAccountValue *res;
1794 Account *acc = nullptr;
1795 gnc_numeric value;
1796 static auto account_type = get_swig_type ("_p_Account");
1797 SCM val;
1798
1799 /* Get the account */
1800 val = SCM_CAR (valuearg);
1801 if (!SWIG_IsPointerOfType (val, account_type))
1802 return nullptr;
1803
1804 acc = static_cast<Account*>(SWIG_MustGetPtr(val, account_type, 1, 0));
1805
1806 /* Get the value */
1807 val = SCM_CDR (valuearg);
1808 value = gnc_scm_to_numeric (val);
1809
1810 /* Build and return the object */
1811 res = g_new0 (GncAccountValue, 1);
1812 res->account = acc;
1813 res->value = value;
1814 return res;
1815}
1816
1817SCM gnc_account_value_ptr_to_scm (GncAccountValue *av)
1818{
1819 static auto account_type = get_swig_type ("_p_Account");
1820 gnc_commodity * com;
1821 gnc_numeric val;
1822
1823 if (!av) return SCM_BOOL_F;
1824
1825 com = xaccAccountGetCommodity (av->account);
1826 val = gnc_numeric_convert (av->value, gnc_commodity_get_fraction (com),
1827 GNC_HOW_RND_ROUND_HALF_UP);
1828
1829 return scm_cons (SWIG_NewPointerObj(av->account, account_type, 0),
1830 gnc_numeric_to_scm (val));
1831}
1832
1833typedef struct
1834{
1835 SCM proc;
1836 int num_args;
1838
1839
1840static void
1841delete_scm_hook (gpointer data)
1842{
1843 auto scm = static_cast<GncScmDangler*>(data);
1844 scm_gc_unprotect_object(scm->proc);
1845 g_free(scm);
1846}
1847
1848static void
1849scm_hook_cb (gpointer data, GncScmDangler *scm)
1850{
1851 ENTER("data %p, cbarg %p", data, scm);
1852
1853 if (scm->num_args == 0)
1854 scm_call_0 (scm->proc);
1855 else
1856 {
1857 static auto stype = get_swig_type ("_p_QofSession");
1858 // XXX: FIXME: We really should make sure this is a session!!! */
1859 scm_call_1 (scm->proc, SWIG_NewPointerObj(data, stype, 0));
1860 }
1861
1862 LEAVE("");
1863}
1864
1865void
1866gnc_hook_add_scm_dangler (const gchar *name, SCM proc)
1867{
1868 GncScmDangler *scm;
1869 int num_args;
1870
1871 ENTER("list %s, proc ???", name);
1872 num_args = gnc_hook_num_args(name);
1873 g_return_if_fail(num_args >= 0);
1874 scm = g_new0(GncScmDangler, 1);
1875 scm_gc_protect_object(proc);
1876 scm->proc = proc;
1877 scm->num_args = num_args;
1878 gnc_hook_add_dangler(name, (GFunc)scm_hook_cb,
1879 (GDestroyNotify) delete_scm_hook, scm);
1880 LEAVE("");
1881}
1882
1883time64
1884gnc_parse_time_to_time64 (const gchar *s, const gchar *format)
1885{
1886 struct tm tm{};
1887
1888 g_return_val_if_fail(s && format, -1);
1889
1890 if (!strptime(s, format, &tm))
1891 return -1;
1892
1893 return gnc_mktime(&tm);
1894}
1895
Account handling public routines.
Date and Time handling routines.
All type declarations for the whole Gnucash engine.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
Definition gnc-date.cpp:219
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
GDate time64_to_gdate(time64 t)
Returns the GDate in which the time64 occurs.
const gchar * QofIdType
QofIdType declaration.
Definition qofid.h:80
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition guid.cpp:165
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition guid.cpp:139
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:208
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
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...
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
@ GNC_ERROR_OVERFLOW
Intermediate result overflow.
@ GNC_ERROR_ARG
Argument is not a valid number.
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
QofNumericMatch
Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED.
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
Combine two queries together using the Boolean set (logical) operator 'op'.
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition qofquery.h:105
QofDateMatch
Comparisons for QOF_TYPE_DATE The QOF_DATE_MATCH_DAY comparison rounds the two time values to mid-day...
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.
QofCharMatch
A CHAR type is for a RECNCell, Comparisons for QOF_TYPE_CHAR 'ANY' will match any character in the st...
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.
QofQuery * qof_query_invert(QofQuery *q)
Make a copy of the indicated query, inverting the sense of the search.
QofGuidMatch
QofStringMatch
List of known core query data-types... Each core query type defines it's set of optional "comparator ...
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
QofQuery * qof_query_create(void)
Create a new query.
Definition qofquery.cpp:918
void qof_query_search_for(QofQuery *q, QofIdTypeConst obj_type)
Set the object type to be searched for.
Definition qofquery.cpp:926
QofQueryCompare
Standard Query comparators, for how to compare objects in a predicate.
QofIdType qof_query_get_search_for(const QofQuery *q)
Return the type of data we're querying for.
void qof_query_set_max_results(QofQuery *q, int n)
Set the maximum number of results that should be returned.
@ QOF_GUID_MATCH_ALL
These expect a GList* of objects and calls the QofAccessFunc routine on each item in the list to obta...
@ QOF_GUID_MATCH_ANY
These expect a single object and expect the QofAccessFunc returns GncGUID*.
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_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...
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
A Query.
Definition qofquery.cpp:75