mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-26 19:00:18 -06:00
bf55c30aeb
There are a very few left that need deeper study, but this gets rid of most of the noise. For the most part it's just getting rid of extra variables or removing an assignment that is always replaced later but before any reads of the variable. A few are discarded result variables.
1991 lines
50 KiB
C
1991 lines
50 KiB
C
/********************************************************************\
|
|
* engine-helpers.c -- gnucash engine helper functions *
|
|
* Copyright (C) 2000 Linas Vepstas <linas@linas.org> *
|
|
* Copyright (C) 2001 Linux Developers Group, Inc. *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License*
|
|
* along with this program; if not, contact: *
|
|
* *
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
* *
|
|
\********************************************************************/
|
|
|
|
#include <config.h>
|
|
|
|
#include "swig-runtime.h"
|
|
#include <libguile.h>
|
|
#include <string.h>
|
|
|
|
#include "Account.h"
|
|
#include "engine-helpers.h"
|
|
#include "engine-helpers-guile.h"
|
|
#include "glib-helpers.h"
|
|
#include "gnc-date.h"
|
|
#include "gnc-engine.h"
|
|
#include "gnc-session.h"
|
|
#include "guile-mappings.h"
|
|
#include "gnc-guile-utils.h"
|
|
#include <qof.h>
|
|
#include <qofbookslots.h>
|
|
|
|
/** \todo Code dependent on the private query headers
|
|
qofquery-p.h and qofquerycore-p.h may need to be modified.
|
|
These files are temporarily exported for QOF 0.6.0 but
|
|
cannot be considered "standard" or public parts of QOF. */
|
|
#include "qofquery-p.h"
|
|
#include "qofquerycore-p.h"
|
|
|
|
#define FUNC_NAME G_STRFUNC
|
|
|
|
static QofLogModule log_module = GNC_MOD_ENGINE;
|
|
|
|
/** Gets the transaction Number or split Action based on book option:
|
|
* if the book option is TRUE (split action is used for NUM) and a
|
|
* split is provided, split-action is returned; if book option is FALSE
|
|
* (tran-num is used for NUM) and a trans is provided, transaction-num
|
|
* is returned; if split is provided and tran is NULL, split-action is
|
|
* returned; if tran is provided and split is NULL, transaction-num is
|
|
* returned. Otherwise NULL is returned.*/
|
|
const char *
|
|
gnc_get_num_action (const Transaction *trans, const Split *split)
|
|
{
|
|
gboolean num_action = qof_book_use_split_action_for_num_field
|
|
(qof_session_get_book(gnc_get_current_session ()));
|
|
|
|
if (trans && !split)
|
|
return xaccTransGetNum(trans);
|
|
if (split && !trans)
|
|
return xaccSplitGetAction(split);
|
|
if (trans && split)
|
|
{
|
|
if (num_action)
|
|
return xaccSplitGetAction(split);
|
|
else
|
|
return xaccTransGetNum(trans);
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
/** Opposite of 'gnc_get_num_action'; if the book option is TRUE (split action
|
|
* is used for NUM) and a trans is provided, transaction-num is returned; if
|
|
* book option is FALSE (tran-num is used for NUM) and a split is provided,
|
|
* split-action is returned; if split is provided and tran is NULL,
|
|
* split-action is returned; if tran is provided and split is NULL,
|
|
* transaction-num is returned. Otherwise NULL is returned.*/
|
|
const char *
|
|
gnc_get_action_num (const Transaction *trans, const Split *split)
|
|
{
|
|
gboolean num_action = qof_book_use_split_action_for_num_field
|
|
(qof_session_get_book(gnc_get_current_session ()));
|
|
|
|
if (trans && !split)
|
|
return xaccTransGetNum(trans);
|
|
if (split && !trans)
|
|
return xaccSplitGetAction(split);
|
|
if (trans && split)
|
|
{
|
|
if (num_action)
|
|
return xaccTransGetNum(trans);
|
|
else
|
|
return xaccSplitGetAction(split);
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
/** Sets the transaction Number and/or split Action based on book option:
|
|
* if the book option is TRUE (split action is to be used for NUM) then 'num'
|
|
* sets split-action and, if 'tran' and 'action' are provided, 'action'
|
|
* sets transaction-num; if book option is FALSE (tran-num is to be used for NUM)
|
|
* then 'num' sets transaction-num and, if 'split' and 'action' are
|
|
* provided, 'action' sets 'split-action'. If any arguments are NULL (#f, for
|
|
* the guile version), no change is made to the field that would otherwise be
|
|
* affected. If 'tran' and 'num' are passed with 'split and 'action' set to
|
|
* NULL, it is xaccTransSetNum (trans, num). Likewise, if 'split and 'action'
|
|
* are passed with 'tran' and 'num' set to NULL, it is xaccSplitSetAction (split,
|
|
* action). */
|
|
void
|
|
gnc_set_num_action (Transaction *trans, Split *split,
|
|
const char *num, const char *action)
|
|
{
|
|
gboolean num_action = qof_book_use_split_action_for_num_field
|
|
(qof_session_get_book(gnc_get_current_session ()));
|
|
|
|
if (trans && num && !split && !action)
|
|
{
|
|
xaccTransSetNum (trans, num);
|
|
return;
|
|
}
|
|
|
|
if (!trans && !num && split && action)
|
|
{
|
|
xaccSplitSetAction (split, action);
|
|
return;
|
|
}
|
|
|
|
if (trans)
|
|
{
|
|
if (!num_action && num)
|
|
xaccTransSetNum (trans, num);
|
|
if (num_action && action)
|
|
xaccTransSetNum (trans, action);
|
|
}
|
|
|
|
if (split)
|
|
{
|
|
if (!num_action && action)
|
|
xaccSplitSetAction (split, action);
|
|
if (num_action && num)
|
|
xaccSplitSetAction (split, num);
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
/* Notification of Book Option Changes */
|
|
/************************************************************/
|
|
|
|
static GOnce bo_init_once = G_ONCE_INIT;
|
|
static GHashTable *bo_callback_hash = NULL;
|
|
static GHookList *bo_final_hook_list = NULL;
|
|
|
|
static gpointer
|
|
bo_init (gpointer unused)
|
|
{
|
|
bo_callback_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
|
|
bo_final_hook_list = g_malloc(sizeof(GHookList));
|
|
g_hook_list_init(bo_final_hook_list, sizeof(GHook));
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
bo_call_hook (GHook *hook, gpointer data)
|
|
{
|
|
((GFunc)hook->func)(data, hook->data);
|
|
}
|
|
|
|
/** Calls registered callbacks when num_field_source book option changes so that
|
|
* registers/reports can update themselves */
|
|
void
|
|
gnc_book_option_num_field_source_change (gboolean num_action)
|
|
{
|
|
GHookList *hook_list;
|
|
const gchar *key = OPTION_NAME_NUM_FIELD_SOURCE;
|
|
|
|
g_once(&bo_init_once, bo_init, NULL);
|
|
|
|
hook_list = g_hash_table_lookup(bo_callback_hash, key);
|
|
if (hook_list != NULL)
|
|
g_hook_list_marshal(hook_list, TRUE, bo_call_hook, &num_action);
|
|
g_hook_list_invoke(bo_final_hook_list, TRUE);
|
|
}
|
|
|
|
/** Calls registered callbacks when book_currency book option changes so that
|
|
* registers/reports can update themselves */
|
|
void
|
|
gnc_book_option_book_currency_selected (gboolean use_book_currency)
|
|
{
|
|
GHookList *hook_list;
|
|
const gchar *key = OPTION_NAME_BOOK_CURRENCY;
|
|
|
|
g_once(&bo_init_once, bo_init, NULL);
|
|
|
|
hook_list = g_hash_table_lookup(bo_callback_hash, key);
|
|
if (hook_list != NULL)
|
|
g_hook_list_marshal(hook_list, TRUE, bo_call_hook, &use_book_currency);
|
|
g_hook_list_invoke(bo_final_hook_list, TRUE);
|
|
}
|
|
|
|
void
|
|
gnc_book_option_register_cb (gchar *key, GncBOCb func, gpointer user_data)
|
|
{
|
|
GHookList *hook_list;
|
|
GHook *hook;
|
|
|
|
g_once(&bo_init_once, bo_init, NULL);
|
|
hook_list = g_hash_table_lookup(bo_callback_hash, key);
|
|
if (hook_list == NULL)
|
|
{
|
|
hook_list = g_malloc(sizeof(GHookList));
|
|
g_hook_list_init(hook_list, sizeof(GHook));
|
|
g_hash_table_insert(bo_callback_hash, (gpointer)key, hook_list);
|
|
}
|
|
|
|
hook = g_hook_find_func_data(hook_list, TRUE, func, user_data);
|
|
if (hook != NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
hook = g_hook_alloc(hook_list);
|
|
hook->func = func;
|
|
hook->data = user_data;
|
|
g_hook_append(hook_list, hook);
|
|
}
|
|
|
|
void
|
|
gnc_book_option_remove_cb (gchar *key, GncBOCb func, gpointer user_data)
|
|
{
|
|
GHookList *hook_list;
|
|
GHook *hook;
|
|
|
|
g_once(&bo_init_once, bo_init, NULL);
|
|
hook_list = g_hash_table_lookup(bo_callback_hash, key);
|
|
if (hook_list == NULL)
|
|
return;
|
|
hook = g_hook_find_func_data(hook_list, TRUE, func, user_data);
|
|
if (hook == NULL)
|
|
return;
|
|
|
|
g_hook_destroy_link(hook_list, hook);
|
|
if (hook_list->hooks == NULL)
|
|
{
|
|
g_hash_table_remove(bo_callback_hash, key);
|
|
g_free(hook_list);
|
|
}
|
|
}
|
|
|
|
|
|
GDate gnc_time64_to_GDate(SCM x)
|
|
{
|
|
time64 time = scm_to_int64 (x);
|
|
return time64_to_gdate(time);
|
|
}
|
|
|
|
SCM
|
|
gnc_guid2scm(GncGUID guid)
|
|
{
|
|
char string[GUID_ENCODING_LENGTH + 1];
|
|
|
|
if (!guid_to_string_buff(&guid, string))
|
|
return SCM_BOOL_F;
|
|
|
|
return scm_from_utf8_string(string);
|
|
}
|
|
|
|
GncGUID
|
|
gnc_scm2guid(SCM guid_scm)
|
|
{
|
|
GncGUID guid;
|
|
gchar * str;
|
|
|
|
if (!scm_is_string(guid_scm)
|
|
|| (GUID_ENCODING_LENGTH != scm_c_string_length (guid_scm)))
|
|
{
|
|
return *guid_null();
|
|
}
|
|
str = gnc_scm_to_utf8_string (guid_scm);
|
|
string_to_guid(str, &guid);
|
|
g_free (str);
|
|
return guid;
|
|
}
|
|
|
|
int
|
|
gnc_guid_p(SCM guid_scm)
|
|
{
|
|
GncGUID guid;
|
|
gchar * str;
|
|
int return_int;
|
|
|
|
if (!scm_is_string(guid_scm))
|
|
return FALSE;
|
|
|
|
if (GUID_ENCODING_LENGTH != scm_c_string_length (guid_scm))
|
|
{
|
|
return FALSE;
|
|
}
|
|
str = gnc_scm_to_utf8_string (guid_scm);
|
|
return_int = string_to_guid(str, &guid);
|
|
g_free (str);
|
|
return return_int;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* type converters for query API
|
|
********************************************************************/
|
|
|
|
/* The query scm representation is a list of pairs, where the
|
|
* car of each pair is one of the following symbols:
|
|
*
|
|
* Symbol cdr
|
|
* 'terms list of OR terms
|
|
* 'primary-sort scm rep of sort_type_t
|
|
* 'secondary-sort scm rep of sort_type_t
|
|
* 'tertiary-sort scm rep of sort_type_t
|
|
* 'primary-increasing boolean
|
|
* 'secondary-increasing boolean
|
|
* 'tertiary-increasing boolean
|
|
* 'max-splits integer
|
|
*
|
|
* Each OR term is a list of AND terms.
|
|
* Each AND term is a list of one of the following forms:
|
|
*
|
|
* ('pd-amount pr-type sense-bool amt-match-how amt-match-sign amount)
|
|
* ('pd-account pr-type sense-bool acct-match-how list-of-account-guids)
|
|
* ('pd-string pr-type sense-bool case-sense-bool use-regexp-bool string)
|
|
* ('pd-cleared pr-type sense-bool cleared-field)
|
|
* ('pd-balance pr-type sense-bool balance-field)
|
|
*/
|
|
|
|
typedef enum
|
|
{
|
|
gnc_QUERY_v1 = 1,
|
|
gnc_QUERY_v2
|
|
} query_version_t;
|
|
|
|
/* QofCompareFunc */
|
|
|
|
static QofQueryCompare
|
|
gnc_query_scm2compare (SCM how_scm)
|
|
{
|
|
return scm_to_int(how_scm);
|
|
}
|
|
|
|
/* QofStringMatch */
|
|
static QofStringMatch
|
|
gnc_query_scm2string (SCM how_scm)
|
|
{
|
|
return scm_to_int(how_scm);
|
|
}
|
|
|
|
/* QofDateMatch */
|
|
static QofDateMatch
|
|
gnc_query_scm2date (SCM how_scm)
|
|
{
|
|
return scm_to_int(how_scm);
|
|
}
|
|
|
|
/* QofNumericMatch */
|
|
static QofNumericMatch
|
|
gnc_query_scm2numericop (SCM how_scm)
|
|
{
|
|
return scm_to_int(how_scm);
|
|
}
|
|
|
|
/* QofGuidMatch */
|
|
static QofGuidMatch
|
|
gnc_query_scm2guid (SCM how_scm)
|
|
{
|
|
return scm_to_int(how_scm);
|
|
}
|
|
|
|
/* QofCharMatch */
|
|
static QofCharMatch
|
|
gnc_query_scm2char (SCM how_scm)
|
|
{
|
|
return scm_to_int(how_scm);
|
|
}
|
|
|
|
static QofGuidMatch
|
|
gnc_scm2acct_match_how (SCM how_scm)
|
|
{
|
|
QofGuidMatch res;
|
|
gchar *how = gnc_scm_symbol_to_locale_string (how_scm);
|
|
|
|
if (!g_strcmp0 (how, "acct-match-all"))
|
|
res = QOF_GUID_MATCH_ALL;
|
|
else if (!g_strcmp0 (how, "acct-match-any"))
|
|
res = QOF_GUID_MATCH_ANY;
|
|
else if (!g_strcmp0 (how, "acct-match-none"))
|
|
res = QOF_GUID_MATCH_NONE;
|
|
else
|
|
{
|
|
PINFO ("invalid account match: %s", how);
|
|
res = QOF_GUID_MATCH_NULL;
|
|
}
|
|
|
|
g_free (how);
|
|
return res;
|
|
}
|
|
|
|
static QofQueryCompare
|
|
gnc_scm2amt_match_how (SCM how_scm)
|
|
{
|
|
QofQueryCompare res;
|
|
gchar *how = gnc_scm_symbol_to_locale_string (how_scm);
|
|
|
|
if (!g_strcmp0 (how, "amt-match-atleast"))
|
|
res = QOF_COMPARE_GTE;
|
|
else if (!g_strcmp0 (how, "amt-match-atmost"))
|
|
res = QOF_COMPARE_LTE;
|
|
else if (!g_strcmp0 (how, "amt-match-exactly"))
|
|
res = QOF_COMPARE_EQUAL;
|
|
else
|
|
{
|
|
PINFO ("invalid amount match: %s", how);
|
|
res = QOF_COMPARE_EQUAL;
|
|
}
|
|
|
|
g_free (how);
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
gnc_scm2bitfield (SCM field_scm)
|
|
{
|
|
int field = 0;
|
|
|
|
if (!scm_is_list (field_scm))
|
|
return 0;
|
|
|
|
while (!scm_is_null (field_scm))
|
|
{
|
|
SCM scm;
|
|
int bit;
|
|
|
|
scm = SCM_CAR (field_scm);
|
|
field_scm = SCM_CDR (field_scm);
|
|
|
|
bit = scm_to_int(scm);
|
|
field |= bit;
|
|
}
|
|
|
|
return field;
|
|
}
|
|
|
|
static cleared_match_t
|
|
gnc_scm2cleared_match_how (SCM how_scm)
|
|
{
|
|
return gnc_scm2bitfield (how_scm);
|
|
}
|
|
|
|
static gboolean
|
|
gnc_scm2balance_match_how (SCM how_scm, gboolean *resp)
|
|
{
|
|
gchar *how;
|
|
|
|
if (!scm_is_list (how_scm))
|
|
return FALSE;
|
|
|
|
if (scm_is_null (how_scm))
|
|
return FALSE;
|
|
|
|
/* Only allow a single-entry list */
|
|
if (!scm_is_null (SCM_CDR (how_scm)))
|
|
return FALSE;
|
|
|
|
how = gnc_scm_symbol_to_locale_string (SCM_CAR(how_scm));
|
|
|
|
if (!g_strcmp0 (how, "balance-match-balanced"))
|
|
*resp = TRUE;
|
|
else
|
|
*resp = FALSE;
|
|
|
|
g_free (how);
|
|
return TRUE;
|
|
}
|
|
|
|
static SCM
|
|
gnc_guid_glist2scm (const GList *account_guids)
|
|
{
|
|
SCM guids = SCM_EOL;
|
|
const GList *node;
|
|
|
|
for (node = account_guids; node; node = node->next)
|
|
{
|
|
GncGUID *guid = node->data;
|
|
|
|
if (guid)
|
|
guids = scm_cons (gnc_guid2scm (*guid), guids);
|
|
}
|
|
|
|
return scm_reverse (guids);
|
|
}
|
|
|
|
static GList *
|
|
gnc_scm2guid_glist (SCM guids_scm)
|
|
{
|
|
GList *guids = NULL;
|
|
|
|
if (!scm_is_list (guids_scm))
|
|
return NULL;
|
|
|
|
while (!scm_is_null (guids_scm))
|
|
{
|
|
SCM guid_scm = SCM_CAR (guids_scm);
|
|
GncGUID *guid = NULL;
|
|
|
|
if (guid_scm != SCM_BOOL_F)
|
|
{
|
|
guid = guid_malloc ();
|
|
*guid = gnc_scm2guid (guid_scm);
|
|
}
|
|
|
|
guids = g_list_prepend (guids, guid);
|
|
|
|
guids_scm = SCM_CDR (guids_scm);
|
|
}
|
|
|
|
return g_list_reverse (guids);
|
|
}
|
|
|
|
static void
|
|
gnc_guid_glist_free (GList *guids)
|
|
{
|
|
GList *node;
|
|
|
|
for (node = guids; node; node = node->next)
|
|
guid_free (node->data);
|
|
|
|
g_list_free (guids);
|
|
}
|
|
|
|
static SCM
|
|
gnc_query_numeric2scm (gnc_numeric val)
|
|
{
|
|
return scm_cons (scm_from_int64 (val.num),
|
|
scm_from_int64 (val.denom));
|
|
}
|
|
|
|
static gboolean
|
|
gnc_query_numeric_p (SCM pair)
|
|
{
|
|
return (scm_is_pair (pair));
|
|
}
|
|
|
|
static gnc_numeric
|
|
gnc_query_scm2numeric (SCM pair)
|
|
{
|
|
SCM denom;
|
|
SCM num;
|
|
|
|
num = SCM_CAR (pair);
|
|
denom = SCM_CDR (pair);
|
|
|
|
return gnc_numeric_create (scm_to_int64 (num),
|
|
scm_to_int64 (denom));
|
|
}
|
|
|
|
static SCM
|
|
gnc_query_path2scm (const GSList *path)
|
|
{
|
|
SCM path_scm = SCM_EOL;
|
|
const GSList *node;
|
|
|
|
for (node = path; node; node = node->next)
|
|
{
|
|
const char *key = node->data;
|
|
|
|
if (key)
|
|
path_scm = scm_cons (scm_from_utf8_string (key), path_scm);
|
|
}
|
|
|
|
return scm_reverse (path_scm);
|
|
}
|
|
|
|
GSList *
|
|
gnc_query_scm2path (SCM path_scm)
|
|
{
|
|
GSList *path = NULL;
|
|
|
|
if (!scm_is_list (path_scm))
|
|
return NULL;
|
|
|
|
while (!scm_is_null (path_scm))
|
|
{
|
|
SCM key_scm = SCM_CAR (path_scm);
|
|
char *key;
|
|
|
|
if (!scm_is_string (key_scm))
|
|
break;
|
|
|
|
key = gnc_scm_to_utf8_string(key_scm);
|
|
path = g_slist_prepend (path, key);
|
|
path_scm = SCM_CDR (path_scm);
|
|
}
|
|
|
|
return g_slist_reverse (path);
|
|
}
|
|
|
|
static void
|
|
gnc_query_path_free (GSList *path)
|
|
{
|
|
GSList *node;
|
|
|
|
for (node = path; node; node = node->next)
|
|
g_free (node->data);
|
|
|
|
g_slist_free (path);
|
|
}
|
|
|
|
|
|
static SCM
|
|
gnc_queryterm2scm (const QofQueryTerm *qt)
|
|
{
|
|
SCM qt_scm = SCM_EOL;
|
|
QofQueryPredData *pd = NULL;
|
|
|
|
qt_scm = scm_cons (gnc_query_path2scm (qof_query_term_get_param_path (qt)),
|
|
qt_scm);
|
|
qt_scm = scm_cons (SCM_BOOL (qof_query_term_is_inverted (qt)), qt_scm);
|
|
|
|
pd = qof_query_term_get_pred_data (qt);
|
|
qt_scm = scm_cons (scm_from_locale_symbol (pd->type_name), qt_scm);
|
|
qt_scm = scm_cons (scm_from_long (pd->how), qt_scm);
|
|
|
|
if (!g_strcmp0 (pd->type_name, QOF_TYPE_STRING))
|
|
{
|
|
query_string_t pdata = (query_string_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
|
|
qt_scm = scm_cons (SCM_BOOL (pdata->is_regex), qt_scm);
|
|
qt_scm = scm_cons (pdata->matchstring ? scm_from_utf8_string (pdata->matchstring) : SCM_BOOL_F, qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_DATE))
|
|
{
|
|
query_date_t pdata = (query_date_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
|
|
qt_scm = scm_cons (scm_from_int64 (pdata->date), qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_NUMERIC))
|
|
{
|
|
query_numeric_t pdata = (query_numeric_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
|
|
qt_scm = scm_cons (gnc_query_numeric2scm (pdata->amount), qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_GUID))
|
|
{
|
|
query_guid_t pdata = (query_guid_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
|
|
qt_scm = scm_cons (gnc_guid_glist2scm (pdata->guids), qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_INT64))
|
|
{
|
|
query_int64_t pdata = (query_int64_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_int64 (pdata->val), qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_DOUBLE))
|
|
{
|
|
query_double_t pdata = (query_double_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_double (pdata->val), qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_BOOLEAN))
|
|
{
|
|
query_boolean_t pdata = (query_boolean_t) pd;
|
|
|
|
qt_scm = scm_cons (SCM_BOOL (pdata->val), qt_scm);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd->type_name, QOF_TYPE_CHAR))
|
|
{
|
|
query_char_t pdata = (query_char_t) pd;
|
|
|
|
qt_scm = scm_cons (scm_from_long (pdata->options), qt_scm);
|
|
qt_scm = scm_cons (pdata->char_list ? scm_from_utf8_string (pdata->char_list) : SCM_BOOL_F, qt_scm);
|
|
|
|
}
|
|
else
|
|
{
|
|
PWARN ("query core type %s not supported", pd->type_name);
|
|
return SCM_BOOL_F;
|
|
}
|
|
|
|
return scm_reverse (qt_scm);
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_term_query_v2 (SCM qt_scm)
|
|
{
|
|
QofQuery *q = NULL;
|
|
QofQueryPredData *pd = NULL;
|
|
SCM scm;
|
|
gchar *type = NULL;
|
|
GSList *path = NULL;
|
|
gboolean inverted = FALSE;
|
|
QofQueryCompare compare_how;
|
|
|
|
if (!scm_is_list (qt_scm) || scm_is_null (qt_scm))
|
|
return NULL;
|
|
|
|
do
|
|
{
|
|
/* param path */
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (!scm_is_list (scm))
|
|
break;
|
|
path = gnc_query_scm2path (scm);
|
|
|
|
/* inverted */
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (!scm_is_bool (scm))
|
|
break;
|
|
inverted = scm_is_true (scm);
|
|
|
|
/* type */
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (!scm_is_symbol (scm))
|
|
break;
|
|
type = gnc_scm_symbol_to_locale_string (scm);
|
|
|
|
/* QofCompareFunc */
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
compare_how = gnc_query_scm2compare (scm);
|
|
|
|
/* Now compute the predicate */
|
|
|
|
if (!g_strcmp0 (type, QOF_TYPE_STRING))
|
|
{
|
|
QofStringMatch options;
|
|
gboolean is_regex;
|
|
gchar *matchstring;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (scm_is_null (scm)) break;
|
|
options = gnc_query_scm2string (scm);
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (!scm_is_bool (scm)) break;
|
|
is_regex = scm_is_true (scm);
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (!scm_is_string (scm)) break;
|
|
|
|
matchstring = gnc_scm_to_utf8_string (scm);
|
|
|
|
pd = qof_query_string_predicate (compare_how, matchstring,
|
|
options, is_regex);
|
|
g_free (matchstring);
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_DATE))
|
|
{
|
|
QofDateMatch options;
|
|
time64 date;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
options = gnc_query_scm2date (scm);
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
date = scm_to_int64 (scm);
|
|
|
|
pd = qof_query_date_predicate (compare_how, options, date);
|
|
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_NUMERIC))
|
|
{
|
|
QofNumericMatch options;
|
|
gnc_numeric val;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
options = gnc_query_scm2numericop (scm);
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (!gnc_query_numeric_p (scm))
|
|
break;
|
|
val = gnc_query_scm2numeric (scm);
|
|
|
|
pd = qof_query_numeric_predicate (compare_how, options, val);
|
|
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_GUID))
|
|
{
|
|
QofGuidMatch options;
|
|
GList *guids;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
options = gnc_query_scm2guid (scm);
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (!scm_is_list (scm))
|
|
break;
|
|
guids = gnc_scm2guid_glist (scm);
|
|
|
|
pd = qof_query_guid_predicate (options, guids);
|
|
|
|
gnc_guid_glist_free (guids);
|
|
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_INT64))
|
|
{
|
|
gint64 val;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
val = scm_to_int64 (scm);
|
|
|
|
pd = qof_query_int64_predicate (compare_how, val);
|
|
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_DOUBLE))
|
|
{
|
|
double val;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (!scm_is_number (scm))
|
|
break;
|
|
val = scm_to_double (scm);
|
|
|
|
pd = qof_query_double_predicate (compare_how, val);
|
|
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_BOOLEAN))
|
|
{
|
|
gboolean val;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (!scm_is_bool (scm))
|
|
break;
|
|
val = scm_is_true (scm);
|
|
|
|
pd = qof_query_boolean_predicate (compare_how, val);
|
|
|
|
}
|
|
else if (!g_strcmp0 (type, QOF_TYPE_CHAR))
|
|
{
|
|
QofCharMatch options;
|
|
gchar *char_list;
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
qt_scm = SCM_CDR (qt_scm);
|
|
if (scm_is_null (scm))
|
|
break;
|
|
options = gnc_query_scm2char (scm);
|
|
|
|
scm = SCM_CAR (qt_scm);
|
|
if (!scm_is_string (scm))
|
|
break;
|
|
char_list = gnc_scm_to_utf8_string (scm);
|
|
|
|
pd = qof_query_char_predicate (options, char_list);
|
|
g_free (char_list);
|
|
}
|
|
else
|
|
{
|
|
PWARN ("query core type %s not supported", type);
|
|
break;
|
|
}
|
|
|
|
g_free (type);
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if (pd)
|
|
{
|
|
q = qof_query_create ();
|
|
qof_query_add_term (q, path, pd, QOF_QUERY_OR);
|
|
if (inverted)
|
|
{
|
|
QofQuery *outq = qof_query_invert (q);
|
|
qof_query_destroy (q);
|
|
q = outq;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gnc_query_path_free (path);
|
|
}
|
|
|
|
return q;
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_term_query_v1 (SCM query_term_scm)
|
|
{
|
|
gboolean ok = FALSE;
|
|
gchar * pd_type = NULL;
|
|
gchar * pr_type = NULL;
|
|
gboolean sense = FALSE;
|
|
QofQuery *q = NULL;
|
|
SCM scm;
|
|
|
|
if (!scm_is_list (query_term_scm) ||
|
|
scm_is_null (query_term_scm))
|
|
{
|
|
PINFO ("null term");
|
|
return NULL;
|
|
}
|
|
|
|
do
|
|
{
|
|
/* pd_type */
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
pd_type = gnc_scm_symbol_to_locale_string (scm);
|
|
|
|
/* pr_type */
|
|
if (scm_is_null (query_term_scm))
|
|
{
|
|
PINFO ("null pr_type");
|
|
break;
|
|
}
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
pr_type = gnc_scm_symbol_to_locale_string (scm);
|
|
|
|
/* sense */
|
|
if (scm_is_null (query_term_scm))
|
|
{
|
|
PINFO ("null sense");
|
|
break;
|
|
}
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
sense = scm_is_true (scm);
|
|
|
|
q = qof_query_create_for(GNC_ID_SPLIT);
|
|
|
|
if (!g_strcmp0 (pd_type, "pd-date"))
|
|
{
|
|
gboolean use_start;
|
|
gboolean use_end;
|
|
time64 start;
|
|
time64 end;
|
|
|
|
/* use_start */
|
|
if (scm_is_null (query_term_scm))
|
|
{
|
|
PINFO ("null use_start");
|
|
break;
|
|
}
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
use_start = scm_is_true (scm);
|
|
|
|
/* start */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
start = scm_to_int64 (scm);
|
|
|
|
/* use_end */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
use_end = scm_is_true (scm);
|
|
|
|
/* end */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
end = scm_to_int64 (scm);
|
|
|
|
xaccQueryAddDateMatchTT (q, use_start, start, use_end, end, QOF_QUERY_OR);
|
|
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd_type, "pd-amount"))
|
|
{
|
|
QofQueryCompare how;
|
|
QofNumericMatch amt_sgn;
|
|
double amount;
|
|
gnc_numeric val;
|
|
|
|
/* how */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
how = gnc_scm2amt_match_how (scm);
|
|
|
|
/* amt_sgn */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
amt_sgn = gnc_query_scm2numericop (scm);
|
|
|
|
/* amount */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
scm = SCM_CAR (query_term_scm);
|
|
val = gnc_numeric_create (scm_to_int64(scm_numerator(scm)),
|
|
scm_to_int64(scm_denominator(scm)));
|
|
|
|
if (!g_strcmp0 (pr_type, "pr-price"))
|
|
{
|
|
xaccQueryAddSharePriceMatch (q, val, how, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pr_type, "pr-shares"))
|
|
{
|
|
xaccQueryAddSharesMatch (q, val, how, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pr_type, "pr-value"))
|
|
{
|
|
xaccQueryAddValueMatch (q, val, amt_sgn, how, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
PINFO ("unknown amount predicate: %s", pr_type);
|
|
}
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd_type, "pd-account"))
|
|
{
|
|
QofGuidMatch how;
|
|
GList *account_guids;
|
|
|
|
/* how */
|
|
if (scm_is_null (query_term_scm))
|
|
{
|
|
PINFO ("pd-account: null how");
|
|
break;
|
|
}
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
how = gnc_scm2acct_match_how (scm);
|
|
|
|
/* account guids */
|
|
if (scm_is_null (query_term_scm))
|
|
{
|
|
PINFO ("pd-account: null guids");
|
|
break;
|
|
}
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
|
|
account_guids = gnc_scm2guid_glist (scm);
|
|
|
|
xaccQueryAddAccountGUIDMatch (q, account_guids, how, QOF_QUERY_OR);
|
|
|
|
gnc_guid_glist_free (account_guids);
|
|
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd_type, "pd-string"))
|
|
{
|
|
gboolean case_sens;
|
|
gboolean use_regexp;
|
|
gchar *matchstring;
|
|
|
|
/* case_sens */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
case_sens = scm_is_true (scm);
|
|
|
|
/* use_regexp */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
use_regexp = scm_is_true (scm);
|
|
|
|
/* matchstring */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
matchstring = gnc_scm_to_utf8_string (scm);
|
|
|
|
if (!g_strcmp0 (pr_type, "pr-action"))
|
|
{
|
|
xaccQueryAddActionMatch (q, matchstring, case_sens, use_regexp,
|
|
QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pr_type, "pr-desc"))
|
|
{
|
|
xaccQueryAddDescriptionMatch (q, matchstring, case_sens,
|
|
use_regexp, QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pr_type, "pr-memo"))
|
|
{
|
|
xaccQueryAddMemoMatch (q, matchstring, case_sens, use_regexp,
|
|
QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pr_type, "pr-num"))
|
|
{
|
|
xaccQueryAddNumberMatch (q, matchstring, case_sens, use_regexp,
|
|
QOF_COMPARE_CONTAINS, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
PINFO ("Unknown string predicate: %s", pr_type);
|
|
}
|
|
g_free (matchstring);
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd_type, "pd-cleared"))
|
|
{
|
|
cleared_match_t how;
|
|
|
|
/* how */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
how = gnc_scm2cleared_match_how (scm);
|
|
|
|
xaccQueryAddClearedMatch (q, how, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd_type, "pd-balance"))
|
|
{
|
|
gboolean how;
|
|
|
|
/* how */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
if (gnc_scm2balance_match_how (scm, &how) == FALSE)
|
|
break;
|
|
|
|
xaccQueryAddBalanceMatch (q, how, QOF_QUERY_OR);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else if (!g_strcmp0 (pd_type, "pd-guid"))
|
|
{
|
|
GncGUID guid;
|
|
QofIdType id_type;
|
|
|
|
/* guid */
|
|
if (scm_is_null (query_term_scm))
|
|
break;
|
|
|
|
scm = SCM_CAR (query_term_scm);
|
|
query_term_scm = SCM_CDR (query_term_scm);
|
|
guid = gnc_scm2guid (scm);
|
|
|
|
/* id type */
|
|
scm = SCM_CAR (query_term_scm);
|
|
id_type = (QofIdType) gnc_scm_to_utf8_string (scm);
|
|
|
|
xaccQueryAddGUIDMatch (q, &guid, id_type, QOF_QUERY_OR);
|
|
g_free ((void *) id_type);
|
|
ok = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
PINFO ("Unknown Predicate: %s", pd_type);
|
|
}
|
|
|
|
g_free (pd_type);
|
|
g_free (pr_type);
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if (ok)
|
|
{
|
|
QofQuery *out_q;
|
|
|
|
if (sense)
|
|
out_q = q;
|
|
else
|
|
{
|
|
out_q = qof_query_invert (q);
|
|
qof_query_destroy (q);
|
|
}
|
|
|
|
return out_q;
|
|
}
|
|
|
|
qof_query_destroy (q);
|
|
return NULL;
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_term_query (SCM query_term_scm, query_version_t vers)
|
|
{
|
|
switch (vers)
|
|
{
|
|
case gnc_QUERY_v1:
|
|
return gnc_scm2query_term_query_v1 (query_term_scm);
|
|
case gnc_QUERY_v2:
|
|
return gnc_scm2query_term_query_v2 (query_term_scm);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static SCM
|
|
gnc_query_terms2scm (const GList *terms)
|
|
{
|
|
SCM or_terms = SCM_EOL;
|
|
const GList *or_node;
|
|
|
|
for (or_node = terms; or_node; or_node = or_node->next)
|
|
{
|
|
SCM and_terms = SCM_EOL;
|
|
GList *and_node;
|
|
|
|
for (and_node = or_node->data; and_node; and_node = and_node->next)
|
|
{
|
|
QofQueryTerm *qt = and_node->data;
|
|
SCM qt_scm;
|
|
|
|
qt_scm = gnc_queryterm2scm (qt);
|
|
|
|
and_terms = scm_cons (qt_scm, and_terms);
|
|
}
|
|
|
|
and_terms = scm_reverse (and_terms);
|
|
|
|
or_terms = scm_cons (and_terms, or_terms);
|
|
}
|
|
|
|
return scm_reverse (or_terms);
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_and_terms (SCM and_terms, query_version_t vers)
|
|
{
|
|
QofQuery *q = NULL;
|
|
|
|
if (!scm_is_list (and_terms))
|
|
return NULL;
|
|
|
|
while (!scm_is_null (and_terms))
|
|
{
|
|
SCM term;
|
|
|
|
term = SCM_CAR (and_terms);
|
|
and_terms = SCM_CDR (and_terms);
|
|
|
|
if (!q)
|
|
q = gnc_scm2query_term_query (term, vers);
|
|
else
|
|
{
|
|
QofQuery *q_and;
|
|
QofQuery *q_new;
|
|
|
|
q_and = gnc_scm2query_term_query (term, vers);
|
|
|
|
if (q_and)
|
|
{
|
|
q_new = qof_query_merge (q, q_and, QOF_QUERY_AND);
|
|
|
|
if (q_new)
|
|
{
|
|
qof_query_destroy (q);
|
|
q = q_new;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return q;
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_or_terms (SCM or_terms, query_version_t vers)
|
|
{
|
|
QofQuery *q = NULL;
|
|
|
|
if (!scm_is_list (or_terms))
|
|
return NULL;
|
|
|
|
q = qof_query_create_for(GNC_ID_SPLIT);
|
|
|
|
while (!scm_is_null (or_terms))
|
|
{
|
|
SCM and_terms;
|
|
|
|
and_terms = SCM_CAR (or_terms);
|
|
or_terms = SCM_CDR (or_terms);
|
|
|
|
if (!q)
|
|
q = gnc_scm2query_and_terms (and_terms, vers);
|
|
else
|
|
{
|
|
QofQuery *q_or;
|
|
QofQuery *q_new;
|
|
|
|
q_or = gnc_scm2query_and_terms (and_terms, vers);
|
|
|
|
if (q_or)
|
|
{
|
|
q_new = qof_query_merge (q, q_or, QOF_QUERY_OR);
|
|
|
|
if (q_new)
|
|
{
|
|
qof_query_destroy (q);
|
|
q = q_new;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return q;
|
|
}
|
|
|
|
static SCM
|
|
gnc_query_sort2scm (const QofQuerySort *qs)
|
|
{
|
|
SCM sort_scm = SCM_EOL;
|
|
GSList *path;
|
|
|
|
path = qof_query_sort_get_param_path (qs);
|
|
if (path == NULL)
|
|
return SCM_BOOL_F;
|
|
|
|
sort_scm = scm_cons (gnc_query_path2scm (path), sort_scm);
|
|
sort_scm = scm_cons (scm_from_int (qof_query_sort_get_sort_options (qs)), sort_scm);
|
|
sort_scm = scm_cons (SCM_BOOL (qof_query_sort_get_increasing (qs)), sort_scm);
|
|
|
|
return scm_reverse (sort_scm);
|
|
}
|
|
|
|
static gboolean
|
|
gnc_query_scm2sort (SCM sort_scm, GSList **path, gint *options, gboolean *inc)
|
|
{
|
|
SCM val;
|
|
GSList *p;
|
|
gint o;
|
|
gboolean i;
|
|
|
|
g_return_val_if_fail (path && options && inc, FALSE);
|
|
g_return_val_if_fail (*path == NULL, FALSE);
|
|
|
|
/* This is ok -- it means we have an empty sort. Don't do anything */
|
|
if (scm_is_bool (sort_scm))
|
|
return TRUE;
|
|
|
|
/* Ok, this had better be a list */
|
|
if (!scm_is_list (sort_scm))
|
|
return FALSE;
|
|
|
|
/* Parse the path, options, and increasing */
|
|
val = SCM_CAR (sort_scm);
|
|
sort_scm = SCM_CDR (sort_scm);
|
|
if (!scm_is_list (val))
|
|
return FALSE;
|
|
p = gnc_query_scm2path (val);
|
|
|
|
/* options */
|
|
val = SCM_CAR (sort_scm);
|
|
sort_scm = SCM_CDR (sort_scm);
|
|
if (!scm_is_number (val))
|
|
{
|
|
gnc_query_path_free (p);
|
|
return FALSE;
|
|
}
|
|
o = scm_to_int (val);
|
|
|
|
/* increasing */
|
|
val = SCM_CAR (sort_scm);
|
|
sort_scm = SCM_CDR (sort_scm);
|
|
if (!scm_is_bool (val))
|
|
{
|
|
gnc_query_path_free (p);
|
|
return FALSE;
|
|
}
|
|
i = scm_is_true (val);
|
|
|
|
/* EOL */
|
|
if (!scm_is_null (sort_scm))
|
|
{
|
|
gnc_query_path_free (p);
|
|
return FALSE;
|
|
}
|
|
*path = p;
|
|
*options = o;
|
|
*inc = i;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SCM
|
|
gnc_query2scm (QofQuery *q)
|
|
{
|
|
SCM query_scm = SCM_EOL;
|
|
SCM pair;
|
|
QofQuerySort *s1, *s2, *s3;
|
|
|
|
if (!q) return SCM_BOOL_F;
|
|
|
|
/* terms */
|
|
pair = scm_cons (gnc_query_terms2scm (qof_query_get_terms (q)), SCM_EOL);
|
|
pair = scm_cons (scm_from_locale_symbol ("terms"), pair);
|
|
query_scm = scm_cons (pair, query_scm);
|
|
|
|
/* search-for */
|
|
pair = scm_cons (scm_from_locale_symbol (qof_query_get_search_for (q)), SCM_EOL);
|
|
pair = scm_cons (scm_from_locale_symbol ("search-for"), pair);
|
|
query_scm = scm_cons (pair, query_scm);
|
|
|
|
/* sorts... */
|
|
qof_query_get_sorts (q, &s1, &s2, &s3);
|
|
|
|
/* primary-sort */
|
|
pair = scm_cons (gnc_query_sort2scm (s1), SCM_EOL);
|
|
pair = scm_cons (scm_from_locale_symbol ("primary-sort"), pair);
|
|
query_scm = scm_cons (pair, query_scm);
|
|
|
|
/* secondary-sort */
|
|
pair = scm_cons (gnc_query_sort2scm (s2), SCM_EOL);
|
|
pair = scm_cons (scm_from_locale_symbol ("secondary-sort"), pair);
|
|
query_scm = scm_cons (pair, query_scm);
|
|
|
|
/* tertiary-sort */
|
|
pair = scm_cons (gnc_query_sort2scm (s3), SCM_EOL);
|
|
pair = scm_cons (scm_from_locale_symbol ("tertiary-sort"), pair);
|
|
query_scm = scm_cons (pair, query_scm);
|
|
|
|
/* max results */
|
|
pair = scm_cons (scm_from_int (qof_query_get_max_results (q)), SCM_EOL);
|
|
pair = scm_cons (scm_from_locale_symbol ("max-results"), pair);
|
|
query_scm = scm_cons (pair, query_scm);
|
|
|
|
/* Reverse this list; tag it as 'query-v2' */
|
|
pair = scm_reverse (query_scm);
|
|
return scm_cons (scm_from_locale_symbol ("query-v2"), pair);
|
|
}
|
|
|
|
static GSList *
|
|
gnc_query_sort_to_list (const gchar * symbol)
|
|
{
|
|
GSList *path = NULL;
|
|
|
|
if (!symbol)
|
|
return NULL;
|
|
|
|
if (!g_strcmp0 (symbol, "by-none"))
|
|
{
|
|
path = NULL;
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-standard"))
|
|
{
|
|
path = g_slist_prepend (path, QUERY_DEFAULT_SORT);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-date") ||
|
|
!g_strcmp0 (symbol, "by-date-rounded"))
|
|
{
|
|
path = g_slist_prepend (path, TRANS_DATE_POSTED);
|
|
path = g_slist_prepend (path, SPLIT_TRANS);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-date-entered") ||
|
|
!g_strcmp0 (symbol, "by-date-entered-rounded"))
|
|
{
|
|
path = g_slist_prepend (path, TRANS_DATE_ENTERED);
|
|
path = g_slist_prepend (path, SPLIT_TRANS);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-date-reconciled") ||
|
|
!g_strcmp0 (symbol, "by-date-reconciled-rounded"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_DATE_RECONCILED);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-num"))
|
|
{
|
|
path = g_slist_prepend (path, TRANS_NUM);
|
|
path = g_slist_prepend (path, SPLIT_TRANS);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-amount"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_VALUE);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-memo"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_MEMO);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-desc"))
|
|
{
|
|
path = g_slist_prepend (path, TRANS_DESCRIPTION);
|
|
path = g_slist_prepend (path, SPLIT_TRANS);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-reconcile"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_RECONCILE);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-account-full-name"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_ACCT_FULLNAME);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-account-code"))
|
|
{
|
|
path = g_slist_prepend (path, ACCOUNT_CODE_);
|
|
path = g_slist_prepend (path, SPLIT_ACCOUNT);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-corr-account-full-name"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_CORR_ACCT_NAME);
|
|
|
|
}
|
|
else if (!g_strcmp0 (symbol, "by-corr-account-code"))
|
|
{
|
|
path = g_slist_prepend (path, SPLIT_CORR_ACCT_CODE);
|
|
|
|
}
|
|
else
|
|
{
|
|
PERR ("Unknown sort-type, %s", symbol);
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_v1 (SCM query_scm)
|
|
{
|
|
QofQuery *q = NULL;
|
|
gboolean ok = TRUE;
|
|
gchar * primary_sort = NULL;
|
|
gchar * secondary_sort = NULL;
|
|
gchar * tertiary_sort = NULL;
|
|
gboolean primary_increasing = TRUE;
|
|
gboolean secondary_increasing = TRUE;
|
|
gboolean tertiary_increasing = TRUE;
|
|
int max_splits = -1;
|
|
|
|
while (!scm_is_null (query_scm))
|
|
{
|
|
gchar *symbol;
|
|
SCM sym_scm;
|
|
SCM value;
|
|
SCM pair;
|
|
|
|
pair = SCM_CAR (query_scm);
|
|
query_scm = SCM_CDR (query_scm);
|
|
|
|
if (!scm_is_pair (pair))
|
|
{
|
|
PERR ("Not a Pair");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
sym_scm = SCM_CAR (pair);
|
|
value = SCM_CADR (pair);
|
|
|
|
if (!scm_is_symbol (sym_scm))
|
|
{
|
|
PERR ("Not a symbol");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
symbol = gnc_scm_symbol_to_locale_string (sym_scm);
|
|
if (!symbol)
|
|
{
|
|
PERR ("No string found");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (g_strcmp0 ("terms", symbol) == 0)
|
|
{
|
|
if (q)
|
|
qof_query_destroy (q);
|
|
|
|
q = gnc_scm2query_or_terms (value, gnc_QUERY_v1);
|
|
if (!q)
|
|
{
|
|
PINFO ("invalid terms");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (g_strcmp0 ("primary-sort", symbol) == 0)
|
|
{
|
|
if (!scm_is_symbol (value))
|
|
{
|
|
PINFO ("Invalid primary sort");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
primary_sort = gnc_scm_symbol_to_locale_string (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("secondary-sort", symbol) == 0)
|
|
{
|
|
if (!scm_is_symbol (value))
|
|
{
|
|
PINFO ("Invalid secondary sort");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
secondary_sort = gnc_scm_symbol_to_locale_string (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("tertiary-sort", symbol) == 0)
|
|
{
|
|
if (!scm_is_symbol (value))
|
|
{
|
|
PINFO ("Invalid tertiary sort");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
tertiary_sort = gnc_scm_symbol_to_locale_string (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("primary-increasing", symbol) == 0)
|
|
{
|
|
primary_increasing = scm_is_true (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("secondary-increasing", symbol) == 0)
|
|
{
|
|
secondary_increasing = scm_is_true (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("tertiary-increasing", symbol) == 0)
|
|
{
|
|
tertiary_increasing = scm_is_true (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("max-splits", symbol) == 0)
|
|
{
|
|
if (!scm_is_number (value))
|
|
{
|
|
PERR ("invalid max-splits");
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
max_splits = scm_to_int (value);
|
|
|
|
}
|
|
else
|
|
{
|
|
PERR ("Unknown symbol: %s", symbol);
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
g_free (symbol);
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
GSList *s1, *s2, *s3;
|
|
s1 = gnc_query_sort_to_list (primary_sort);
|
|
s2 = gnc_query_sort_to_list (secondary_sort);
|
|
s3 = gnc_query_sort_to_list (tertiary_sort);
|
|
|
|
qof_query_set_sort_order (q, s1, s2, s3);
|
|
qof_query_set_sort_increasing (q, primary_increasing, secondary_increasing,
|
|
tertiary_increasing);
|
|
qof_query_set_max_results (q, max_splits);
|
|
}
|
|
else
|
|
{
|
|
qof_query_destroy (q);
|
|
q = NULL;
|
|
}
|
|
|
|
g_free (primary_sort);
|
|
g_free (secondary_sort);
|
|
g_free (tertiary_sort);
|
|
|
|
return q;
|
|
}
|
|
|
|
static QofQuery *
|
|
gnc_scm2query_v2 (SCM query_scm)
|
|
{
|
|
QofQuery *q = NULL;
|
|
gboolean ok = TRUE;
|
|
gchar * search_for = NULL;
|
|
GSList *sp1 = NULL, *sp2 = NULL, *sp3 = NULL;
|
|
gint so1 = 0, so2 = 0, so3 = 0;
|
|
gboolean si1 = TRUE, si2 = TRUE, si3 = TRUE;
|
|
int max_results = -1;
|
|
|
|
while (!scm_is_null (query_scm))
|
|
{
|
|
gchar *symbol;
|
|
SCM sym_scm;
|
|
SCM value;
|
|
SCM pair;
|
|
|
|
pair = SCM_CAR (query_scm);
|
|
query_scm = SCM_CDR (query_scm);
|
|
|
|
if (!scm_is_pair (pair))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
sym_scm = SCM_CAR (pair);
|
|
value = SCM_CADR (pair);
|
|
|
|
if (!scm_is_symbol (sym_scm))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
symbol = gnc_scm_symbol_to_locale_string (sym_scm);
|
|
if (!symbol)
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (!g_strcmp0 ("terms", symbol))
|
|
{
|
|
if (q)
|
|
qof_query_destroy (q);
|
|
|
|
q = gnc_scm2query_or_terms (value, gnc_QUERY_v2);
|
|
if (!q)
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (!g_strcmp0 ("search-for", symbol))
|
|
{
|
|
if (!scm_is_symbol (value))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
search_for = gnc_scm_symbol_to_locale_string (value);
|
|
|
|
}
|
|
else if (g_strcmp0 ("primary-sort", symbol) == 0)
|
|
{
|
|
if (! gnc_query_scm2sort (value, &sp1, &so1, &si1))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (!g_strcmp0 ("secondary-sort", symbol))
|
|
{
|
|
if (! gnc_query_scm2sort (value, &sp2, &so2, &si2))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (!g_strcmp0 ("tertiary-sort", symbol))
|
|
{
|
|
if (! gnc_query_scm2sort (value, &sp3, &so3, &si3))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (!g_strcmp0 ("max-results", symbol))
|
|
{
|
|
if (!scm_is_number (value))
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
max_results = scm_to_int (value);
|
|
|
|
}
|
|
else
|
|
{
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
g_free (symbol);
|
|
}
|
|
|
|
if (ok && search_for)
|
|
{
|
|
qof_query_search_for (q, search_for);
|
|
qof_query_set_sort_order (q, sp1, sp2, sp3);
|
|
qof_query_set_sort_options (q, so1, so2, so3);
|
|
qof_query_set_sort_increasing (q, si1, si2, si3);
|
|
qof_query_set_max_results (q, max_results);
|
|
}
|
|
else
|
|
{
|
|
qof_query_destroy (q);
|
|
q = NULL;
|
|
}
|
|
|
|
g_free (search_for);
|
|
|
|
return q;
|
|
}
|
|
|
|
QofQuery *
|
|
gnc_scm2query (SCM query_scm)
|
|
{
|
|
SCM q_type;
|
|
gchar *type;
|
|
QofQuery *q = NULL;
|
|
|
|
/* Not a list or NULL? No need to go further */
|
|
if (!scm_is_list (query_scm) || scm_is_null (query_scm))
|
|
return NULL;
|
|
|
|
/* Grab the 'type' (for v2 and above) */
|
|
q_type = SCM_CAR (query_scm);
|
|
|
|
if (!scm_is_symbol (q_type))
|
|
{
|
|
if (scm_is_pair (q_type))
|
|
{
|
|
/* Version-1 queries are just a list */
|
|
return gnc_scm2query_v1 (query_scm);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Ok, the LHS is the version and the RHS is the actual query list */
|
|
type = gnc_scm_symbol_to_locale_string (q_type);
|
|
if (!type)
|
|
return NULL;
|
|
|
|
if (!g_strcmp0 (type, "query-v2"))
|
|
q = gnc_scm2query_v2 (SCM_CDR (query_scm));
|
|
|
|
g_free (type);
|
|
return q;
|
|
}
|
|
|
|
gnc_numeric
|
|
gnc_scm_to_numeric(SCM gncnum)
|
|
{
|
|
if (scm_is_signed_integer(scm_numerator(gncnum), INT64_MIN, INT64_MAX) &&
|
|
scm_is_signed_integer(scm_denominator(gncnum), INT64_MIN, INT64_MAX))
|
|
return gnc_numeric_create(scm_to_int64(scm_numerator(gncnum)),
|
|
scm_to_int64(scm_denominator(gncnum)));
|
|
return gnc_numeric_create(0, GNC_ERROR_OVERFLOW);
|
|
}
|
|
|
|
SCM
|
|
gnc_numeric_to_scm(gnc_numeric arg)
|
|
{
|
|
return scm_divide(scm_from_int64(arg.num),
|
|
scm_from_int64(arg.denom));
|
|
}
|
|
|
|
static SCM
|
|
gnc_generic_to_scm(const void *cx, const gchar *type_str)
|
|
{
|
|
swig_type_info * stype = NULL;
|
|
void *x = (void*) cx;
|
|
|
|
if (!x) return SCM_BOOL_F;
|
|
stype = SWIG_TypeQuery(type_str);
|
|
|
|
if (!stype)
|
|
{
|
|
PERR("Unknown SWIG Type: %s ", type_str);
|
|
return SCM_BOOL_F;
|
|
}
|
|
|
|
return SWIG_NewPointerObj(x, stype, 0);
|
|
}
|
|
|
|
static void *
|
|
gnc_scm_to_generic(SCM scm, const gchar *type_str)
|
|
{
|
|
swig_type_info * stype = NULL;
|
|
|
|
stype = SWIG_TypeQuery(type_str);
|
|
if (!stype)
|
|
{
|
|
PERR("Unknown SWIG Type: %s ", type_str);
|
|
return NULL;
|
|
}
|
|
|
|
if (!SWIG_IsPointerOfType(scm, stype))
|
|
return NULL;
|
|
|
|
return SWIG_MustGetPtr(scm, stype, 1, 0);
|
|
}
|
|
|
|
gnc_commodity *
|
|
gnc_scm_to_commodity(SCM scm)
|
|
{
|
|
return gnc_scm_to_generic(scm, "_p_gnc_commodity");
|
|
}
|
|
|
|
SCM
|
|
gnc_commodity_to_scm (const gnc_commodity *commodity)
|
|
{
|
|
return gnc_generic_to_scm(commodity, "_p_gnc_commodity");
|
|
}
|
|
|
|
SCM
|
|
gnc_book_to_scm (const QofBook *book)
|
|
{
|
|
return gnc_generic_to_scm(book, "_p_QofBook");
|
|
}
|