mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
QOF 0.6.1 release update
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@12299 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -436,8 +436,8 @@ if test x$QOF_XML_DIR = x; then
|
||||
QOF_VERSION="internal"
|
||||
QOF_PREFIX="internal"
|
||||
QOF_XML_DIR=`eval echo ${datadir}/xml/qsf`
|
||||
LIBQOF_LIBRARY_VERSION=1:1:0
|
||||
LIBQOF_BACKEND_QSF_LIBRARY_VERSION=0:0:0
|
||||
LIBQOF_LIBRARY_VERSION=1:2:0
|
||||
LIBQOF_BACKEND_QSF_LIBRARY_VERSION=0:1:0
|
||||
AC_SUBST(LIBQOF_LIBRARY_VERSION)
|
||||
AC_SUBST(LIBQOF_BACKEND_QSF_LIBRARY_VERSION)
|
||||
AC_DEFINE(HAVE_LIBQOF,,[We will use the internal QOF code])
|
||||
|
@@ -5,13 +5,13 @@
|
||||
<qsf-map
|
||||
xmlns="http://qof.sourceforge.net/">
|
||||
<definition qof_version="3">
|
||||
<define e_type="pilot_expenses">Pilot-link QOF expenses</define>
|
||||
<define e_type="pilot_datebook">Pilot-link QOF datebook</define>
|
||||
<define e_type="pilot_address">Pilot-link QOF address</define>
|
||||
<define e_type="gncInvoice">Invoice</define>
|
||||
<define e_type="Trans">Transaction</define>
|
||||
<define e_type="gncEntry">Order/Invoice/Bill Entry</define>
|
||||
<default name="mileage_rate" type="numeric" value="28/100"/>
|
||||
<define e_type="pilot_expenses"/>
|
||||
<define e_type="pilot_datebook"/>
|
||||
<define e_type="pilot_address"/>
|
||||
<define e_type="gncInvoice"/>
|
||||
<define e_type="Trans"/>
|
||||
<define e_type="gncEntry"/>
|
||||
<default name="mileage_rate" type="numeric" value="30/100"/>
|
||||
<default name="use_weekday_descriptor" type="boolean" value="true"/>
|
||||
<default name="use_discount" type="boolean" value="false"/>
|
||||
<default name="tax_included" type="boolean" value="false"/>
|
||||
@@ -29,20 +29,28 @@ xmlns="http://qof.sourceforge.net/">
|
||||
<if boolean="use_weekday_descriptor">
|
||||
<set format="%A">expense_date</set>
|
||||
</if>
|
||||
<else type="qof_expenses">
|
||||
<else type="pilot_expenses">
|
||||
<set>expense_vendor</set>
|
||||
</else>
|
||||
<else type="pilot_datebook">
|
||||
<set>description</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="string" value="action">
|
||||
<if type="qof-expenses">
|
||||
<if type="pilot_expenses">
|
||||
<set>Material</set>
|
||||
</if>
|
||||
<else type="qof-datebook">
|
||||
<else type="pilot_datebook">
|
||||
<set>Hours</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="string" value="notes">
|
||||
<set object="qof-expenses">expense_note</set>
|
||||
<if type="pilot-expenses">
|
||||
<set>expense_note</set>
|
||||
</if>
|
||||
<else type="pilot_datebook">
|
||||
<set>note</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="guid" value="bill-to"/>
|
||||
<calculate type="boolean" value="invoice-taxable"/>
|
||||
@@ -54,20 +62,18 @@ xmlns="http://qof.sourceforge.net/">
|
||||
</calculate>
|
||||
<calculate type="numeric" value="iprice">
|
||||
<if type="string" value="expense_type">
|
||||
<equals type="string" value="etMileage">
|
||||
<equals type="string" value="Mileage">
|
||||
<set>mileage_rate</set>
|
||||
</equals>
|
||||
</if>
|
||||
</calculate>
|
||||
<calculate type="numeric" value="bprice"/>
|
||||
<calculate type="numeric" value="qty">
|
||||
<if string="expense_type">
|
||||
<equals type="string" value="etMileage">
|
||||
<set object="qof-expenses">expense_amount</set>
|
||||
</equals>
|
||||
<if type="pilot_datebook">
|
||||
<set>end_time-start_time</set>
|
||||
</if>
|
||||
<else type="string" value="expense_type">
|
||||
<set>0/1</set>
|
||||
<else type="pilot_expenses">
|
||||
<set>expense_amount</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="numeric" value="invoice-discount">
|
||||
|
@@ -18,8 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** @addtogroup Backend
|
||||
@@ -101,11 +100,6 @@ GNU GPL licence and QSF is free software.
|
||||
- Adding more map support, some parts of the map are still not coded. equals,
|
||||
variables and the conditional logic may not be up to the task of the
|
||||
datebook repetition calculations.
|
||||
- Rationalise the API - remove functions that shouldn't be public.
|
||||
|
||||
\todo QOF contains numerous g_string_sprintf and g_string_sprintfa calls.
|
||||
These are deprecated and should be renamed to g_string_printf and g_string_append_printf
|
||||
respectively.
|
||||
|
||||
QSF is in three sections:
|
||||
- QSF Backend : a QofBackend for file:/ QSF objects and maps.
|
||||
@@ -114,36 +108,93 @@ QSF is in three sections:
|
||||
qsf-xml.c
|
||||
- QSF Map : Validation, processing and conversion routines.
|
||||
qsf-xml-map.c
|
||||
|
||||
To work with QSF, your QOF objects must have:
|
||||
- a create: function in the QofObject definition
|
||||
- a foreach: function in the QofObject definition
|
||||
- QofParam params[] registered with QOF using
|
||||
qof_class_register and containing all necessary parameters
|
||||
to reconstruct this object without any further information.
|
||||
- Logical distinction between those parameters that should be
|
||||
set (have a QofAccessFunc and QofSetterFunc) and those that
|
||||
should only be calculated (only a QofAccessFunc).
|
||||
|
||||
If you begin your QSF session with ::QOF_STDOUT as the book_id,
|
||||
QSF will write to STDOUT - usually a terminal. This is used by QOF
|
||||
applications to provide data streaming. If you don't want terminal
|
||||
output, take care to check the path given to
|
||||
::qof_session_begin - don't try to change it later!
|
||||
|
||||
The XML is validated against the QSF object schema before being
|
||||
written (to file or stdout).
|
||||
|
||||
Check the QofBackendError - don't assume the file is OK.
|
||||
|
||||
@{ */
|
||||
/** @file qof-backend-qsf.h
|
||||
@brief QSF API - Backend, maps and objects.
|
||||
@brief QSF API - Backend, maps, objects and configuration.
|
||||
@author Copyright (C) 2004-2005 Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
#ifndef _QOF_BACKEND_QSF_H
|
||||
#define _QOF_BACKEND_QSF_H
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "qoflog.h"
|
||||
#include "qofbackend.h"
|
||||
#include "qof-be-utils.h"
|
||||
|
||||
#define QOF_MOD_QSF "qof-backend-qsf"
|
||||
|
||||
/** \brief Describe this backend to the application.
|
||||
|
||||
Sets QSF Backend Version 0.1, access method = file:
|
||||
Sets QSF Backend Version 0.2, access method = file:
|
||||
|
||||
This is the QOF backend interface, not a GnuCash module.
|
||||
The version number only changes if:
|
||||
-# The map schema is modified, or
|
||||
-# The object schema is modified, or
|
||||
-# The QofBackendProvider struct is modified in QOF to
|
||||
support new members and QSF can support the new function, or
|
||||
-# The QofBackendOption settings are modified.
|
||||
|
||||
v0.2 introduces the QSF_MAP_FILES QofBackendOption.
|
||||
|
||||
Initialises the backend and provides access to the
|
||||
functions that will load and save the data. Initialises
|
||||
default values for the QofBackendOption KvpFrame.
|
||||
|
||||
Calls gettext because QofBackendOption
|
||||
strings are translatable.
|
||||
*/
|
||||
void qsf_provider_init(void);
|
||||
|
||||
/** \brief Create a new QSF backend.
|
||||
|
||||
Initialises the backend and provides access to the
|
||||
functions that will load and save the data.
|
||||
/** \name Supported backend configurations
|
||||
@{
|
||||
*/
|
||||
QofBackend* qsf_backend_new(void);
|
||||
|
||||
/** \brief compression level
|
||||
|
||||
\b Type: gint (KVP_TYPE_GINT64)
|
||||
|
||||
Use GINT_TO_POINTER() to set a integer value between 0 and 9.
|
||||
*/
|
||||
#define QSF_COMPRESS "compression_level"
|
||||
|
||||
/** \brief selected QSF maps
|
||||
|
||||
\b Type: GList* (KVP_TYPE_GLIST) of const char* (QOF_TYPE_STRING) values.
|
||||
|
||||
Defaults to the pre-installed QSF map(s) but may be overridden
|
||||
by the application to pass full path(s) of user selected
|
||||
QSF map file(s).
|
||||
|
||||
If you override the list, it is advisable to only specify the single
|
||||
map file for this QSF object to reduce the amount of error checking
|
||||
required within the backend. Simply reset the QofBackendOption before
|
||||
another file is to be opened. It is up to the application to decide how
|
||||
to offer multiple map selections to the user.
|
||||
|
||||
*/
|
||||
#define QSF_MAP_FILES "selected_map_files"
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
@@ -5,7 +5,6 @@
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@codehelp.co.uk
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -19,12 +18,12 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "qof.h"
|
||||
#include "qof-backend-qsf.h"
|
||||
#include "qsf-xml.h"
|
||||
#include "qsf-dir.h"
|
||||
@@ -32,46 +31,13 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define QSF_TYPE_BINARY "binary"
|
||||
#define QSF_TYPE_GLIST "glist"
|
||||
#define QSF_TYPE_FRAME "frame"
|
||||
#define QSF_COMPRESS "compression_level"
|
||||
#define QSF_TYPE_GLIST "glist"
|
||||
#define QSF_TYPE_FRAME "frame"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QSF;
|
||||
static int use_gz_level = 0;
|
||||
static void qsf_object_commitCB(gpointer key, gpointer value, gpointer data);
|
||||
|
||||
static void option_cb (QofBackendOption *option, gpointer data)
|
||||
{
|
||||
if(0 == safe_strcmp(QSF_COMPRESS, option->option_name)) {
|
||||
use_gz_level = *(gint*)option->value;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_load_config(QofBackend *be, KvpFrame *config)
|
||||
{
|
||||
qof_backend_option_foreach(config, option_cb, NULL);
|
||||
}
|
||||
|
||||
static KvpFrame*
|
||||
qsf_get_config(QofBackend *be)
|
||||
{
|
||||
QofBackendOption *option;
|
||||
|
||||
if(!be) { return NULL; }
|
||||
qof_backend_prepare_frame(be);
|
||||
option = g_new0(QofBackendOption, 1);
|
||||
option->option_name = QSF_COMPRESS;
|
||||
option->description = _("Level of compression to use: 0 for none, 9 for highest.");
|
||||
option->tooltip = _("QOF can compress QSF XML files using gzip. "
|
||||
"Note that compression is not used when outputting to STDOUT.");
|
||||
option->type = KVP_TYPE_GINT64;
|
||||
option->value = (gpointer)&use_gz_level;
|
||||
qof_backend_prepare_option(be, option);
|
||||
g_free(option);
|
||||
return qof_backend_complete_frame(be);
|
||||
}
|
||||
|
||||
struct QSFBackend_s
|
||||
struct QSFBackend_s
|
||||
{
|
||||
QofBackend be;
|
||||
qsf_param *params;
|
||||
@@ -80,7 +46,73 @@ struct QSFBackend_s
|
||||
|
||||
typedef struct QSFBackend_s QSFBackend;
|
||||
|
||||
void
|
||||
static void option_cb (QofBackendOption *option, gpointer data)
|
||||
{
|
||||
qsf_param *params;
|
||||
|
||||
params = (qsf_param*)data;
|
||||
g_return_if_fail(params);
|
||||
if(0 == safe_strcmp(QSF_COMPRESS, option->option_name)) {
|
||||
params->use_gz_level = GPOINTER_TO_INT(option->value);
|
||||
}
|
||||
if (0 == safe_strcmp(QSF_MAP_FILES, option->option_name)) {
|
||||
params->map_files = g_list_copy(option->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_load_config(QofBackend *be, KvpFrame *config)
|
||||
{
|
||||
QSFBackend *qsf_be;
|
||||
qsf_param *params;
|
||||
|
||||
qsf_be = (QSFBackend*)be;
|
||||
g_return_if_fail(qsf_be->params);
|
||||
params = qsf_be->params;
|
||||
qof_backend_option_foreach(config, option_cb, params);
|
||||
}
|
||||
|
||||
static KvpFrame*
|
||||
qsf_get_config(QofBackend *be)
|
||||
{
|
||||
QofBackendOption *option;
|
||||
QSFBackend *qsf_be;
|
||||
qsf_param *params;
|
||||
|
||||
if(!be) { return NULL; }
|
||||
qsf_be = (QSFBackend*)be;
|
||||
g_return_val_if_fail(qsf_be->params, NULL);
|
||||
params = qsf_be->params;
|
||||
qof_backend_prepare_frame(be);
|
||||
option = g_new0(QofBackendOption, 1);
|
||||
option->option_name = QSF_COMPRESS;
|
||||
option->description = _("Level of compression to use: 0 for none, 9 for highest.");
|
||||
option->tooltip = _("QOF can compress QSF XML files using gzip. "
|
||||
"Note that compression is not used when outputting to STDOUT.");
|
||||
option->type = KVP_TYPE_GINT64;
|
||||
option->value = GINT_TO_POINTER(params->use_gz_level);
|
||||
qof_backend_prepare_option(be, option);
|
||||
g_free(option);
|
||||
option = g_new0(QofBackendOption, 1);
|
||||
option->option_name = QSF_MAP_FILES;
|
||||
option->description = _("List of QSF map files to use for this session.");
|
||||
option->tooltip = _("QOF can convert objects within QSF XML files "
|
||||
"using a map of the changes required.");
|
||||
option->type = KVP_TYPE_GLIST;
|
||||
option->value = params->map_files;
|
||||
qof_backend_prepare_option(be, option);
|
||||
g_free(option);
|
||||
return qof_backend_complete_frame(be);
|
||||
}
|
||||
|
||||
GList**
|
||||
qsf_map_prepare_list(GList **maps)
|
||||
{
|
||||
*maps = g_list_prepend(*maps, "pilot-qsf-GnuCashInvoice.xml");
|
||||
return maps;
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_param_init(qsf_param *params)
|
||||
{
|
||||
Timespec *qsf_ts;
|
||||
@@ -93,13 +125,16 @@ qsf_param_init(qsf_param *params)
|
||||
|
||||
g_return_if_fail(params != NULL);
|
||||
params->count = 0;
|
||||
params->use_gz_level = 0;
|
||||
params->supported_types = NULL;
|
||||
params->file_type = QSF_UNDEF;
|
||||
params->qsf_ns = NULL;
|
||||
params->output_doc = NULL;
|
||||
params->output_node = NULL;
|
||||
params->lister = NULL;
|
||||
params->full_kvp_path = NULL;
|
||||
params->map_ns = NULL;
|
||||
params->map_files = NULL;
|
||||
params->qsf_object_list = NULL;
|
||||
params->qsf_parameter_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
params->qsf_default_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
@@ -129,6 +164,8 @@ qsf_param_init(qsf_param *params)
|
||||
g_hash_table_insert(params->qsf_default_hash, "qsf_enquiry_date", qsf_enquiry_date);
|
||||
g_hash_table_insert(params->qsf_default_hash, "qsf_time_now", &qsf_time_now_t);
|
||||
g_hash_table_insert(params->qsf_default_hash, "qsf_time_string", qsf_time_string);
|
||||
/* default map files */
|
||||
params->map_files = *qsf_map_prepare_list(¶ms->map_files);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -136,7 +173,6 @@ qsf_determine_file_type(const char *path)
|
||||
{
|
||||
struct stat sbuf;
|
||||
|
||||
PINFO (" %s", path);
|
||||
if (!path) { return TRUE; }
|
||||
if (0 == safe_strcmp(path, QOF_STDOUT)) { return TRUE; }
|
||||
if (stat(path, &sbuf) <0) { return FALSE; }
|
||||
@@ -148,8 +184,7 @@ qsf_determine_file_type(const char *path)
|
||||
}
|
||||
|
||||
/* GnuCash does LOTS of filesystem work, QSF is going to leave most of it to libxml2. :-)
|
||||
Just strip the file: from the start of the book_path URL. Locks and file
|
||||
creation are not implemented.
|
||||
Just strip the file: from the start of the book_path URL. Locks are not implemented.
|
||||
*/
|
||||
static void
|
||||
qsf_session_begin(QofBackend *be, QofSession *session, const char *book_path,
|
||||
@@ -165,6 +200,7 @@ qsf_session_begin(QofBackend *be, QofSession *session, const char *book_path,
|
||||
qsf_be->fullpath = NULL;
|
||||
if(book_path == NULL)
|
||||
{
|
||||
/* use stdout */
|
||||
qof_backend_set_error(be, ERR_BACKEND_NO_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -181,9 +217,33 @@ qsf_session_begin(QofBackend *be, QofSession *session, const char *book_path,
|
||||
else {
|
||||
qsf_be->fullpath = g_strdup(book_path);
|
||||
}
|
||||
if(create_if_nonexistent)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(qsf_be->fullpath, "a+");
|
||||
if(f) {fclose(f); }
|
||||
else
|
||||
{
|
||||
qof_backend_set_error(be, ERR_BACKEND_READONLY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
qof_backend_set_error(be, ERR_BACKEND_NO_ERR);
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_free_params(qsf_param *params)
|
||||
{
|
||||
g_hash_table_destroy(params->qsf_calculate_hash);
|
||||
g_hash_table_destroy(params->qsf_default_hash);
|
||||
if(params->referenceList) {
|
||||
g_list_free(params->referenceList);
|
||||
}
|
||||
g_slist_free(params->supported_types);
|
||||
if(params->map_ns) { xmlFreeNs(params->map_ns); }
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_session_end( QofBackend *be)
|
||||
{
|
||||
@@ -197,70 +257,12 @@ qsf_session_end( QofBackend *be)
|
||||
xmlCleanupParser();
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
qsf_destroy_backend (QofBackend *be)
|
||||
{
|
||||
g_free(be);
|
||||
}
|
||||
|
||||
QofBackendError
|
||||
qof_session_load_our_qsf_object(QofSession *first_session, const char *path)
|
||||
{
|
||||
QofSession *qsf_session;
|
||||
|
||||
qsf_session = qof_session_new();
|
||||
qof_session_begin(qsf_session, path, FALSE, FALSE);
|
||||
qof_session_load(qsf_session, NULL);
|
||||
/* FIXME: This needs to return success and set the open not merge error in file_open */
|
||||
return ERR_QSF_OPEN_NOT_MERGE;
|
||||
}
|
||||
|
||||
QofBackendError
|
||||
qof_session_load_qsf_object(QofSession *first_session, const char *path)
|
||||
{
|
||||
PINFO ("%s = ERR_QSF_NO_MAP", path);
|
||||
return ERR_QSF_NO_MAP;
|
||||
}
|
||||
|
||||
void
|
||||
qsf_file_type(QofBackend *be, QofBook *book)
|
||||
{
|
||||
QSFBackend *qsf_be;
|
||||
qsf_param *params;
|
||||
char *path;
|
||||
gboolean result;
|
||||
|
||||
g_return_if_fail(be != NULL);
|
||||
g_return_if_fail(book != NULL);
|
||||
qsf_be = (QSFBackend*) be;
|
||||
g_return_if_fail(qsf_be != NULL);
|
||||
g_return_if_fail(qsf_be->fullpath != NULL);
|
||||
g_return_if_fail(qsf_be->params != NULL);
|
||||
params = qsf_be->params;
|
||||
params->book = book;
|
||||
path = g_strdup(qsf_be->fullpath);
|
||||
params->filepath = g_strdup(path);
|
||||
qof_backend_get_error(be);
|
||||
result = is_our_qsf_object_be(params);
|
||||
if(result) {
|
||||
params->file_type = OUR_QSF_OBJ;
|
||||
result = load_our_qsf_object(book, path, params);
|
||||
if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
|
||||
return;
|
||||
}
|
||||
else if(is_qsf_object_be(params)) {
|
||||
params->file_type = IS_QSF_OBJ;
|
||||
result = load_qsf_object(book, path, params);
|
||||
if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
|
||||
}
|
||||
if(result == FALSE) {
|
||||
if(is_qsf_map_be(params)) {
|
||||
params->file_type = IS_QSF_MAP;
|
||||
qof_backend_set_error(be, ERR_QSF_MAP_NOT_OBJ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ent_ref_cb (QofEntity* ent, gpointer user_data)
|
||||
{
|
||||
@@ -307,7 +309,7 @@ insert_ref_cb(QofObject *obj, gpointer user_data)
|
||||
Load QofEntity into QofBook from XML in memory
|
||||
==================================================*/
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
qsfdoc_to_qofbook(xmlDocPtr doc, qsf_param *params)
|
||||
{
|
||||
QofInstance *inst;
|
||||
@@ -346,6 +348,124 @@ qsfdoc_to_qofbook(xmlDocPtr doc, qsf_param *params)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* QofBackend routine to load from file - needs a map.
|
||||
*/
|
||||
static gboolean
|
||||
load_qsf_object(QofBook *book, const char *fullpath, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr qsf_root, map_root;
|
||||
xmlDocPtr mapDoc, foreign_doc;
|
||||
gchar *map_path, *map_file;
|
||||
GList *maps;
|
||||
|
||||
maps = params->map_files;
|
||||
map_path = NULL;
|
||||
mapDoc = NULL;
|
||||
if(!maps) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
|
||||
return FALSE;
|
||||
}
|
||||
/* use default maps */
|
||||
map_file = g_strdup(maps->data);
|
||||
foreign_doc = xmlParseFile(fullpath);
|
||||
if (foreign_doc == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
qsf_root = NULL;
|
||||
qsf_root = xmlDocGetRootElement(foreign_doc);
|
||||
params->qsf_ns = qsf_root->ns;
|
||||
params->book = book;
|
||||
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
|
||||
if(!map_path) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
|
||||
return FALSE;
|
||||
}
|
||||
mapDoc = xmlParseFile(map_path);
|
||||
if(!mapDoc) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(mapDoc);
|
||||
params->map_ns = map_root->ns;
|
||||
params->input_doc = qsf_object_convert(mapDoc, qsf_root, params);
|
||||
qsfdoc_to_qofbook(params->input_doc, params);
|
||||
g_free(map_file);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_our_qsf_object(QofBook *book, const char *fullpath, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr qsf_root;
|
||||
|
||||
params->input_doc = xmlParseFile(fullpath);
|
||||
if (params->input_doc == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
qsf_root = NULL;
|
||||
qsf_root = xmlDocGetRootElement(params->input_doc);
|
||||
params->qsf_ns = qsf_root->ns;
|
||||
return qsfdoc_to_qofbook(params->input_doc, params);
|
||||
}
|
||||
|
||||
/* Determine the type of QSF and load it into the QofBook
|
||||
|
||||
- is_our_qsf_object, OUR_QSF_OBJ, QSF object file using only QOF objects known
|
||||
to the calling process. No map is required.
|
||||
- is_qsf_object, IS_QSF_OBJ, QSF object file that may or may not have a QSF map
|
||||
to convert external objects. This temporary type will be set to HAVE_QSF_MAP
|
||||
if a suitable map exists, or an error value returned: ERR_QSF_NO_MAP,
|
||||
ERR_QSF_BAD_MAP or ERR_QSF_WRONG_MAP. This allows the calling process to inform
|
||||
the user that the QSF itself is valid but a suitable map cannot be found.
|
||||
- is_qsf_map, IS_QSF_MAP, QSF map file. In the backend, this generates
|
||||
ERR_QSF_MAP_NOT_OBJ but it can be used internally when processing maps to
|
||||
match a QSF object.
|
||||
|
||||
returns NULL on error, otherwise a pointer to the QofBook. Use
|
||||
the qof_book_merge API to merge the new data into the current
|
||||
QofBook.
|
||||
*/
|
||||
static void
|
||||
qsf_file_type(QofBackend *be, QofBook *book)
|
||||
{
|
||||
QSFBackend *qsf_be;
|
||||
qsf_param *params;
|
||||
char *path;
|
||||
gboolean result;
|
||||
|
||||
g_return_if_fail(be != NULL);
|
||||
g_return_if_fail(book != NULL);
|
||||
qsf_be = (QSFBackend*) be;
|
||||
g_return_if_fail(qsf_be != NULL);
|
||||
g_return_if_fail(qsf_be->fullpath != NULL);
|
||||
g_return_if_fail(qsf_be->params != NULL);
|
||||
params = qsf_be->params;
|
||||
params->book = book;
|
||||
path = g_strdup(qsf_be->fullpath);
|
||||
params->filepath = g_strdup(path);
|
||||
qof_backend_get_error(be);
|
||||
result = is_our_qsf_object_be(params);
|
||||
if(result) {
|
||||
params->file_type = OUR_QSF_OBJ;
|
||||
result = load_our_qsf_object(book, path, params);
|
||||
if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
|
||||
return;
|
||||
}
|
||||
else if(is_qsf_object_be(params)) {
|
||||
params->file_type = IS_QSF_OBJ;
|
||||
result = load_qsf_object(book, path, params);
|
||||
if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
|
||||
}
|
||||
if(result == FALSE) {
|
||||
if(is_qsf_map_be(params)) {
|
||||
params->file_type = IS_QSF_MAP;
|
||||
qof_backend_set_error(be, ERR_QSF_MAP_NOT_OBJ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_object_sequence(QofParam *qof_param, gpointer data)
|
||||
{
|
||||
@@ -399,112 +519,93 @@ qsf_supported_parameters(gpointer type, gpointer user_data)
|
||||
static KvpValueType
|
||||
qsf_to_kvp_helper(const char *type_string)
|
||||
{
|
||||
if(0 == safe_strcmp(QOF_TYPE_STRING, type_string)) { return KVP_TYPE_STRING; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_GUID, type_string)) { return KVP_TYPE_GUID; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_INT64, type_string)) { return KVP_TYPE_GINT64; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_DOUBLE, type_string)) { return KVP_TYPE_DOUBLE; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_NUMERIC, type_string)) { return KVP_TYPE_NUMERIC; }
|
||||
if(0 == safe_strcmp(QSF_TYPE_BINARY, type_string)) { return KVP_TYPE_BINARY; }
|
||||
if(0 == safe_strcmp(QSF_TYPE_GLIST, type_string)) { return KVP_TYPE_GLIST; }
|
||||
if(0 == safe_strcmp(QSF_TYPE_FRAME, type_string)) { return KVP_TYPE_FRAME; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_INT64, type_string)) { return KVP_TYPE_GINT64; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_DOUBLE, type_string)) { return KVP_TYPE_DOUBLE; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_NUMERIC, type_string)) { return KVP_TYPE_NUMERIC; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_STRING, type_string)) { return KVP_TYPE_STRING; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_GUID, type_string)) { return KVP_TYPE_GUID; }
|
||||
if(0 == safe_strcmp(QOF_TYPE_DATE, type_string)) { return KVP_TYPE_TIMESPEC; }
|
||||
if(0 == safe_strcmp(QSF_TYPE_BINARY, type_string)) { return KVP_TYPE_BINARY; }
|
||||
if(0 == safe_strcmp(QSF_TYPE_GLIST, type_string)) { return KVP_TYPE_GLIST; }
|
||||
if(0 == safe_strcmp(QSF_TYPE_FRAME, type_string)) { return KVP_TYPE_FRAME; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QofIdTypeConst
|
||||
kvp_value_to_qof_type_helper(KvpValueType n)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
case KVP_TYPE_GINT64 : { return QOF_TYPE_INT64; break; }
|
||||
case KVP_TYPE_DOUBLE : { return QOF_TYPE_DOUBLE; break; }
|
||||
case KVP_TYPE_NUMERIC : { return QOF_TYPE_NUMERIC; break; }
|
||||
case KVP_TYPE_STRING : { return QOF_TYPE_STRING; break; }
|
||||
case KVP_TYPE_GUID : { return QOF_TYPE_GUID; break; }
|
||||
case KVP_TYPE_TIMESPEC : { return QOF_TYPE_DATE; break; }
|
||||
case KVP_TYPE_BINARY : { return QSF_TYPE_BINARY; break; }
|
||||
case KVP_TYPE_GLIST : { return QSF_TYPE_GLIST; break; }
|
||||
case KVP_TYPE_FRAME : { return QSF_TYPE_FRAME; break; }
|
||||
default : { return NULL; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qsf_from_kvp_helper(const char *path, KvpValue *content, gpointer data)
|
||||
{
|
||||
qsf_param *params;
|
||||
QofParam *qof_param;
|
||||
xmlNodePtr node;
|
||||
KvpValueType n;
|
||||
gchar *full_path;
|
||||
|
||||
params = (qsf_param*)data;
|
||||
qof_param = params->qof_param;
|
||||
full_path = NULL;
|
||||
g_return_if_fail(params && path && content);
|
||||
ENTER (" path=%s", path);
|
||||
switch(kvp_value_get_type(content))
|
||||
ENTER (" ");
|
||||
n = kvp_value_get_type(content);
|
||||
switch(n)
|
||||
{
|
||||
case KVP_TYPE_STRING:
|
||||
case KVP_TYPE_GINT64 :
|
||||
case KVP_TYPE_DOUBLE :
|
||||
case KVP_TYPE_NUMERIC :
|
||||
case KVP_TYPE_STRING :
|
||||
case KVP_TYPE_GUID :
|
||||
case KVP_TYPE_TIMESPEC :
|
||||
case KVP_TYPE_BINARY :
|
||||
case KVP_TYPE_GLIST :
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QOF_TYPE_STRING);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_GUID:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QOF_TYPE_GUID);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_BINARY:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QSF_TYPE_BINARY);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_GLIST:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QSF_TYPE_GLIST);
|
||||
full_path = g_strconcat(params->full_kvp_path, "/", path, NULL);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST full_path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE,
|
||||
BAD_CAST kvp_value_to_qof_type_helper(n));
|
||||
PINFO (" set %s", kvp_value_to_qof_type_helper(n));
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_FRAME:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QSF_TYPE_FRAME);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_GINT64:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QOF_TYPE_INT64);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_DOUBLE:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QOF_TYPE_DOUBLE);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_NUMERIC:
|
||||
{
|
||||
node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
|
||||
BAD_CAST qof_param->param_type));
|
||||
xmlNodeAddContent(node, BAD_CAST kvp_value_to_bare_string(content));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST path);
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_VALUE, BAD_CAST QOF_TYPE_NUMERIC);
|
||||
if(!params->full_kvp_path) { params->full_kvp_path = g_strdup(path); }
|
||||
else {
|
||||
params->full_kvp_path = g_strconcat(params->full_kvp_path,
|
||||
"/", path, NULL);
|
||||
}
|
||||
PINFO (" full=%s, path=%s ", params->full_kvp_path, path);
|
||||
kvp_frame_for_each_slot(kvp_value_get_frame(content),
|
||||
qsf_from_kvp_helper, params);
|
||||
g_free(params->full_kvp_path);
|
||||
params->full_kvp_path = NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{ break; }
|
||||
{
|
||||
PERR (" unsupported value = %d", kvp_value_get_type(content));
|
||||
break;
|
||||
}
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
@@ -693,14 +794,15 @@ qsf_entity_foreach(QofEntity *ent, gpointer data)
|
||||
}
|
||||
if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_KVP))
|
||||
{
|
||||
qsf_kvp = kvp_frame_copy(qof_param->param_getfcn(ent,qof_param));
|
||||
qsf_kvp = (KvpFrame*)qof_param->param_getfcn(ent,qof_param);
|
||||
if(kvp_frame_is_empty(qsf_kvp)) { LEAVE(" "); return; }
|
||||
params->qof_param = qof_param;
|
||||
params->output_node = object_node;
|
||||
kvp_frame_for_each_slot(qsf_kvp, qsf_from_kvp_helper, params);
|
||||
}
|
||||
if((qof_param->param_setfcn != NULL) && (qof_param->param_getfcn != NULL))
|
||||
{
|
||||
for( supported = g_slist_copy(params->supported_types);
|
||||
for( supported = g_slist_copy(params->supported_types);
|
||||
supported != NULL; supported = g_slist_next(supported))
|
||||
{
|
||||
if(0 == safe_strcmp((const char*)supported->data, (const char*)qof_param->param_type))
|
||||
@@ -722,7 +824,7 @@ qsf_foreach_obj_type(QofObject *qsf_obj, gpointer data)
|
||||
qsf_param *params;
|
||||
QofBook *book;
|
||||
GSList *support;
|
||||
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
params = (qsf_param*) data;
|
||||
/* Skip unsupported objects */
|
||||
@@ -749,10 +851,11 @@ qofbook_to_qsf(QofBook *book, qsf_param *params)
|
||||
xmlDocPtr doc;
|
||||
gchar buffer[GUID_ENCODING_LENGTH + 1];
|
||||
const GUID *book_guid;
|
||||
|
||||
|
||||
g_return_val_if_fail(book != NULL, NULL);
|
||||
params->book = book;
|
||||
params->referenceList = g_list_copy((GList*)qof_book_get_data(book, ENTITYREFERENCE));
|
||||
params->referenceList =
|
||||
g_list_copy((GList*)qof_book_get_data(book, ENTITYREFERENCE));
|
||||
doc = xmlNewDoc(BAD_CAST QSF_XML_VERSION);
|
||||
top_node = xmlNewNode(NULL, BAD_CAST QSF_ROOT_TAG);
|
||||
xmlDocSetRootElement(doc, top_node);
|
||||
@@ -763,7 +866,8 @@ qofbook_to_qsf(QofBook *book, qsf_param *params)
|
||||
xmlNewProp(node, BAD_CAST QSF_BOOK_COUNT, BAD_CAST "1");
|
||||
book_guid = qof_book_get_guid(book);
|
||||
guid_to_string_buff(book_guid, buffer);
|
||||
xmlNewChild(params->book_node, params->qsf_ns, BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
|
||||
xmlNewChild(params->book_node, params->qsf_ns,
|
||||
BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
|
||||
params->output_doc = doc;
|
||||
params->book_node = node;
|
||||
qof_object_foreach_type(qsf_foreach_obj_type, params);
|
||||
@@ -780,9 +884,9 @@ write_qsf_from_book(const char *path, QofBook *book, qsf_param *params)
|
||||
be = qof_book_get_backend(book);
|
||||
qsf_doc = qofbook_to_qsf(book, params);
|
||||
write_result = 0;
|
||||
if((use_gz_level > 0) && (use_gz_level <= 9))
|
||||
if((params->use_gz_level > 0) && (params->use_gz_level <= 9))
|
||||
{
|
||||
xmlSetDocCompressMode(qsf_doc, use_gz_level);
|
||||
xmlSetDocCompressMode(qsf_doc, params->use_gz_level);
|
||||
}
|
||||
g_return_if_fail(qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
|
||||
write_result = xmlSaveFormatFileEnc(path, qsf_doc, "UTF-8", 1);
|
||||
@@ -804,10 +908,9 @@ write_qsf_to_stdout(QofBook *book, qsf_param *params)
|
||||
xmlSaveFormatFileEnc("-", qsf_doc, "UTF-8", 1);
|
||||
fprintf(stdout, "\n");
|
||||
xmlFreeDoc(qsf_doc);
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
qsf_write_file(QofBackend *be, QofBook *book)
|
||||
{
|
||||
QSFBackend *qsf_be;
|
||||
@@ -826,51 +929,6 @@ qsf_write_file(QofBackend *be, QofBook *book)
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
/* QofBackend routine to load from file - needs a map.
|
||||
*/
|
||||
gboolean
|
||||
load_qsf_object(QofBook *book, const char *fullpath, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr qsf_root, map_root;
|
||||
xmlDocPtr mapDoc, foreign_doc;
|
||||
gchar *map_path, *map_file;
|
||||
|
||||
map_file = g_strdup("pilot-qsf-GnuCashInvoice.xml");
|
||||
foreign_doc = xmlParseFile(fullpath);
|
||||
if (foreign_doc == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
qsf_root = NULL;
|
||||
qsf_root = xmlDocGetRootElement(foreign_doc);
|
||||
params->qsf_ns = qsf_root->ns;
|
||||
params->book = book;
|
||||
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
|
||||
if(map_path == NULL) { return FALSE; }
|
||||
mapDoc = xmlParseFile(map_path);
|
||||
map_root = xmlDocGetRootElement(mapDoc);
|
||||
params->map_ns = map_root->ns;
|
||||
params->input_doc = qsf_object_convert(mapDoc, qsf_root, params);
|
||||
qsfdoc_to_qofbook(params->input_doc, params);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
load_our_qsf_object(QofBook *book, const char *fullpath, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr qsf_root;
|
||||
|
||||
params->input_doc = xmlParseFile(fullpath);
|
||||
if (params->input_doc == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
qsf_root = NULL;
|
||||
qsf_root = xmlDocGetRootElement(params->input_doc);
|
||||
params->qsf_ns = qsf_root->ns;
|
||||
return qsfdoc_to_qofbook(params->input_doc, params);
|
||||
}
|
||||
|
||||
KvpValue*
|
||||
string_to_kvp_value(const char *content, KvpValueType type)
|
||||
{
|
||||
@@ -882,7 +940,7 @@ string_to_kvp_value(const char *content, KvpValueType type)
|
||||
struct tm kvp_time;
|
||||
time_t kvp_time_t;
|
||||
Timespec cm_date;
|
||||
|
||||
|
||||
switch(type) {
|
||||
case KVP_TYPE_GINT64:
|
||||
errno = 0;
|
||||
@@ -932,9 +990,9 @@ string_to_kvp_value(const char *content, KvpValueType type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*======================================================
|
||||
/* ======================================================
|
||||
Commit XML data from file to QofEntity in a QofBook
|
||||
========================================================*/
|
||||
========================================================= */
|
||||
void
|
||||
qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
@@ -971,10 +1029,8 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
void (*i32_setter) (QofEntity*, gint32);
|
||||
void (*i64_setter) (QofEntity*, gint64);
|
||||
void (*char_setter) (QofEntity*, char);
|
||||
void (*kvp_frame_setter) (QofEntity*, KvpFrame*);
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
g_return_if_fail(value != NULL);
|
||||
g_return_if_fail(data && value && key);
|
||||
params = (qsf_param*)data;
|
||||
node = (xmlNodePtr)value;
|
||||
parameter_name = (const char*)key;
|
||||
@@ -989,11 +1045,11 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
cm_setter = qof_class_get_parameter_setter(obj_type, parameter_name);
|
||||
cm_param = qof_class_get_parameter(obj_type, parameter_name);
|
||||
object_set = params->object_set;
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_STRING) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_STRING) == 0) {
|
||||
string_setter = (void(*)(QofEntity*, const char*))cm_setter;
|
||||
if(string_setter != NULL) { string_setter(qsf_ent, (char*)xmlNodeGetContent(node)); }
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_DATE) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_DATE) == 0) {
|
||||
date_setter = (void(*)(QofEntity*, Timespec))cm_setter;
|
||||
timechk = NULL;
|
||||
timechk = strptime((char*)xmlNodeGetContent(node), QSF_XSD_TIME, &qsf_time);
|
||||
@@ -1003,12 +1059,12 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
if(date_setter != NULL) { date_setter(qsf_ent, cm_date); }
|
||||
}
|
||||
if((safe_strcmp(qof_type, QOF_TYPE_NUMERIC) == 0) ||
|
||||
(safe_strcmp(qof_type, QOF_TYPE_DEBCRED) == 0)) {
|
||||
(safe_strcmp(qof_type, QOF_TYPE_DEBCRED) == 0)) {
|
||||
numeric_setter = (void(*)(QofEntity*, gnc_numeric))cm_setter;
|
||||
string_to_gnc_numeric((char*)xmlNodeGetContent(node), &cm_numeric);
|
||||
if(numeric_setter != NULL) { numeric_setter(qsf_ent, cm_numeric); }
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_GUID) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_GUID) == 0) {
|
||||
cm_guid = g_new(GUID, 1);
|
||||
if(TRUE != string_to_guid((char*)xmlNodeGetContent(node), cm_guid))
|
||||
{
|
||||
@@ -1018,7 +1074,7 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
return;
|
||||
}
|
||||
reference_type = (char*)xmlGetProp(node, BAD_CAST QSF_OBJECT_TYPE);
|
||||
if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
|
||||
if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
|
||||
{
|
||||
qof_entity_set_guid(qsf_ent, cm_guid);
|
||||
}
|
||||
@@ -1029,7 +1085,7 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_INT32) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_INT32) == 0) {
|
||||
errno = 0;
|
||||
cm_i32 = (gint32)strtol ((char*)xmlNodeGetContent(node), &tail, 0);
|
||||
if(errno == 0) {
|
||||
@@ -1038,7 +1094,7 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
}
|
||||
else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_INT64) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_INT64) == 0) {
|
||||
errno = 0;
|
||||
cm_i64 = strtoll((char*)xmlNodeGetContent(node), &tail, 0);
|
||||
if(errno == 0) {
|
||||
@@ -1047,7 +1103,7 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
}
|
||||
else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_DOUBLE) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_DOUBLE) == 0) {
|
||||
errno = 0;
|
||||
cm_double = strtod((char*)xmlNodeGetContent(node), &tail);
|
||||
if(errno == 0) {
|
||||
@@ -1055,22 +1111,22 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
if(double_setter != NULL) { double_setter(qsf_ent, cm_double); }
|
||||
}
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_BOOLEAN) == 0){
|
||||
if(0 == safe_strcasecmp((char*)xmlNodeGetContent(node), QSF_XML_BOOLEAN_TEST)) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_BOOLEAN) == 0){
|
||||
if(0 == safe_strcasecmp((char*)xmlNodeGetContent(node),
|
||||
QSF_XML_BOOLEAN_TEST)) {
|
||||
cm_boolean = TRUE;
|
||||
}
|
||||
else { cm_boolean = FALSE; }
|
||||
boolean_setter = (void(*)(QofEntity*, gboolean))cm_setter;
|
||||
if(boolean_setter != NULL) { boolean_setter(qsf_ent, cm_boolean); }
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_KVP) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_KVP) == 0) {
|
||||
cm_type = qsf_to_kvp_helper((char*)xmlGetProp(node, BAD_CAST QSF_OBJECT_VALUE));
|
||||
if(!cm_type) { return; }
|
||||
cm_value = string_to_kvp_value((char*)xmlNodeGetContent(node), cm_type);
|
||||
cm_kvp = kvp_frame_copy(cm_param->param_getfcn(qsf_ent, cm_param));
|
||||
cm_kvp = kvp_frame_set_value(cm_kvp, (char*)xmlGetProp(node, BAD_CAST QSF_OBJECT_KVP), cm_value);
|
||||
kvp_frame_setter = (void(*)(QofEntity*, KvpFrame*))cm_setter;
|
||||
if(kvp_frame_setter != NULL) { kvp_frame_setter(qsf_ent, cm_kvp); }
|
||||
cm_kvp = (KvpFrame*)cm_param->param_getfcn(qsf_ent, cm_param);
|
||||
cm_kvp = kvp_frame_set_value(cm_kvp, (char*)xmlGetProp(node,
|
||||
BAD_CAST QSF_OBJECT_KVP), cm_value);
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_COLLECT) == 0) {
|
||||
QofCollection *qsf_coll;
|
||||
@@ -1087,10 +1143,10 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
PINFO (" string to guid collect failed for %s", xmlNodeGetContent(node));
|
||||
return;
|
||||
}
|
||||
// create a QofEntityReference with this type and GUID.
|
||||
// there is only one entity each time.
|
||||
// cm_guid contains the GUID of the reference.
|
||||
// type is the type of the reference.
|
||||
/* create a QofEntityReference with this type and GUID.
|
||||
there is only one entity each time.
|
||||
cm_guid contains the GUID of the reference.
|
||||
type is the type of the reference. */
|
||||
reference = g_new0(QofEntityReference, 1);
|
||||
reference->type = g_strdup(qsf_ent->e_type);
|
||||
reference->ref_guid = cm_guid;
|
||||
@@ -1101,7 +1157,7 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
reference->param = copy_param;
|
||||
params->referenceList = g_list_append(params->referenceList, reference);
|
||||
}
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_CHAR) == 0) {
|
||||
if(safe_strcmp(qof_type, QOF_TYPE_CHAR) == 0) {
|
||||
char_getter = (char (*)(xmlNodePtr))xmlNodeGetContent;
|
||||
cm_char = char_getter(node);
|
||||
char_setter = (void(*)(QofEntity*, char))cm_setter;
|
||||
@@ -1109,12 +1165,12 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
|
||||
}
|
||||
}
|
||||
|
||||
QofBackend*
|
||||
static QofBackend*
|
||||
qsf_backend_new(void)
|
||||
{
|
||||
QSFBackend *qsf_be;
|
||||
QofBackend *be;
|
||||
|
||||
|
||||
qsf_be = g_new0(QSFBackend, 1);
|
||||
be = (QofBackend*) qsf_be;
|
||||
qof_backend_init(be);
|
||||
@@ -1139,7 +1195,7 @@ qsf_backend_new(void)
|
||||
/* The QSF backend is not multi-user. */
|
||||
be->events_pending = NULL;
|
||||
be->process_events = NULL;
|
||||
|
||||
|
||||
be->sync = qsf_write_file;
|
||||
/* use for maps, later. */
|
||||
be->load_config = qsf_load_config;
|
||||
@@ -1149,12 +1205,10 @@ qsf_backend_new(void)
|
||||
return be;
|
||||
}
|
||||
|
||||
/** \brief The QOF method of loading each backend.
|
||||
|
||||
QSF does not use a GnuCash module, it is loaded using the QOF
|
||||
method - QofBackendProvider.
|
||||
/* The QOF method of loading each backend.
|
||||
QSF is loaded as a GModule using the QOF method - QofBackendProvider.
|
||||
*/
|
||||
static void
|
||||
static void
|
||||
qsf_provider_free (QofBackendProvider *prov)
|
||||
{
|
||||
prov->provider_name = NULL;
|
||||
@@ -1162,8 +1216,6 @@ qsf_provider_free (QofBackendProvider *prov)
|
||||
g_free (prov);
|
||||
}
|
||||
|
||||
/* although we call gettext here, none of the
|
||||
QofBackendProvider strings are translatable. */
|
||||
void
|
||||
qsf_provider_init(void)
|
||||
{
|
||||
@@ -1176,7 +1228,7 @@ qsf_provider_init(void)
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
#endif
|
||||
prov = g_new0 (QofBackendProvider, 1);
|
||||
prov->provider_name = "QSF Backend Version 0.1";
|
||||
prov->provider_name = "QSF Backend Version 0.2";
|
||||
prov->access_method = "file";
|
||||
prov->partial_book_supported = TRUE;
|
||||
prov->backend_new = qsf_backend_new;
|
||||
|
@@ -2,10 +2,9 @@
|
||||
* qsf-xml-map.c
|
||||
*
|
||||
* Sat Jan 1 07:31:55 2005
|
||||
* Copyright 2005 Neil Williams
|
||||
* Copyright 2005-2006 Neil Williams
|
||||
* linux@codehelp.co.uk
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -19,8 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
@@ -30,10 +28,13 @@
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include "qof.h"
|
||||
#include "qof-backend-qsf.h"
|
||||
#include "qsf-xml.h"
|
||||
#include "qsf-dir.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QSF;
|
||||
|
||||
static void
|
||||
qsf_date_default_handler(const char *default_name, GHashTable *qsf_default_hash,
|
||||
xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
|
||||
@@ -66,7 +67,7 @@ qsf_string_default_handler(const char *default_name, GHashTable *qsf_default_has
|
||||
xmlNodeAddContent(node, output);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
qsf_map_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid)
|
||||
{
|
||||
xmlChar *qof_version, *match;
|
||||
@@ -118,21 +119,21 @@ gboolean is_qsf_object_with_map_be(char *map_file, qsf_param *params)
|
||||
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
|
||||
if(path == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if(doc == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) {
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
object_root = xmlDocGetRootElement(doc);
|
||||
if(map_path == NULL) {
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
map_doc = xmlParseFile(map_path);
|
||||
@@ -140,9 +141,9 @@ gboolean is_qsf_object_with_map_be(char *map_file, qsf_param *params)
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, map_doc)) {
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, map_doc)) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_MAP);
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(map_doc);
|
||||
valid.map_calculated_count = 0;
|
||||
@@ -251,7 +252,7 @@ gboolean is_qsf_map_be(qsf_param *params)
|
||||
}
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_MAP);
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(doc);
|
||||
map_ns = map_root->ns;
|
||||
@@ -281,7 +282,7 @@ gboolean is_qsf_map(const char *path)
|
||||
doc = xmlParseFile(path);
|
||||
if(doc == NULL) { return FALSE; }
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) {
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(doc);
|
||||
map_ns = map_root->ns;
|
||||
@@ -301,7 +302,7 @@ static void
|
||||
qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
|
||||
{
|
||||
xmlChar *qsf_enum;
|
||||
|
||||
|
||||
g_return_if_fail(params->qsf_define_hash != NULL);
|
||||
if (qsf_is_element(child, ns, MAP_DEFINE_TAG)) {
|
||||
if(NULL == g_hash_table_lookup(params->qsf_define_hash,
|
||||
@@ -312,6 +313,7 @@ qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
|
||||
}
|
||||
else {
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_MAP);
|
||||
PERR (" ERR_QSF_BAD_MAP set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -320,18 +322,20 @@ qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
|
||||
{
|
||||
qsf_enum = xmlNodeGetContent(child);
|
||||
/** Use content to discriminate enums in QOF */
|
||||
PERR (" enum todo incomplete");
|
||||
/** \todo FIXME: the default enum value is not used
|
||||
implemented properly or fully handled.
|
||||
*/
|
||||
if(NULL == g_hash_table_lookup(params->qsf_default_hash,
|
||||
xmlNodeGetContent(child)))
|
||||
{
|
||||
g_hash_table_insert(params->qsf_default_hash,
|
||||
g_hash_table_insert(params->qsf_default_hash,
|
||||
xmlNodeGetContent(child), child);
|
||||
}
|
||||
else
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_MAP);
|
||||
PERR (" ERR_QSF_BAD_MAP set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -348,13 +352,14 @@ qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
|
||||
xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_MAP);
|
||||
LEAVE (" ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
qsf_map_top_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
{
|
||||
xmlChar *qof_version;
|
||||
@@ -369,6 +374,7 @@ qsf_map_top_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
g_string_printf(buff, "%i", QSF_QOF_VERSION);
|
||||
if(xmlStrcmp(qof_version, BAD_CAST buff->str) != 0) {
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_QOF_VERSION);
|
||||
PERR (" ERR_QSF_BAD_QOF_VERSION set");
|
||||
return;
|
||||
}
|
||||
iter.ns = ns;
|
||||
@@ -394,7 +400,7 @@ qsf_else_set_value(xmlNodePtr parent, GHashTable *default_hash,
|
||||
}
|
||||
|
||||
/* Handles the set tag in the map.
|
||||
This function will be overhauled once inside QOF
|
||||
This function will be overhauled once inside QOF
|
||||
QOF hook required for "Lookup in the receiving application"
|
||||
*/
|
||||
static char*
|
||||
@@ -403,25 +409,27 @@ qsf_set_handler(xmlNodePtr parent, GHashTable *default_hash,
|
||||
{
|
||||
xmlNodePtr cur_node, lookup_node;
|
||||
|
||||
ENTER (" lookup problem");
|
||||
content = NULL;
|
||||
for(cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
if(qsf_is_element(cur_node, params->map_ns, QSF_CONDITIONAL_SET))
|
||||
if(qsf_is_element(cur_node, params->map_ns, QSF_CONDITIONAL_SET))
|
||||
{
|
||||
content = (char*)xmlGetProp(cur_node, BAD_CAST QSF_OPTION);
|
||||
if(qsf_strings_equal(xmlGetProp(cur_node, BAD_CAST QSF_OPTION), "qsf_lookup_string"))
|
||||
if(qsf_strings_equal(xmlGetProp(cur_node, BAD_CAST QSF_OPTION), "qsf_lookup_string"))
|
||||
{
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(default_hash,
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(default_hash,
|
||||
xmlNodeGetContent(cur_node));
|
||||
content = (char*)xmlGetProp(lookup_node, BAD_CAST MAP_VALUE_ATTR);
|
||||
/** \todo FIXME: do the lookup. type is defined by output object. */
|
||||
/* Find by name, get GUID, return GUID as string. */
|
||||
g_message("Lookup %s in the receiving application\n", content );
|
||||
LEAVE (" todo");
|
||||
return content;
|
||||
}
|
||||
if(content)
|
||||
if(content)
|
||||
{
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(default_hash,
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(default_hash,
|
||||
xmlNodeGetContent(cur_node));
|
||||
content = (char*)xmlGetProp(lookup_node, BAD_CAST "value");
|
||||
return content;
|
||||
@@ -432,10 +440,12 @@ qsf_set_handler(xmlNodePtr parent, GHashTable *default_hash,
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(params->qsf_parameter_hash,
|
||||
xmlGetProp(parent->parent, BAD_CAST MAP_TYPE_ATTR));
|
||||
if(lookup_node) { return (char*)xmlNodeGetContent(lookup_node); }
|
||||
LEAVE (" check arguments");
|
||||
return (char*)xmlNodeGetContent(cur_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
LEAVE (" null");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -490,6 +500,7 @@ qsf_set_format_value(xmlChar *format, char *qsf_time_now_as_string,
|
||||
|
||||
result = 0;
|
||||
if(format == NULL) { return; }
|
||||
ENTER (" ");
|
||||
content = xmlNodeGetContent(cur_node);
|
||||
output = (time_t*) g_hash_table_lookup(params->qsf_default_hash, content);
|
||||
if(!output) {
|
||||
@@ -501,13 +512,13 @@ qsf_set_format_value(xmlChar *format, char *qsf_time_now_as_string,
|
||||
/** \todo qsf_parameter_hash check correct arguments */
|
||||
kl = (xmlNodePtr) g_hash_table_lookup(params->qsf_parameter_hash, content);
|
||||
if(!kl) {
|
||||
printf("no suitable date set.\n");
|
||||
LEAVE (" no suitable date set.");
|
||||
return;
|
||||
}
|
||||
/** Read the object value as a dateTime */
|
||||
strptime((char*)xmlNodeGetContent(kl), QSF_XSD_TIME, tmp);
|
||||
if(!tmp) {
|
||||
printf("empty date field in QSF object.\n");
|
||||
LEAVE (" empty date field in QSF object.\n");
|
||||
return;
|
||||
}
|
||||
tester = mktime(tmp);
|
||||
@@ -520,6 +531,7 @@ qsf_set_format_value(xmlChar *format, char *qsf_time_now_as_string,
|
||||
/** QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats.
|
||||
*/
|
||||
strftime(qsf_time_now_as_string, QSF_DATE_LENGTH, (char*)format, gmtime(output));
|
||||
LEAVE (" ok");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -546,7 +558,6 @@ qsf_calculate_conditional(xmlNodePtr param_node, xmlNodePtr child, qsf_param *pa
|
||||
|
||||
output_content = NULL;
|
||||
if(qsf_is_element(param_node, params->map_ns, QSF_CONDITIONAL)) {
|
||||
printf("param_node=%s\n", param_node->name);
|
||||
if(params->boolean_calculation_done == 0) {
|
||||
/* set handler */
|
||||
output_content = BAD_CAST qsf_set_handler(param_node, params->qsf_default_hash,
|
||||
@@ -559,7 +570,7 @@ qsf_calculate_conditional(xmlNodePtr param_node, xmlNodePtr child, qsf_param *pa
|
||||
BAD_CAST QSF_BOOLEAN_DEFAULT) ), BAD_CAST MAP_VALUE_ATTR);
|
||||
}
|
||||
/* Is the default set to true? */
|
||||
if( 0 == qsf_compare_tag_strings(output_content, QSF_XML_BOOLEAN_TEST))
|
||||
if( 0 == qsf_compare_tag_strings(output_content, QSF_XML_BOOLEAN_TEST))
|
||||
{
|
||||
qsf_boolean_set_value(param_node, params, (char*)output_content, params->map_ns);
|
||||
export_node = xmlAddChild(params->lister, xmlNewNode(params->qsf_ns,
|
||||
@@ -587,13 +598,13 @@ qsf_add_object_tag(qsf_param *params, int count)
|
||||
extra_node = xmlAddChild(params->output_node,
|
||||
xmlNewNode(params->qsf_ns, BAD_CAST QSF_OBJECT_TAG));
|
||||
xmlNewProp(extra_node, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(params->cur_node, BAD_CAST QSF_OBJECT_TYPE));
|
||||
xmlGetProp(params->convert_node, BAD_CAST QSF_OBJECT_TYPE));
|
||||
property = xmlCharStrdup(str->str);
|
||||
xmlNewProp(extra_node, BAD_CAST QSF_OBJECT_COUNT, property);
|
||||
return extra_node;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
qsf_map_object_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr param_node, export_node;
|
||||
@@ -609,7 +620,7 @@ qsf_map_object_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
if(child == NULL) { return; }
|
||||
if(ns == NULL) { return; }
|
||||
params->boolean_calculation_done = 0;
|
||||
|
||||
|
||||
if(qsf_is_element(child, map_ns, MAP_CALCULATE_TAG)) {
|
||||
params->boolean_calculation_done = 0;
|
||||
for(param_node = child->children; param_node != NULL;
|
||||
@@ -669,11 +680,12 @@ qsf_map_object_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
xmlGetProp(child_node, MAP_VALUE_ATTR), child_node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
is_qsf_object_with_map(path, map_path);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
xmlDocPtr
|
||||
qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
|
||||
{
|
||||
@@ -682,6 +694,7 @@ qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
|
||||
xmlNode *cur_node;
|
||||
xmlNode *map_root, *output_root, *output_node;
|
||||
|
||||
ENTER (" ");
|
||||
output_doc = xmlNewDoc(BAD_CAST QSF_XML_VERSION);
|
||||
output_root = xmlDocCopyNode(qsf_root,output_doc,2);
|
||||
xmlSetNs(output_root, params->qsf_ns);
|
||||
@@ -693,11 +706,9 @@ qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
|
||||
iter.ns = params->map_ns;
|
||||
qsf_node_foreach(map_root, qsf_map_top_node_handler, &iter, params);
|
||||
|
||||
// iter.ns = qsf_ns;
|
||||
// qsf_node_foreach(qsf_root, qsf_map_object_handler, &iter, params);
|
||||
for(cur_node = map_root->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
params->cur_node = cur_node;
|
||||
params->convert_node = cur_node;
|
||||
params->count = 0;
|
||||
if(qsf_is_element(cur_node, params->map_ns, MAP_OBJECT_TAG))
|
||||
{
|
||||
@@ -708,5 +719,6 @@ qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
|
||||
}
|
||||
}
|
||||
params->file_type = OUR_QSF_OBJ;
|
||||
LEAVE (" ");
|
||||
return output_doc;
|
||||
}
|
||||
|
@@ -18,30 +18,19 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <libxml/xmlversion.h>
|
||||
#include "qof.h"
|
||||
#include "qof-backend-qsf.h"
|
||||
#include "qsf-dir.h"
|
||||
#include "qsf-xml.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QSF;
|
||||
|
||||
void qsf_free_params(qsf_param *params)
|
||||
{
|
||||
g_hash_table_destroy(params->qsf_calculate_hash);
|
||||
g_hash_table_destroy(params->qsf_default_hash);
|
||||
if(params->referenceList) {
|
||||
g_list_free(params->referenceList);
|
||||
}
|
||||
g_slist_free(params->supported_types);
|
||||
if(params->map_ns) { xmlFreeNs(params->map_ns); }
|
||||
}
|
||||
|
||||
int
|
||||
qsf_compare_tag_strings(const xmlChar *node_name, char *tag_name)
|
||||
{
|
||||
@@ -138,13 +127,13 @@ qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *vali
|
||||
if(g_hash_table_size(valid->validation_table) > count)
|
||||
{
|
||||
valid->valid_object_count++;
|
||||
if(TRUE == qof_class_is_registered((QofIdTypeConst) object_declaration))
|
||||
{
|
||||
valid->qof_registered_count++;
|
||||
if(TRUE == qof_class_is_registered((QofIdTypeConst) object_declaration))
|
||||
{
|
||||
valid->qof_registered_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean is_our_qsf_object(const char *path)
|
||||
@@ -164,13 +153,14 @@ gboolean is_our_qsf_object(const char *path)
|
||||
return FALSE;
|
||||
}
|
||||
object_root = xmlDocGetRootElement(doc);
|
||||
/* check that all objects in the file are already registered in QOF */
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
valid.qof_registered_count = 0;
|
||||
valid.valid_object_count = 0;
|
||||
iter.ns = object_root->ns;
|
||||
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
|
||||
table_count = g_hash_table_size(valid.validation_table);
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
if(table_count == valid.qof_registered_count) { return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
@@ -184,8 +174,9 @@ gboolean is_qsf_object(const char *path)
|
||||
doc = xmlParseFile(path);
|
||||
if(doc == NULL) { return FALSE; }
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) { return FALSE; }
|
||||
/** \todo implement a way of finding more than one map */
|
||||
return is_qsf_object_with_map(path, "pilot-qsf-GnuCashInvoice.xml");
|
||||
/* Note cannot test against a map here, so if the file is valid QSF,
|
||||
accept it and work out the details later. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean is_our_qsf_object_be(qsf_param *params)
|
||||
@@ -209,7 +200,7 @@ gboolean is_our_qsf_object_be(qsf_param *params)
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
|
||||
return FALSE;
|
||||
@@ -234,7 +225,9 @@ gboolean is_our_qsf_object_be(qsf_param *params)
|
||||
|
||||
gboolean is_qsf_object_be(qsf_param *params)
|
||||
{
|
||||
gboolean result;
|
||||
xmlDocPtr doc;
|
||||
GList *maps;
|
||||
char *path;
|
||||
|
||||
g_return_val_if_fail((params != NULL),FALSE);
|
||||
@@ -258,8 +251,14 @@ gboolean is_qsf_object_be(qsf_param *params)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
/** \todo implement a way of finding more than one map */
|
||||
return is_qsf_object_with_map_be("pilot-qsf-GnuCashInvoice.xml", params);
|
||||
result = FALSE;
|
||||
/* retrieve list of maps from config frame. */
|
||||
for(maps = params->map_files; maps; maps=maps->next)
|
||||
{
|
||||
result = is_qsf_object_with_map_be(maps->data, params);
|
||||
if(result) { break;}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -18,15 +18,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef QSF_XML_H
|
||||
#define QSF_XML_H
|
||||
|
||||
/** @file qsf-xml.h
|
||||
@brief Private QSF header
|
||||
@brief Private QSF header - not for use by applications
|
||||
@author Copyright (C) 2004-2005 Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
@@ -39,15 +38,7 @@
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include "gnc-date.h"
|
||||
#include "qof_book_merge.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofclass.h"
|
||||
#include "qofobject.h"
|
||||
#include "kvp_frame.h"
|
||||
#include "qofbackend-p.h"
|
||||
#include "qofsession-p.h"
|
||||
#include "qofbook-p.h"
|
||||
#include "qof.h"
|
||||
|
||||
#if defined(HAVE_GETTEXT) /* HAVE_GETTEXT */
|
||||
|
||||
@@ -118,14 +109,18 @@ Make sure the same version of QOF is in use in both applications.
|
||||
|
||||
The map namespace is not included as maps are not currently written out by QOF.
|
||||
*/
|
||||
#define QSF_DATE_LENGTH 31 /**< Max length of QSF_XSD_TIME */
|
||||
#define QSF_BOOK_TAG "book" /**< First level child: book tag - the ::QofBook. */
|
||||
#define QSF_BOOK_GUID "book-guid" /**< QOF GUID tag for the QofBook described by this QSF object file */
|
||||
#define QSF_BOOK_COUNT "count" /**< Sequential counter of each book in this file */
|
||||
#define QSF_OBJECT_TAG "object" /**< Second level child: object tag */
|
||||
#define QSF_OBJECT_TYPE "type" /**< QSF parameter name for object type specifiers */
|
||||
#define QSF_OBJECT_COUNT "count" /**< Sequential counter for each QSF object in this file */
|
||||
#define QSF_XML_VERSION "1.0" /**< The current XML version. */
|
||||
#define QSF_DATE_LENGTH MAX_DATE_LENGTH /**< Max length of QSF_XSD_TIME.
|
||||
|
||||
MAX_DATE_LENGTH itself is defined in gnc-date.h */
|
||||
#define QSF_BOOK_TAG "book" /**< First level child: book tag - the ::QofBook. */
|
||||
#define QSF_BOOK_GUID "book-guid" /**< QOF GUID tag for the QofBook
|
||||
described by this QSF object file */
|
||||
#define QSF_BOOK_COUNT "count" /**< Sequential counter of each book in this file */
|
||||
#define QSF_OBJECT_TAG "object" /**< Second level child: object tag */
|
||||
#define QSF_OBJECT_TYPE "type" /**< QSF parameter name for object type specifiers */
|
||||
#define QSF_OBJECT_COUNT "count" /**< Sequential counter for each QSF object
|
||||
in this file */
|
||||
#define QSF_XML_VERSION "1.0" /**< The current XML version. */
|
||||
|
||||
/** @} */
|
||||
/** @name Representing KVP as XML
|
||||
@@ -161,11 +156,12 @@ No text content allowed.
|
||||
Attributes: e_type Copied directly from the QofObject definition.
|
||||
Content: The full QofObject description for the defined QOF object.
|
||||
*/
|
||||
#define MAP_DEFAULT_TAG "default" /**< User editable defaults for data not available within the
|
||||
available QSF objects.
|
||||
#define MAP_DEFAULT_TAG "default" /**< User editable defaults for data not
|
||||
available within the available QSF objects.
|
||||
|
||||
Some defaults will relate to how to format descriptive dates, whether discount should be considered,
|
||||
which account to use for certain QSF data from applications that don't use accounts.
|
||||
Some defaults will relate to how to format descriptive dates, whether discount
|
||||
should be considered, which account to use for certain QSF data from applications
|
||||
that don't use accounts.
|
||||
|
||||
Some defaults are pre-defined and cannot be over-written:
|
||||
- qsf_time_now
|
||||
@@ -173,10 +169,10 @@ Some defaults are pre-defined and cannot be over-written:
|
||||
|
||||
Attributes (All are mandatory):
|
||||
|
||||
\a name The text name for this default. Certain pre-defined defaults exist but user- or
|
||||
map-defined defaults can have any unique text name. Spaces are \b NOT allowed, use undersccores
|
||||
instead. The value of name must not duplicate any existing default, define, object or parameter
|
||||
unless the special type, enum, is used.
|
||||
\a name The text name for this default. Certain pre-defined defaults exist but
|
||||
user- or map-defined defaults can have any unique text name. Spaces are \b NOT allowed,
|
||||
use undersccores instead. The value of name must not duplicate any existing default,
|
||||
define, object or parameter unless the special type, enum, is used.
|
||||
|
||||
\a type QOF_TYPE - must be one of the recognised QOF data types for the
|
||||
qof_version in use or the special type, enum.
|
||||
@@ -188,10 +184,10 @@ qof_version in use or the special type, enum.
|
||||
|
||||
A boolean default is not output in the QSF directly, instead the value is
|
||||
used in the calculations to modify certain values. If the boolean default
|
||||
is set to true, the if statement containing the boolean name will be evaluated. If the boolean
|
||||
default is set to false, the corresponding else will be evaluted. Make sure your
|
||||
calculations contain an appropriate else statement so that the boolean value
|
||||
can be adjusted without invalidating the map!
|
||||
is set to true, the if statement containing the boolean name will be evaluated.
|
||||
If the boolean default is set to false, the corresponding else will be evaluted.
|
||||
Make sure your calculations contain an appropriate else statement so that the
|
||||
boolean value can be adjusted without invalidating the map!
|
||||
|
||||
QSF deals with partial QofBooks - each object is fully described but the
|
||||
book does not have to contain any specific object types or have any
|
||||
@@ -209,51 +205,60 @@ required object is converted to the GUID for that specific entity. The
|
||||
map cannot contain the GUID as it is generic and used by multiple users.
|
||||
|
||||
\attention Using enumerators
|
||||
- enum types are the only defaults that are allowed to use the same name value more than once.
|
||||
- enum types are the only defaults that are allowed to use the same name value
|
||||
more than once.
|
||||
- enum types are used to increase the readability of a QSF map.
|
||||
- The enum name acts to group the enum values together - in a similar fashion to radio buttons in HTML forms.
|
||||
- The enum name acts to group the enum values together - in a similar fashion to
|
||||
radio buttons in HTML forms.
|
||||
- enum types are used only where the QOF object itself uses an enum type.
|
||||
|
||||
e.g. the tax_included enum type allows maps to use the full name of the enum value GNC_TAXINCLUDED_YES,
|
||||
instead of the cryptic digit value, 1.
|
||||
e.g. the tax_included enum type allows maps to use the full name of the enum
|
||||
value GNC_TAXINCLUDED_YES, instead of the cryptic digit value, 1.
|
||||
|
||||
*/
|
||||
#define MAP_OBJECT_TAG "object" /**< Contains all the calculations to make one object from others.
|
||||
#define MAP_OBJECT_TAG "object" /**< Contains all the calculations to make one
|
||||
object from others.
|
||||
|
||||
Note that creating an object for the import application can involve using data from more than one
|
||||
QSF object, as well as defaults and lookups in the import application itself. Conditionals, simple
|
||||
arithmetic and date/time formatting options are also available.
|
||||
Note that creating an object for the import application can involve using data
|
||||
from more than one QSF object, as well as defaults and lookups in the import
|
||||
application itself. Conditionals, simple arithmetic and date/time formatting
|
||||
options are also available.
|
||||
*/
|
||||
#define MAP_CALCULATE_TAG "calculate" /**< One calculation for every parameter that needs to be set.
|
||||
#define MAP_CALCULATE_TAG "calculate" /**< One calculation for every parameter
|
||||
that needs to be set.
|
||||
|
||||
QSF follows the same rule as qof_book_merge. Only if a getter and a setter function are defined for
|
||||
a parameter is it available to QSF. If a ::QofAccessFunc and ::QofSetterFunc are both defined
|
||||
for any QofObject parameter, that parameter \b MUST be calculated in any map that defines that object.
|
||||
QSF follows the same rule as qof_book_merge. Only if a getter and a setter
|
||||
function are defined for a parameter is it available to QSF. If a ::QofAccessFunc
|
||||
and ::QofSetterFunc are both defined for any QofObject parameter, that parameter
|
||||
\b MUST be calculated in any map that defines that object.
|
||||
*/
|
||||
#define MAP_QOF_VERSION "qof_version" /**< This is the QOF_OBJECT_VERSION from QOF.
|
||||
|
||||
QSF maps may need to be updated if QOF itself is upgraded. This setting is coded into QOF and
|
||||
maps for one version cannot necessarily be used by other versions. At the first release of QSF,
|
||||
QOF_OBJECT_VERSION = 3.
|
||||
QSF maps may need to be updated if QOF itself is upgraded. This setting is coded
|
||||
into QOF and maps for one version cannot necessarily be used by other versions.
|
||||
At the first release of QSF, QOF_OBJECT_VERSION = 3.
|
||||
*/
|
||||
#define MAP_NAME_ATTR "name" /**< The name of the default setting.
|
||||
|
||||
Use this name to refer to the value of this default in the map calculations.
|
||||
|
||||
Make sure that the type of this default matches the type of the parameter being set by the
|
||||
parent calculation!
|
||||
Make sure that the type of this default matches the type of the parameter being
|
||||
set by the parent calculation!
|
||||
*/
|
||||
#define MAP_TYPE_ATTR "type" /**< QSF will NOT convert between QOF types.
|
||||
|
||||
QSF will allow a conditional to use a parameter of one type to determine the value from a parameter of
|
||||
another type, but the final value assigned \b MUST be of the same type as the parent calculation.
|
||||
QSF will allow a conditional to use a parameter of one type to determine the
|
||||
value from a parameter of another type, but the final value assigned \b MUST be
|
||||
of the same type as the parent calculation.
|
||||
*/
|
||||
#define MAP_VALUE_ATTR "value" /**< The value of the tag, used in defaults and calculations.
|
||||
#define MAP_VALUE_ATTR "value" /**< The value of the tag, used in defaults and
|
||||
calculations.
|
||||
|
||||
The value of a default is a string representation of the value to be inserted into
|
||||
the calculation where the default is used.
|
||||
|
||||
The value of a calculation is the name of the parameter that will be set by that calculation.
|
||||
The value of a calculation is the name of the parameter that will be set by that
|
||||
calculation.
|
||||
*/
|
||||
#define MAP_E_TYPE "e_type" /**< Validates the objects defined in the map
|
||||
|
||||
@@ -283,16 +288,17 @@ Conditionals can reference parameter as well as object values.
|
||||
Map assignments can use the native values within the output object. The output object
|
||||
must support setting the relevant parameter using the value exactly as given in the map
|
||||
because the relevant set() function will be called using this value. This may reduce the
|
||||
readability of the map but the relevant application could also be modified to support a more
|
||||
readable set function.
|
||||
readability of the map but the relevant application could also be modified to support
|
||||
a more readable set function.
|
||||
*/
|
||||
#define QSF_CONDITIONAL_ELSE "else" /**< Alternative
|
||||
|
||||
if(){} else{} is also supported. Nesting of conditionals causes problems for validating the
|
||||
final map against any sensible XML Schema and a map that doesn't validate will be rejected.
|
||||
When editing conditionals in a QSF map, ALWAYS validate the map using xmllint. If necessary,
|
||||
define a variable at the foot of the definitions block, using a similar syntax to a default,
|
||||
then use that variable in another conditional
|
||||
if(){} else{} is also supported. Nesting of conditionals causes problems for
|
||||
validating the final map against any sensible XML Schema and a map that doesn't
|
||||
validate will be rejected. When editing conditionals in a QSF map, ALWAYS
|
||||
validate the map using xmllint. If necessary, define a variable at the foot of
|
||||
the definitions block, using a similar syntax to a default, then use that
|
||||
variable in another conditional
|
||||
|
||||
\a variable \a name="my_rate" \a type="numeric" \a value="0/1"
|
||||
|
||||
@@ -322,7 +328,8 @@ on other data types will be ignored.
|
||||
|
||||
/** @} */
|
||||
|
||||
#define QSF_XSD_TIME QOF_UTC_DATE_FORMAT /**< xsd:dateTime format in coordinated universal time, UTC.
|
||||
#define QSF_XSD_TIME QOF_UTC_DATE_FORMAT /**< xsd:dateTime format in coordinated
|
||||
universal time, UTC.
|
||||
|
||||
You can reproduce the string from the GNU/Linux command line using the date utility:
|
||||
|
||||
@@ -332,21 +339,22 @@ date -u +%Y-%m-%dT%H:%M:%SZ
|
||||
|
||||
The datestring must be timezone independent and include all specified fields.
|
||||
|
||||
Remember to use gmtime() NOT localtime()!. From the command line, use the -u switch with the
|
||||
date command: date -u
|
||||
Remember to use gmtime() NOT localtime()!. From the command line, use the
|
||||
-u switch with the date command: date -u
|
||||
|
||||
To generate a timestamp based on a real time, use the qsf_time_now and qsf_time_string defaults.
|
||||
To generate a timestamp based on a real time, use the qsf_time_now and
|
||||
qsf_time_string defaults.
|
||||
|
||||
qsf_time_now : Format: QOF_TYPE_DATE. The current time taken from the moment the default
|
||||
is read into a QSF object at runtime.
|
||||
qsf_time_now : Format: QOF_TYPE_DATE. The current time taken from the moment
|
||||
the default is read into a QSF object at runtime.
|
||||
|
||||
qsf_time_string : Format: QOF_TYPE_STRING. The current timestamp taken from the moment the
|
||||
default is read into a QSF object at runtime. This form is used when the output parameter
|
||||
needs a formatted date string, not an actual date object. The format is determined by the
|
||||
optional format attribute of the set tag which takes the same operators as the GNU C Library
|
||||
for strftime() and output may therefore be dependent on the locale of the calling process -
|
||||
\b take \b care. Default value is %F, used when qsf_time_string is set without the format
|
||||
attribute.
|
||||
qsf_time_string : Format: QOF_TYPE_STRING. The current timestamp taken from the
|
||||
moment the default is read into a QSF object at runtime. This form is used when
|
||||
the output parameter needs a formatted date string, not an actual date object.
|
||||
The format is determined by the optional format attribute of the set tag which
|
||||
takes the same operators as the GNU C Library for strftime() and output may therefore
|
||||
be dependent on the locale of the calling process - \b take \b care. Default value
|
||||
is %F, used when qsf_time_string is set without the format attribute.
|
||||
|
||||
Both defaults use UTC.
|
||||
|
||||
@@ -371,10 +379,16 @@ typedef struct qsf_metadata
|
||||
GList *referenceList; /**< Table of references, ::QofEntityReference. */
|
||||
GHashTable *qsf_parameter_hash; /**< Hashtable of parameters for each object */
|
||||
GHashTable *qsf_calculate_hash, *qsf_default_hash, *qsf_define_hash;
|
||||
GSList *supported_types; /**< The partial list of QOF types currently supported, in QSF order. */
|
||||
xmlDocPtr input_doc, output_doc; /**< Pointers to the input and output xml document(s). */
|
||||
/** \todo Review the list of xml nodes in qsf_param and rationalise. */
|
||||
xmlNodePtr child_node, cur_node, param_node, output_node, output_root, book_node, lister;
|
||||
GSList *supported_types; /**< The list of QOF types currently supported, in QSF order. */
|
||||
xmlDocPtr input_doc; /**< Pointer to the input xml document(s). */
|
||||
xmlDocPtr output_doc; /**< Pointer to the output xml document(s). */
|
||||
xmlNodePtr child_node; /**< The current child_node. */
|
||||
xmlNodePtr convert_node; /**< Node in the converted object */
|
||||
xmlNodePtr param_node; /**< Node for parameter data. */
|
||||
xmlNodePtr output_node; /**< Node in the output document. */
|
||||
xmlNodePtr output_root; /**< Root node of the output document. */
|
||||
xmlNodePtr book_node; /**< Node for the book. */
|
||||
xmlNodePtr lister; /**< Comparison node for map defaults. */
|
||||
xmlNsPtr qsf_ns, map_ns; /**< Separate namespaces for QSF objects and QSF maps. */
|
||||
const char *qof_type; /**< Holds details of the QOF_TYPE */
|
||||
QofIdType qof_obj_type; /**< current QofObject type (e_type) for the parameters. */
|
||||
@@ -387,23 +401,19 @@ typedef struct qsf_metadata
|
||||
Theoretically, QSF can handle multiple QofBooks - currently limited to 1.
|
||||
*/
|
||||
int boolean_calculation_done; /**< simple trip once this boolean is complete. */
|
||||
char *filepath; /**< Path to the QSF file. */
|
||||
char *filepath; /**< Path to the QSF file. */
|
||||
gchar* full_kvp_path; /**< Full path for each KvpValue written out. */
|
||||
gint use_gz_level; /**< Default compression level. */
|
||||
GList *map_files; /**< List of selected map files for this session.
|
||||
|
||||
Defaults to the pre-installed QSF maps, currently: pilot-qsf-GnuCashInvoice.xml
|
||||
*/
|
||||
}qsf_param;
|
||||
|
||||
/** \brief Free the QSF context.
|
||||
|
||||
Frees the two GHashTables, the GSList, the output xmlDoc
|
||||
and the two xmlNs namespaces.
|
||||
*/
|
||||
void qsf_free_params(qsf_param *params);
|
||||
|
||||
/** \brief Validation metadata
|
||||
|
||||
The validation is a separate parse with separate data.
|
||||
This may change but it currently saves workload.
|
||||
|
||||
\todo Examine ways of making the Validation metadata
|
||||
into a sub-set of the main code, not an island on it's own.
|
||||
This is used to determine which backend should load the data.
|
||||
*/
|
||||
typedef struct qsf_validates
|
||||
{
|
||||
@@ -416,7 +426,6 @@ typedef struct qsf_validates
|
||||
int qof_registered_count;
|
||||
}qsf_validator;
|
||||
|
||||
|
||||
/** \brief shorthand function
|
||||
|
||||
This may look repetitive but each one is used separately
|
||||
@@ -457,28 +466,6 @@ objects that are also registered with QOF in the host application.
|
||||
void
|
||||
qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid);
|
||||
|
||||
/** @name Map Checks
|
||||
@{
|
||||
Check that the map is sufficient for this object.
|
||||
|
||||
Map is usable if all input objects are defined in the object file.
|
||||
Count define tags, subtract those calculated in the map (defined as objects)
|
||||
Check each remaining object e_type and description against the objects
|
||||
declared in the object file. Fail if some map objects remain undefined.
|
||||
|
||||
not finished - expect noticeable changes.
|
||||
|
||||
*/
|
||||
void
|
||||
qsf_map_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid);
|
||||
|
||||
void
|
||||
qsf_map_top_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params);
|
||||
|
||||
void
|
||||
qsf_map_object_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params);
|
||||
/** @} */
|
||||
|
||||
/** \brief Compares an xmlDoc in memory against the schema file.
|
||||
|
||||
@param schema_dir set at compile time to $prefix/share/qsf/
|
||||
@@ -494,6 +481,52 @@ Incorrect validation will result in output to the terminal window.
|
||||
gboolean
|
||||
qsf_is_valid(const char *schema_dir, const char* schema_filename, xmlDocPtr doc);
|
||||
|
||||
/** \brief Prepare the default list of maps.
|
||||
|
||||
Prepend the default maps to the supplied GList.
|
||||
|
||||
The GList remains the property of the caller.
|
||||
*/
|
||||
GList** qsf_map_prepare_list(GList **maps);
|
||||
|
||||
/** \name Why two sets of functions and typedefs?
|
||||
|
||||
These functions are in pairs, one to use in an existing session and one to use
|
||||
when deciding which backend should be selected for a new session.
|
||||
- When there is an existing QofSession, the qsf_param
|
||||
context will be available, so set error codes in the backend.
|
||||
Use the *_be functions.
|
||||
- When just determining the type of file, qsf_param is
|
||||
not necessary and no backend is available (it has not been selected yet).
|
||||
Use the twin function. e.g. in ::qsf_file_type()
|
||||
|
||||
@{
|
||||
*/
|
||||
/** \brief map and qsf object callback
|
||||
|
||||
This callback cannot do both the map and the validation tasks
|
||||
because validation sometimes needs to be done without qsf_params.
|
||||
|
||||
e.g. when selecting which backend should be used for a particular
|
||||
data source where two or more backends share the same access_method.
|
||||
*/
|
||||
typedef void (* qsf_nodeCB)(xmlNodePtr, xmlNsPtr, qsf_param*);
|
||||
/** \brief validator callback
|
||||
|
||||
\todo The need for separate metadata means a separate callback typedef
|
||||
is needed for the validator, but this should be fixed to only need one.
|
||||
*/
|
||||
typedef void (* qsf_validCB)(xmlNodePtr, xmlNsPtr, qsf_validator*);
|
||||
/** \brief One iterator, two typedefs
|
||||
|
||||
\todo resolve the two callbacks in ::qsf_node_iterate into one.
|
||||
*/
|
||||
struct qsf_node_iterate {
|
||||
qsf_nodeCB *fcn;
|
||||
qsf_validCB *v_fcn;
|
||||
xmlNsPtr ns;
|
||||
};
|
||||
|
||||
/** \brief Validate a QSF file and identify a suitable QSF map
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
@@ -512,172 +545,6 @@ file are defined in the QSF map.
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object_be(qsf_param *params);
|
||||
|
||||
/** \brief Validate a QSF file and determine type.
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to see if it is registered
|
||||
with QOF within the QOF environment of the calling process.
|
||||
|
||||
Files that pass the test can be imported into the QOF appliction without the need
|
||||
for a QSF map.
|
||||
|
||||
@return TRUE if the file validates and all objects pass,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_our_qsf_object_be(qsf_param *params);
|
||||
|
||||
/** \brief Validate a QSF map file.
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated aginst the QSF map schema, qsf-map.xsd.xsml. This
|
||||
function is called by ::is_qsf_object. If called directly, the map file
|
||||
is validated and closed with a QofBackend error. QSF maps do not contain
|
||||
user data and are used to import QSF object files.
|
||||
|
||||
@return TRUE if the map validates, otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_map_be(qsf_param *params);
|
||||
|
||||
/** \brief Validate a QSF file and a selected QSF map
|
||||
|
||||
@param map_path Absolute or relative path to the selected QSF map file
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if the supplied QSF
|
||||
map is suitable. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
\todo Need to code for how to find these files.
|
||||
|
||||
|
||||
@return TRUE if the file validates and the supplied QSF map is usable,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object_with_map_be(char *map_path, qsf_param *params);
|
||||
|
||||
gboolean is_qsf_object_with_map(const char *path, char *map_file);
|
||||
|
||||
/** \brief QOF processing routine.
|
||||
|
||||
Called by ::qof_session_load if a map is required.
|
||||
Accepts QSF_OBJECT.
|
||||
|
||||
Checks available QSF maps for match. Only succeeds if a suitable map exists.
|
||||
|
||||
*/
|
||||
gboolean
|
||||
load_qsf_object(QofBook *book, const char *fullpath, qsf_param *params);
|
||||
|
||||
/** \brief QOF processing routine.
|
||||
|
||||
Called using ::qof_session_load when all objects defined in the
|
||||
XML are registered in the current instance of QOF.
|
||||
*/
|
||||
gboolean
|
||||
load_our_qsf_object(QofBook *book, const char *fullpath, qsf_param *params);
|
||||
|
||||
/** \brief Book and book-guid node handler.
|
||||
|
||||
Reads the book count="" attribute (currently only 1 QofBook is supported per QSF object file)
|
||||
Sets the book-guid as the GUID of the current QofBackend QofBook in qsf_param.
|
||||
Calls the next handler, qsf_object_node_handler, with the child of the book tag.
|
||||
*/
|
||||
void qsf_book_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params);
|
||||
|
||||
/** \brief Commit the QSF object data to a new QofBook.
|
||||
|
||||
The parentage of qof_book_merge should be obvious in this function.
|
||||
|
||||
Large chunks were just lifted directly from the commit loop and adjusted
|
||||
to obtain the data to commit from the xmlNodePtr instead of qof_book_mergeRule. If
|
||||
anything, it's easier here because all entities are new, there are no targets.
|
||||
|
||||
Unlike qof_book_merge, this routine runs once per parameter within a loop
|
||||
that iterates over objects - it does not have a loop of it's own.
|
||||
|
||||
All entities are new.
|
||||
|
||||
Using the parent of the current node to
|
||||
retrieve the type parameter of the parent provides the type parameter of
|
||||
the object tag - the e_type of the current QofObject which allows
|
||||
qof_class_get_parameter_setter(obj_type, key);
|
||||
|
||||
@param key name of the parameter: QofIdType
|
||||
@param value xmlNodePtr value->name == QOF_TYPE, content(value) = data to commit.
|
||||
@param data qsf_param* - inevitably.
|
||||
|
||||
*/
|
||||
void qsf_object_commitCB(gpointer key, gpointer value, gpointer data);
|
||||
|
||||
/** \brief Convert a string value into KvpValue
|
||||
|
||||
Partner to ::kvp_value_to_string. Given the type of KvpValue
|
||||
required, attempts to convert the string into that type of
|
||||
value.
|
||||
|
||||
@param content A string representation of the value, ideally as
|
||||
output by kvp_value_to_string.
|
||||
@param type KvpValueType of the intended KvpValue
|
||||
|
||||
@return KvpValue* or NULL on failure.
|
||||
*/
|
||||
KvpValue*
|
||||
string_to_kvp_value(const char *content, KvpValueType type);
|
||||
|
||||
/** \brief Backend init routine.
|
||||
|
||||
Sets the sequence of parameters to match the schema and provide a reliable
|
||||
parse. Sets the default strings for qsf_enquiry_date, qsf_time_now and
|
||||
qsf_time_string.
|
||||
|
||||
Filters the parameter list to set each type in this order:
|
||||
- QOF_TYPE_STRING
|
||||
- QOF_TYPE_GUID
|
||||
- QOF_TYPE_BOOLEAN
|
||||
- QOF_TYPE_NUMERIC
|
||||
- QOF_TYPE_DATE
|
||||
- QOF_TYPE_INT32
|
||||
- QOF_TYPE_INT64
|
||||
- QOF_TYPE_DOUBLE
|
||||
- QOF_TYPE_CHAR
|
||||
- QOF_TYPE_KVP
|
||||
- QOF_TYPE_COLLECT
|
||||
- QOF_TYPE_CHOICE
|
||||
|
||||
*/
|
||||
void qsf_param_init(qsf_param *params);
|
||||
|
||||
|
||||
/** \brief map callback
|
||||
|
||||
Investigate ways to get the map callback to do both
|
||||
the map and the validation tasks.
|
||||
**/
|
||||
typedef void (* qsf_nodeCB)(xmlNodePtr, xmlNsPtr, qsf_param*);
|
||||
|
||||
/** \brief validator callback
|
||||
|
||||
\todo The need for separate metadata means a separate callback typedef
|
||||
is needed for the validator, but this should be fixed to only need one.
|
||||
*/
|
||||
typedef void (* qsf_validCB)(xmlNodePtr, xmlNsPtr, qsf_validator*);
|
||||
|
||||
|
||||
/** \brief One iterator, two typedefs
|
||||
|
||||
\todo resolve the two callbacks in ::qsf_node_iterate into one.
|
||||
*/
|
||||
struct qsf_node_iterate {
|
||||
qsf_nodeCB *fcn;
|
||||
qsf_validCB *v_fcn;
|
||||
xmlNsPtr ns;
|
||||
};
|
||||
|
||||
/** \brief Validate a QSF file and identify a suitable QSF map
|
||||
|
||||
@param path Absolute or relative path to the file to be validated.
|
||||
@@ -696,15 +563,24 @@ file are defined in the QSF map.
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object(const char *path);
|
||||
|
||||
/** \brief Validate a QSF file and determine type.
|
||||
|
||||
@param path Absolute or relative path to the file to be validated
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
These functions are in pairs. When called from within a QofSession, the qsf_param
|
||||
context will be available. When just determining the type of file, qsf_param is
|
||||
not necessary. Use the *_be functions from within the QofBackend and the
|
||||
corresponding function in other code.
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to see if it is registered
|
||||
with QOF within the QOF environment of the calling process.
|
||||
|
||||
Files that pass the test can be imported into the QOF appliction without the need
|
||||
for a QSF map.
|
||||
|
||||
@return TRUE if the file validates and all objects pass,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_our_qsf_object_be(qsf_param *params);
|
||||
/** \brief Validate a QSF file.
|
||||
|
||||
@param path Absolute or relative path to the file to be validated
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to see if it is registered
|
||||
@@ -717,7 +593,18 @@ for a QSF map.
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_our_qsf_object(const char *path);
|
||||
/** \brief Validate a QSF map file.
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated aginst the QSF map schema, qsf-map.xsd.xsml. This
|
||||
function is called by ::is_qsf_object. If called directly, the map file
|
||||
is validated and closed with a QofBackend error. QSF maps do not contain
|
||||
user data and are used to import QSF object files.
|
||||
|
||||
@return TRUE if the map validates, otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_map_be(qsf_param *params);
|
||||
/** \brief Validate a QSF map file.
|
||||
|
||||
@param path Absolute or relative path to the file to be validated
|
||||
@@ -735,62 +622,81 @@ user data but are used to import QSF object files from other applications.
|
||||
@return TRUE if the map validates, otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_map(const char *path);
|
||||
/** \brief Validate a QSF file and a selected QSF map
|
||||
|
||||
/** \brief Determine the type of QSF and load it into the QofBook
|
||||
@param map_path Absolute or relative path to the selected QSF map file
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
- is_our_qsf_object, OUR_QSF_OBJ, QSF object file using only QOF objects known to the calling process.
|
||||
No map is required.
|
||||
- is_qsf_object, IS_QSF_OBJ, QSF object file that may or may not have a QSF map
|
||||
to convert external objects. This temporary type will be set to HAVE_QSF_MAP if a suitable
|
||||
map exists, or an error value returned: ERR_QSF_NO_MAP, ERR_QSF_BAD_MAP or ERR_QSF_WRONG_MAP
|
||||
This allows the calling process to inform the user that the QSF itself is valid but a
|
||||
suitable map cannot be found.
|
||||
- is_qsf_map, IS_QSF_MAP, QSF map file. In the backend, this generates ERR_QSF_MAP_NOT_OBJ but
|
||||
it can be used internally when processing maps to match a QSF object.
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if the supplied QSF
|
||||
map is suitable. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
@return NULL on error, otherwise a pointer to the QofBook. Use
|
||||
the qof_book_merge API to merge the new data into the current
|
||||
QofBook.
|
||||
This backend twin also sets QofBackendError codes.
|
||||
|
||||
@return TRUE if the file validates and the supplied QSF map is usable,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
void
|
||||
qsf_file_type (QofBackend *be, QofBook *book);
|
||||
gboolean is_qsf_object_with_map_be(char *map_path, qsf_param *params);
|
||||
/** \brief Validate a QSF file and a selected QSF map
|
||||
|
||||
@param map_path Absolute or relative path to the selected QSF map file
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if the supplied QSF
|
||||
map is suitable. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
@return TRUE if the file validates and the supplied QSF map is usable,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object_with_map(const char *path, char *map_file);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** \brief Book and book-guid node handler.
|
||||
|
||||
Reads the book count="" attribute (currently only 1 QofBook is supported per QSF object file)
|
||||
Sets the book-guid as the GUID of the current QofBackend QofBook in qsf_param.
|
||||
Calls the next handler, qsf_object_node_handler, with the child of the book tag.
|
||||
*/
|
||||
void qsf_book_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params);
|
||||
|
||||
/** \brief Convert a string value into KvpValue
|
||||
|
||||
Partner to ::kvp_value_to_string. Given the type of KvpValue
|
||||
required, attempts to convert the string into that type of
|
||||
value.
|
||||
|
||||
@param content A string representation of the value, ideally as
|
||||
output by kvp_value_to_string.
|
||||
@param type KvpValueType of the intended KvpValue
|
||||
|
||||
@return KvpValue* or NULL on failure.
|
||||
*/
|
||||
KvpValue*
|
||||
string_to_kvp_value(const char *content, KvpValueType type);
|
||||
|
||||
/** Validate the children of the parent node.
|
||||
|
||||
\note Slightly different to qsf_node_foreach because
|
||||
the validation can be run without qsf_param being
|
||||
initialized.
|
||||
*/
|
||||
void
|
||||
qsf_valid_foreach(xmlNodePtr parent, qsf_validCB cb,
|
||||
struct qsf_node_iterate *iter, qsf_validator *valid);
|
||||
|
||||
/** Iterate over the children of the parent node.
|
||||
|
||||
Only iterates over the immediate children of the parent -
|
||||
this function is \b not recursive.
|
||||
*/
|
||||
void
|
||||
qsf_node_foreach(xmlNodePtr parent, qsf_nodeCB cb,
|
||||
struct qsf_node_iterate *iter, qsf_param *params);
|
||||
|
||||
/** \brief Loads the QSF into a QofSession, ready to merge.
|
||||
|
||||
Loads a QSF object file containing only GnuCash objects
|
||||
into a second QofSession.
|
||||
|
||||
@param first_session A QofSession pointer to the original session. This
|
||||
will become the target of the subsequent qof_book_merge.
|
||||
|
||||
@param path Absolute or relative path to the file to be loaded
|
||||
|
||||
@return ERR_BACKEND_NO_ERR == 0 on success, otherwise the QofBackendError
|
||||
set by the QSFBackend.
|
||||
|
||||
\todo Build the qof_book_merge code onto this function if session loads
|
||||
properly.
|
||||
*/
|
||||
QofBackendError
|
||||
qof_session_load_our_qsf_object(QofSession *first_session, const char *path);
|
||||
|
||||
/** \brief Placeholder so far.
|
||||
|
||||
\todo Determine the map to use and convert the QOF objects
|
||||
|
||||
Much of the map code is written but there is still work to do.
|
||||
*/
|
||||
QofBackendError
|
||||
qof_session_load_qsf_object(QofSession *first_session, const char *path);
|
||||
|
||||
/** \brief Convert between QSF objects
|
||||
|
||||
This is the main workhorse of the conversion between QSF objects using
|
||||
@@ -808,45 +714,14 @@ be loaded into the book.
|
||||
xmlDocPtr
|
||||
qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params);
|
||||
|
||||
/** Despite the name, this function handles the QSF object book tag
|
||||
AND the object tags.
|
||||
|
||||
Used to parse object and map files.
|
||||
*/
|
||||
void
|
||||
qsf_object_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params);
|
||||
|
||||
/** \brief Backend routine to write a file or stdout.
|
||||
|
||||
This function is used by ::qof_session_save to write any QofBook to QSF,
|
||||
any process that can create a new QofSession and populate the QofBook
|
||||
with QOF objects can write the data as QSF XML - the book does not need
|
||||
an AccountGroup. Remember that only fully \b QOF-compliant objects
|
||||
are supported by QSF.
|
||||
|
||||
Your QOF objects must have:
|
||||
- a create: function in the QofObject definition
|
||||
- a foreach: function in the QofObject definition
|
||||
- QofParam params[] registered with QOF using
|
||||
qof_class_register and containing all necessary parameters
|
||||
to reconstruct this object without any further information.
|
||||
- Logical distinction between those parameters that should be
|
||||
set (have a QofAccessFunc and QofSetterFunc) and those that
|
||||
should only be calculated (only a QofAccessFunc).
|
||||
|
||||
If you begin your QSF session with ::QOF_STDOUT as the book_id,
|
||||
QSF will write to STDOUT - usually a terminal. This is used by QOF
|
||||
applications to provide data streaming. If you don't want terminal
|
||||
output, take care to check the path given to
|
||||
::qof_session_begin - don't try to change it later!
|
||||
|
||||
The XML is validated against the QSF object schema before being
|
||||
written (to file or stdout).
|
||||
|
||||
Check the QofBackendError - don't assume the file is OK.
|
||||
|
||||
*/
|
||||
void qsf_write_file(QofBackend *be, QofBook *book);
|
||||
|
||||
/** \brief Create a new QSF backend.
|
||||
*/
|
||||
QofBackend* qsf_backend_new(void);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
|
@@ -7,11 +7,11 @@ AM_CFLAGS = \
|
||||
${GLIB_CFLAGS}
|
||||
|
||||
libqof_la_SOURCES = \
|
||||
deprecated.c \
|
||||
gnc-date.c \
|
||||
gnc-engine-util.c \
|
||||
gnc-numeric.c \
|
||||
gnc-event.c \
|
||||
gnc-trace.c \
|
||||
guid.c \
|
||||
kvp_frame.c \
|
||||
kvp-util.c \
|
||||
@@ -23,6 +23,7 @@ libqof_la_SOURCES = \
|
||||
qofinstance.c \
|
||||
qofquery.c \
|
||||
qofbook.c \
|
||||
qoflog.c \
|
||||
qofobject.c \
|
||||
qofquerycore.c \
|
||||
qofsession.c \
|
||||
@@ -31,11 +32,11 @@ libqof_la_SOURCES = \
|
||||
qofincludedir = ${pkgincludedir}
|
||||
|
||||
qofinclude_HEADERS = \
|
||||
deprecated.h \
|
||||
gnc-date.h \
|
||||
gnc-engine-util.h \
|
||||
gnc-numeric.h \
|
||||
gnc-event.h \
|
||||
gnc-trace.h \
|
||||
guid.h \
|
||||
kvp_frame.h \
|
||||
kvp-util.h \
|
||||
@@ -53,6 +54,7 @@ qofinclude_HEADERS = \
|
||||
qofinstance.h \
|
||||
qofquery.h \
|
||||
qofbook.h \
|
||||
qoflog.h \
|
||||
qofobject.h \
|
||||
qofquerycore.h \
|
||||
qofsession.h \
|
||||
@@ -72,7 +74,7 @@ noinst_HEADERS = \
|
||||
qofquerycore-p.h \
|
||||
qofsession-p.h
|
||||
|
||||
QOFLIBdir = $(libdir)
|
||||
QOFLIBdir = $(QOF_LIB_DIR)
|
||||
|
||||
EXTRA_DIST = \
|
||||
qofla-dir.h.in \
|
||||
|
54
lib/libqof/qof/deprecated.c
Normal file
54
lib/libqof/qof/deprecated.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/* *****************************************************************\
|
||||
* deprecated.c -- QOF deprecated function replacements *
|
||||
* Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk> *
|
||||
* *
|
||||
* 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 "qof.h"
|
||||
|
||||
/* Don't be fooled: gnc_trace_num_spaces has external linkage and
|
||||
static storage, but can't be defined with 'extern' because it has
|
||||
an initializer, and can't be declared with 'static' because that
|
||||
would give it internal linkage. (this is why it is deprecated) */
|
||||
gint __attribute__ ((unused)) gnc_trace_num_spaces = 0;
|
||||
void gnc_log_init (void) { qof_log_init(); }
|
||||
void gnc_set_log_level(QofLogModule log_module, gncLogLevel level)
|
||||
{
|
||||
qof_log_set_level(log_module, (QofLogLevel)level);
|
||||
}
|
||||
void gnc_set_log_level_global(gncLogLevel level)
|
||||
{
|
||||
qof_log_set_level_global((QofLogLevel)level);
|
||||
}
|
||||
void gnc_set_logfile (FILE *outfile)
|
||||
{
|
||||
qof_log_set_file(outfile);
|
||||
}
|
||||
const char * gnc_log_prettify (const char *name)
|
||||
{
|
||||
return qof_log_prettify(name);
|
||||
}
|
||||
void gnc_start_clock (int a, QofLogModule b, gncLogLevel c, const char *d, const char *e, ...) { }
|
||||
void gnc_report_clock (int a, QofLogModule b, gncLogLevel c, const char *d, const char *e, ...) { }
|
||||
void gnc_report_clock_total (int a, QofLogModule b, gncLogLevel c, const char *d, const char *e, ...) { }
|
||||
gboolean gnc_should_log(QofLogModule log_module, gncLogLevel log_level)
|
||||
{
|
||||
return qof_log_check(log_module, log_level);
|
||||
}
|
75
lib/libqof/qof/deprecated.h
Normal file
75
lib/libqof/qof/deprecated.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/***************************************************************************
|
||||
* deprecated.h
|
||||
*
|
||||
* Mon Nov 21 14:08:25 2005
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@codehelp.co.uk
|
||||
****************************************************************************/
|
||||
/*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DEPRECATED_H
|
||||
#define _DEPRECATED_H
|
||||
#include "qof.h"
|
||||
|
||||
/** @file deprecated.h
|
||||
@brief transitional header from libqof1 to libqof2
|
||||
*/
|
||||
|
||||
/** \deprecated use QofLogLevel instead */
|
||||
#define gncLogLevel QofLogLevel
|
||||
|
||||
/** \deprecated use qof_log_init_filename instead */
|
||||
void gnc_log_init (void);
|
||||
|
||||
/** \deprecated use qof_log_set_level insead. */
|
||||
void gnc_set_log_level(QofLogModule module, gncLogLevel level);
|
||||
|
||||
/** \deprecated use qof_log_set_level_global instead. */
|
||||
void gnc_set_log_level_global(gncLogLevel level);
|
||||
|
||||
/** \deprecated use qof_log_set_file instead. */
|
||||
void gnc_set_logfile (FILE *outfile);
|
||||
|
||||
/** \deprecated use qof_log_prettify instead. */
|
||||
const char * gnc_log_prettify (const char *name);
|
||||
|
||||
/** \deprecated use qof_log_check instead. */
|
||||
gboolean gnc_should_log(QofLogModule log_module, gncLogLevel log_level);
|
||||
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_FATAL QOF_LOG_FATAL
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_ERROR QOF_LOG_ERROR
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_WARNING QOF_LOG_WARNING
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_INFO QOF_LOG_INFO
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_DEBUG QOF_LOG_DEBUG
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_DETAIL QOF_LOG_DETAIL
|
||||
/** \deprecated */
|
||||
#define GNC_LOG_TRACE QOF_LOG_TRACE
|
||||
|
||||
/** \deprecated use qof_start_clock */
|
||||
void gnc_start_clock (int, QofLogModule, gncLogLevel, const char*, const char*, ...);
|
||||
/** \deprecated use qof_report_clock */
|
||||
void gnc_report_clock (int, QofLogModule, gncLogLevel, const char*, const char*, ...);
|
||||
/** \deprecated use qof_report_clock_total */
|
||||
void gnc_report_clock_total (int, QofLogModule, gncLogLevel, const char*, const char*, ...);
|
||||
|
||||
#endif /* _DEPRECATED_H */
|
@@ -1,8 +1,9 @@
|
||||
/********************************************************************\
|
||||
* gnc-date.c -- misc utility functions to handle date and time *
|
||||
* (to be renamed qofdate.c in libqof2) *
|
||||
* *
|
||||
* Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu> *
|
||||
* Copyright (C) 1998-2000, 20003 Linas Vepstas <linas@linas.org> *
|
||||
* Copyright (C) 1998-2000, 2003 Linas Vepstas <linas@linas.org> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
@@ -27,7 +28,7 @@
|
||||
#define __EXTENSIONS__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* to be renamed qofdate.c */
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_LANGINFO_D_FMT
|
||||
@@ -42,7 +43,7 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "gnc-date.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "qof.h"
|
||||
|
||||
#ifndef HAVE_STRPTIME
|
||||
#include "strptime.h"
|
||||
@@ -235,12 +236,11 @@ timespec_abs(const Timespec *t)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** \brief Converts any time on a day to midday that day.
|
||||
/* Converts any time on a day to midday that day.
|
||||
|
||||
* given a timepair contains any time on a certain day (local time)
|
||||
* converts it to be midday that day.
|
||||
* converts it to be midday that day.
|
||||
*/
|
||||
|
||||
Timespec
|
||||
timespecCanonicalDayTime(Timespec t)
|
||||
{
|
||||
@@ -257,20 +257,16 @@ timespecCanonicalDayTime(Timespec t)
|
||||
|
||||
int gnc_date_my_last_mday (int month, int year)
|
||||
{
|
||||
gboolean is_leap;
|
||||
static int days_in_month[2][12] =
|
||||
{/* non leap */ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
/* leap */ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
|
||||
static int last_day_of_month[2][12] = {
|
||||
/* non leap */ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
/* leap */ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
};
|
||||
|
||||
/* Is this a leap year? */
|
||||
if (year % 2000 == 0)
|
||||
is_leap = TRUE;
|
||||
else if (year % 400 == 0)
|
||||
is_leap = FALSE;
|
||||
else
|
||||
is_leap = (year % 4 == 0);
|
||||
|
||||
return days_in_month[is_leap][month-1];
|
||||
if (year % 2000 == 0) return last_day_of_month[1][month-1];
|
||||
if (year % 400 == 0 ) return last_day_of_month[0][month-1];
|
||||
if (year % 4 == 0 ) return last_day_of_month[1][month-1];
|
||||
return last_day_of_month[0][month-1];
|
||||
}
|
||||
|
||||
/* Retrieve the last numerical day of the month
|
||||
@@ -327,7 +323,7 @@ void date_add_months (struct tm *tm, int months, gboolean track_last_day)
|
||||
if (!track_last_day)
|
||||
return;
|
||||
|
||||
/* Track last day of the month, i.e. 1/31 -> 2/28 -> 3/30 */
|
||||
/* Track last day of the month, i.e. 1/31 -> 2/28 -> 3/31 */
|
||||
new_last_mday = date_get_last_mday(tm);
|
||||
if (was_last_day || (tm->tm_mday > new_last_mday))
|
||||
tm->tm_mday = new_last_mday;
|
||||
@@ -462,7 +458,7 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
|
||||
case QOF_DATE_FORMAT_CE:
|
||||
flen = g_snprintf (buff, len, "%2d.%2d.%-4d", day, month, year);
|
||||
break;
|
||||
case QOF_DATE_FORMAT_LOCALE:
|
||||
case QOF_DATE_FORMAT_LOCALE:
|
||||
{
|
||||
struct tm tm_str;
|
||||
time_t t;
|
||||
@@ -476,8 +472,8 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
|
||||
t = mktime (&tm_str);
|
||||
localtime_r (&t, &tm_str);
|
||||
flen = strftime (buff, len, GNC_D_FMT, &tm_str);
|
||||
if (flen != 0)
|
||||
break;
|
||||
if (flen != 0)
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case QOF_DATE_FORMAT_ISO:
|
||||
@@ -674,20 +670,20 @@ qof_print_date_time_buff (char * buff, size_t len, time_t secs)
|
||||
size_t
|
||||
qof_print_time_buff (char * buff, size_t len, time_t secs)
|
||||
{
|
||||
int flen;
|
||||
int flen;
|
||||
struct tm ltm, gtm;
|
||||
|
||||
if (!buff) return 0;
|
||||
|
||||
if (!buff) return 0;
|
||||
if(dateFormat == QOF_DATE_FORMAT_UTC)
|
||||
{
|
||||
gtm = *gmtime (&secs);
|
||||
flen = strftime(buff, len, QOF_UTC_DATE_FORMAT, >m);
|
||||
return flen;
|
||||
}
|
||||
ltm = *localtime (&secs);
|
||||
flen = strftime (buff, len, GNC_T_FMT, <m);
|
||||
|
||||
return flen;
|
||||
ltm = *localtime (&secs);
|
||||
flen = strftime (buff, len, GNC_T_FMT, <m);
|
||||
|
||||
return flen;
|
||||
}
|
||||
|
||||
/* ============================================================== */
|
||||
@@ -1013,6 +1009,7 @@ Timespec
|
||||
gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
{
|
||||
char buf[4];
|
||||
gchar *dupe;
|
||||
Timespec ts;
|
||||
struct tm stm;
|
||||
long int nsec =0;
|
||||
@@ -1020,7 +1017,7 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
ts.tv_sec=0;
|
||||
ts.tv_nsec=0;
|
||||
if (!str) return ts;
|
||||
|
||||
dupe = g_strdup(str);
|
||||
stm.tm_year = atoi(str) - 1900;
|
||||
str = strchr (str, '-'); if (str) { str++; } else { return ts; }
|
||||
stm.tm_mon = atoi(str) - 1;
|
||||
@@ -1077,9 +1074,9 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
* We want to work with universal time. Thus, add an offset
|
||||
* to undo the damage that mktime causes.
|
||||
*/
|
||||
{
|
||||
{
|
||||
struct tm tmp_tm;
|
||||
struct tm *tm;
|
||||
struct tm tm;
|
||||
long int tz;
|
||||
int tz_hour;
|
||||
time_t secs;
|
||||
@@ -1091,23 +1088,57 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
|
||||
secs = mktime (&tmp_tm);
|
||||
|
||||
if(secs < 0)
|
||||
{
|
||||
/* Workaround buggy mktime implementations that get confused
|
||||
on the day daylight saving starts or ends. (OSX) */
|
||||
PWARN (" mktime failed to handle daylight saving: "
|
||||
"tm_hour=%d tm_year=%d tm_min=%d tm_sec=%d tm_isdst=%d for string=%s",
|
||||
stm.tm_hour, stm.tm_year, stm.tm_min,
|
||||
stm.tm_sec, stm.tm_isdst, dupe );
|
||||
tmp_tm.tm_hour++;
|
||||
secs = mktime (&tmp_tm);
|
||||
if (secs < 0)
|
||||
{
|
||||
/* if, for some strange reason, first attempt didn't fix it,
|
||||
try reversing the workaround. */
|
||||
tmp_tm.tm_hour -= 2;
|
||||
secs = mktime (&tmp_tm);
|
||||
}
|
||||
if (secs < 0)
|
||||
{
|
||||
/* Seriously buggy mktime - give up. */
|
||||
PERR (" unable to recover from buggy mktime ");
|
||||
g_free(dupe);
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
/* The call to localtime is 'bogus', but it forces 'timezone' to
|
||||
* be set. Note that we must use the accurate date, since the
|
||||
* value of 'gnc_timezone' includes daylight savings corrections
|
||||
* for that date. */
|
||||
tm = localtime (&secs);
|
||||
|
||||
tz = gnc_timezone (tm);
|
||||
tm = *localtime_r (&secs, &tm);
|
||||
|
||||
tz = gnc_timezone (&tmp_tm);
|
||||
|
||||
tz_hour = tz / 3600;
|
||||
stm.tm_hour -= tz_hour;
|
||||
stm.tm_min -= (tz - (3600 * tz_hour)) / 60;
|
||||
stm.tm_min -= (tz % 3600) / 60;
|
||||
stm.tm_isdst = tmp_tm.tm_isdst;
|
||||
ts.tv_sec = mktime (&stm);
|
||||
if(ts.tv_sec < 0) {
|
||||
PWARN (" mktime failed to adjust calculated time:"
|
||||
" tm_hour=%d tm_year=%d tm_min=%d tm_sec=%d tm_isdst=%d",
|
||||
stm.tm_hour, stm.tm_year, stm.tm_min,
|
||||
stm.tm_sec, stm.tm_isdst );
|
||||
/* Try and make some sense of the result. */
|
||||
ts.tv_sec = secs - tz;
|
||||
}
|
||||
ts.tv_nsec = nsec;
|
||||
}
|
||||
|
||||
ts.tv_sec = mktime (&stm);
|
||||
ts.tv_nsec = nsec;
|
||||
|
||||
g_free(dupe);
|
||||
return ts;
|
||||
}
|
||||
|
||||
@@ -1117,8 +1148,8 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
char *
|
||||
gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
|
||||
{
|
||||
int len;
|
||||
int tz_hour, tz_min;
|
||||
int len, tz_hour, tz_min;
|
||||
long int secs;
|
||||
char cyn;
|
||||
time_t tmp;
|
||||
struct tm parsed;
|
||||
@@ -1126,10 +1157,9 @@ gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
|
||||
tmp = ts.tv_sec;
|
||||
localtime_r(&tmp, &parsed);
|
||||
|
||||
tz_hour = gnc_timezone (&parsed) / 3600;
|
||||
tz_min = (gnc_timezone (&parsed) - 3600*tz_hour) / 60;
|
||||
if (0>tz_min) { tz_min +=60; tz_hour --; }
|
||||
if (60<=tz_min) { tz_min -=60; tz_hour ++; }
|
||||
secs = gnc_timezone (&parsed);
|
||||
tz_hour = secs / 3600;
|
||||
tz_min = (secs % 3600) / 60;
|
||||
|
||||
/* We also have to print the sign by hand, to work around a bug
|
||||
* in the glibc 2.1.3 printf (where %+02d fails to zero-pad).
|
||||
@@ -1268,7 +1298,7 @@ gnc_timezone (struct tm *tm)
|
||||
/* timezone is seconds *west* of UTC and is
|
||||
* not adjusted for daylight savings time.
|
||||
* In Spring, we spring forward, wheee! */
|
||||
return timezone - (tm->tm_isdst > 0 ? 60 * 60 : 0);
|
||||
return (long int)(timezone - (tm->tm_isdst > 0 ? 3600 : 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1387,5 +1417,53 @@ gnc_timet_get_today_end (void)
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
gboolean
|
||||
qof_date_add_days(Timespec *ts, gint days)
|
||||
{
|
||||
struct tm tm;
|
||||
time_t tt;
|
||||
|
||||
g_return_val_if_fail(ts, FALSE);
|
||||
tt = timespecToTime_t(*ts);
|
||||
tm = *gmtime_r(&tt, &tm);
|
||||
tm.tm_mday += days;
|
||||
/* let mktime normalise the months and year
|
||||
because we aren't tracking last_day_of_month */
|
||||
tt = mktime(&tm);
|
||||
if(tt < 0) { return FALSE; }
|
||||
timespecFromTime_t(ts, tt);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
qof_date_add_months(Timespec *ts, gint months, gboolean track_last_day)
|
||||
{
|
||||
struct tm tm;
|
||||
time_t tt;
|
||||
gint new_last_mday;
|
||||
gboolean was_last_day;
|
||||
|
||||
g_return_val_if_fail(ts, FALSE);
|
||||
tt = timespecToTime_t(*ts);
|
||||
tm = *gmtime_r(&tt, &tm);
|
||||
was_last_day = date_is_last_mday(&tm);
|
||||
tm.tm_mon += months;
|
||||
while (tm.tm_mon > 11) {
|
||||
tm.tm_mon -= 12;
|
||||
tm.tm_year++;
|
||||
}
|
||||
if (track_last_day) {
|
||||
/* Track last day of the month, i.e. 1/31 -> 2/28 -> 3/31 */
|
||||
new_last_mday = date_get_last_mday(&tm);
|
||||
if (was_last_day || (tm.tm_mday > new_last_mday)) {
|
||||
tm.tm_mday = new_last_mday;
|
||||
}
|
||||
}
|
||||
tt = mktime(&tm);
|
||||
if(tt < 0) { return FALSE; }
|
||||
timespecFromTime_t(ts, tt);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/********************** END OF FILE *********************************\
|
||||
\********************************************************************/
|
||||
|
@@ -1,3 +1,10 @@
|
||||
/***************************************************************************
|
||||
* gnc-date.h (to be renamed qofdate.h)
|
||||
*
|
||||
* Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu>
|
||||
* Copyright (C) 1998-2000, 2003 Linas Vepstas <linas@linas.org>
|
||||
* Copyright 2005 Neil Williams <linux@codehelp.co.uk>
|
||||
****************************************************************************/
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
@@ -46,11 +53,13 @@
|
||||
If a file-io backend needs date handling, it should do it itself,
|
||||
instead of depending on the routines here.
|
||||
|
||||
(to be renamed qofdate.h in libqof2.)
|
||||
|
||||
@author Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu>
|
||||
@author Copyright (C) 1998-2001,2003 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
/* @{
|
||||
/** @{
|
||||
@file gnc-date.h
|
||||
@brief Date and Time handling routines
|
||||
*/
|
||||
@@ -91,6 +100,9 @@ typedef enum
|
||||
#define DATE_FORMAT_FIRST QOF_DATE_FORMAT_US
|
||||
#define DATE_FORMAT_LAST QOF_DATE_FORMAT_LOCALE
|
||||
|
||||
/** \deprecated qof_date_format_get_format has been replaced
|
||||
by qof_date_text_format_get_string */
|
||||
#define qof_date_format_get_format qof_date_text_format_get_string
|
||||
|
||||
/**
|
||||
* This is how to format the month, as a number, an abbreviated string,
|
||||
@@ -237,8 +249,26 @@ char * gnc_timespec_to_iso8601_buff (Timespec ts, char * buff);
|
||||
* routine might return incorrect values for dates before 1970. */
|
||||
void gnc_timespec2dmy (Timespec ts, int *day, int *month, int *year);
|
||||
|
||||
/** Add a number of months to a time value and normalize. Optionally
|
||||
* also track the last day of the month, i.e. 1/31 -> 2/28 -> 3/30. */
|
||||
/** \brief Add a number of days to a Timespec and normalise.
|
||||
|
||||
Together with qof_date_add_months, replaces date_add_months.
|
||||
|
||||
\return FALSE on error, otherwise TRUE.
|
||||
*/
|
||||
gboolean qof_date_add_days(Timespec *ts, gint days);
|
||||
|
||||
/** \brief Add a number of months to a Timespec and normalise.
|
||||
|
||||
Optionally track the last day of the month so that adding one
|
||||
month to 31st January returns 28th February (29th in a leap year)
|
||||
and adding three months returns 30th April.
|
||||
|
||||
\return FALSE on error, otherwise TRUE.
|
||||
*/
|
||||
gboolean qof_date_add_months(Timespec *ts, gint months, gboolean track_last_day);
|
||||
|
||||
/** \deprecated Add a number of months to a time value and normalize. Optionally
|
||||
* also track the last day of the month, i.e. 1/31 -> 2/28 -> 3/31. */
|
||||
void date_add_months (struct tm *tm, int months, gboolean track_last_day);
|
||||
|
||||
/** \warning hack alert XXX FIXME -- these date routines return incorrect
|
||||
@@ -501,7 +531,7 @@ int date_get_last_mday(struct tm *tm);
|
||||
/** Is the mday field the last day of the specified month.*/
|
||||
gboolean date_is_last_mday(struct tm *tm);
|
||||
|
||||
/** DOCUMENT ME! Probably the same as date_get_last_mday() */
|
||||
/** \deprecated Use date_get_last_mday() */
|
||||
int gnc_date_my_last_mday (int month, int year);
|
||||
/** DOCUMENT ME! Probably the same as date_get_last_mday() */
|
||||
int gnc_timespec_last_mday (Timespec ts);
|
||||
@@ -536,4 +566,3 @@ char * xaccDateUtilGetStampNow (void);
|
||||
//@}
|
||||
//@}
|
||||
#endif /* GNC_DATE_H */
|
||||
|
||||
|
@@ -23,6 +23,8 @@
|
||||
@{ */
|
||||
/** @file gnc-engine-util.h
|
||||
@brief QOF utility functions
|
||||
(This file is due to be renamed qofutil.h in libqof2.
|
||||
It will remain as a placeholder during libqof1.)
|
||||
@author Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu>
|
||||
@author Copyright (C) 2000 Bill Gribble <grib@billgribble.com>
|
||||
@author Copyright (C) 1997-2002,2004 Linas Vepstas <linas@linas.org>
|
||||
@@ -36,14 +38,17 @@
|
||||
#include "config.h"
|
||||
#include "qof.h"
|
||||
|
||||
/** Macros *****************************************************/
|
||||
/* Macros *****************************************************/
|
||||
|
||||
/* CAS: Notice that this macro does nothing if pointer args are equal.
|
||||
Otherwise, it returns an integer. Actually, perhaps these macro
|
||||
should be private. They are NOT good substitutes for the function
|
||||
versions like safe_strcmp(). Maybe external users of these 3
|
||||
macros should be converted to use safe_strcmp(). Actually, THESE
|
||||
MACROS AFFECT CONTROL FLOW. YUCK! */
|
||||
/** \deprecated Use the function versions, safe_strcmp() and
|
||||
safe_strcasecmp(). These macros will be made private in libqof2.
|
||||
|
||||
If the pointer arguments are equal, the macro does nothing and
|
||||
safe_strcmp / safe_strcasecmp return 0.
|
||||
|
||||
These macros change program control flow and are not good
|
||||
substitutes for the function equivalents.
|
||||
*/
|
||||
#define SAFE_STRCMP_REAL(fcn,da,db) { \
|
||||
if ((da) && (db)) { \
|
||||
if ((da) != (db)) { \
|
||||
@@ -60,7 +65,9 @@
|
||||
} \
|
||||
}
|
||||
|
||||
/** \deprecated use safe_strcmp() */
|
||||
#define SAFE_STRCMP(da,db) SAFE_STRCMP_REAL(strcmp,(da),(db))
|
||||
/** \deprecated use safe_strcasecmp() */
|
||||
#define SAFE_STRCASECMP(da,db) SAFE_STRCMP_REAL(strcasecmp,(da),(db))
|
||||
|
||||
/** \name typedef enum as string macros
|
||||
@@ -85,7 +92,7 @@
|
||||
const char* name##asString(name n);
|
||||
|
||||
#define AS_STRING_FUNC(name, list) \
|
||||
const char* name##asString(name n) { \
|
||||
const char* name##asString(name n) { \
|
||||
switch (n) { \
|
||||
list(AS_STRING_CASE) \
|
||||
default: return ""; } }
|
||||
@@ -107,11 +114,20 @@
|
||||
@{
|
||||
|
||||
Similar but used when the enum is NOT a typedef
|
||||
note the LACK of a define_enum macro - don't use one!
|
||||
Make sure you use the DEFINE_ENUM_NON_TYPEDEF macro.
|
||||
|
||||
You can precede the FROM_STRING_FUNC_NON_TYPEDEF
|
||||
and AS_STRING_FUNC_NON_TYPEDEF macros with the
|
||||
keyword static if appropriate.
|
||||
|
||||
ENUM_BODY is used in both types.
|
||||
*/
|
||||
|
||||
#define DEFINE_ENUM_NON_TYPEDEF(name, list) \
|
||||
enum name { \
|
||||
list(ENUM_BODY) \
|
||||
};
|
||||
|
||||
#define FROM_STRING_DEC_NON_TYPEDEF(name, list) \
|
||||
void name##fromString \
|
||||
(const char* str, enum name *type);
|
||||
@@ -129,9 +145,9 @@
|
||||
const char* name##asString(enum name n);
|
||||
|
||||
#define AS_STRING_FUNC_NON_TYPEDEF(name, list) \
|
||||
const char* name##asString(enum name n) { \
|
||||
switch (n) { \
|
||||
list(AS_STRING_CASE_NON_TYPEDEF) \
|
||||
const char* name##asString(enum name n) { \
|
||||
switch (n) { \
|
||||
list(AS_STRING_CASE_NON_TYPEDEF) \
|
||||
default: return ""; } }
|
||||
|
||||
#define AS_STRING_CASE_NON_TYPEDEF(name, value) \
|
||||
@@ -139,11 +155,14 @@
|
||||
|
||||
/** @} */
|
||||
|
||||
/* Define the long long int conversion for scanf */
|
||||
/** \deprecated Define the long long int conversion for scanf
|
||||
* HAVE_SCANF_LLD will be removed from libqof2
|
||||
* */
|
||||
#if HAVE_SCANF_LLD
|
||||
# define GNC_SCANF_LLD "%lld"
|
||||
# define GNC_SCANF_LLD "%lld" /**< \deprecated
|
||||
use G_GINT64_FORMAT instead. */
|
||||
#else
|
||||
# define GNC_SCANF_LLD "%qd"
|
||||
# define GNC_SCANF_LLD "%qd" /**< \deprecated */
|
||||
#endif
|
||||
|
||||
/** @name Convenience wrappers
|
||||
@@ -152,25 +171,50 @@
|
||||
|
||||
/** \brief Initialise the Query Object Framework
|
||||
|
||||
Used for non-Guile applications or test routines.
|
||||
Use in place of separate init functions (like guid_init()
|
||||
and qof_query_init() etc.) to protect against future changes.
|
||||
*/
|
||||
void qof_init (void);
|
||||
|
||||
/** \brief Safely close down the Query Object Framework
|
||||
|
||||
Used for non-Guile applications or test routines.
|
||||
Use in place of separate close / shutdown functions
|
||||
(like guid_shutdown(), qof_query_shutdown() etc.) to protect
|
||||
against future changes.
|
||||
*/
|
||||
void qof_close (void);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** Prototypes *************************************************/
|
||||
/* **** Prototypes *********************************************/
|
||||
|
||||
/** The safe_strcmp compares strings a and b the same way that strcmp()
|
||||
* does, except that either may be null. This routine assumes that
|
||||
* a non-null string is always greater than a null string.
|
||||
*/
|
||||
/** The safe_strcmp compares strings da and db the same way that strcmp()
|
||||
does, except that either may be null. This routine assumes that
|
||||
a non-null string is always greater than a null string.
|
||||
|
||||
@param da string 1.
|
||||
@param db string 2.
|
||||
|
||||
@return If da == NULL && db != NULL, returns -1.
|
||||
If da != NULL && db == NULL, returns +1.
|
||||
If da != NULL && db != NULL, returns the result of
|
||||
strcmp(da, db).
|
||||
If da == NULL && db == NULL, returns 0.
|
||||
*/
|
||||
int safe_strcmp (const char * da, const char * db);
|
||||
|
||||
/** case sensitive comparison of strings da and db - either
|
||||
may be NULL. A non-NULL string is greater than a NULL string.
|
||||
|
||||
@param da string 1.
|
||||
@param db string 2.
|
||||
|
||||
@return If da == NULL && db != NULL, returns -1.
|
||||
If da != NULL && db == NULL, returns +1.
|
||||
If da != NULL && db != NULL, returns the result of
|
||||
strcmp(da, db).
|
||||
If da == NULL && db == NULL, returns 0.
|
||||
*/
|
||||
int safe_strcasecmp (const char * da, const char * db);
|
||||
|
||||
/** The null_strcmp compares strings a and b the same way that strcmp()
|
||||
@@ -212,10 +256,12 @@ const char * qof_util_whitespace_filter (const char * val);
|
||||
int qof_util_bool_to_int (const char * val);
|
||||
|
||||
|
||||
/** Gnucash's String Cache:
|
||||
/** The QOF String Cache:
|
||||
*
|
||||
* Many strings used throughout the engine are likely to be duplicated.
|
||||
* So we provide a reference counted cache system for the strings, which
|
||||
* Many strings used throughout QOF and QOF applications are likely to
|
||||
* be duplicated.
|
||||
*
|
||||
* QOF provides a reference counted cache system for the strings, which
|
||||
* shares strings whenever possible.
|
||||
*
|
||||
* Use gnc_string_cache_insert to insert a string into the cache (it
|
||||
@@ -242,19 +288,21 @@ int qof_util_bool_to_int (const char * val);
|
||||
|
||||
/** \deprecated use qof_init instead.
|
||||
|
||||
Get the gnc_string_cache. Create it if it doesn't exist already
|
||||
Get the gnc_string_cache. Create it if it doesn't exist already.
|
||||
*/
|
||||
GCache* gnc_engine_get_string_cache(void);
|
||||
|
||||
/** Destroy the gnc_string_cache */
|
||||
void gnc_engine_string_cache_destroy (void);
|
||||
|
||||
/* You can use this function as a destroy notifier for a GHashTable
|
||||
that uses common strings as keys (or values, for that matter.) */
|
||||
/** You can use this function as a destroy notifier for a GHashTable
|
||||
that uses common strings as keys (or values, for that matter.)
|
||||
*/
|
||||
void gnc_string_cache_remove(gconstpointer key);
|
||||
|
||||
/* You can use this function with g_hash_table_insert(), or the key
|
||||
(or value), as long as you use the destroy notifier above. */
|
||||
/** You can use this function with g_hash_table_insert(), or the key
|
||||
(or value), as long as you use the destroy notifier above.
|
||||
*/
|
||||
gpointer gnc_string_cache_insert(gpointer key);
|
||||
|
||||
#define CACHE_INSERT(str) gnc_string_cache_insert((gpointer)(str));
|
||||
|
@@ -27,11 +27,11 @@
|
||||
#include "gnc-event.h"
|
||||
#include "qofid.h"
|
||||
|
||||
/* XXX deprecated, but still usedion on postgres backend */
|
||||
/** \deprecated */
|
||||
void gnc_engine_generate_event (const GUID *, QofIdType, GNCEngineEventType);
|
||||
|
||||
/* generates an event even when events are suspended! */
|
||||
void gnc_engine_force_event (QofEntity *entity,
|
||||
void gnc_engine_force_event (QofEntity *entity,
|
||||
GNCEngineEventType event_type);
|
||||
|
||||
#endif
|
||||
|
@@ -22,12 +22,10 @@
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "qof.h"
|
||||
#include "gnc-event-p.h"
|
||||
#include "gnc-trace.h"
|
||||
|
||||
|
||||
/** Declarations ****************************************************/
|
||||
/* Declarations ****************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -37,8 +35,7 @@ typedef struct
|
||||
gint handler_id;
|
||||
} HandlerInfo;
|
||||
|
||||
|
||||
/** Static Variables ************************************************/
|
||||
/* Static Variables ************************************************/
|
||||
static guint suspend_counter = 0;
|
||||
static gint next_handler_id = 1;
|
||||
static GList *handlers = NULL;
|
||||
@@ -46,8 +43,7 @@ static GList *handlers = NULL;
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = QOF_MOD_ENGINE;
|
||||
|
||||
|
||||
/** Implementations *************************************************/
|
||||
/* Implementations *************************************************/
|
||||
|
||||
gint
|
||||
gnc_engine_register_event_handler (GNCEngineEventHandler handler,
|
||||
|
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
/** @file gnc-event.h
|
||||
@brief engine event handling interface
|
||||
(to be renamed qofevent.h in libqof2)
|
||||
@author Copyright 2000 Dave Peticolas <dave@krondo.com>
|
||||
*/
|
||||
|
||||
|
@@ -75,7 +75,7 @@ gnc_numeric_check(gnc_numeric in)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Find the least common multiple of the denominators of a and b.
|
||||
*/
|
||||
|
||||
@@ -106,7 +106,7 @@ gnc_numeric_lcd(gnc_numeric a, gnc_numeric b)
|
||||
}
|
||||
|
||||
|
||||
/** Return the ratio n/d reduced so that there are no common factors. */
|
||||
/* Return the ratio n/d reduced so that there are no common factors. */
|
||||
static inline gnc_numeric
|
||||
reduce128(qofint128 n, gint64 d)
|
||||
{
|
||||
@@ -140,7 +140,7 @@ reduce128(qofint128 n, gint64 d)
|
||||
return out;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_zero_p
|
||||
********************************************************************/
|
||||
|
||||
@@ -164,7 +164,7 @@ gnc_numeric_zero_p(gnc_numeric a)
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_negative_p
|
||||
********************************************************************/
|
||||
|
||||
@@ -188,7 +188,7 @@ gnc_numeric_negative_p(gnc_numeric a)
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_positive_p
|
||||
********************************************************************/
|
||||
|
||||
@@ -212,7 +212,7 @@ gnc_numeric_positive_p(gnc_numeric a)
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_compare
|
||||
* returns 1 if a>b, -1 if b>a, 0 if a == b
|
||||
********************************************************************/
|
||||
@@ -252,7 +252,7 @@ gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_eq
|
||||
********************************************************************/
|
||||
|
||||
@@ -263,7 +263,7 @@ gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_equal
|
||||
********************************************************************/
|
||||
|
||||
@@ -300,7 +300,7 @@ gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_same
|
||||
* would a and b be equal() if they were both converted to the same
|
||||
* denominator?
|
||||
@@ -319,7 +319,7 @@ gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom,
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_add
|
||||
********************************************************************/
|
||||
|
||||
@@ -410,7 +410,7 @@ gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
||||
return gnc_numeric_convert(sum, denom, how);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_sub
|
||||
********************************************************************/
|
||||
|
||||
@@ -429,7 +429,7 @@ gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
|
||||
return gnc_numeric_add (a, nb, denom, how);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_mul
|
||||
********************************************************************/
|
||||
|
||||
@@ -548,7 +548,7 @@ gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_div
|
||||
********************************************************************/
|
||||
|
||||
@@ -680,7 +680,7 @@ dive_done:
|
||||
return gnc_numeric_convert(quotient, denom, how);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_neg
|
||||
* negate the argument
|
||||
********************************************************************/
|
||||
@@ -693,7 +693,7 @@ gnc_numeric_neg(gnc_numeric a) {
|
||||
return gnc_numeric_create(- a.num, a.denom);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_neg
|
||||
* return the absolute value of the argument
|
||||
********************************************************************/
|
||||
@@ -707,7 +707,7 @@ gnc_numeric_abs(gnc_numeric a)
|
||||
return gnc_numeric_create(ABS(a.num), a.denom);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_convert
|
||||
********************************************************************/
|
||||
|
||||
@@ -962,8 +962,8 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** reduce a fraction by GCF elimination. This is NOT done as a
|
||||
/* *******************************************************************
|
||||
* reduce a fraction by GCF elimination. This is NOT done as a
|
||||
* part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified
|
||||
* as the output denominator.
|
||||
********************************************************************/
|
||||
@@ -996,7 +996,7 @@ gnc_numeric_reduce(gnc_numeric in)
|
||||
return out;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* double_to_gnc_numeric
|
||||
********************************************************************/
|
||||
|
||||
@@ -1068,7 +1068,7 @@ double_to_gnc_numeric(double in, gint64 denom, gint how)
|
||||
return out;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_to_double
|
||||
********************************************************************/
|
||||
|
||||
@@ -1085,7 +1085,7 @@ gnc_numeric_to_double(gnc_numeric in)
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_error
|
||||
********************************************************************/
|
||||
|
||||
@@ -1096,7 +1096,7 @@ gnc_numeric_error(GNCNumericErrorCode error_code)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_add_with_error
|
||||
********************************************************************/
|
||||
|
||||
@@ -1118,7 +1118,7 @@ gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
|
||||
return sum;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_sub_with_error
|
||||
********************************************************************/
|
||||
|
||||
@@ -1139,7 +1139,7 @@ gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_mul_with_error
|
||||
********************************************************************/
|
||||
|
||||
@@ -1160,7 +1160,7 @@ gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric_div_with_error
|
||||
********************************************************************/
|
||||
|
||||
@@ -1180,7 +1180,7 @@ gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
|
||||
return quot;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric text IO
|
||||
********************************************************************/
|
||||
|
||||
@@ -1240,7 +1240,7 @@ string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* gnc_numeric misc testing
|
||||
********************************************************************/
|
||||
#ifdef _GNC_NUMERIC_TEST
|
||||
|
@@ -53,7 +53,7 @@ this may not be good enough. For example,
|
||||
|
||||
@verbatim
|
||||
#include <glib.h>
|
||||
#include "gnc-numeric.h"
|
||||
#include <qof.h>
|
||||
#include <math.h>
|
||||
|
||||
int
|
||||
@@ -85,6 +85,7 @@ main(int argc, char ** argv)
|
||||
@{ */
|
||||
/** @file gnc-numeric.h
|
||||
@brief An exact-rational-number library for gnucash.
|
||||
(to be renamed qofnumeric.h in libqof2)
|
||||
@author Copyright (C) 2000 Bill Gribble
|
||||
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
@@ -264,7 +265,7 @@ typedef enum {
|
||||
|
||||
/** Values that can be passed as the 'denom' argument.
|
||||
* The include a positive number n to be used as the
|
||||
* denominator of the output value. Other possibilities
|
||||
* denominator of the output value. Other possibilities
|
||||
* include the list below:
|
||||
*/
|
||||
|
||||
|
@@ -1,370 +0,0 @@
|
||||
/* *****************************************************************\
|
||||
* gnc-trace.c -- QOF error logging and tracing facility *
|
||||
* Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org> *
|
||||
* Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk> *
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
* Author: Rob Clark (rclark@cs.hmc.edu) *
|
||||
* Author: Linas Vepstas (linas@linas.org) *
|
||||
\********************************************************************/
|
||||
|
||||
/** @addtogroup Trace
|
||||
@{ */
|
||||
|
||||
/** @file gnc-trace.c
|
||||
@brief QOF error logging facility
|
||||
@author Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#else
|
||||
/* What to do? */
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include "qof.h"
|
||||
#include "gnc-trace.h"
|
||||
|
||||
static FILE *fout = NULL;
|
||||
static gchar* filename = NULL;
|
||||
|
||||
static const int MAX_TRACE_FILENAME = 100;
|
||||
static GHashTable *log_table = NULL;
|
||||
|
||||
AS_STRING_FUNC(gncLogLevel, LOG_LEVEL_LIST) /**< enum_as_string function
|
||||
|
||||
uses the enum_as_string macro from QOF
|
||||
but the From macro is not required. Lookups
|
||||
are done on the string. */
|
||||
|
||||
FROM_STRING_FUNC(gncLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
/* Don't be fooled: gnc_trace_num_spaces has external linkage and
|
||||
static storage, but can't be defined with 'extern' because it has
|
||||
an initializer, and can't be declared with 'static' because that
|
||||
would give it internal linkage. */
|
||||
gint __attribute__ ((unused)) gnc_trace_num_spaces = 0;
|
||||
|
||||
static void
|
||||
fh_printer (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
extern gint gnc_trace_num_spaces;
|
||||
FILE *fh = user_data;
|
||||
fprintf (fh, "%*s%s\n", gnc_trace_num_spaces, "", message);
|
||||
fflush(fh);
|
||||
}
|
||||
|
||||
void
|
||||
gnc_log_init (void)
|
||||
{
|
||||
if(!fout) //allow gnc_set_logfile
|
||||
{
|
||||
fout = fopen ("/tmp/qof.trace", "w");
|
||||
}
|
||||
|
||||
if(!fout && (filename = (char *)g_malloc(MAX_TRACE_FILENAME))) {
|
||||
snprintf(filename, MAX_TRACE_FILENAME-1, "/tmp/qof.trace.%d",
|
||||
getpid());
|
||||
fout = fopen (filename, "w");
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
if(!fout)
|
||||
fout = stderr;
|
||||
|
||||
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, fh_printer, fout);
|
||||
}
|
||||
|
||||
/* Set the logging level of the given module. */
|
||||
void
|
||||
gnc_set_log_level(QofLogModule log_module, gncLogLevel level)
|
||||
{
|
||||
gchar* level_string;
|
||||
|
||||
if(!log_module || level == 0) { return; }
|
||||
level_string = g_strdup(gncLogLevelasString(level));
|
||||
if(!log_table)
|
||||
{
|
||||
log_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
}
|
||||
g_hash_table_insert(log_table, (gpointer)log_module, level_string);
|
||||
}
|
||||
|
||||
static void
|
||||
log_module_foreach(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
g_hash_table_insert(log_table, key, data);
|
||||
}
|
||||
|
||||
/* Set the logging level for all known modules. */
|
||||
void
|
||||
gnc_set_log_level_global(gncLogLevel level)
|
||||
{
|
||||
gchar* level_string;
|
||||
|
||||
if(!log_table || level == 0) { return; }
|
||||
level_string = g_strdup(gncLogLevelasString(level));
|
||||
g_hash_table_foreach(log_table, log_module_foreach, level_string);
|
||||
}
|
||||
|
||||
void
|
||||
gnc_set_logfile (FILE *outfile)
|
||||
{
|
||||
if(!outfile) { fout = stderr; return; }
|
||||
fout = outfile;
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_init_filename (const gchar* logfilename)
|
||||
{
|
||||
if(!logfilename)
|
||||
{
|
||||
fout = stderr;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = g_strdup(logfilename);
|
||||
fout = fopen(filename, "w");
|
||||
}
|
||||
gnc_log_init();
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_shutdown (void)
|
||||
{
|
||||
if(fout && fout != stderr) { fclose(fout); }
|
||||
if(filename) { g_free(filename); }
|
||||
g_hash_table_destroy(log_table);
|
||||
}
|
||||
|
||||
#define MAX_CHARS 50
|
||||
/* gnc_log_prettify() cleans up subroutine names. AIX/xlC has the habit
|
||||
* of printing signatures not names; clean this up. On other operating
|
||||
* systems, truncate name to 30 chars. Note this routine is not thread
|
||||
* safe. Note we wouldn't need this routine if AIX did something more
|
||||
* reasonable. Hope thread safety doesn't poke us in eye. */
|
||||
const char *
|
||||
gnc_log_prettify (const char *name)
|
||||
{
|
||||
static char bf[128];
|
||||
char *p;
|
||||
|
||||
if (!name)
|
||||
return "";
|
||||
|
||||
strncpy (bf, name, MAX_CHARS-1); bf[MAX_CHARS-2] = 0;
|
||||
p = strchr (bf, '(');
|
||||
|
||||
if (p)
|
||||
{
|
||||
*(p+1) = ')';
|
||||
*(p+2) = 0x0;
|
||||
}
|
||||
else
|
||||
strcpy (&bf[MAX_CHARS-4], "...()");
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
#define NUM_CLOCKS 10
|
||||
|
||||
static
|
||||
struct timeval gnc_clock[NUM_CLOCKS] = {
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
};
|
||||
|
||||
static
|
||||
struct timeval gnc_clock_total[NUM_CLOCKS] = {
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
};
|
||||
|
||||
void
|
||||
gnc_start_clock (int clockno, QofLogModule log_module, gncLogLevel log_level,
|
||||
const char *function_name, const char *format, ...)
|
||||
{
|
||||
struct timezone tz;
|
||||
va_list ap;
|
||||
|
||||
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
|
||||
gettimeofday (&gnc_clock[clockno], &tz);
|
||||
|
||||
if (!fout) gnc_log_init();
|
||||
|
||||
fprintf (fout, "Clock %d Start: %s: ",
|
||||
clockno, gnc_log_prettify (function_name));
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
vfprintf (fout, format, ap);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
fprintf (fout, "\n");
|
||||
fflush (fout);
|
||||
}
|
||||
|
||||
void
|
||||
gnc_report_clock (int clockno, QofLogModule log_module, gncLogLevel log_level,
|
||||
const char *function_name, const char *format, ...)
|
||||
{
|
||||
struct timezone tz;
|
||||
struct timeval now;
|
||||
va_list ap;
|
||||
|
||||
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
|
||||
gettimeofday (&now, &tz);
|
||||
|
||||
/* need to borrow to make difference */
|
||||
if (now.tv_usec < gnc_clock[clockno].tv_usec)
|
||||
{
|
||||
now.tv_sec --;
|
||||
now.tv_usec += 1000000;
|
||||
}
|
||||
now.tv_sec -= gnc_clock[clockno].tv_sec;
|
||||
now.tv_usec -= gnc_clock[clockno].tv_usec;
|
||||
|
||||
gnc_clock_total[clockno].tv_sec += now.tv_sec;
|
||||
gnc_clock_total[clockno].tv_usec += now.tv_usec;
|
||||
|
||||
if (!fout) gnc_log_init();
|
||||
|
||||
fprintf (fout, "Clock %d Elapsed: %ld.%06lds %s: ",
|
||||
clockno, (long int) now.tv_sec, (long int) now.tv_usec,
|
||||
gnc_log_prettify (function_name));
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
vfprintf (fout, format, ap);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
fprintf (fout, "\n");
|
||||
fflush (fout);
|
||||
}
|
||||
|
||||
void
|
||||
gnc_report_clock_total (int clockno,
|
||||
QofLogModule log_module, gncLogLevel log_level,
|
||||
const char *function_name, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
|
||||
|
||||
/* need to normalize usec */
|
||||
while (gnc_clock_total[clockno].tv_usec >= 1000000)
|
||||
{
|
||||
gnc_clock_total[clockno].tv_sec ++;
|
||||
gnc_clock_total[clockno].tv_usec -= 1000000;
|
||||
}
|
||||
|
||||
if (!fout) gnc_log_init();
|
||||
|
||||
fprintf (fout, "Clock %d Total Elapsed: %ld.%06lds %s: ",
|
||||
clockno,
|
||||
(long int) gnc_clock_total[clockno].tv_sec,
|
||||
(long int) gnc_clock_total[clockno].tv_usec,
|
||||
gnc_log_prettify (function_name));
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
vfprintf (fout, format, ap);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
fprintf (fout, "\n");
|
||||
fflush (fout);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gnc_should_log(QofLogModule log_module, gncLogLevel log_level)
|
||||
{
|
||||
gchar* log_string;
|
||||
gncLogLevel maximum; /* Any log_level less than this will be logged. */
|
||||
|
||||
log_string = NULL;
|
||||
if(!log_table || log_module == NULL || log_level == 0) { return FALSE; }
|
||||
log_string = (gchar*)g_hash_table_lookup(log_table, log_module);
|
||||
/* if log_module not found, do not log. */
|
||||
if(!log_string) { return FALSE; }
|
||||
maximum = gncLogLevelfromString(log_string);
|
||||
if(log_level <= maximum) { return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void qof_log_set_default(gncLogLevel log_level)
|
||||
{
|
||||
gnc_set_log_level(QOF_MOD_BACKEND, log_level);
|
||||
gnc_set_log_level(QOF_MOD_CLASS, log_level);
|
||||
gnc_set_log_level(QOF_MOD_ENGINE, log_level);
|
||||
gnc_set_log_level(QOF_MOD_OBJECT, log_level);
|
||||
gnc_set_log_level(QOF_MOD_KVP, log_level);
|
||||
gnc_set_log_level(QOF_MOD_MERGE, log_level);
|
||||
gnc_set_log_level(QOF_MOD_QUERY, log_level);
|
||||
gnc_set_log_level(QOF_MOD_SESSION, log_level);
|
||||
}
|
||||
|
||||
struct hash_s
|
||||
{
|
||||
QofLogCB cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static void hash_cb (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
struct hash_s *iter;
|
||||
|
||||
iter = (struct hash_s*)data;
|
||||
if(!iter) { return; }
|
||||
(iter->cb)(key, value, iter->data);
|
||||
}
|
||||
|
||||
void qof_log_module_foreach(QofLogCB cb, gpointer data)
|
||||
{
|
||||
struct hash_s iter;
|
||||
|
||||
if(!cb) { return; }
|
||||
iter.cb = cb;
|
||||
iter.data = data;
|
||||
g_hash_table_foreach(log_table, hash_cb, (gpointer)&iter);
|
||||
}
|
||||
|
||||
gint qof_log_module_count(void)
|
||||
{
|
||||
if(!log_table) { return 0; }
|
||||
return g_hash_table_size(log_table);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/************************* END OF FILE ******************************\
|
||||
\********************************************************************/
|
@@ -1,274 +0,0 @@
|
||||
/********************************************************************\
|
||||
* gnc-trace.h -- QOF error logging and tracing facility *
|
||||
* Copyright (C) 1998-2003 Linas Vepstas <linas@linas.org> *
|
||||
* Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk> *
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
* Author: Linas Vepstas (linas@linas.org) *
|
||||
\********************************************************************/
|
||||
|
||||
/** @addtogroup Trace
|
||||
@{ */
|
||||
|
||||
/** @file gnc-trace.h
|
||||
* @brief QOF error logging and tracing facility
|
||||
* @author Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
#ifndef GNC_TRACE_H
|
||||
#define GNC_TRACE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "qof.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#define QOF_MOD_ENGINE "qof-engine"
|
||||
|
||||
#define LOG_LEVEL_LIST(_) \
|
||||
_(GNC_LOG_FATAL, = 0) \
|
||||
_(GNC_LOG_ERROR, = 1) \
|
||||
_(GNC_LOG_WARNING, = 2) \
|
||||
_(GNC_LOG_INFO, = 3) \
|
||||
_(GNC_LOG_DEBUG, = 4) \
|
||||
_(GNC_LOG_DETAIL, = 5) \
|
||||
_(GNC_LOG_TRACE, = 6)
|
||||
|
||||
DEFINE_ENUM (gncLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
/** Convert gncLogLevel to a string.
|
||||
|
||||
The macro correlates the enum value and an
|
||||
exact copy as a string, removing the need to
|
||||
keep two separate lists in sync.
|
||||
*/
|
||||
AS_STRING_DEC(gncLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
/** Convert the log_string to a gncLogLevel
|
||||
|
||||
Only for use as a partner to ::gncLogLevelasString
|
||||
*/
|
||||
FROM_STRING_DEC(gncLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
#define GNC_TRACE_INDENT_WIDTH 4
|
||||
|
||||
/** Initialize the error logging subsystem
|
||||
|
||||
\note Applications should call gnc_set_logfile
|
||||
to set the output, otherwise the
|
||||
default of \a /tmp/qof.trace will be used.
|
||||
|
||||
As an alternative, use qof_log_init_filename
|
||||
which sets the filename and initialises the
|
||||
logging subsystem in one operation.
|
||||
*/
|
||||
void gnc_log_init (void);
|
||||
|
||||
/** Set the logging level of the given log_module. */
|
||||
void gnc_set_log_level(QofLogModule module, gncLogLevel level);
|
||||
|
||||
/** Set the logging level for all known log_modules.
|
||||
|
||||
\note Unless a log_module has been registered using
|
||||
gnc_set_log_level, it will be unaffected by this change.
|
||||
|
||||
*/
|
||||
void gnc_set_log_level_global(gncLogLevel level);
|
||||
|
||||
/** Specify an alternate log output, to pipe or file. By default,
|
||||
* all logging goes to /tmp/qof.trace
|
||||
|
||||
Needs to be called \b before gnc_log_init()
|
||||
*/
|
||||
void gnc_set_logfile (FILE *outfile);
|
||||
|
||||
/** Specify a filename for log output.
|
||||
|
||||
Calls gnc_log_init() for you.
|
||||
*/
|
||||
void qof_log_init_filename (const gchar* logfilename);
|
||||
|
||||
/** Be nice, close the logfile is possible. */
|
||||
void qof_log_shutdown (void);
|
||||
|
||||
/** gnc_log_prettify() cleans up subroutine names. AIX/xlC has the habit
|
||||
* of printing signatures not names; clean this up. On other operating
|
||||
* systems, truncate name to 30 chars. Note this routine is not thread
|
||||
* safe. Note we wouldn't need this routine if AIX did something more
|
||||
* reasonable. Hope thread safety doesn't poke us in eye. */
|
||||
const char * gnc_log_prettify (const char *name);
|
||||
|
||||
/** Do not log log_modules that have not been enabled.
|
||||
|
||||
Whether to log cannot be decided inline because a hashtable is
|
||||
now used. This is the price of extending logging to non-Gnucash
|
||||
log_modules.
|
||||
|
||||
*/
|
||||
gboolean gnc_should_log(QofLogModule log_module, gncLogLevel log_level);
|
||||
|
||||
/** Set the default QOF log_modules to the log level. */
|
||||
void qof_log_set_default(gncLogLevel log_level);
|
||||
|
||||
typedef void (*QofLogCB) (QofLogModule log_module, gncLogLevel* log_level, gpointer user_data);
|
||||
|
||||
/** Iterate over each known log_module
|
||||
|
||||
Only log_modules with log_levels set will
|
||||
be available.
|
||||
*/
|
||||
void qof_log_module_foreach(QofLogCB cb, gpointer data);
|
||||
|
||||
/** Number of log_modules registered*/
|
||||
gint qof_log_module_count(void);
|
||||
|
||||
#define FUNK gnc_log_prettify(__FUNCTION__)
|
||||
|
||||
/** Log error/waring/info messages to stderr or to other pipe.
|
||||
* This logging infrastructure is meant for validating the
|
||||
* correctness of the execution of the code. 'Info' level
|
||||
* messages help trace program flow. 'Error' messages are
|
||||
* meant to indicate internal data inconsistencies.
|
||||
*
|
||||
* Messages can be logged to stdout, stderr, or to any desired
|
||||
* FILE * file handle. Use fdopen() to get a file handle from a
|
||||
* file descriptor. Use gnc_set_logfile to set the logging file
|
||||
* handle.
|
||||
*/
|
||||
|
||||
/** Log an fatal error */
|
||||
#define FATAL(format, args...) do { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
|
||||
"Fatal Error: %s(): " format, FUNK , ## args); \
|
||||
} while (0)
|
||||
|
||||
/** Log an serious error */
|
||||
#define PERR(format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_ERROR)) {\
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
|
||||
"Error: %s(): " format, FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Log an warning */
|
||||
#define PWARN(format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_WARNING)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
|
||||
"Warning: %s(): " format, FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print an informational note */
|
||||
#define PINFO(format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_INFO)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
|
||||
"Info: %s(): " format, \
|
||||
FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print an debugging message */
|
||||
#define DEBUG(format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_DEBUG)) {\
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Debug: %s(): " format, \
|
||||
FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print an function entry debugging message */
|
||||
#define ENTER(format, args...) do { \
|
||||
extern gint gnc_trace_num_spaces; \
|
||||
if (gnc_should_log (log_module, GNC_LOG_DEBUG)) {\
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Enter in %s: %s()" format, __FILE__, \
|
||||
FUNK , ## args); \
|
||||
gnc_trace_num_spaces += GNC_TRACE_INDENT_WIDTH;\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print an function exit debugging message */
|
||||
#define LEAVE(format, args...) do { \
|
||||
extern gint gnc_trace_num_spaces; \
|
||||
if (gnc_should_log (log_module, GNC_LOG_DEBUG)) {\
|
||||
gnc_trace_num_spaces -= GNC_TRACE_INDENT_WIDTH;\
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Leave: %s()" format, \
|
||||
FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print an function trace debugging message */
|
||||
#define TRACE(format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_TRACE)) {\
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Trace: %s(): " format, FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEBUGCMD(x) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_DEBUG)) { \
|
||||
(x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/** Infrastructure to make timing measurements for critical peices
|
||||
* of code. Used for only for performance tuning & debugging.
|
||||
*/
|
||||
|
||||
void gnc_start_clock (int clockno, QofLogModule log_module, gncLogLevel log_level,
|
||||
const char *function_name, const char *format, ...);
|
||||
|
||||
void gnc_report_clock (int clockno,
|
||||
QofLogModule log_module,
|
||||
gncLogLevel log_level,
|
||||
const char *function_name,
|
||||
const char *format, ...);
|
||||
|
||||
void gnc_report_clock_total (int clockno,
|
||||
QofLogModule log_module,
|
||||
gncLogLevel log_level,
|
||||
const char *function_name,
|
||||
const char *format, ...);
|
||||
|
||||
/** start a particular timer */
|
||||
#define START_CLOCK(clockno,format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_INFO)) \
|
||||
gnc_start_clock (clockno, log_module, GNC_LOG_INFO, \
|
||||
__FUNCTION__, format , ## args); \
|
||||
} while (0)
|
||||
|
||||
/** report elapsed time since last report on a particular timer */
|
||||
#define REPORT_CLOCK(clockno,format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_INFO)) \
|
||||
gnc_report_clock (clockno, log_module, GNC_LOG_INFO, \
|
||||
__FUNCTION__, format , ## args); \
|
||||
} while (0)
|
||||
|
||||
/** report total elapsed time since timer started */
|
||||
#define REPORT_CLOCK_TOTAL(clockno,format, args...) do { \
|
||||
if (gnc_should_log (log_module, GNC_LOG_INFO)) \
|
||||
gnc_report_clock_total (clockno, log_module, GNC_LOG_INFO, \
|
||||
__FUNCTION__, format , ## args); \
|
||||
} while (0)
|
||||
|
||||
#endif /* GNC_TRACE_H */
|
||||
/* @} */
|
@@ -38,23 +38,20 @@
|
||||
#include <sys/times.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "guid.h"
|
||||
#include "qof.h"
|
||||
#include "md5.h"
|
||||
#include "qofid.h"
|
||||
#include "gnc-trace.h"
|
||||
|
||||
# ifndef P_tmpdir
|
||||
# define P_tmpdir "/tmp"
|
||||
# endif
|
||||
|
||||
/** Constants *******************************************************/
|
||||
/* Constants *******************************************************/
|
||||
#define DEBUG_GUID 0
|
||||
#define BLOCKSIZE 4096
|
||||
#define THRESHOLD (2 * BLOCKSIZE)
|
||||
|
||||
|
||||
/** Static global variables *****************************************/
|
||||
/* Static global variables *****************************************/
|
||||
static gboolean guid_initialized = FALSE;
|
||||
static struct md5_ctx guid_context;
|
||||
#ifndef HAVE_GLIB29
|
||||
@@ -64,7 +61,7 @@ static GMemChunk *guid_memchunk = NULL;
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = QOF_MOD_ENGINE;
|
||||
|
||||
/** Memory management routines ***************************************/
|
||||
/* Memory management routines ***************************************/
|
||||
#ifdef HAVE_GLIB29
|
||||
GUID *
|
||||
guid_malloc (void)
|
||||
@@ -81,6 +78,7 @@ guid_free (GUID *guid)
|
||||
g_slice_free(GUID, guid);
|
||||
}
|
||||
#else /* !HAVE_GLIB29 */
|
||||
|
||||
static void
|
||||
guid_memchunk_init (void)
|
||||
{
|
||||
@@ -127,8 +125,8 @@ guid_null(void)
|
||||
int i;
|
||||
char *tmp = "NULLGUID.EMPTY.";
|
||||
|
||||
/* 16th space for '\O' */
|
||||
for (i = 0; i < 16; i++)
|
||||
/* 16th space for '\O' */
|
||||
for (i = 0; i < 16; i++)
|
||||
null_guid.data[i] = tmp[i];
|
||||
|
||||
null_inited = 1;
|
||||
@@ -137,7 +135,7 @@ guid_null(void)
|
||||
return &null_guid;
|
||||
}
|
||||
|
||||
/** Function implementations ****************************************/
|
||||
/* Function implementations ****************************************/
|
||||
|
||||
/* This code is based on code in md5.c in GNU textutils. */
|
||||
static size_t
|
||||
@@ -495,16 +493,16 @@ guid_new(GUID *guid)
|
||||
init_from_time();
|
||||
|
||||
/* Make it a little extra salty. I think init_from_time was buggy,
|
||||
* or something, since duplicate id's actually happened. Or something
|
||||
* like that. I think this is because init_from_time kept returning
|
||||
* the same values too many times in a row. So we'll do some 'block
|
||||
* chaining', and feed in the old guid as new random data.
|
||||
*
|
||||
* Anyway, I think the whole fact that I saw a bunch of duplicate
|
||||
* id's at one point, but can't reproduce the bug is rather alarming.
|
||||
* Something must be broken somewhere, and merely adding more salt
|
||||
* is just hiding the problem, not fixing it.
|
||||
*/
|
||||
* or something, since duplicate id's actually happened. Or something
|
||||
* like that. I think this is because init_from_time kept returning
|
||||
* the same values too many times in a row. So we'll do some 'block
|
||||
* chaining', and feed in the old guid as new random data.
|
||||
*
|
||||
* Anyway, I think the whole fact that I saw a bunch of duplicate
|
||||
* id's at one point, but can't reproduce the bug is rather alarming.
|
||||
* Something must be broken somewhere, and merely adding more salt
|
||||
* is just hiding the problem, not fixing it.
|
||||
*/
|
||||
init_from_int (433781*counter);
|
||||
init_from_buff (guid->data, 16);
|
||||
|
||||
|
@@ -38,8 +38,10 @@
|
||||
or beyond.
|
||||
|
||||
QOF GUID's can be used independently of any other subsystem
|
||||
in QOF. In particular, they do not require the use of
|
||||
other parts of the object subsystem.
|
||||
in QOF. In particular, they do not require the use of
|
||||
other parts of the object subsystem. New GUID's are usually
|
||||
created by initialising a new entity using qof_instance_init,
|
||||
rather than calling GUID functions directly.
|
||||
|
||||
@{ */
|
||||
/** @file guid.h
|
||||
@@ -127,19 +129,13 @@ void guid_new(GUID *guid);
|
||||
/** Generate a new id. If no initialization function has been called,
|
||||
* guid_init() will be called before the id is created.
|
||||
*
|
||||
* @return guid A pointer to a data structure containing a new GUID.
|
||||
* The memory pointed to is owned by this routine and the guid must
|
||||
* be copied out.
|
||||
*
|
||||
* CAS: huh? make that: @return guid A data structure containing a newly
|
||||
* allocated GUID. Caller is responsible for calling guid_free().
|
||||
* @return guid A data structure containing a newly allocated GUID.
|
||||
* Caller is responsible for calling guid_free().
|
||||
*/
|
||||
GUID guid_new_return(void);
|
||||
|
||||
/** Returns a GUID which is guaranteed to never reference any entity. */
|
||||
/* CAS: AFAICT: this isn't really guaranteed, but it's only as likely
|
||||
as any other md5 collision. This could be guaranteed if GUID
|
||||
contained a validity flag. */
|
||||
/** Returns a GUID which is guaranteed
|
||||
to never reference any entity. */
|
||||
const GUID * guid_null (void);
|
||||
|
||||
/** Efficiently allocate & free memory for GUIDs */
|
||||
|
@@ -24,7 +24,7 @@
|
||||
@{
|
||||
*/
|
||||
/** @file kvp-util.h
|
||||
@brief GnuCash KVP utility functions
|
||||
@brief QOF KVP utility functions
|
||||
*/
|
||||
/** @name Hash Utilities
|
||||
@{
|
||||
|
@@ -31,20 +31,12 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "gnc-date.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-numeric.h"
|
||||
#include "guid.h"
|
||||
#include "kvp_frame.h"
|
||||
|
||||
#include "qof.h"
|
||||
|
||||
/* Note that we keep the keys for this hash table in a GCache
|
||||
* (gnc_string_cache), as it is very likely we will see the
|
||||
* same keys over and over again */
|
||||
|
||||
/* TODO: set the cache handling functions with hash_table_new_full */
|
||||
|
||||
struct _KvpFrame
|
||||
{
|
||||
GHashTable * hash;
|
||||
@@ -76,7 +68,7 @@ struct _KvpValue
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = QOF_MOD_KVP;
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* KvpFrame functions
|
||||
********************************************************************/
|
||||
|
||||
@@ -245,7 +237,7 @@ get_or_make (KvpFrame *fr, const char * key)
|
||||
return next_frame;
|
||||
}
|
||||
|
||||
/* Get pointer to last frame in path. If teh path doesn't exist,
|
||||
/* Get pointer to last frame in path. If the path doesn't exist,
|
||||
* it is created. The string stored in keypath will be hopelessly
|
||||
* mangled .
|
||||
*/
|
||||
@@ -312,16 +304,16 @@ kvp_frame_get_frame_or_null_slash_trash (const KvpFrame *frame, char *key_path)
|
||||
*/
|
||||
|
||||
static inline KvpFrame *
|
||||
get_trailer_make (KvpFrame * frame, const char * key_path, const char **end_key)
|
||||
get_trailer_make (KvpFrame * frame, const char * key_path, char **end_key)
|
||||
{
|
||||
const char *last_key;
|
||||
char *last_key;
|
||||
|
||||
if (!frame || !key_path || (0 == key_path[0])) return NULL;
|
||||
|
||||
last_key = strrchr (key_path, '/');
|
||||
if (NULL == last_key)
|
||||
{
|
||||
last_key = key_path;
|
||||
last_key = (char *) key_path;
|
||||
}
|
||||
else if (last_key == key_path)
|
||||
{
|
||||
@@ -354,16 +346,16 @@ get_trailer_make (KvpFrame * frame, const char * key_path, const char **end_key)
|
||||
*/
|
||||
|
||||
static inline const KvpFrame *
|
||||
get_trailer_or_null (const KvpFrame * frame, const char * key_path, const char **end_key)
|
||||
get_trailer_or_null (const KvpFrame * frame, const char * key_path, char **end_key)
|
||||
{
|
||||
const char *last_key;
|
||||
char *last_key;
|
||||
|
||||
if (!frame || !key_path || (0 == key_path[0])) return NULL;
|
||||
|
||||
last_key = strrchr (key_path, '/');
|
||||
if (NULL == last_key)
|
||||
{
|
||||
last_key = key_path;
|
||||
last_key = (char *) key_path;
|
||||
}
|
||||
else if (last_key == key_path)
|
||||
{
|
||||
@@ -469,7 +461,7 @@ KvpFrame *
|
||||
kvp_frame_set_value_nc (KvpFrame * frame, const char * key_path,
|
||||
KvpValue * value)
|
||||
{
|
||||
const char *last_key;
|
||||
char *last_key;
|
||||
|
||||
frame = get_trailer_make (frame, key_path, &last_key);
|
||||
if (!frame) return NULL;
|
||||
@@ -482,7 +474,7 @@ kvp_frame_set_value (KvpFrame * frame, const char * key_path,
|
||||
const KvpValue * value)
|
||||
{
|
||||
KvpValue *new_value = NULL;
|
||||
const char *last_key;
|
||||
char *last_key;
|
||||
|
||||
frame = get_trailer_make (frame, key_path, &last_key);
|
||||
if (!frame) return NULL;
|
||||
@@ -497,7 +489,7 @@ kvp_frame_replace_value_nc (KvpFrame * frame, const char * key_path,
|
||||
KvpValue * new_value)
|
||||
{
|
||||
KvpValue * old_value;
|
||||
const char *last_key;
|
||||
char *last_key;
|
||||
|
||||
last_key = NULL;
|
||||
if (new_value)
|
||||
@@ -519,7 +511,7 @@ kvp_frame_replace_value_nc (KvpFrame * frame, const char * key_path,
|
||||
KvpFrame *
|
||||
kvp_frame_add_value_nc(KvpFrame * frame, const char * path, KvpValue *value)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
KvpValue *oldvalue;
|
||||
|
||||
frame = (KvpFrame *) get_trailer_or_null (frame, path, &key);
|
||||
@@ -855,7 +847,7 @@ kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc)
|
||||
gint64
|
||||
kvp_frame_get_gint64(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_gint64(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -863,7 +855,7 @@ kvp_frame_get_gint64(const KvpFrame *frame, const char *path)
|
||||
double
|
||||
kvp_frame_get_double(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_double(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -871,7 +863,7 @@ kvp_frame_get_double(const KvpFrame *frame, const char *path)
|
||||
gnc_numeric
|
||||
kvp_frame_get_numeric(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_numeric(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -879,7 +871,7 @@ kvp_frame_get_numeric(const KvpFrame *frame, const char *path)
|
||||
char *
|
||||
kvp_frame_get_string(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_string(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -887,7 +879,7 @@ kvp_frame_get_string(const KvpFrame *frame, const char *path)
|
||||
GUID *
|
||||
kvp_frame_get_guid(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_guid(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -896,7 +888,7 @@ void *
|
||||
kvp_frame_get_binary(const KvpFrame *frame, const char *path,
|
||||
guint64 * size_return)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_binary(kvp_frame_get_slot (frame, key), size_return);
|
||||
}
|
||||
@@ -904,7 +896,7 @@ kvp_frame_get_binary(const KvpFrame *frame, const char *path,
|
||||
Timespec
|
||||
kvp_frame_get_timespec(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_timespec(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -912,7 +904,7 @@ kvp_frame_get_timespec(const KvpFrame *frame, const char *path)
|
||||
KvpFrame *
|
||||
kvp_frame_get_frame(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_value_get_frame(kvp_frame_get_slot (frame, key));
|
||||
}
|
||||
@@ -920,7 +912,7 @@ kvp_frame_get_frame(const KvpFrame *frame, const char *path)
|
||||
KvpValue *
|
||||
kvp_frame_get_value(const KvpFrame *frame, const char *path)
|
||||
{
|
||||
const char *key = NULL;
|
||||
char *key = NULL;
|
||||
frame = get_trailer_or_null (frame, path, &key);
|
||||
return kvp_frame_get_slot (frame, key);
|
||||
}
|
||||
@@ -1039,7 +1031,7 @@ kvp_frame_get_slot_path_gslist (KvpFrame *frame,
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* kvp glist functions
|
||||
********************************************************************/
|
||||
|
||||
@@ -1109,7 +1101,7 @@ kvp_glist_compare(const GList * list1, const GList * list2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* KvpValue functions
|
||||
********************************************************************/
|
||||
|
||||
@@ -1637,6 +1629,13 @@ kvp_value_glist_to_string(const GList *list)
|
||||
return tmp2;
|
||||
}
|
||||
|
||||
static void
|
||||
kvp_frame_to_bare_string_helper(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
gchar **str = (gchar**)data;
|
||||
*str = g_strdup_printf("%s", kvp_value_to_bare_string((KvpValue *)value));
|
||||
}
|
||||
|
||||
gchar*
|
||||
kvp_value_to_bare_string(const KvpValue *val)
|
||||
{
|
||||
@@ -1645,7 +1644,7 @@ kvp_value_to_bare_string(const KvpValue *val)
|
||||
const gchar *ctmp;
|
||||
|
||||
g_return_val_if_fail(val, NULL);
|
||||
|
||||
tmp1 = g_strdup("");
|
||||
switch(kvp_value_get_type(val))
|
||||
{
|
||||
case KVP_TYPE_GINT64:
|
||||
@@ -1675,13 +1674,13 @@ kvp_value_to_bare_string(const KvpValue *val)
|
||||
break;
|
||||
|
||||
case KVP_TYPE_TIMESPEC:
|
||||
tmp1 = g_new0 (char, 40);
|
||||
gnc_timespec_to_iso8601_buff (kvp_value_get_timespec (val), tmp1);
|
||||
tmp2 = g_strdup_printf("%s", tmp1);
|
||||
g_free(tmp1);
|
||||
return tmp2;
|
||||
{
|
||||
time_t t;
|
||||
t = timespecToTime_t(kvp_value_get_timespec(val));
|
||||
qof_date_format_set(QOF_DATE_FORMAT_UTC);
|
||||
return qof_print_date(t);
|
||||
break;
|
||||
|
||||
}
|
||||
case KVP_TYPE_BINARY:
|
||||
{
|
||||
guint64 len;
|
||||
@@ -1693,19 +1692,26 @@ kvp_value_to_bare_string(const KvpValue *val)
|
||||
break;
|
||||
|
||||
case KVP_TYPE_GLIST:
|
||||
/* borked. kvp_value_glist_to_string is a debug fcn */
|
||||
{
|
||||
tmp1 = kvp_value_glist_to_string(kvp_value_get_glist(val));
|
||||
tmp2 = g_strdup_printf("%s", tmp1 ? tmp1 : "");
|
||||
g_free(tmp1);
|
||||
return tmp2;
|
||||
break;
|
||||
|
||||
}
|
||||
case KVP_TYPE_FRAME:
|
||||
tmp1 = kvp_frame_to_string(kvp_value_get_frame(val));
|
||||
tmp2 = g_strdup_printf("%s", tmp1 ? tmp1 : "");
|
||||
g_free(tmp1);
|
||||
return tmp2;
|
||||
break;
|
||||
{
|
||||
KvpFrame *frame;
|
||||
|
||||
frame = kvp_value_get_frame(val);
|
||||
if (frame->hash) {
|
||||
tmp1 = g_strdup("");
|
||||
g_hash_table_foreach(frame->hash, kvp_frame_to_bare_string_helper, &tmp1);
|
||||
}
|
||||
return tmp1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return g_strdup_printf(" ");
|
||||
break;
|
||||
@@ -1746,7 +1752,7 @@ kvp_value_to_string(const KvpValue *val)
|
||||
break;
|
||||
|
||||
case KVP_TYPE_GUID:
|
||||
/* THREAD-UNSAFE */
|
||||
/* THREAD-UNSAFE */
|
||||
ctmp = guid_to_string(kvp_value_get_guid(val));
|
||||
tmp2 = g_strdup_printf("KVP_VALUE_GUID(%s)", ctmp ? ctmp : "");
|
||||
return tmp2;
|
||||
|
@@ -75,7 +75,7 @@ typedef struct _KvpFrame KvpFrame;
|
||||
/** A KvpValue is a union with possible types enumerated in the
|
||||
* KvpValueType enum. */
|
||||
typedef struct _KvpValue KvpValue;
|
||||
|
||||
|
||||
/** \brief possible types in the union KvpValue
|
||||
* \todo : People have asked for boolean values,
|
||||
* e.g. in xaccAccountSetAutoInterestXfer
|
||||
@@ -99,12 +99,14 @@ typedef enum {
|
||||
KVP_TYPE_FRAME /**< no QOF equivalent. */
|
||||
} KvpValueType;
|
||||
|
||||
/** \deprecated Deprecated backwards compat tokens
|
||||
/** \deprecated Deprecated backwards compat token
|
||||
|
||||
do \b not use these in new code.
|
||||
do \b not use these in new code.
|
||||
*/
|
||||
#define kvp_frame KvpFrame
|
||||
/** \deprecated Deprecated backwards compat token */
|
||||
#define kvp_value KvpValue
|
||||
/** \deprecated Deprecated backwards compat token */
|
||||
#define kvp_value_t KvpValueType
|
||||
|
||||
/** @name KvpFrame Constructors
|
||||
@@ -241,7 +243,7 @@ KvpValue * kvp_frame_replace_value_nc (KvpFrame * frame, const char * slot,
|
||||
* 'November', respectively. This routine also handles % encoding.
|
||||
*
|
||||
* This routine treats all values as strings; it does *not* attempt
|
||||
* to perform any type-conversion.
|
||||
* to perform any type-conversion.
|
||||
* */
|
||||
void kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc);
|
||||
/** @} */
|
||||
|
@@ -35,7 +35,7 @@
|
||||
#ifndef QOF_BE_UTILS_H
|
||||
#define QOF_BE_UTILS_H
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "qoflog.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "qofbackend-p.h"
|
||||
#include "qofbook.h"
|
||||
@@ -46,13 +46,12 @@
|
||||
* @param inst: an instance of QofInstance
|
||||
*
|
||||
* The caller should use this macro first and then perform any other operations.
|
||||
|
||||
|
||||
Uses newly created functions to allow the macro to be used
|
||||
when QOF is linked as a library. qofbackend-p.h is a private header.
|
||||
*/
|
||||
|
||||
#define QOF_BEGIN_EDIT(inst) \
|
||||
QofBackend * be; \
|
||||
if (!(inst)) return; \
|
||||
\
|
||||
(inst)->editlevel++; \
|
||||
@@ -66,12 +65,15 @@
|
||||
ENTER ("(inst=%p)", (inst)); \
|
||||
\
|
||||
/* See if there's a backend. If there is, invoke it. */ \
|
||||
be = qof_book_get_backend ((inst)->book); \
|
||||
if (be && qof_backend_begin_exists((be))) { \
|
||||
qof_backend_run_begin((be), (inst)); \
|
||||
} else { \
|
||||
/* We tried and failed to start transaction! */ \
|
||||
(inst)->dirty = TRUE; \
|
||||
{ \
|
||||
QofBackend * be; \
|
||||
be = qof_book_get_backend ((inst)->book); \
|
||||
if (be && qof_backend_begin_exists(be)) { \
|
||||
qof_backend_run_begin(be, (inst)); \
|
||||
} else { \
|
||||
/* We tried and failed to start transaction! */ \
|
||||
(inst)->dirty = TRUE; \
|
||||
} \
|
||||
} \
|
||||
LEAVE (" ");
|
||||
|
||||
@@ -102,15 +104,15 @@ gboolean qof_begin_edit(QofInstance *inst);
|
||||
(inst)->editlevel--; \
|
||||
if (0 < (inst)->editlevel) return; \
|
||||
\
|
||||
/* The pricedb suffers from delayed update... */ \
|
||||
/* The pricedb suffers from delayed update... */ \
|
||||
/* This may be setting a bad precedent for other types, I fear. */ \
|
||||
/* Other types probably really should handle begin like this. */ \
|
||||
if ((-1 == (inst)->editlevel) && (inst)->dirty) \
|
||||
{ \
|
||||
QofBackend * be; \
|
||||
be = qof_book_get_backend ((inst)->book); \
|
||||
if (be && qof_backend_begin_exists((be))) { \
|
||||
qof_backend_run_begin((be), (inst)); \
|
||||
if (be && qof_backend_begin_exists(be)) { \
|
||||
qof_backend_run_begin(be, (inst)); \
|
||||
} \
|
||||
(inst)->editlevel = 0; \
|
||||
} \
|
||||
@@ -148,7 +150,7 @@ gboolean qof_commit_edit(QofInstance *inst);
|
||||
\
|
||||
/* See if there's a backend. If there is, invoke it. */ \
|
||||
be = qof_book_get_backend ((inst)->book); \
|
||||
if (be && qof_backend_commit_exists((be))) \
|
||||
if (be && qof_backend_commit_exists(be)) \
|
||||
{ \
|
||||
QofBackendError errcode; \
|
||||
\
|
||||
@@ -157,7 +159,7 @@ gboolean qof_commit_edit(QofInstance *inst);
|
||||
errcode = qof_backend_get_error (be); \
|
||||
} while (ERR_BACKEND_NO_ERR != errcode); \
|
||||
\
|
||||
qof_backend_run_commit((be), (inst)); \
|
||||
qof_backend_run_commit(be, (inst)); \
|
||||
errcode = qof_backend_get_error (be); \
|
||||
if (ERR_BACKEND_NO_ERR != errcode) \
|
||||
{ \
|
||||
|
@@ -74,7 +74,7 @@
|
||||
/** @} */
|
||||
|
||||
#include "qofid.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "qoflog.h"
|
||||
#include "gnc-date.h"
|
||||
#include "gnc-numeric.h"
|
||||
#include "gnc-event.h"
|
||||
@@ -97,5 +97,13 @@
|
||||
#include "qof_book_merge.h"
|
||||
#include "qof-be-utils.h"
|
||||
#include "qofla-dir.h"
|
||||
#include "deprecated.h"
|
||||
|
||||
/** allow easy logging of QSF debug messages */
|
||||
#define QOF_MOD_QSF "qof-backend-qsf"
|
||||
/** allow easy loading of the QSF backend */
|
||||
#define QSF_BACKEND_LIB "libqof-backend-qsf"
|
||||
/** allow easy loading of the QSF backend */
|
||||
#define QSF_MODULE_INIT "qsf_provider_init"
|
||||
|
||||
#endif /* QOF_H_ */
|
||||
|
@@ -16,16 +16,12 @@
|
||||
* 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 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
* *
|
||||
********************************************************************/
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "qof_book_merge.h"
|
||||
#include "qofinstance-p.h"
|
||||
#include "qofchoice.h"
|
||||
#include "qofid-p.h"
|
||||
#include "qof.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_MERGE;
|
||||
|
||||
@@ -698,7 +694,7 @@ qof_book_mergeCommitRuleLoop(
|
||||
registered_type = TRUE;
|
||||
}
|
||||
if(safe_strcmp(rule->mergeType, QOF_TYPE_CHOICE) == 0) {
|
||||
referenceEnt = cm_param->param_getfcn(rule->importEnt, cm_param);
|
||||
referenceEnt = cm_param->param_getfcn(rule->importEnt, cm_param);
|
||||
reference_setter = (void(*)(QofEntity*, QofEntity*))cm_param->param_setfcn;
|
||||
if(reference_setter != NULL)
|
||||
{
|
||||
@@ -795,6 +791,11 @@ reformat to QSF_XSD_TIME or the QSF XML will
|
||||
FAIL the schema validation and QSF exports will become invalid.
|
||||
|
||||
The QOF_TYPE_BOOLEAN is lowercase for the same reason.
|
||||
|
||||
\todo deprecate and replace with
|
||||
gchar* qof_instance_param_as_string(const QofParam*, QofInstance*);
|
||||
and then add
|
||||
gchar* qof_class_get_param_as_string(QofIdTypeConst, QofInstance*); ?
|
||||
*/
|
||||
char*
|
||||
qof_book_merge_param_as_string(QofParam *qtparam, QofEntity *qtEnt)
|
||||
|
@@ -16,8 +16,8 @@
|
||||
* 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 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
* *
|
||||
********************************************************************/
|
||||
|
||||
@@ -68,6 +68,7 @@ any error values to the calling process. ::qof_book_mergeInit returns a
|
||||
pointer to the ::qof_book_mergeData struct - the calling process needs to
|
||||
make sure this is non-NULL to know that the Init has been successful.
|
||||
|
||||
(to be renamed qofbookmerge.h in libqof2)
|
||||
@{
|
||||
*/
|
||||
/** @file qof_book_merge.h
|
||||
@@ -81,7 +82,7 @@ make sure this is non-NULL to know that the Init has been successful.
|
||||
#include "qofclass.h"
|
||||
#include "qofobject.h"
|
||||
#include "qofinstance.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "qoflog.h"
|
||||
|
||||
/** \brief Results of collisions and user resolution.
|
||||
|
||||
|
@@ -313,7 +313,7 @@ struct QofBackend_s
|
||||
gboolean (*process_events) (QofBackend *);
|
||||
|
||||
QofBePercentageFunc percentage;
|
||||
|
||||
|
||||
QofBackendProvider *provider;
|
||||
|
||||
/** Document Me !!! what is this supposed to do ?? */
|
||||
@@ -329,8 +329,7 @@ struct QofBackend_s
|
||||
*/
|
||||
char * fullpath;
|
||||
|
||||
#ifdef GNUCASH_MAJOR_VERSION
|
||||
/** XXX price_lookup should be removed during the redesign
|
||||
/** \deprecated price_lookup should be removed during the redesign
|
||||
* of the SQL backend... prices can now be queried using
|
||||
* the generic query mechanism.
|
||||
*
|
||||
@@ -340,13 +339,12 @@ struct QofBackend_s
|
||||
*/
|
||||
void (*price_lookup) (QofBackend *, gpointer);
|
||||
|
||||
/** XXX Export should really _NOT_ be here, but is left here for now.
|
||||
/** \deprecated Export should really _NOT_ be here, but is left here for now.
|
||||
* I'm not sure where this should be going to. It should be
|
||||
* removed ASAP. This is a temporary hack-around until period-closing
|
||||
* is fully implemented.
|
||||
*/
|
||||
void (*export) (QofBackend *, QofBook *);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
@@ -31,8 +31,8 @@
|
||||
#include <glib.h>
|
||||
#include <gmodule.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include "qof.h"
|
||||
#include "qofbackend-p.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_BACKEND;
|
||||
@@ -40,7 +40,7 @@ static QofLogModule log_module = QOF_MOD_BACKEND;
|
||||
#define QOF_CONFIG_DESC "desc"
|
||||
#define QOF_CONFIG_TIP "tip"
|
||||
|
||||
/********************************************************************\
|
||||
/* *******************************************************************\
|
||||
* error handling *
|
||||
\********************************************************************/
|
||||
|
||||
@@ -89,7 +89,6 @@ qof_backend_set_message (QofBackend *be, const char *format, ...)
|
||||
be->error_msg = buffer;
|
||||
}
|
||||
|
||||
/* This should always return a valid char * */
|
||||
char *
|
||||
qof_backend_get_message (QofBackend *be)
|
||||
{
|
||||
@@ -100,9 +99,9 @@ qof_backend_get_message (QofBackend *be)
|
||||
|
||||
/*
|
||||
* Just return the contents of the error_msg and then set it to
|
||||
* NULL. This is necessary, because the Backends don't seem to
|
||||
* have a destroy_backend function to take care if freeing stuff
|
||||
* up. The calling function should free the copy.
|
||||
* NULL. This is necessary, because the Backends don't seem to
|
||||
* have a destroy_backend function to take care of freeing stuff
|
||||
* up. The calling function should free the copy.
|
||||
* Also, this is consistent with the qof_backend_get_error() popping.
|
||||
*/
|
||||
|
||||
@@ -141,13 +140,10 @@ qof_backend_init(QofBackend *be)
|
||||
be->error_msg = NULL;
|
||||
be->percentage = NULL;
|
||||
be->backend_configuration = kvp_frame_new();
|
||||
|
||||
#ifdef GNUCASH_MAJOR_VERSION
|
||||
/* XXX remove these */
|
||||
be->fullpath = NULL;
|
||||
be->price_lookup = NULL;
|
||||
be->export = NULL;
|
||||
#endif
|
||||
|
||||
/* to be removed */
|
||||
be->price_lookup = NULL;
|
||||
be->export = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -195,11 +191,10 @@ void qof_backend_prepare_option(QofBackend *be, QofBackendOption *option)
|
||||
count = be->config_count;
|
||||
count++;
|
||||
value = NULL;
|
||||
ENTER (" %d", count);
|
||||
switch (option->type)
|
||||
{
|
||||
case KVP_TYPE_GINT64 : {
|
||||
value = kvp_value_new_gint64(*(gint64*)option->value);
|
||||
value = kvp_value_new_gint64(GPOINTER_TO_INT(option->value));
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_DOUBLE : {
|
||||
@@ -226,22 +221,16 @@ void qof_backend_prepare_option(QofBackend *be, QofBackendOption *option)
|
||||
if(value) {
|
||||
temp = g_strdup_printf("/%s", option->option_name);
|
||||
kvp_frame_set_value(be->backend_configuration, temp, value);
|
||||
PINFO (" setting value at %s", temp);
|
||||
g_free(temp);
|
||||
temp = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, option->option_name);
|
||||
PINFO (" setting description %s at %s", option->description, temp);
|
||||
kvp_frame_set_string(be->backend_configuration, temp, option->description);
|
||||
PINFO (" check= %s", kvp_frame_get_string(be->backend_configuration, temp));
|
||||
g_free(temp);
|
||||
temp = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, option->option_name);
|
||||
PINFO (" setting tooltip %s at %s", option->tooltip, temp);
|
||||
kvp_frame_set_string(be->backend_configuration, temp, option->tooltip);
|
||||
PINFO (" check= %s", kvp_frame_get_string(be->backend_configuration, temp));
|
||||
g_free(temp);
|
||||
/* only increment the counter if successful */
|
||||
be->config_count = count;
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
KvpFrame* qof_backend_complete_frame(QofBackend *be)
|
||||
@@ -397,7 +386,6 @@ gboolean
|
||||
qof_load_backend_library (const char *directory,
|
||||
const char* filename, const char* init_fcn)
|
||||
{
|
||||
struct stat sbuf;
|
||||
gchar *fullpath;
|
||||
typedef void (* backend_init) (void);
|
||||
GModule *backend;
|
||||
@@ -406,8 +394,6 @@ qof_load_backend_library (const char *directory,
|
||||
|
||||
g_return_val_if_fail(g_module_supported(), FALSE);
|
||||
fullpath = g_module_build_path(directory, filename);
|
||||
PINFO (" fullpath=%s", fullpath);
|
||||
g_return_val_if_fail((stat(fullpath, &sbuf) == 0), FALSE);
|
||||
backend = g_module_open(fullpath, G_MODULE_BIND_LAZY);
|
||||
if(!backend) {
|
||||
g_message ("%s: %s\n", PACKAGE, g_module_error ());
|
||||
|
@@ -43,68 +43,70 @@
|
||||
#include "qofid-p.h"
|
||||
#include "qofinstance-p.h"
|
||||
|
||||
/** Book structure */
|
||||
/* Book structure */
|
||||
struct _QofBook
|
||||
{
|
||||
QofInstance inst; /**< Unique guid for this book. */
|
||||
QofInstance inst; /* Unique guid for this book. */
|
||||
|
||||
/** The entity table associates the GUIDs of all the objects
|
||||
/* The entity table associates the GUIDs of all the objects
|
||||
* belonging to this book, with their pointers to the respective
|
||||
* objects. This allows a lookup of objects based on thier guid.
|
||||
*/
|
||||
GHashTable * hash_of_collections;
|
||||
|
||||
/** In order to store arbitrary data, for extensibility, add a table
|
||||
/* In order to store arbitrary data, for extensibility, add a table
|
||||
* that will be used to hold arbitrary pointers.
|
||||
*/
|
||||
GHashTable *data_tables;
|
||||
|
||||
/** Hash table of destroy callbacks for the data table. */
|
||||
/* Hash table of destroy callbacks for the data table. */
|
||||
GHashTable *data_table_finalizers;
|
||||
|
||||
/** state flag: 'y' means 'open for editing',
|
||||
* 'n' means 'book is closed'
|
||||
* xxxxx shouldn't this be replaced by the instance editlevel ???
|
||||
/* state flag: 'y' means 'open for editing',
|
||||
* 'n' means 'book is closed'
|
||||
* xxxxx shouldn't this be replaced by the instance editlevel ???
|
||||
*/
|
||||
char book_open;
|
||||
|
||||
/** a flag denoting whether the book is closing down, used to
|
||||
/* a flag denoting whether the book is closing down, used to
|
||||
* help the QOF objects shut down cleanly without maintaining
|
||||
* internal consistency.
|
||||
* XXX shouldn't this be replaced by instance->do_free ???
|
||||
* XXX shouldn't this be replaced by instance->do_free ???
|
||||
*/
|
||||
gboolean shutting_down;
|
||||
|
||||
/** version number, used for tracking multiuser updates */
|
||||
|
||||
/* version number, used for tracking multiuser updates */
|
||||
gint32 version;
|
||||
|
||||
/** To be technically correct, backends belong to sessions and
|
||||
* not books. So the pointer below "really shouldn't be here",
|
||||
* except that it provides a nice convenience, avoiding a lookup
|
||||
* from the session. Better solutions welcome ... */
|
||||
/* To be technically correct, backends belong to sessions and
|
||||
* not books. So the pointer below "really shouldn't be here",
|
||||
* except that it provides a nice convenience, avoiding a lookup
|
||||
* from the session. Better solutions welcome ... */
|
||||
QofBackend *backend;
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/** Backend private expansion data */
|
||||
guint32 idata; /**< used by the sql backend for kvp management */
|
||||
/* Backend private expansion data */
|
||||
guint32 idata; /* used by the sql backend for kvp management */
|
||||
};
|
||||
|
||||
/**
|
||||
* These qof_book_set_*() routines are used by backends to
|
||||
* initialize the pointers in the book structure to
|
||||
* something that contains actual data. These routines
|
||||
/*
|
||||
* qof_book_set_backend() is used by backends to
|
||||
* initialize the pointers in the book structure to
|
||||
* something that contains actual data. These routines
|
||||
* should not be used otherwise. (Its somewhat questionable
|
||||
* if the backends should even be doing this much, but for
|
||||
* backwards compatibility, we leave these here.)
|
||||
*/
|
||||
void qof_book_set_schedxactions( QofBook *book, GList *newList );
|
||||
|
||||
void qof_book_set_backend (QofBook *book, QofBackend *be);
|
||||
|
||||
/** Register books with the engine */
|
||||
/** \deprecated */
|
||||
void qof_book_set_schedxactions( QofBook *book, GList *newList );
|
||||
|
||||
/* Register books with the engine */
|
||||
gboolean qof_book_register (void);
|
||||
|
||||
/** @deprecated */
|
||||
/** @deprecated use qof_entity_set_guid instead but only in
|
||||
backends (when reading the GUID from the data source). */
|
||||
#define qof_book_set_guid(book,guid) \
|
||||
qof_entity_set_guid(QOF_ENTITY(book), guid)
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************\
|
||||
* qofbook.c -- dataset access (set of accounting books) *
|
||||
* qofbook.c -- dataset access (set of books of entities) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
@@ -24,8 +24,7 @@
|
||||
* qofbook.c
|
||||
*
|
||||
* FUNCTION:
|
||||
* Encapsulate all the information about a gnucash dataset.
|
||||
* See src/doc/books.txt for design overview.
|
||||
* Encapsulate all the information about a QOF dataset.
|
||||
*
|
||||
* HISTORY:
|
||||
* Created by Linas Vepstas December 1998
|
||||
@@ -40,18 +39,12 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "gnc-event.h"
|
||||
#include "qof.h"
|
||||
#include "gnc-event-p.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "qofbackend-p.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofbook-p.h"
|
||||
#include "qofclass.h"
|
||||
#include "qofid-p.h"
|
||||
#include "qofobject-p.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#include "guid.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_ENGINE;
|
||||
|
||||
@@ -117,7 +110,7 @@ qof_book_destroy (QofBook *book)
|
||||
book->shutting_down = TRUE;
|
||||
gnc_engine_force_event (&book->inst.entity, GNC_EVENT_DESTROY);
|
||||
|
||||
/* Call the list of finalizers, let them do their thing.
|
||||
/* Call the list of finalizers, let them do their thing.
|
||||
* Do this before tearing into the rest of the book.
|
||||
*/
|
||||
g_hash_table_foreach (book->data_table_finalizers, book_final, book);
|
||||
@@ -290,32 +283,32 @@ void qof_book_mark_closed (QofBook *book)
|
||||
|
||||
gchar qof_book_get_open_marker(QofBook *book)
|
||||
{
|
||||
if(!book) { return 'n'; }
|
||||
return book->book_open;
|
||||
if(!book) { return 'n'; }
|
||||
return book->book_open;
|
||||
}
|
||||
|
||||
gint32 qof_book_get_version (QofBook *book)
|
||||
{
|
||||
if(!book) { return -1; }
|
||||
return book->version;
|
||||
if(!book) { return -1; }
|
||||
return book->version;
|
||||
}
|
||||
|
||||
guint32 qof_book_get_idata (QofBook *book)
|
||||
{
|
||||
if(!book) { return 0; }
|
||||
return book->idata;
|
||||
if(!book) { return 0; }
|
||||
return book->idata;
|
||||
}
|
||||
|
||||
void qof_book_set_version (QofBook *book, gint32 version)
|
||||
{
|
||||
if(!book && version < 0) { return; }
|
||||
book->version = version;
|
||||
if(!book && version < 0) { return; }
|
||||
book->version = version;
|
||||
}
|
||||
|
||||
void qof_book_set_idata(QofBook *book, guint32 idata)
|
||||
{
|
||||
if(!book && idata < 0) { return; }
|
||||
book->idata = idata;
|
||||
if(!book && idata < 0) { return; }
|
||||
book->idata = idata;
|
||||
}
|
||||
|
||||
gint64
|
||||
|
@@ -21,13 +21,13 @@
|
||||
/** @addtogroup Object
|
||||
@{ */
|
||||
/** @addtogroup Book
|
||||
A QOF Book is a dataset. It provides a single handle
|
||||
A QOF Book is a dataset. It provides a single handle
|
||||
through which all the various collections of entities
|
||||
can be found. In particular, given only the type of
|
||||
the entity, the collection can be found.
|
||||
|
||||
|
||||
Books also provide the 'natural' place to working with
|
||||
a storage backend, as a book can encapsulate everything
|
||||
a storage backend, as a book can encapsulate everything
|
||||
held in storage.
|
||||
@{ */
|
||||
/** @file qofbook.h
|
||||
@@ -45,7 +45,7 @@
|
||||
#include "kvp_frame.h"
|
||||
|
||||
/** @brief Encapsulates all the information about a dataset
|
||||
* manipulated by GnuCash. This is the top-most structure
|
||||
* manipulated by QOF. This is the top-most structure
|
||||
* used for anchoring data.
|
||||
*/
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
/** \brief QofBook reference */
|
||||
typedef struct _QofBook QofBook;
|
||||
|
||||
|
||||
/** GList of QofBook */
|
||||
typedef GList QofBookList;
|
||||
|
||||
@@ -70,12 +70,12 @@ typedef void (*QofBookFinalCB) (QofBook *, gpointer key, gpointer user_data);
|
||||
|
||||
/** Register the book object with the QOF object system. */
|
||||
gboolean qof_book_register (void);
|
||||
|
||||
|
||||
/** Allocate, initialise and return a new QofBook. Books contain references
|
||||
* to all of the top-level object containers. */
|
||||
QofBook * qof_book_new (void);
|
||||
|
||||
/** End any editing sessions associated with book, and free all memory
|
||||
/** End any editing sessions associated with book, and free all memory
|
||||
associated with it. */
|
||||
void qof_book_destroy (QofBook *book);
|
||||
|
||||
@@ -86,17 +86,17 @@ and once marked closed, books cannnot be marked as open.
|
||||
*/
|
||||
void qof_book_mark_closed (QofBook *book);
|
||||
|
||||
/** \return The table of entities of the given type.
|
||||
/** Return The table of entities of the given type.
|
||||
*
|
||||
* When an object's constructor calls qof_instance_init(), a
|
||||
* reference to the object is stored in the book. The book stores
|
||||
* all the references to initialized instances, sorted by type. This
|
||||
* function returns a collection of the references for the specified
|
||||
* type.
|
||||
*
|
||||
*
|
||||
* If the collection doesn't yet exist for the indicated type,
|
||||
* it is created. Thus, this routine is gaurenteed to return
|
||||
* a non-NULL value. (Unless the system malloc failed (out of
|
||||
* a non-NULL value. (Unless the system malloc failed (out of
|
||||
* memory) in which case what happens??).
|
||||
*/
|
||||
QofCollection * qof_book_get_collection (QofBook *, QofIdType);
|
||||
@@ -105,32 +105,32 @@ QofCollection * qof_book_get_collection (QofBook *, QofIdType);
|
||||
typedef void (*QofCollectionForeachCB) (QofCollection *, gpointer user_data);
|
||||
void qof_book_foreach_collection (QofBook *, QofCollectionForeachCB, gpointer);
|
||||
|
||||
/** \return The kvp data for the book.
|
||||
* Note that the book KVP data is persistant, and is stored/retrieved
|
||||
/** Return The kvp data for the book.
|
||||
* Note that the book KVP data is persistent, and is stored/retrieved
|
||||
* from the file/database. Thus, the book KVP is the correct place to
|
||||
* store data that needs to be persistant accross sessions (or shared
|
||||
* store data that needs to be persistent accross sessions (or shared
|
||||
* between multiple users). To store application runtime data, use
|
||||
* qof_book_set_data() instead.
|
||||
*/
|
||||
#define qof_book_get_slots(book) qof_instance_get_slots(QOF_INSTANCE(book))
|
||||
|
||||
/** The qof_book_set_data() allows arbitrary pointers to structs
|
||||
* to be stored in QofBook. This is the "prefered" method for
|
||||
/** The qof_book_set_data() allows arbitrary pointers to structs
|
||||
* to be stored in QofBook. This is the "preferred" method for
|
||||
* extending QofBook to hold new data types. This is also
|
||||
* the ideal location to store other arbitrary runtime data
|
||||
* the ideal location to store other arbitrary runtime data
|
||||
* that the application may need.
|
||||
*
|
||||
* The book data differs from the book KVP in that the contents
|
||||
* of the book KVP are persistant (are saved and restored to file
|
||||
* of the book KVP are persistent (are saved and restored to file
|
||||
* or database), whereas the data pointers exist only at runtime.
|
||||
*/
|
||||
void qof_book_set_data (QofBook *book, const char *key, gpointer data);
|
||||
|
||||
/** Same as qof_book_set_data(), except that the callback will be called
|
||||
* when the book is destroyed. The argument to the callback will be
|
||||
* when the book is destroyed. The argument to the callback will be
|
||||
* the book followed by the data pointer.
|
||||
*/
|
||||
void qof_book_set_data_fin (QofBook *book, const char *key, gpointer data,
|
||||
void qof_book_set_data_fin (QofBook *book, const char *key, gpointer data,
|
||||
QofBookFinalCB);
|
||||
|
||||
/** Retrieves arbitrary pointers to structs stored by qof_book_set_data. */
|
||||
@@ -139,20 +139,20 @@ gpointer qof_book_get_data (QofBook *book, const char *key);
|
||||
/** Is the book shutting down? */
|
||||
gboolean qof_book_shutting_down (QofBook *book);
|
||||
|
||||
/** qof_book_not_saved() will return TRUE if any
|
||||
/** qof_book_not_saved() will return TRUE if any
|
||||
* data in the book hasn't been saved to long-term storage.
|
||||
* (Actually, that's not quite true. The book doesn't know
|
||||
* (Actually, that's not quite true. The book doesn't know
|
||||
* anything about saving. Its just that whenever data is modified,
|
||||
* the 'dirty' flag is set. This routine returns the value of the
|
||||
* 'dirty' flag. Its up to the backend to periodically reset this
|
||||
* the 'dirty' flag is set. This routine returns the value of the
|
||||
* 'dirty' flag. Its up to the backend to periodically reset this
|
||||
* flag, when it actually does save the data.)
|
||||
*/
|
||||
gboolean qof_book_not_saved (QofBook *book);
|
||||
|
||||
/** The qof_book_mark_saved() routine marks the book as having been
|
||||
* saved (to a file, to a database). Used by backends to mark the
|
||||
* notsaved flag as FALSE just after loading. Also used by the
|
||||
* main window code when the used has said to abandon any changes.
|
||||
* notsaved flag as FALSE just after loading. Can also be used
|
||||
* by the frontend when the used has said to abandon any changes.
|
||||
*/
|
||||
void qof_book_mark_saved(QofBook *book);
|
||||
|
||||
@@ -160,7 +160,7 @@ void qof_book_mark_saved(QofBook *book);
|
||||
* is marked 'dirty'. */
|
||||
void qof_book_kvp_changed (QofBook *book);
|
||||
|
||||
/** The qof_book_equal() method returns TRUE if books are equal.
|
||||
/** The qof_book_equal() method returns TRUE if books are equal.
|
||||
* XXX this routine is broken, and does not currently compare data.
|
||||
*/
|
||||
gboolean qof_book_equal (QofBook *book_1, QofBook *book_2);
|
||||
|
@@ -18,8 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
@@ -18,8 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _QOFCHOICE_H
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************\
|
||||
* qofclass-p.h -- Private API for registering queriable objects *
|
||||
* qofclass-p.h -- Private API for registering queryable objects *
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
@@ -23,7 +23,6 @@
|
||||
/** @addtogroup Object
|
||||
@{ */
|
||||
/** @addtogroup Object_Private
|
||||
Private interfaces, not meant to be used by applications.
|
||||
@{ */
|
||||
/** @name Class_Private
|
||||
@{ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************\
|
||||
* qofclass.c -- provide QOF paramterized data objects *
|
||||
* qofclass.c -- provide QOF parameterized data objects *
|
||||
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
@@ -25,11 +25,8 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "qofclass.h"
|
||||
#include "qof.h"
|
||||
#include "qofclass-p.h"
|
||||
#include "qofquery.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_CLASS;
|
||||
|
||||
@@ -43,47 +40,18 @@ static gboolean clear_table (gpointer key, gpointer value, gpointer user_data)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* PUBLISHED API FUNCTIONS */
|
||||
/* *******************************************************************/
|
||||
/* PRIVATE FUNCTIONS */
|
||||
|
||||
void
|
||||
qof_class_register (QofIdTypeConst obj_name,
|
||||
QofSortFunc default_sort_function,
|
||||
const QofParam *params)
|
||||
static gboolean check_init (void)
|
||||
{
|
||||
GHashTable *ht;
|
||||
int i;
|
||||
if (initialized) return TRUE;
|
||||
|
||||
if (!obj_name) return;
|
||||
|
||||
if (default_sort_function)
|
||||
{
|
||||
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
|
||||
}
|
||||
|
||||
ht = g_hash_table_lookup (classTable, obj_name);
|
||||
|
||||
/* If it doesn't already exist, create a new table for this object */
|
||||
if (!ht)
|
||||
{
|
||||
ht = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (classTable, (char *)obj_name, ht);
|
||||
}
|
||||
|
||||
/* At least right now, we allow dummy, parameterless objects,
|
||||
* for testing purposes. Although I suppose that should be
|
||||
* an error.. */
|
||||
/* Now insert all the parameters */
|
||||
if (params)
|
||||
{
|
||||
for (i = 0; params[i].param_name; i++)
|
||||
g_hash_table_insert (ht,
|
||||
(char *)params[i].param_name,
|
||||
(gpointer)&(params[i]));
|
||||
}
|
||||
PERR("You must call qof_class_init() before using qof_class.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
qof_class_init(void)
|
||||
{
|
||||
if (initialized) return;
|
||||
@@ -93,7 +61,7 @@ qof_class_init(void)
|
||||
sortTable = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
qof_class_shutdown (void)
|
||||
{
|
||||
if (!initialized) return;
|
||||
@@ -104,17 +72,66 @@ qof_class_shutdown (void)
|
||||
g_hash_table_destroy (sortTable);
|
||||
}
|
||||
|
||||
QofSortFunc
|
||||
qof_class_get_default_sort (QofIdTypeConst obj_name)
|
||||
{
|
||||
if (!obj_name) return NULL;
|
||||
return g_hash_table_lookup (sortTable, obj_name);
|
||||
}
|
||||
|
||||
/* *******************************************************************/
|
||||
/* PUBLISHED API FUNCTIONS */
|
||||
|
||||
void
|
||||
qof_class_register (QofIdTypeConst obj_name,
|
||||
QofSortFunc default_sort_function,
|
||||
const QofParam *params)
|
||||
{
|
||||
GHashTable *ht;
|
||||
int i;
|
||||
|
||||
if (!obj_name) return;
|
||||
if (!check_init()) return;
|
||||
|
||||
if (default_sort_function)
|
||||
{
|
||||
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
|
||||
}
|
||||
|
||||
ht = g_hash_table_lookup (classTable, obj_name);
|
||||
|
||||
/* If it doesn't already exist, create a new table for this object */
|
||||
if (!ht)
|
||||
{
|
||||
ht = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (classTable, (char *)obj_name, ht);
|
||||
}
|
||||
|
||||
/* At least right now, we allow dummy, parameterless objects,
|
||||
* for testing purposes. Although I suppose that should be
|
||||
* an error.. */
|
||||
/* Now insert all the parameters */
|
||||
if (params)
|
||||
{
|
||||
for (i = 0; params[i].param_name; i++)
|
||||
g_hash_table_insert (ht,
|
||||
(char *)params[i].param_name,
|
||||
(gpointer)&(params[i]));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
qof_class_is_registered (QofIdTypeConst obj_name)
|
||||
{
|
||||
if (!obj_name) return FALSE;
|
||||
if (!check_init()) return FALSE;
|
||||
|
||||
if (g_hash_table_lookup (classTable, obj_name)) return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const QofParam *
|
||||
const QofParam *
|
||||
qof_class_get_parameter (QofIdTypeConst obj_name,
|
||||
const char *parameter)
|
||||
{
|
||||
@@ -122,6 +139,7 @@ qof_class_get_parameter (QofIdTypeConst obj_name,
|
||||
|
||||
g_return_val_if_fail (obj_name, NULL);
|
||||
g_return_val_if_fail (parameter, NULL);
|
||||
if (!check_init()) return NULL;
|
||||
|
||||
ht = g_hash_table_lookup (classTable, obj_name);
|
||||
if (!ht)
|
||||
@@ -133,7 +151,7 @@ qof_class_get_parameter (QofIdTypeConst obj_name,
|
||||
return (g_hash_table_lookup (ht, parameter));
|
||||
}
|
||||
|
||||
QofAccessFunc
|
||||
QofAccessFunc
|
||||
qof_class_get_parameter_getter (QofIdTypeConst obj_name,
|
||||
const char *parameter)
|
||||
{
|
||||
@@ -149,7 +167,7 @@ qof_class_get_parameter_getter (QofIdTypeConst obj_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QofSetterFunc
|
||||
QofSetterFunc
|
||||
qof_class_get_parameter_setter (QofIdTypeConst obj_name,
|
||||
const char *parameter)
|
||||
{
|
||||
@@ -165,7 +183,7 @@ qof_class_get_parameter_setter (QofIdTypeConst obj_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QofType
|
||||
QofType
|
||||
qof_class_get_parameter_type (QofIdTypeConst obj_name,
|
||||
const char *param_name)
|
||||
{
|
||||
@@ -179,13 +197,6 @@ qof_class_get_parameter_type (QofIdTypeConst obj_name,
|
||||
return (prm->param_type);
|
||||
}
|
||||
|
||||
QofSortFunc
|
||||
qof_class_get_default_sort (QofIdTypeConst obj_name)
|
||||
{
|
||||
if (!obj_name) return NULL;
|
||||
return g_hash_table_lookup (sortTable, obj_name);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
struct class_iterate {
|
||||
@@ -193,12 +204,12 @@ struct class_iterate {
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static void
|
||||
static void
|
||||
class_foreach_cb (gpointer key, gpointer item, gpointer arg)
|
||||
{
|
||||
struct class_iterate *iter = arg;
|
||||
QofIdTypeConst id = key;
|
||||
|
||||
|
||||
iter->fcn (id, iter->data);
|
||||
}
|
||||
|
||||
@@ -223,7 +234,7 @@ struct parm_iterate {
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static void
|
||||
static void
|
||||
param_foreach_cb (gpointer key, gpointer item, gpointer arg)
|
||||
{
|
||||
struct parm_iterate *iter = arg;
|
||||
@@ -262,18 +273,18 @@ find_reference_param_cb(QofParam *param, gpointer user_data)
|
||||
|
||||
b = (struct param_ref_list*)user_data;
|
||||
if((param->param_getfcn == NULL)||(param->param_setfcn == NULL)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_STRING)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_NUMERIC)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DATE)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_CHAR)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DEBCRED)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_GUID)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT32)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT64)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DOUBLE)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_KVP)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_ID_BOOK)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_STRING)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_NUMERIC)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DATE)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_CHAR)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DEBCRED)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_GUID)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT32)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT64)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DOUBLE)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_KVP)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN)) { return; }
|
||||
if(0 == safe_strcmp(param->param_type, QOF_ID_BOOK)) { return; }
|
||||
b->list = g_list_append(b->list, param);
|
||||
}
|
||||
|
||||
|
@@ -121,7 +121,7 @@ qof_gobject_getter (gpointer data, QofParam *getter)
|
||||
else
|
||||
if (G_IS_PARAM_SPEC_INT(gps))
|
||||
{
|
||||
int ival;
|
||||
long ival;
|
||||
|
||||
GValue gval = {G_TYPE_INVALID};
|
||||
g_value_init (&gval, G_TYPE_INT);
|
||||
@@ -133,7 +133,7 @@ qof_gobject_getter (gpointer data, QofParam *getter)
|
||||
else
|
||||
if (G_IS_PARAM_SPEC_UINT(gps))
|
||||
{
|
||||
int ival;
|
||||
long ival;
|
||||
GValue gval = {G_TYPE_INVALID};
|
||||
g_value_init (&gval, G_TYPE_UINT);
|
||||
g_object_get_property (gob, getter->param_name, &gval);
|
||||
@@ -144,14 +144,14 @@ qof_gobject_getter (gpointer data, QofParam *getter)
|
||||
else
|
||||
if (G_IS_PARAM_SPEC_BOOLEAN(gps))
|
||||
{
|
||||
int ival;
|
||||
gboolean ival;
|
||||
|
||||
GValue gval = {G_TYPE_INVALID};
|
||||
g_value_init (&gval, G_TYPE_BOOLEAN);
|
||||
g_object_get_property (gob, getter->param_name, &gval);
|
||||
|
||||
ival = g_value_get_boolean (&gval);
|
||||
return (gpointer) ival;
|
||||
return GINT_TO_POINTER( ival);
|
||||
}
|
||||
|
||||
PWARN ("unhandled parameter type %s for paramter %s",
|
||||
@@ -164,7 +164,7 @@ qof_gobject_double_getter (gpointer data, QofParam *getter)
|
||||
{
|
||||
GObject *gob = data;
|
||||
double fval;
|
||||
|
||||
|
||||
GParamSpec *gps = getter->param_userdata;
|
||||
|
||||
/* Note that the return type must actually be of type
|
||||
|
@@ -84,4 +84,3 @@ void qof_gobject_register_instance (QofBook *book, QofType, GObject *);
|
||||
#endif /* QOF_GOBJ_H */
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
|
@@ -23,7 +23,6 @@
|
||||
/** @addtogroup Object
|
||||
@{ */
|
||||
/** @addtogroup Object_Private
|
||||
Private interfaces, not meant to be used by applications.
|
||||
@{ */
|
||||
/** @name Entity_Private
|
||||
@{ */
|
||||
@@ -35,10 +34,10 @@
|
||||
|
||||
#include "qofid.h"
|
||||
|
||||
/* This file defines an engine-only API for using gnucash entity
|
||||
/* This file defines an engine-only API for using QOF entity
|
||||
* identifiers. */
|
||||
|
||||
/** Set the ID of the entity, over-riding teh previous ID.
|
||||
/** Set the ID of the entity, over-riding the previous ID.
|
||||
* Very dangerous, use only for file i/o work.
|
||||
*/
|
||||
void qof_entity_set_guid (QofEntity *ent, const GUID *guid);
|
||||
|
@@ -27,10 +27,8 @@
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "qofid.h"
|
||||
#include "qof.h"
|
||||
#include "qofid-p.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_ENGINE;
|
||||
|
||||
@@ -53,11 +51,11 @@ qof_entity_init (QofEntity *ent, QofIdType type, QofCollection * tab)
|
||||
g_return_if_fail (NULL != tab);
|
||||
|
||||
/* XXX We passed redundant info to this routine ... but I think that's
|
||||
* OK, it might eliminate programming errors. */
|
||||
* OK, it might eliminate programming errors. */
|
||||
if (safe_strcmp(tab->e_type, type))
|
||||
{
|
||||
PERR ("attempt to insert \"%s\" into \"%s\"", type, tab->e_type);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
ent->e_type = CACHE_INSERT (type);
|
||||
|
||||
@@ -289,7 +287,7 @@ qof_collection_lookup_entity (QofCollection *col, const GUID * guid)
|
||||
QofEntity *ent;
|
||||
g_return_val_if_fail (col, NULL);
|
||||
if (guid == NULL) return NULL;
|
||||
ent = g_hash_table_lookup (col->hash_of_entities, guid->data);
|
||||
ent = g_hash_table_lookup (col->hash_of_entities, guid);
|
||||
return ent;
|
||||
}
|
||||
|
||||
@@ -326,22 +324,19 @@ qof_collection_count (QofCollection *col)
|
||||
gboolean
|
||||
qof_collection_is_dirty (QofCollection *col)
|
||||
{
|
||||
if (!col) return FALSE;
|
||||
return col->is_dirty;
|
||||
return col ? col->is_dirty : FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
qof_collection_mark_clean (QofCollection *col)
|
||||
{
|
||||
if (!col) return;
|
||||
col->is_dirty = FALSE;
|
||||
if (col) { col->is_dirty = FALSE; }
|
||||
}
|
||||
|
||||
void
|
||||
qof_collection_mark_dirty (QofCollection *col)
|
||||
{
|
||||
if (!col) return;
|
||||
col->is_dirty = TRUE;
|
||||
if (col) { col->is_dirty = TRUE; }
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
@@ -349,15 +344,13 @@ qof_collection_mark_dirty (QofCollection *col)
|
||||
gpointer
|
||||
qof_collection_get_data (QofCollection *col)
|
||||
{
|
||||
if (!col) return NULL;
|
||||
return col->data;
|
||||
return col ? col->data : NULL;
|
||||
}
|
||||
|
||||
void
|
||||
qof_collection_set_data (QofCollection *col, gpointer user_data)
|
||||
{
|
||||
if (!col) return;
|
||||
col->data = user_data;
|
||||
if (col) { col->data = user_data; }
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
@@ -376,8 +369,8 @@ static void foreach_cb (gpointer key, gpointer item, gpointer arg)
|
||||
}
|
||||
|
||||
void
|
||||
qof_collection_foreach (QofCollection *col,
|
||||
QofEntityForeachCB cb_func, gpointer user_data)
|
||||
qof_collection_foreach (QofCollection *col, QofEntityForeachCB cb_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct _iterate iter;
|
||||
|
||||
|
@@ -46,13 +46,18 @@
|
||||
Identifiers can be encoded as hex strings.
|
||||
|
||||
GUID Identifiers are 'typed' with strings. The native ids used
|
||||
by QOF are defined below. An id with type QOF_ID_NONE does not
|
||||
refer to any entity, although that may change (???). An id with
|
||||
type QOF_ID_NULL does not refer to any entity, and will never refer
|
||||
to any entity. An identifier with any other type may refer to an
|
||||
actual entity, but that is not guaranteed (??? Huh?). If an id
|
||||
does refer to an entity, the type of the entity will match the
|
||||
type of the identifier.
|
||||
by QOF are defined below.
|
||||
-# An id with type QOF_ID_NONE does not
|
||||
refer to any entity.
|
||||
-# An id with type QOF_ID_NULL does not refer
|
||||
to any entity, and will never refer to any entity.
|
||||
=# An identifier with any other type may refer to an
|
||||
actual entity, but that is not guaranteed as that entity does
|
||||
not have to exist within the current book. (See ::PARTIAL_QOFBOOK).
|
||||
Also, creating a new entity from a data source involves creating
|
||||
a temporary GUID and then setting the value from the data source.
|
||||
If an id does refer to an entity, the type of the entity will match
|
||||
the type of the identifier.
|
||||
|
||||
If you have a type name, and you want to have a way of finding
|
||||
a collection that is associated with that type, then you must use
|
||||
@@ -105,9 +110,11 @@ typedef const gchar* QofLogModule;
|
||||
})
|
||||
|
||||
/** return TRUE if object is of the given type */
|
||||
#define QOF_CHECK_TYPE(obj,type) (0 == QSTRCMP((type),(((QofEntity *)(obj))->e_type)))
|
||||
#define QOF_CHECK_TYPE(obj,type) (((obj) != NULL) && \
|
||||
(0 == QSTRCMP((type),(((QofEntity *)(obj))->e_type))))
|
||||
|
||||
/** cast object to the indicated type, print error message if its bad */
|
||||
/** cast object to the indicated type,
|
||||
print error message if its bad */
|
||||
#define QOF_CHECK_CAST(obj,e_type,c_type) ( \
|
||||
QOF_CHECK_TYPE((obj),(e_type)) ? \
|
||||
(c_type *) (obj) : \
|
||||
@@ -138,7 +145,7 @@ typedef struct QofCollection_s QofCollection;
|
||||
|
||||
struct QofEntity_s
|
||||
{
|
||||
QofIdType e_type;
|
||||
QofIdType e_type;
|
||||
GUID guid;
|
||||
QofCollection * collection;
|
||||
};
|
||||
@@ -178,8 +185,8 @@ QofEntity * qof_collection_lookup_entity (QofCollection *, const GUID *);
|
||||
typedef void (*QofEntityForeachCB) (QofEntity *, gpointer user_data);
|
||||
|
||||
/** Call the callback for each entity in the collection. */
|
||||
void qof_collection_foreach (QofCollection *,
|
||||
QofEntityForeachCB, gpointer user_data);
|
||||
void qof_collection_foreach (QofCollection *, QofEntityForeachCB,
|
||||
gpointer user_data);
|
||||
|
||||
/** Store and retreive arbitrary object-defined data
|
||||
*
|
||||
|
@@ -26,20 +26,12 @@
|
||||
* Copyright (C) 2003 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
/** @addtogroup Object
|
||||
@{ */
|
||||
/** @addtogroup Object_Private
|
||||
Private interfaces, not meant to be used by applications.
|
||||
@{ */
|
||||
/** @name Instance_Private
|
||||
@{ */
|
||||
|
||||
#ifndef QOF_INSTANCE_P_H
|
||||
#define QOF_INSTANCE_P_H
|
||||
|
||||
#include "qofinstance.h"
|
||||
|
||||
/**
|
||||
/*
|
||||
* UNDER CONSTRUCTION!
|
||||
* This is mostly scaffolding for now,
|
||||
* eventually, it may hold more fields, such as refrence counting...
|
||||
@@ -47,19 +39,19 @@
|
||||
*/
|
||||
struct QofInstance_s
|
||||
{
|
||||
/** Globally unique id identifying this instance */
|
||||
/* Globally unique id identifying this instance */
|
||||
QofEntity entity;
|
||||
|
||||
/** The entity_table in which this instance is stored */
|
||||
/* The entity_table in which this instance is stored */
|
||||
QofBook * book;
|
||||
|
||||
/** kvp_data is a key-value pair database for storing arbirtary
|
||||
/* kvp_data is a key-value pair database for storing arbirtary
|
||||
* information associated with this instance.
|
||||
* See src/engine/kvp_doc.txt for a list and description of the
|
||||
* important keys. */
|
||||
KvpFrame *kvp_data;
|
||||
|
||||
/** Timestamp used to track the last modification to this
|
||||
/* Timestamp used to track the last modification to this
|
||||
* instance. Typically used to compare two versions of the
|
||||
* same object, to see which is newer. When used with the
|
||||
* SQL backend, this field is reserved for SQL use, to compare
|
||||
@@ -67,31 +59,27 @@ struct QofInstance_s
|
||||
*/
|
||||
Timespec last_update;
|
||||
|
||||
/** Keep track of nesting level of begin/end edit calls */
|
||||
/* Keep track of nesting level of begin/end edit calls */
|
||||
int editlevel;
|
||||
|
||||
/** In process of being destroyed */
|
||||
/* In process of being destroyed */
|
||||
gboolean do_free;
|
||||
|
||||
/** dirty/clean flag. If dirty, then this instance has been modified,
|
||||
* but has not yet been written out to storage (file/database)
|
||||
/* dirty/clean flag. If dirty, then this instance has been modified,
|
||||
* but has not yet been written out to storage (file/database)
|
||||
*/
|
||||
gboolean dirty;
|
||||
};
|
||||
|
||||
/** reset the dirty flag */
|
||||
/* reset the dirty flag */
|
||||
void qof_instance_mark_clean (QofInstance *);
|
||||
|
||||
void qof_instance_set_slots (QofInstance *, KvpFrame *);
|
||||
|
||||
/** Set the last_update time. Reserved for use by the SQL backend;
|
||||
/* Set the last_update time. Reserved for use by the SQL backend;
|
||||
* used for comparing version in local memory to that in remote
|
||||
* server.
|
||||
*/
|
||||
void qof_instance_set_last_update (QofInstance *inst, Timespec ts);
|
||||
|
||||
/* @} */
|
||||
/* @} */
|
||||
/* @} */
|
||||
|
||||
#endif /* QOF_INSTANCE_P_H */
|
||||
|
@@ -23,18 +23,14 @@
|
||||
/*
|
||||
* Object instance holds many common fields that most
|
||||
* gnucash objects use.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2003 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
#include "gnc-trace.h"
|
||||
|
||||
#include "qof.h"
|
||||
#include "kvp-util-p.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofbook-p.h"
|
||||
#include "qofid.h"
|
||||
#include "qofid-p.h"
|
||||
#include "qofinstance.h"
|
||||
#include "qofinstance-p.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_ENGINE;
|
||||
@@ -51,7 +47,7 @@ qof_instance_create (QofIdType type, QofBook *book)
|
||||
return inst;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
qof_instance_init (QofInstance *inst, QofIdType type, QofBook *book)
|
||||
{
|
||||
QofCollection *col;
|
||||
@@ -68,7 +64,7 @@ qof_instance_init (QofInstance *inst, QofIdType type, QofBook *book)
|
||||
qof_entity_init (&inst->entity, type, col);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
qof_instance_release (QofInstance *inst)
|
||||
{
|
||||
kvp_frame_delete (inst->kvp_data);
|
||||
@@ -85,14 +81,14 @@ qof_instance_get_guid (QofInstance *inst)
|
||||
return &inst->entity.guid;
|
||||
}
|
||||
|
||||
QofBook *
|
||||
QofBook *
|
||||
qof_instance_get_book (QofInstance *inst)
|
||||
{
|
||||
if (!inst) return NULL;
|
||||
return inst->book;
|
||||
}
|
||||
|
||||
KvpFrame*
|
||||
KvpFrame*
|
||||
qof_instance_get_slots (QofInstance *inst)
|
||||
{
|
||||
if (!inst) return NULL;
|
||||
@@ -102,15 +98,15 @@ qof_instance_get_slots (QofInstance *inst)
|
||||
Timespec
|
||||
qof_instance_get_last_update (QofInstance *inst)
|
||||
{
|
||||
if (!inst)
|
||||
if (!inst)
|
||||
{
|
||||
Timespec ts = {0,-1};
|
||||
Timespec ts = {0,-1};
|
||||
return ts;
|
||||
}
|
||||
return inst->last_update;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
qof_instance_version_cmp (QofInstance *left, QofInstance *right)
|
||||
{
|
||||
if (!left && !right) return 0;
|
||||
@@ -174,7 +170,7 @@ qof_instance_mark_clean (QofInstance *inst)
|
||||
inst->dirty = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
qof_instance_set_slots (QofInstance *inst, KvpFrame *frm)
|
||||
{
|
||||
if (!inst) return;
|
||||
|
363
lib/libqof/qof/qoflog.c
Normal file
363
lib/libqof/qof/qoflog.c
Normal file
@@ -0,0 +1,363 @@
|
||||
/* **************************************************************************
|
||||
* qoflog.c
|
||||
*
|
||||
* Mon Nov 21 14:41:59 2005
|
||||
* Author: Rob Clark (rclark@cs.hmc.edu) *
|
||||
* Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org>
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@codehelp.co.uk
|
||||
*************************************************************************** */
|
||||
/*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#warning unistd required.
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include "qof.h"
|
||||
#include "qoflog.h"
|
||||
|
||||
#define QOF_LOG_MAX_CHARS 50
|
||||
#define QOF_LOG_INDENT_WIDTH 4
|
||||
#define NUM_CLOCKS 10
|
||||
|
||||
static FILE *fout = NULL;
|
||||
static gchar* filename = NULL;
|
||||
static gchar* function_buffer = NULL;
|
||||
static const int MAX_TRACE_FILENAME = 100;
|
||||
static GHashTable *log_table = NULL;
|
||||
static gint qof_log_num_spaces = 0;
|
||||
|
||||
/* uses the enum_as_string macro.
|
||||
Lookups are done on the string. */
|
||||
AS_STRING_FUNC(QofLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
FROM_STRING_FUNC(QofLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
void
|
||||
qof_log_add_indent(void)
|
||||
{
|
||||
qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
|
||||
}
|
||||
|
||||
gint
|
||||
qof_log_get_indent(void)
|
||||
{
|
||||
return qof_log_num_spaces;
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_drop_indent(void)
|
||||
{
|
||||
qof_log_num_spaces -= QOF_LOG_INDENT_WIDTH;
|
||||
if(qof_log_num_spaces < 0)
|
||||
{
|
||||
qof_log_num_spaces = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fh_printer (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
FILE *fh = user_data;
|
||||
fprintf (fh, "%*s%s\n", qof_log_num_spaces, "", message);
|
||||
fflush(fh);
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_init (void)
|
||||
{
|
||||
if(!fout) /* allow qof_log_set_file */
|
||||
{
|
||||
fout = fopen ("/tmp/qof.trace", "w");
|
||||
}
|
||||
|
||||
if(!fout && (filename = (char *)g_malloc(MAX_TRACE_FILENAME))) {
|
||||
snprintf(filename, MAX_TRACE_FILENAME-1, "/tmp/qof.trace.%d",
|
||||
getpid());
|
||||
fout = fopen (filename, "w");
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
if(!fout)
|
||||
fout = stderr;
|
||||
|
||||
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, fh_printer, fout);
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_set_level(QofLogModule log_module, QofLogLevel level)
|
||||
{
|
||||
gchar* level_string;
|
||||
|
||||
if(!log_module || level == 0) { return; }
|
||||
level_string = g_strdup(QofLogLevelasString(level));
|
||||
if(!log_table)
|
||||
{
|
||||
log_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
}
|
||||
g_hash_table_insert(log_table, (gpointer)log_module, level_string);
|
||||
}
|
||||
|
||||
static void
|
||||
log_module_foreach(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
g_hash_table_insert(log_table, key, data);
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_set_level_global(QofLogLevel level)
|
||||
{
|
||||
gchar* level_string;
|
||||
|
||||
if(!log_table || level == 0) { return; }
|
||||
level_string = g_strdup(QofLogLevelasString(level));
|
||||
g_hash_table_foreach(log_table, log_module_foreach, level_string);
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_set_file (FILE *outfile)
|
||||
{
|
||||
if(!outfile) { fout = stderr; return; }
|
||||
fout = outfile;
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_init_filename (const gchar* logfilename)
|
||||
{
|
||||
if(!logfilename)
|
||||
{
|
||||
fout = stderr;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = g_strdup(logfilename);
|
||||
fout = fopen(filename, "w");
|
||||
}
|
||||
qof_log_init();
|
||||
}
|
||||
|
||||
void
|
||||
qof_log_shutdown (void)
|
||||
{
|
||||
if(fout && fout != stderr) { fclose(fout); }
|
||||
if(filename) { g_free(filename); }
|
||||
if(function_buffer) { g_free(function_buffer); }
|
||||
g_hash_table_destroy(log_table);
|
||||
}
|
||||
|
||||
const char *
|
||||
qof_log_prettify (const char *name)
|
||||
{
|
||||
char *p, *buffer;
|
||||
gint length;
|
||||
|
||||
if (!name) { return ""; }
|
||||
buffer = g_strndup(name, QOF_LOG_MAX_CHARS - 1);
|
||||
length = strlen(buffer);
|
||||
p = g_strstr_len(buffer, length, "(");
|
||||
if (p)
|
||||
{
|
||||
*(p+1) = ')';
|
||||
*(p+2) = 0x0;
|
||||
}
|
||||
else { strcpy (&buffer[QOF_LOG_MAX_CHARS - 4], "...()"); }
|
||||
function_buffer = g_strdup(buffer);
|
||||
g_free(buffer);
|
||||
return function_buffer;
|
||||
}
|
||||
|
||||
static
|
||||
struct timeval qof_clock[NUM_CLOCKS] = {
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
};
|
||||
|
||||
static
|
||||
struct timeval qof_clock_total[NUM_CLOCKS] = {
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
};
|
||||
|
||||
void
|
||||
qof_start_clock (int clockno, QofLogModule log_module, QofLogLevel log_level,
|
||||
const char *function_name, const char *format, ...)
|
||||
{
|
||||
struct timezone tz;
|
||||
va_list ap;
|
||||
|
||||
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
|
||||
gettimeofday (&qof_clock[clockno], &tz);
|
||||
|
||||
if (!fout) qof_log_init();
|
||||
|
||||
fprintf (fout, "Clock %d Start: %s: ",
|
||||
clockno, qof_log_prettify (function_name));
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
vfprintf (fout, format, ap);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
fprintf (fout, "\n");
|
||||
fflush (fout);
|
||||
}
|
||||
|
||||
void
|
||||
qof_report_clock (int clockno, QofLogModule log_module, QofLogLevel log_level,
|
||||
const char *function_name, const char *format, ...)
|
||||
{
|
||||
struct timezone tz;
|
||||
struct timeval now;
|
||||
va_list ap;
|
||||
|
||||
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
|
||||
gettimeofday (&now, &tz);
|
||||
|
||||
/* need to borrow to make difference */
|
||||
if (now.tv_usec < qof_clock[clockno].tv_usec)
|
||||
{
|
||||
now.tv_sec --;
|
||||
now.tv_usec += 1000000;
|
||||
}
|
||||
now.tv_sec -= qof_clock[clockno].tv_sec;
|
||||
now.tv_usec -= qof_clock[clockno].tv_usec;
|
||||
|
||||
qof_clock_total[clockno].tv_sec += now.tv_sec;
|
||||
qof_clock_total[clockno].tv_usec += now.tv_usec;
|
||||
|
||||
if (!fout) qof_log_init();
|
||||
|
||||
fprintf (fout, "Clock %d Elapsed: %ld.%06lds %s: ",
|
||||
clockno, (long int) now.tv_sec, (long int) now.tv_usec,
|
||||
qof_log_prettify (function_name));
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
vfprintf (fout, format, ap);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
fprintf (fout, "\n");
|
||||
fflush (fout);
|
||||
}
|
||||
|
||||
void
|
||||
qof_report_clock_total (int clockno,
|
||||
QofLogModule log_module, QofLogLevel log_level,
|
||||
const char *function_name, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
|
||||
|
||||
/* need to normalize usec */
|
||||
while (qof_clock_total[clockno].tv_usec >= 1000000)
|
||||
{
|
||||
qof_clock_total[clockno].tv_sec ++;
|
||||
qof_clock_total[clockno].tv_usec -= 1000000;
|
||||
}
|
||||
|
||||
if (!fout) qof_log_init();
|
||||
|
||||
fprintf (fout, "Clock %d Total Elapsed: %ld.%06lds %s: ",
|
||||
clockno,
|
||||
(long int) qof_clock_total[clockno].tv_sec,
|
||||
(long int) qof_clock_total[clockno].tv_usec,
|
||||
qof_log_prettify (function_name));
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
vfprintf (fout, format, ap);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
fprintf (fout, "\n");
|
||||
fflush (fout);
|
||||
}
|
||||
|
||||
gboolean
|
||||
qof_log_check(QofLogModule log_module, QofLogLevel log_level)
|
||||
{
|
||||
gchar* log_string;
|
||||
QofLogLevel maximum; /* Any log_level less than this will be logged. */
|
||||
|
||||
log_string = NULL;
|
||||
if(!log_table || log_module == NULL || log_level == 0) { return FALSE; }
|
||||
log_string = (gchar*)g_hash_table_lookup(log_table, log_module);
|
||||
/* if log_module not found, do not log. */
|
||||
if(!log_string) { return FALSE; }
|
||||
maximum = QofLogLevelfromString(log_string);
|
||||
if(log_level <= maximum) { return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void qof_log_set_default(QofLogLevel log_level)
|
||||
{
|
||||
qof_log_set_level(QOF_MOD_BACKEND, log_level);
|
||||
qof_log_set_level(QOF_MOD_CLASS, log_level);
|
||||
qof_log_set_level(QOF_MOD_ENGINE, log_level);
|
||||
qof_log_set_level(QOF_MOD_OBJECT, log_level);
|
||||
qof_log_set_level(QOF_MOD_KVP, log_level);
|
||||
qof_log_set_level(QOF_MOD_MERGE, log_level);
|
||||
qof_log_set_level(QOF_MOD_QUERY, log_level);
|
||||
qof_log_set_level(QOF_MOD_SESSION, log_level);
|
||||
}
|
||||
|
||||
struct hash_s
|
||||
{
|
||||
QofLogCB cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static void hash_cb (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
struct hash_s *iter;
|
||||
|
||||
iter = (struct hash_s*)data;
|
||||
if(!iter) { return; }
|
||||
(iter->cb)(key, value, iter->data);
|
||||
}
|
||||
|
||||
void qof_log_module_foreach(QofLogCB cb, gpointer data)
|
||||
{
|
||||
struct hash_s iter;
|
||||
|
||||
if(!cb) { return; }
|
||||
iter.cb = cb;
|
||||
iter.data = data;
|
||||
g_hash_table_foreach(log_table, hash_cb, (gpointer)&iter);
|
||||
}
|
||||
|
||||
gint qof_log_module_count(void)
|
||||
{
|
||||
if(!log_table) { return 0; }
|
||||
return g_hash_table_size(log_table);
|
||||
}
|
||||
|
||||
/* ************************ END OF FILE **************************** */
|
274
lib/libqof/qof/qoflog.h
Normal file
274
lib/libqof/qof/qoflog.h
Normal file
@@ -0,0 +1,274 @@
|
||||
/***************************************************************************
|
||||
* qof-log.h
|
||||
*
|
||||
* Mon Nov 21 14:35:26 2005
|
||||
* Author: Rob Clark (rclark@cs.hmc.edu) *
|
||||
* Copyright (C) 1998-2003 Linas Vepstas <linas@linas.org>
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@codehelp.co.uk
|
||||
****************************************************************************/
|
||||
/*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
/** @addtogroup Trace
|
||||
@{ */
|
||||
|
||||
/** @file qof-log.h
|
||||
* @brief QOF error logging and tracing facility
|
||||
*/
|
||||
|
||||
#ifndef _QOF_LOG_H
|
||||
#define _QOF_LOG_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#define QOF_MOD_ENGINE "qof-engine"
|
||||
|
||||
#define LOG_LEVEL_LIST(_) \
|
||||
_(QOF_LOG_FATAL, = 0) \
|
||||
_(QOF_LOG_ERROR, = 1) \
|
||||
_(QOF_LOG_WARNING, = 2) \
|
||||
_(QOF_LOG_INFO, = 3) \
|
||||
_(QOF_LOG_DEBUG, = 4) \
|
||||
_(QOF_LOG_DETAIL, = 5) \
|
||||
_(QOF_LOG_TRACE, = 6)
|
||||
|
||||
DEFINE_ENUM (QofLogLevel, LOG_LEVEL_LIST)
|
||||
|
||||
AS_STRING_DEC(QofLogLevel, LOG_LEVEL_LIST) /**< Convert QofLogLevel to a string.
|
||||
|
||||
The macro correlates the enum value and an
|
||||
exact copy as a string, removing the need to
|
||||
keep two separate lists in sync.
|
||||
*/
|
||||
|
||||
FROM_STRING_DEC(QofLogLevel, LOG_LEVEL_LIST) /**< Convert the
|
||||
log_string to a QofLogLevel
|
||||
|
||||
Only for use as a partner to ::QofLogLevelasString
|
||||
*/
|
||||
|
||||
/** indents once for each ENTER macro */
|
||||
void qof_log_add_indent(void);
|
||||
|
||||
/** gets the running total of the indent */
|
||||
gint qof_log_get_indent(void);
|
||||
|
||||
/** drops back one indent for each LEAVE macro
|
||||
|
||||
indent is reset to zero if less than a single indent would exist.
|
||||
*/
|
||||
void qof_log_drop_indent(void);
|
||||
|
||||
/** Initialize the error logging subsystem
|
||||
|
||||
\deprecated Applications need to call
|
||||
qof_log_set_file to set the output, otherwise
|
||||
the default of \a /tmp/qof.trace will be used.
|
||||
|
||||
Instead, use qof_log_init_filename
|
||||
which sets the filename and initialises the
|
||||
logging subsystem in one operation.
|
||||
*/
|
||||
void qof_log_init (void);
|
||||
|
||||
/** Set the logging level of the given log_module. */
|
||||
void qof_log_set_level(QofLogModule module, QofLogLevel level);
|
||||
|
||||
/** Set the logging level for all known log_modules.
|
||||
|
||||
\note Unless a log_module has been registered using
|
||||
qof_log_set_level, it will be unaffected by this change.
|
||||
|
||||
*/
|
||||
void qof_log_set_level_global(QofLogLevel level);
|
||||
|
||||
/** Specify an alternate log output, to pipe or file.
|
||||
By default, all logging goes to /tmp/qof.trace
|
||||
|
||||
Needs to be called \b before qof_log_init()
|
||||
\deprecated
|
||||
*/
|
||||
void qof_log_set_file (FILE *outfile);
|
||||
|
||||
/** Specify a filename for log output.
|
||||
|
||||
Calls qof_log_init() for you.
|
||||
*/
|
||||
void qof_log_init_filename (const gchar* logfilename);
|
||||
|
||||
/** Be nice, close the logfile if possible. */
|
||||
void qof_log_shutdown (void);
|
||||
|
||||
/** qof_log_prettify() cleans up subroutine names. AIX/xlC has the habit
|
||||
* of printing signatures not names; clean this up. On other operating
|
||||
* systems, truncate name to QOF_LOG_MAX_CHARS chars. */
|
||||
const char * qof_log_prettify (const char *name);
|
||||
|
||||
/** Do not log log_modules that have not been enabled. */
|
||||
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level);
|
||||
|
||||
/** Set the default QOF log_modules to the log level. */
|
||||
void qof_log_set_default(QofLogLevel log_level);
|
||||
|
||||
typedef void (*QofLogCB) (QofLogModule log_module, QofLogLevel* log_level,
|
||||
gpointer user_data);
|
||||
|
||||
/** Iterate over each known log_module
|
||||
|
||||
Only log_modules with log_levels set will
|
||||
be available.
|
||||
*/
|
||||
void qof_log_module_foreach(QofLogCB cb, gpointer data);
|
||||
|
||||
/** Number of log_modules registered*/
|
||||
gint qof_log_module_count(void);
|
||||
|
||||
#define FUNK qof_log_prettify(__FUNCTION__)
|
||||
|
||||
/** Log error/warning/info messages to stderr or to a file.
|
||||
* This logging infrastructure is meant for validating the
|
||||
* correctness of the execution of the code. 'Info' level
|
||||
* messages help trace program flow. 'Error' messages are
|
||||
* meant to indicate internal data inconsistencies.
|
||||
*
|
||||
* Messages can be logged to stdout, stderr, or to any desired
|
||||
* file.
|
||||
*/
|
||||
|
||||
/** Log a fatal error */
|
||||
#define FATAL(format, args...) do { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
|
||||
"Fatal Error: %s(): " format, FUNK , ## args); \
|
||||
} while (0)
|
||||
|
||||
/** Log a serious error */
|
||||
#define PERR(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_ERROR)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
|
||||
"Error: %s(): " format, FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Log a warning */
|
||||
#define PWARN(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_WARNING)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
|
||||
"Warning: %s(): " format, FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print an informational note */
|
||||
#define PINFO(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_INFO)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
|
||||
"Info: %s(): " format, \
|
||||
FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print a debugging message */
|
||||
#define DEBUG(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_DEBUG)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Debug: %s(): " format, \
|
||||
FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print a function entry debugging message */
|
||||
#define ENTER(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_DEBUG)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Enter in %s: %s()" format, __FILE__, \
|
||||
FUNK , ## args); \
|
||||
qof_log_add_indent(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print a function exit debugging message */
|
||||
#define LEAVE(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_DEBUG)) { \
|
||||
qof_log_drop_indent(); \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Leave: %s()" format, \
|
||||
FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Print a function trace debugging message */
|
||||
#define TRACE(format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_TRACE)) { \
|
||||
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
|
||||
"Trace: %s(): " format, FUNK , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEBUGCMD(x) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_DEBUG)) { \
|
||||
(x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/** Infrastructure to make timing measurements for critical pieces
|
||||
* of code. Used for only for performance tuning & debugging.
|
||||
*/
|
||||
|
||||
void qof_start_clock (int clockno, QofLogModule log_module, QofLogLevel log_level,
|
||||
const char *function_name, const char *format, ...);
|
||||
|
||||
void qof_report_clock (int clockno,
|
||||
QofLogModule log_module,
|
||||
QofLogLevel log_level,
|
||||
const char *function_name,
|
||||
const char *format, ...);
|
||||
|
||||
void qof_report_clock_total (int clockno,
|
||||
QofLogModule log_module,
|
||||
QofLogLevel log_level,
|
||||
const char *function_name,
|
||||
const char *format, ...);
|
||||
|
||||
/** start a particular timer */
|
||||
#define START_CLOCK(clockno,format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_INFO)) \
|
||||
qof_start_clock (clockno, log_module, GNC_LOG_INFO, \
|
||||
__FUNCTION__, format , ## args); \
|
||||
} while (0)
|
||||
|
||||
/** report elapsed time since last report on a particular timer */
|
||||
#define REPORT_CLOCK(clockno,format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_INFO)) \
|
||||
qof_report_clock (clockno, log_module, GNC_LOG_INFO, \
|
||||
__FUNCTION__, format , ## args); \
|
||||
} while (0)
|
||||
|
||||
/** report total elapsed time since timer started */
|
||||
#define REPORT_CLOCK_TOTAL(clockno,format, args...) do { \
|
||||
if (qof_log_check (log_module, GNC_LOG_INFO)) \
|
||||
qof_report_clock_total (clockno, log_module, GNC_LOG_INFO, \
|
||||
__FUNCTION__, format , ## args); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif /* _QOF_LOG_H */
|
||||
|
||||
/** @} */
|
@@ -43,6 +43,18 @@ void qof_object_book_end (QofBook *book);
|
||||
gboolean qof_object_is_dirty (QofBook *book);
|
||||
void qof_object_mark_clean (QofBook *book);
|
||||
|
||||
/** \brief check an object can be created and supports iteration
|
||||
|
||||
\param type_name object to check
|
||||
\param warn If called only once per operation, pass TRUE to log objects
|
||||
that fail the compliance check. To prevent repeated log messages when
|
||||
calling more than once, pass FALSE.
|
||||
|
||||
\return TRUE if object can be created and supports iteration, else FALSE.
|
||||
*/
|
||||
gboolean
|
||||
qof_object_compliance (QofIdTypeConst type_name, gboolean warn);
|
||||
|
||||
#endif /* QOF_OBJECT_P_H_ */
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
@@ -28,11 +28,8 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "qofobject.h"
|
||||
#include "qof.h"
|
||||
#include "qofobject-p.h"
|
||||
#include "qofbook.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_OBJECT;
|
||||
|
||||
@@ -140,6 +137,23 @@ void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
qof_object_compliance (QofIdTypeConst type_name, gboolean warn)
|
||||
{
|
||||
const QofObject *obj;
|
||||
|
||||
obj = qof_object_lookup(type_name);
|
||||
if((obj->create == NULL)||(obj->foreach == NULL)){
|
||||
if(warn)
|
||||
{
|
||||
PINFO (" Object type %s is not fully QOF compliant", obj->e_type);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
|
||||
QofEntityForeachCB cb, gpointer user_data)
|
||||
@@ -147,8 +161,8 @@ qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
|
||||
QofCollection *col;
|
||||
const QofObject *obj;
|
||||
|
||||
if (!book || !type_name) return;
|
||||
ENTER ("type=%s", type_name);
|
||||
if (!book || !type_name) { return; }
|
||||
PINFO ("type=%s", type_name);
|
||||
|
||||
obj = qof_object_lookup (type_name);
|
||||
if (!obj)
|
||||
@@ -157,16 +171,11 @@ qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
|
||||
return;
|
||||
}
|
||||
col = qof_book_get_collection (book, obj->e_type);
|
||||
PINFO ("lookup obj=%p for type=%s", obj, type_name);
|
||||
if (!obj) return;
|
||||
|
||||
PINFO ("type=%s foreach=%p", type_name, obj->foreach);
|
||||
if (!obj) { return; }
|
||||
if (obj->foreach)
|
||||
{
|
||||
obj->foreach (col, cb, user_data);
|
||||
}
|
||||
LEAVE ("type=%s", type_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,9 @@
|
||||
|
||||
// #include "config.h"
|
||||
|
||||
/* NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <libxml/parser.h>
|
||||
@@ -371,7 +374,7 @@ qof_query_pred_numeric_from_xml (xmlNodePtr root)
|
||||
xmlNodePtr node;
|
||||
QofQueryCompare how;
|
||||
QofNumericMatch sm;
|
||||
gnc_numeric num;
|
||||
gnc_numeric num;
|
||||
xmlNodePtr xp;
|
||||
|
||||
xp = root->xmlChildrenNode;
|
||||
@@ -478,7 +481,6 @@ qof_query_param_path_from_xml (xmlNodePtr root)
|
||||
if (0 == strcmp (node->name, "qofquery:param"))
|
||||
{
|
||||
const char *str = GET_TEXT (node);
|
||||
/* BUG? I can't find the matching cache removal. */
|
||||
plist = g_slist_append (plist, CACHE_INSERT(str));
|
||||
}
|
||||
}
|
||||
@@ -631,15 +633,15 @@ qof_query_from_xml (xmlNodePtr root)
|
||||
xmlChar *version;
|
||||
xmlNodePtr qpart;
|
||||
xmlNodePtr node;
|
||||
|
||||
|
||||
if (!root) return NULL;
|
||||
|
||||
|
||||
version = xmlGetProp(root, "version");
|
||||
if (!root->name || strcmp ("qof:qofquery", root->name))
|
||||
{
|
||||
if (!root->name || strcmp ("qof:qofquery", root->name))
|
||||
{
|
||||
// XXX something is wrong. warn ...
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
q = qof_query_create ();
|
||||
|
||||
|
@@ -40,6 +40,9 @@ author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
Unfinished. XXX Why is this easier than reading a text/sql
|
||||
file?
|
||||
|
||||
NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.
|
||||
|
||||
*/
|
||||
/* Given an XML tree, reconstruct and return the equivalent query. */
|
||||
QofQuery *qof_query_from_xml (xmlNodePtr);
|
||||
|
@@ -28,6 +28,9 @@
|
||||
#include "qofquerycore-p.h"
|
||||
#include "kvp_frame.h"
|
||||
|
||||
/* NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.*/
|
||||
|
||||
/* ======================================================= */
|
||||
|
||||
#define PUT_STR(TOK,VAL) { \
|
||||
@@ -221,7 +224,7 @@ qof_query_pred_data_to_xml (QofQueryPredData *pd)
|
||||
query_double_t pdata_db;
|
||||
query_boolean_t pdata_bool;
|
||||
query_char_t pdata_c;
|
||||
|
||||
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-guid");
|
||||
@@ -425,7 +428,7 @@ qof_query_terms_to_xml (QofQuery *q)
|
||||
xmlNodePtr terms;
|
||||
GList *n;
|
||||
xmlNodePtr andt;
|
||||
|
||||
|
||||
terms = NULL;
|
||||
n = qof_query_get_terms (q);
|
||||
if (!n) return NULL;
|
||||
@@ -543,7 +546,7 @@ int main (int argc, char * argv[])
|
||||
xmlChar *xbuf;
|
||||
int bufsz;
|
||||
xmlOutputBufferPtr xbuf;
|
||||
|
||||
|
||||
qof_query_init();
|
||||
qof_object_initialize ();
|
||||
|
||||
|
@@ -25,6 +25,9 @@
|
||||
Copyright (C) 2001,2002,2004 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
/* NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.*/
|
||||
|
||||
#ifndef QOF_QUERY_SERIALIZE_H
|
||||
#define QOF_QUERY_SERIALIZE_H
|
||||
|
||||
|
@@ -29,18 +29,11 @@
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#include "qof.h"
|
||||
#include "qofbackend-p.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofbook-p.h"
|
||||
#include "qofclass.h"
|
||||
#include "qofclass-p.h"
|
||||
#include "qofobject.h"
|
||||
#include "qofquery.h"
|
||||
#include "qofquery-p.h"
|
||||
#include "qofquerycore.h"
|
||||
#include "qofquerycore-p.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QUERY;
|
||||
@@ -370,9 +363,6 @@ check_object (QofQuery *q, gpointer object)
|
||||
QofQueryTerm * qt;
|
||||
int and_terms_ok=1;
|
||||
|
||||
ENTER (" object=%p terms=%p name=%s",
|
||||
object, q->terms, qof_object_printable (q->search_for, object));
|
||||
|
||||
for(or_ptr = q->terms; or_ptr; or_ptr = or_ptr->next)
|
||||
{
|
||||
and_terms_ok = 1;
|
||||
@@ -407,11 +397,7 @@ check_object (QofQuery *q, gpointer object)
|
||||
/* XXX: Don't know how to do this conversion -- do we care? */
|
||||
}
|
||||
}
|
||||
if (and_terms_ok)
|
||||
{
|
||||
LEAVE (" (terms are OK)");
|
||||
return 1;
|
||||
}
|
||||
if (and_terms_ok) { return 1; }
|
||||
}
|
||||
|
||||
/* If there are no terms, assume a "match any" applies.
|
||||
@@ -419,7 +405,6 @@ check_object (QofQuery *q, gpointer object)
|
||||
* may want to get all objects, but in a particular sorted
|
||||
* order.
|
||||
*/
|
||||
LEAVE (" ");
|
||||
if (NULL == q->terms) return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -950,7 +935,7 @@ QofQuery * qof_query_copy (QofQuery *q)
|
||||
return copy;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* qof_query_invert
|
||||
* return a newly-allocated Query object which is the
|
||||
* logical inverse of the original.
|
||||
@@ -1033,7 +1018,7 @@ QofQuery * qof_query_invert (QofQuery *q)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
/* *******************************************************************
|
||||
* qof_query_merge
|
||||
* combine 2 Query objects by the logical operation in "op".
|
||||
********************************************************************/
|
||||
@@ -1273,6 +1258,7 @@ void qof_query_init (void)
|
||||
ENTER (" ");
|
||||
qof_query_core_init ();
|
||||
qof_class_init ();
|
||||
LEAVE ("Completed initialization of QofQuery");
|
||||
}
|
||||
|
||||
void qof_query_shutdown (void)
|
||||
@@ -1414,12 +1400,8 @@ gboolean qof_query_equal (QofQuery *q1, QofQuery *q2)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/***************************************************************************/
|
||||
/* Query Print functions. qof_query_print is public; everthing else supports
|
||||
* that.
|
||||
* Just call qof_query_print(QofQuery *q), and it will print out the query
|
||||
* contents to stderr.
|
||||
/* **************************************************************************/
|
||||
/* Query Print functions for use with qof_log_set_level.
|
||||
*/
|
||||
|
||||
/* Static prototypes */
|
||||
@@ -1434,14 +1416,18 @@ static gchar *qof_query_printDateMatch (QofDateMatch d);
|
||||
static gchar *qof_query_printNumericMatch (QofNumericMatch n);
|
||||
static gchar *qof_query_printGuidMatch (QofGuidMatch g);
|
||||
static gchar *qof_query_printCharMatch (QofCharMatch c);
|
||||
static GString *qof_query_printPredData (QofQueryPredData *pd);
|
||||
static GList *qof_query_printPredData (QofQueryPredData *pd, GList *lst);
|
||||
static GString *qof_query_printParamPath (GSList * parmList);
|
||||
static void qof_query_printValueForParam (QofQueryPredData *pd, GString * gs);
|
||||
static void qof_query_printOutput (GList * output);
|
||||
|
||||
/*
|
||||
This function cycles through a QofQuery object, and
|
||||
prints out the values of the various members of the query
|
||||
/** \deprecated access via qof_log instead.
|
||||
The query will be logged automatically if qof_log_set_default
|
||||
or qof_log_set_level(QOF_MOD_QUERY, ...) are set to QOF_LOG_DEBUG
|
||||
or higher.
|
||||
|
||||
This function cycles through a QofQuery object, and
|
||||
prints out the values of the various members of the query
|
||||
*/
|
||||
void
|
||||
qof_query_print (QofQuery * query)
|
||||
@@ -1489,7 +1475,7 @@ qof_query_printOutput (GList * output)
|
||||
{
|
||||
GString *line = (GString *) lst->data;
|
||||
|
||||
fprintf (stderr, "%s\n", line->str);
|
||||
DEBUG (" %s", line->str);
|
||||
g_string_free (line, TRUE);
|
||||
line = NULL;
|
||||
}
|
||||
@@ -1511,7 +1497,7 @@ qof_query_printSearchFor (QofQuery * query, GList * output)
|
||||
output = g_list_append (output, gs);
|
||||
|
||||
return output;
|
||||
} /* qof_query_printSearchFor */
|
||||
} /* qof_query_printSearchFor */
|
||||
|
||||
/*
|
||||
Run through the terms of the query. This is a outer-inner
|
||||
@@ -1542,7 +1528,7 @@ qof_query_printTerms (QofQuery * query, GList * output)
|
||||
}
|
||||
|
||||
return output;
|
||||
} /* qof_query_printTerms */
|
||||
} /* qof_query_printTerms */
|
||||
|
||||
/*
|
||||
Process the sort parameters
|
||||
@@ -1554,7 +1540,7 @@ qof_query_printSorts (QofQuerySort *s[], const gint numSorts, GList * output)
|
||||
{
|
||||
GSList *gsl, *n = NULL;
|
||||
gint curSort;
|
||||
GString *gs = g_string_new (" Sort Parameters:\n");
|
||||
GString *gs = g_string_new ("Sort Parameters: ");
|
||||
|
||||
for (curSort = 0; curSort < numSorts; curSort++)
|
||||
{
|
||||
@@ -1566,24 +1552,24 @@ qof_query_printSorts (QofQuerySort *s[], const gint numSorts, GList * output)
|
||||
increasing = qof_query_sort_get_increasing (s[curSort]);
|
||||
|
||||
gsl = qof_query_sort_get_param_path (s[curSort]);
|
||||
if (gsl) g_string_append_printf (gs, " Param: ");
|
||||
if (gsl) g_string_append_printf (gs, " Param: ");
|
||||
for (n=gsl; n; n = n->next)
|
||||
{
|
||||
QofIdType param_name = n->data;
|
||||
if (gsl != n)g_string_append_printf (gs, "\n ");
|
||||
if (gsl != n) g_string_append_printf (gs, " ");
|
||||
g_string_append_printf (gs, "%s", param_name);
|
||||
}
|
||||
if (gsl)
|
||||
{
|
||||
g_string_append_printf (gs, " %s\n", increasing ? "DESC" : "ASC");
|
||||
g_string_append_printf (gs, " Options: 0x%x\n", s[curSort]->options);
|
||||
g_string_append_printf (gs, " %s ", increasing ? "DESC" : "ASC");
|
||||
g_string_append_printf (gs, " Options: 0x%x ", s[curSort]->options);
|
||||
}
|
||||
}
|
||||
|
||||
output = g_list_append (output, gs);
|
||||
return output;
|
||||
|
||||
} /* qof_query_printSorts */
|
||||
} /* qof_query_printSorts */
|
||||
|
||||
/*
|
||||
Process the AND terms of the query. This is a GList
|
||||
@@ -1592,7 +1578,7 @@ qof_query_printSorts (QofQuerySort *s[], const gint numSorts, GList * output)
|
||||
static GList *
|
||||
qof_query_printAndTerms (GList * terms, GList * output)
|
||||
{
|
||||
const char *prefix = " AND Terms:";
|
||||
const char *prefix = "AND Terms:";
|
||||
QofQueryTerm *qt;
|
||||
QofQueryPredData *pd;
|
||||
GSList *path;
|
||||
@@ -1608,14 +1594,14 @@ qof_query_printAndTerms (GList * terms, GList * output)
|
||||
invert = qof_query_term_is_inverted (qt);
|
||||
|
||||
if (invert) output = g_list_append (output,
|
||||
g_string_new(" INVERT SENSE "));
|
||||
g_string_new(" INVERT SENSE "));
|
||||
output = g_list_append (output, qof_query_printParamPath (path));
|
||||
output = g_list_append (output, qof_query_printPredData (pd));
|
||||
output = g_list_append (output, g_string_new("\n"));
|
||||
output = qof_query_printPredData (pd, output);
|
||||
// output = g_list_append (output, g_string_new(" "));
|
||||
}
|
||||
|
||||
return output;
|
||||
} /* qof_query_printAndTerms */
|
||||
} /* qof_query_printAndTerms */
|
||||
|
||||
/*
|
||||
Process the parameter types of the predicate data
|
||||
@@ -1624,8 +1610,8 @@ static GString *
|
||||
qof_query_printParamPath (GSList * parmList)
|
||||
{
|
||||
GSList *list = NULL;
|
||||
GString *gs = g_string_new (" Param List:\n");
|
||||
g_string_append (gs, " ");
|
||||
GString *gs = g_string_new ("Param List: ");
|
||||
g_string_append (gs, " ");
|
||||
for (list = parmList; list; list = list->next)
|
||||
{
|
||||
g_string_append (gs, (gchar *) list->data);
|
||||
@@ -1634,31 +1620,32 @@ qof_query_printParamPath (GSList * parmList)
|
||||
}
|
||||
|
||||
return gs;
|
||||
} /* qof_query_printParamPath */
|
||||
} /* qof_query_printParamPath */
|
||||
|
||||
/*
|
||||
Process the PredData of the AND terms
|
||||
*/
|
||||
static GString *
|
||||
qof_query_printPredData (QofQueryPredData *pd)
|
||||
static GList *
|
||||
qof_query_printPredData (QofQueryPredData *pd, GList *lst)
|
||||
{
|
||||
GString *gs;
|
||||
|
||||
gs = g_string_new (" Pred Data:\n ");
|
||||
gs = g_string_new ("Pred Data: ");
|
||||
g_string_append (gs, (gchar *) pd->type_name);
|
||||
|
||||
/* Char Predicate and GUID predicate don't use the 'how' field. */
|
||||
if (safe_strcmp (pd->type_name, QOF_TYPE_CHAR) &&
|
||||
safe_strcmp (pd->type_name, QOF_TYPE_GUID))
|
||||
{
|
||||
g_string_append_printf (gs, "\n how: %s",
|
||||
qof_query_printStringForHow (pd->how));
|
||||
g_string_append_printf (gs, " how: %s",
|
||||
qof_query_printStringForHow (pd->how));
|
||||
}
|
||||
|
||||
lst = g_list_append(lst, gs);
|
||||
gs = g_string_new ("");
|
||||
qof_query_printValueForParam (pd, gs);
|
||||
|
||||
return gs;
|
||||
} /* qof_query_printPredData */
|
||||
lst = g_list_append(lst, gs);
|
||||
return lst;
|
||||
} /* qof_query_printPredData */
|
||||
|
||||
/*
|
||||
Get a string representation for the
|
||||
@@ -1685,7 +1672,7 @@ qof_query_printStringForHow (QofQueryCompare how)
|
||||
}
|
||||
|
||||
return "INVALID HOW";
|
||||
} /* qncQueryPrintStringForHow */
|
||||
} /* qncQueryPrintStringForHow */
|
||||
|
||||
|
||||
static void
|
||||
@@ -1696,47 +1683,46 @@ qof_query_printValueForParam (QofQueryPredData *pd, GString * gs)
|
||||
{
|
||||
GList *node;
|
||||
query_guid_t pdata = (query_guid_t) pd;
|
||||
g_string_append_printf (gs, "\n Match type %s",
|
||||
qof_query_printGuidMatch (pdata->options));
|
||||
g_string_append_printf (gs, "Match type %s",
|
||||
qof_query_printGuidMatch (pdata->options));
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
{
|
||||
/* THREAD-UNSAFE */
|
||||
/* THREAD-UNSAFE */
|
||||
g_string_append_printf (gs, ", guids: %s",
|
||||
guid_to_string ((GUID *) node->data));
|
||||
guid_to_string ((GUID *) node->data));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
|
||||
{
|
||||
query_string_t pdata = (query_string_t) pd;
|
||||
g_string_append_printf (gs, "\n Match type %s",
|
||||
qof_query_printStringMatch (pdata->options));
|
||||
g_string_append_printf (gs, " Match type %s",
|
||||
qof_query_printStringMatch (pdata->options));
|
||||
g_string_append_printf (gs, " %s string: %s",
|
||||
pdata->is_regex ? "Regex" : "Not regex",
|
||||
pdata->matchstring);
|
||||
pdata->is_regex ? "Regex" : "Not regex",
|
||||
pdata->matchstring);
|
||||
return;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
|
||||
{
|
||||
query_numeric_t pdata = (query_numeric_t) pd;
|
||||
g_string_append_printf (gs, "\n Match type %s",
|
||||
qof_query_printNumericMatch (pdata->options));
|
||||
g_string_append_printf (gs, " Match type %s",
|
||||
qof_query_printNumericMatch (pdata->options));
|
||||
g_string_append_printf (gs, " gnc_numeric: %s",
|
||||
gnc_num_dbg_to_string (pdata->amount));
|
||||
gnc_num_dbg_to_string (pdata->amount));
|
||||
return;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
|
||||
{
|
||||
GSList *node;
|
||||
query_kvp_t pdata = (query_kvp_t) pd;
|
||||
g_string_append_printf (gs, "\n kvp path: ");
|
||||
g_string_append_printf (gs, " kvp path: ");
|
||||
for (node = pdata->path; node; node = node->next)
|
||||
{
|
||||
g_string_append_printf (gs, "/%s", (gchar *) node->data);
|
||||
}
|
||||
g_string_append_printf (gs, "\n");
|
||||
g_string_append_printf (gs, " kvp value: %s\n",
|
||||
kvp_value_to_string (pdata->value));
|
||||
g_string_append_printf (gs, " kvp value: %s ",
|
||||
kvp_value_to_string (pdata->value));
|
||||
return;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
|
||||
@@ -1760,16 +1746,16 @@ qof_query_printValueForParam (QofQueryPredData *pd, GString * gs)
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
|
||||
{
|
||||
query_date_t pdata = (query_date_t) pd;
|
||||
g_string_append_printf (gs, "\n Match type %s",
|
||||
qof_query_printDateMatch (pdata->options));
|
||||
g_string_append_printf (gs, " Match type %s",
|
||||
qof_query_printDateMatch (pdata->options));
|
||||
g_string_append_printf (gs, " query_date: %s", gnc_print_date (pdata->date));
|
||||
return;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
|
||||
{
|
||||
query_char_t pdata = (query_char_t) pd;
|
||||
g_string_append_printf (gs, "\n Match type %s",
|
||||
qof_query_printCharMatch (pdata->options));
|
||||
g_string_append_printf (gs, " Match type %s",
|
||||
qof_query_printCharMatch (pdata->options));
|
||||
g_string_append_printf (gs, " char list: %s", pdata->char_list);
|
||||
return;
|
||||
}
|
||||
@@ -1781,7 +1767,7 @@ qof_query_printValueForParam (QofQueryPredData *pd, GString * gs)
|
||||
}
|
||||
/** \todo QOF_TYPE_COLLECT */
|
||||
return;
|
||||
} /* qof_query_printValueForParam */
|
||||
} /* qof_query_printValueForParam */
|
||||
|
||||
/*
|
||||
* Print out a string representation of the
|
||||
@@ -1798,7 +1784,7 @@ qof_query_printStringMatch (QofStringMatch s)
|
||||
return "QOF_STRING_MATCH_CASEINSENSITIVE";
|
||||
}
|
||||
return "UNKNOWN MATCH TYPE";
|
||||
} /* qof_query_printStringMatch */
|
||||
} /* qof_query_printStringMatch */
|
||||
|
||||
/*
|
||||
* Print out a string representation of the
|
||||
@@ -1815,7 +1801,7 @@ qof_query_printDateMatch (QofDateMatch d)
|
||||
return "QOF_DATE_MATCH_DAY";
|
||||
}
|
||||
return "UNKNOWN MATCH TYPE";
|
||||
} /* qof_query_printDateMatch */
|
||||
} /* qof_query_printDateMatch */
|
||||
|
||||
/*
|
||||
* Print out a string representation of the
|
||||
@@ -1834,7 +1820,7 @@ qof_query_printNumericMatch (QofNumericMatch n)
|
||||
return "QOF_NUMERIC_MATCH_ANY";
|
||||
}
|
||||
return "UNKNOWN MATCH TYPE";
|
||||
} /* qof_query_printNumericMatch */
|
||||
} /* qof_query_printNumericMatch */
|
||||
|
||||
/*
|
||||
* Print out a string representation of the
|
||||
@@ -1858,7 +1844,7 @@ qof_query_printGuidMatch (QofGuidMatch g)
|
||||
}
|
||||
|
||||
return "UNKNOWN MATCH TYPE";
|
||||
} /* qof_query_printGuidMatch */
|
||||
} /* qof_query_printGuidMatch */
|
||||
|
||||
/*
|
||||
* Print out a string representation of the
|
||||
@@ -1875,6 +1861,6 @@ qof_query_printCharMatch (QofCharMatch c)
|
||||
return "QOF_CHAR_MATCH_NONE";
|
||||
}
|
||||
return "UNKNOWN MATCH TYPE";
|
||||
} /* qof_query_printGuidMatch */
|
||||
} /* qof_query_printGuidMatch */
|
||||
|
||||
/* ======================== END OF FILE =================== */
|
||||
|
@@ -63,13 +63,6 @@ the canonical form, and the same predicate may be evaluated multiple
|
||||
times per split for complex queries. This is a place where we could
|
||||
probably optimize.
|
||||
|
||||
Evaluation of a Query (see qof_query_run()) is optimized as much as
|
||||
possible by short-circuited evaluation. The predicates in each
|
||||
AND-chain are sorted by predicate type, with Account queries sorted
|
||||
first to allow the evaluator to completely eliminate accounts from the
|
||||
search if there's no chance of them having splits that match.
|
||||
(XXX above no longer applies)
|
||||
|
||||
@{ */
|
||||
/** @file qofquery.h
|
||||
@brief find objects that match a certain expression.
|
||||
@@ -78,7 +71,6 @@ search if there's no chance of them having splits that match.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QOF_QUERYNEW_H
|
||||
#define QOF_QUERYNEW_H
|
||||
|
||||
@@ -101,7 +93,7 @@ typedef enum {
|
||||
QOF_QUERY_XOR
|
||||
} QofQueryOp;
|
||||
|
||||
/* First/only term is same as 'and' */
|
||||
/** First/only term is same as 'and' */
|
||||
#define QOF_QUERY_FIRST_TERM QOF_QUERY_AND
|
||||
|
||||
/** Default sort object type */
|
||||
@@ -151,16 +143,14 @@ QofQuery * qof_query_create_for (QofIdTypeConst obj_type);
|
||||
void qof_query_destroy (QofQuery *q);
|
||||
|
||||
/** Set the object type to be searched for. The results of
|
||||
* performuing the query will be a list of this obj_type.
|
||||
* performing the query will be a list of this obj_type.
|
||||
*/
|
||||
void qof_query_search_for (QofQuery *query, QofIdTypeConst obj_type);
|
||||
|
||||
/** Set the book to be searched. Books contain/identify collections
|
||||
/** Set the book to be searched. Books contain/identify collections
|
||||
* of objects; the search will be performed over those books
|
||||
* specified with this function. If no books are set, no results
|
||||
* will be returned (since there is nothing to search over). (CAS:
|
||||
* Apparently, if no books are set, you'll actually get a critical
|
||||
* assertion failure.)
|
||||
* specified with this function. If no books are set, no results
|
||||
* will be returned (since there is nothing to search over).
|
||||
*
|
||||
* You can search multiple books. To specify multiple books, call
|
||||
* this function multiple times with different arguments.
|
||||
@@ -359,8 +349,11 @@ void qof_query_set_max_results (QofQuery *q, int n);
|
||||
*/
|
||||
gboolean qof_query_equal (QofQuery *q1, QofQuery *q2);
|
||||
|
||||
/** Print the Query in human-readable format.
|
||||
* Useful for debugging and development.
|
||||
/** Log the Query
|
||||
*
|
||||
* \deprecated Do not call directly, use the standard log
|
||||
* module code: ::qof_log_set_level(QOF_MOD_QUERY, QOF_LOG_DEBUG);
|
||||
* or ::qof_log_set_default(QOF_LOG_DEBUG);
|
||||
*/
|
||||
void qof_query_print (QofQuery *query);
|
||||
|
||||
|
@@ -25,10 +25,7 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "qofquery.h"
|
||||
#include "qofquerycore.h"
|
||||
#include "qof.h"
|
||||
#include "qofquerycore-p.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QUERY;
|
||||
@@ -39,7 +36,7 @@ typedef void (*QueryPredDataFree) (QofQueryPredData *pdata);
|
||||
/* A function to copy a query's predicate data */
|
||||
typedef QofQueryPredData *(*QueryPredicateCopyFunc) (QofQueryPredData *pdata);
|
||||
|
||||
/* A function to take the object, apply the getter->param_getfcn,
|
||||
/* A function to take the object, apply the getter->param_getfcn,
|
||||
* and return a printable string. Note that this QofParam->getfnc
|
||||
* function should be returning a type equal to this core object type.
|
||||
*
|
||||
@@ -48,7 +45,7 @@ typedef QofQueryPredData *(*QueryPredicateCopyFunc) (QofQueryPredData *pdata);
|
||||
typedef char * (*QueryToString) (gpointer object, QofParam *getter);
|
||||
|
||||
/* A function to test for equality of predicate data */
|
||||
typedef gboolean (*QueryPredicateEqual) (QofQueryPredData *p1,
|
||||
typedef gboolean (*QueryPredicateEqual) (QofQueryPredData *p1,
|
||||
QofQueryPredData *p2);
|
||||
|
||||
static QueryPredicateCopyFunc qof_query_copy_predicate (QofType type);
|
||||
@@ -124,13 +121,13 @@ static GHashTable *predEqualTable = NULL;
|
||||
PREDICATE_ERROR); \
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* *******************************************************************/
|
||||
/* TYPE-HANDLING FUNCTIONS */
|
||||
|
||||
/* QOF_TYPE_STRING */
|
||||
|
||||
static int
|
||||
string_match_predicate (gpointer object,
|
||||
static int
|
||||
string_match_predicate (gpointer object,
|
||||
QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -169,7 +166,7 @@ string_match_predicate (gpointer object,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
string_compare_func (gpointer a, gpointer b, gint options,
|
||||
QofParam *getter)
|
||||
{
|
||||
@@ -185,7 +182,7 @@ string_compare_func (gpointer a, gpointer b, gint options,
|
||||
return safe_strcmp (s1, s2);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
string_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_string_t pdata = (query_string_t) pd;
|
||||
@@ -207,12 +204,12 @@ string_copy_predicate (QofQueryPredData *pd)
|
||||
|
||||
VERIFY_PDATA_R (query_string_type);
|
||||
|
||||
return qof_query_string_predicate (pd->how, pdata->matchstring,
|
||||
return qof_query_string_predicate (pd->how, pdata->matchstring,
|
||||
pdata->options,
|
||||
pdata->is_regex);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
string_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_string_t pd1 = (query_string_t) p1;
|
||||
@@ -252,7 +249,7 @@ qof_query_string_predicate (QofQueryCompare how,
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
string_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
const char *res;
|
||||
@@ -264,7 +261,7 @@ string_to_string (gpointer object, QofParam *getter)
|
||||
|
||||
/* QOF_TYPE_DATE =================================================== */
|
||||
|
||||
static int
|
||||
static int
|
||||
date_compare (Timespec ta, Timespec tb, QofDateMatch options)
|
||||
{
|
||||
|
||||
@@ -286,7 +283,7 @@ date_compare (Timespec ta, Timespec tb, QofDateMatch options)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
date_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -318,7 +315,7 @@ date_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
|
||||
{
|
||||
Timespec ta, tb;
|
||||
@@ -331,7 +328,7 @@ date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
|
||||
return date_compare (ta, tb, options);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
date_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_date_t pdata = (query_date_t)pd;
|
||||
@@ -351,7 +348,7 @@ date_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_date_predicate (pd->how, pdata->options, pdata->date);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
date_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_date_t pd1 = (query_date_t) p1;
|
||||
@@ -386,7 +383,7 @@ qof_query_date_predicate_get_date (QofQueryPredData *pd, Timespec *date)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
date_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
Timespec ts = ((query_date_getter)getter->param_getfcn)(object, getter);
|
||||
@@ -399,7 +396,7 @@ date_to_string (gpointer object, QofParam *getter)
|
||||
|
||||
/* QOF_TYPE_NUMERIC ================================================= */
|
||||
|
||||
static int
|
||||
static int
|
||||
numeric_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData* pd)
|
||||
{
|
||||
@@ -422,7 +419,7 @@ numeric_match_predicate (gpointer object, QofParam *getter,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Amounts are considered to be 'equal' if they match to
|
||||
/* Amounts are considered to be 'equal' if they match to
|
||||
* four decimal places. (epsilon=1/10000) */
|
||||
if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ) {
|
||||
gnc_numeric cmp_val = gnc_numeric_create (1, 10000);
|
||||
@@ -454,7 +451,7 @@ numeric_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
|
||||
{
|
||||
gnc_numeric va, vb;
|
||||
@@ -464,10 +461,10 @@ numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
|
||||
va = ((query_numeric_getter)getter->param_getfcn) (a, getter);
|
||||
vb = ((query_numeric_getter)getter->param_getfcn) (b, getter);
|
||||
|
||||
return gnc_numeric_compare (va, vb);
|
||||
return gnc_numeric_compare (va, vb);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
numeric_free_pdata (QofQueryPredData* pd)
|
||||
{
|
||||
query_numeric_t pdata = (query_numeric_t)pd;
|
||||
@@ -483,7 +480,7 @@ numeric_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_numeric_predicate (pd->how, pdata->options, pdata->amount);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
numeric_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_numeric_t pd1 = (query_numeric_t) p1;
|
||||
@@ -507,7 +504,7 @@ qof_query_numeric_predicate (QofQueryCompare how,
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
numeric_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
gnc_numeric num;
|
||||
@@ -516,7 +513,7 @@ numeric_to_string (gpointer object, QofParam *getter)
|
||||
return gnc_numeric_to_string (num);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
debcred_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
gnc_numeric num;
|
||||
@@ -527,7 +524,7 @@ debcred_to_string (gpointer object, QofParam *getter)
|
||||
|
||||
/* QOF_TYPE_GUID =================================================== */
|
||||
|
||||
static int
|
||||
static int
|
||||
guid_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -545,17 +542,17 @@ guid_match_predicate (gpointer object, QofParam *getter,
|
||||
* object list
|
||||
*/
|
||||
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
{
|
||||
/* See if this GUID matches the object's guid */
|
||||
for (o_list = object; o_list; o_list = o_list->next)
|
||||
for (o_list = object; o_list; o_list = o_list->next)
|
||||
{
|
||||
guid = ((query_guid_getter)getter->param_getfcn) (o_list->data, getter);
|
||||
if (guid_equal (node->data, guid))
|
||||
if (guid_equal (node->data, guid))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* If o_list is NULL, we've walked the whole list without finding
|
||||
* a match. Therefore break out now, the match has failed.
|
||||
*/
|
||||
@@ -563,7 +560,7 @@ guid_match_predicate (gpointer object, QofParam *getter,
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* The match is complete. If node == NULL then we've succesfully
|
||||
* found a match for all the guids in the predicate. Return
|
||||
* appropriately below.
|
||||
@@ -580,12 +577,12 @@ guid_match_predicate (gpointer object, QofParam *getter,
|
||||
|
||||
o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
|
||||
|
||||
for (node = o_list; node; node = node->next)
|
||||
for (node = o_list; node; node = node->next)
|
||||
{
|
||||
GList *node2;
|
||||
|
||||
/* Search the predicate data for a match */
|
||||
for (node2 = pdata->guids; node2; node2 = node2->next)
|
||||
for (node2 = pdata->guids; node2; node2 = node2->next)
|
||||
{
|
||||
if (guid_equal (node->data, node2->data))
|
||||
break;
|
||||
@@ -605,13 +602,13 @@ guid_match_predicate (gpointer object, QofParam *getter,
|
||||
break;
|
||||
|
||||
default:
|
||||
/* object is a single object, getter returns a GUID*
|
||||
/* object is a single object, getter returns a GUID*
|
||||
*
|
||||
* See if the guid is in the list
|
||||
*/
|
||||
|
||||
guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
{
|
||||
if (guid_equal (node->data, guid))
|
||||
break;
|
||||
@@ -636,7 +633,7 @@ guid_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
guid_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_guid_t pdata = (query_guid_t)pd;
|
||||
@@ -658,7 +655,7 @@ guid_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_guid_predicate (pdata->options, pdata->guids);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
guid_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_guid_t pd1 = (query_guid_t) p1;
|
||||
@@ -667,7 +664,7 @@ guid_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
|
||||
if (pd1->options != pd2->options) return FALSE;
|
||||
if (g_list_length (l1) != g_list_length (l2)) return FALSE;
|
||||
for ( ; l1 ; l1 = l1->next, l2 = l2->next)
|
||||
for ( ; l1 ; l1 = l1->next, l2 = l2->next)
|
||||
{
|
||||
if (!guid_equal (l1->data, l2->data))
|
||||
return FALSE;
|
||||
@@ -689,7 +686,7 @@ qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
|
||||
pdata->options = options;
|
||||
|
||||
pdata->guids = g_list_copy (guid_list);
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
for (node = pdata->guids; node; node = node->next)
|
||||
{
|
||||
GUID *guid = guid_malloc ();
|
||||
*guid = *((GUID *)node->data);
|
||||
@@ -701,7 +698,7 @@ qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
|
||||
/* ================================================================ */
|
||||
/* QOF_TYPE_INT32 */
|
||||
|
||||
static int
|
||||
static int
|
||||
int32_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -731,7 +728,7 @@ int32_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
int32_compare_func (gpointer a, gpointer b, gint options,
|
||||
QofParam *getter)
|
||||
{
|
||||
@@ -746,7 +743,7 @@ int32_compare_func (gpointer a, gpointer b, gint options,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
int32_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_int32_t pdata = (query_int32_t)pd;
|
||||
@@ -762,7 +759,7 @@ int32_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_int32_predicate (pd->how, pdata->val);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
int32_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_int32_t pd1 = (query_int32_t) p1;
|
||||
@@ -781,7 +778,7 @@ qof_query_int32_predicate (QofQueryCompare how, gint32 val)
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
int32_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
gint32 num = ((query_int32_getter)getter->param_getfcn)(object, getter);
|
||||
@@ -792,7 +789,7 @@ int32_to_string (gpointer object, QofParam *getter)
|
||||
/* ================================================================ */
|
||||
/* QOF_TYPE_INT64 */
|
||||
|
||||
static int
|
||||
static int
|
||||
int64_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -822,7 +819,7 @@ int64_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
int64_compare_func (gpointer a, gpointer b, gint options,
|
||||
QofParam *getter)
|
||||
{
|
||||
@@ -837,7 +834,7 @@ int64_compare_func (gpointer a, gpointer b, gint options,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
int64_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_int64_t pdata = (query_int64_t)pd;
|
||||
@@ -853,7 +850,7 @@ int64_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_int64_predicate (pd->how, pdata->val);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
int64_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_int64_t pd1 = (query_int64_t) p1;
|
||||
@@ -872,7 +869,7 @@ qof_query_int64_predicate (QofQueryCompare how, gint64 val)
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
int64_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
gint64 num = ((query_int64_getter)getter->param_getfcn)(object, getter);
|
||||
@@ -883,7 +880,7 @@ int64_to_string (gpointer object, QofParam *getter)
|
||||
/* ================================================================ */
|
||||
/* QOF_TYPE_DOUBLE */
|
||||
|
||||
static int
|
||||
static int
|
||||
double_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -913,7 +910,7 @@ double_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
double_compare_func (gpointer a, gpointer b, gint options,
|
||||
QofParam *getter)
|
||||
{
|
||||
@@ -928,7 +925,7 @@ double_compare_func (gpointer a, gpointer b, gint options,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
double_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_double_t pdata = (query_double_t)pd;
|
||||
@@ -944,7 +941,7 @@ double_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_double_predicate (pd->how, pdata->val);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
double_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_double_t pd1 = (query_double_t) p1;
|
||||
@@ -963,7 +960,7 @@ qof_query_double_predicate (QofQueryCompare how, double val)
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
double_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
double num = ((query_double_getter)getter->param_getfcn)(object, getter);
|
||||
@@ -973,7 +970,7 @@ double_to_string (gpointer object, QofParam *getter)
|
||||
|
||||
/* QOF_TYPE_BOOLEAN =================================================== */
|
||||
|
||||
static int
|
||||
static int
|
||||
boolean_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -995,7 +992,7 @@ boolean_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
boolean_compare_func (gpointer a, gpointer b, gint options,
|
||||
QofParam *getter)
|
||||
{
|
||||
@@ -1008,7 +1005,7 @@ boolean_compare_func (gpointer a, gpointer b, gint options,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
boolean_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_boolean_t pdata = (query_boolean_t)pd;
|
||||
@@ -1024,7 +1021,7 @@ boolean_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_boolean_predicate (pd->how, pdata->val);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
boolean_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_boolean_t pd1 = (query_boolean_t) p1;
|
||||
@@ -1046,7 +1043,7 @@ qof_query_boolean_predicate (QofQueryCompare how, gboolean val)
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
boolean_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
gboolean num = ((query_boolean_getter)getter->param_getfcn)(object, getter);
|
||||
@@ -1056,7 +1053,7 @@ boolean_to_string (gpointer object, QofParam *getter)
|
||||
|
||||
/* QOF_TYPE_CHAR =================================================== */
|
||||
|
||||
static int
|
||||
static int
|
||||
char_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -1080,7 +1077,7 @@ char_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
char_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
|
||||
{
|
||||
char va, vb;
|
||||
@@ -1090,13 +1087,13 @@ char_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
|
||||
return (va-vb);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
char_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_char_t pdata = (query_char_t)pd;
|
||||
VERIFY_PDATA (query_char_type);
|
||||
g_free (pdata->char_list);
|
||||
g_free (pdata);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QofQueryPredData *
|
||||
@@ -1107,7 +1104,7 @@ char_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_char_predicate (pdata->options, pdata->char_list);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
char_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_char_t pd1 = (query_char_t) p1;
|
||||
@@ -1130,7 +1127,7 @@ qof_query_char_predicate (QofCharMatch options, const char *chars)
|
||||
return ((QofQueryPredData*)pdata);
|
||||
}
|
||||
|
||||
static char *
|
||||
static char *
|
||||
char_to_string (gpointer object, QofParam *getter)
|
||||
{
|
||||
char num = ((query_char_getter)getter->param_getfcn)(object, getter);
|
||||
@@ -1140,7 +1137,7 @@ char_to_string (gpointer object, QofParam *getter)
|
||||
|
||||
/* QOF_TYPE_KVP ================================================ */
|
||||
|
||||
static int
|
||||
static int
|
||||
kvp_match_predicate (gpointer object, QofParam *getter,
|
||||
QofQueryPredData *pd)
|
||||
{
|
||||
@@ -1184,7 +1181,7 @@ kvp_match_predicate (gpointer object, QofParam *getter,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
kvp_free_pdata (QofQueryPredData *pd)
|
||||
{
|
||||
query_kvp_t pdata = (query_kvp_t)pd;
|
||||
@@ -1192,13 +1189,13 @@ kvp_free_pdata (QofQueryPredData *pd)
|
||||
|
||||
VERIFY_PDATA (query_kvp_type);
|
||||
kvp_value_delete (pdata->value);
|
||||
for (node = pdata->path; node; node = node->next)
|
||||
for (node = pdata->path; node; node = node->next)
|
||||
{
|
||||
g_free (node->data);
|
||||
node->data = NULL;
|
||||
}
|
||||
g_slist_free (pdata->path);
|
||||
g_free (pdata);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
static QofQueryPredData *
|
||||
@@ -1209,7 +1206,7 @@ kvp_copy_predicate (QofQueryPredData *pd)
|
||||
return qof_query_kvp_predicate (pd->how, pdata->path, pdata->value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static gboolean
|
||||
kvp_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
query_kvp_t pd1 = (query_kvp_t) p1;
|
||||
@@ -1616,7 +1613,7 @@ qof_query_choice_predicate (QofGuidMatch options, GList *guid_list)
|
||||
*/
|
||||
|
||||
|
||||
static void
|
||||
static void
|
||||
qof_query_register_core_object (QofType core_name,
|
||||
QofQueryPredicateFunc pred,
|
||||
QofCompareFunc comp,
|
||||
@@ -1650,7 +1647,7 @@ qof_query_register_core_object (QofType core_name,
|
||||
static void init_tables (void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct
|
||||
struct
|
||||
{
|
||||
QofType name;
|
||||
QofQueryPredicateFunc pred;
|
||||
@@ -1659,10 +1656,10 @@ static void init_tables (void)
|
||||
QueryPredDataFree pd_free;
|
||||
QueryToString toString;
|
||||
QueryPredicateEqual pred_equal;
|
||||
} knownTypes[] =
|
||||
} knownTypes[] =
|
||||
{
|
||||
{ QOF_TYPE_STRING, string_match_predicate, string_compare_func,
|
||||
string_copy_predicate, string_free_pdata, string_to_string,
|
||||
string_copy_predicate, string_free_pdata, string_to_string,
|
||||
string_predicate_equal },
|
||||
{ QOF_TYPE_DATE, date_match_predicate, date_compare_func,
|
||||
date_copy_predicate, date_free_pdata, date_to_string,
|
||||
@@ -1701,7 +1698,7 @@ static void init_tables (void)
|
||||
};
|
||||
|
||||
/* Register the known data types */
|
||||
for (i = 0; i < (sizeof(knownTypes)/sizeof(*knownTypes)); i++)
|
||||
for (i = 0; i < (sizeof(knownTypes)/sizeof(*knownTypes)); i++)
|
||||
{
|
||||
qof_query_register_core_object (knownTypes[i].name,
|
||||
knownTypes[i].pred,
|
||||
@@ -1713,7 +1710,7 @@ static void init_tables (void)
|
||||
}
|
||||
}
|
||||
|
||||
static QueryPredicateCopyFunc
|
||||
static QueryPredicateCopyFunc
|
||||
qof_query_copy_predicate (QofType type)
|
||||
{
|
||||
QueryPredicateCopyFunc rc;
|
||||
@@ -1722,7 +1719,7 @@ qof_query_copy_predicate (QofType type)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static QueryPredDataFree
|
||||
static QueryPredDataFree
|
||||
qof_query_predicate_free (QofType type)
|
||||
{
|
||||
g_return_val_if_fail (type, NULL);
|
||||
@@ -1776,7 +1773,7 @@ qof_query_core_get_compare (QofType type)
|
||||
return g_hash_table_lookup (cmpTable, type);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
qof_query_core_predicate_free (QofQueryPredData *pdata)
|
||||
{
|
||||
QueryPredDataFree free_fcn;
|
||||
@@ -1800,7 +1797,7 @@ qof_query_core_predicate_copy (QofQueryPredData *pdata)
|
||||
return (copy (pdata));
|
||||
}
|
||||
|
||||
char *
|
||||
char *
|
||||
qof_query_core_to_string (QofType type, gpointer object,
|
||||
QofParam *getter)
|
||||
{
|
||||
@@ -1816,7 +1813,7 @@ qof_query_core_to_string (QofType type, gpointer object,
|
||||
return toString (object, getter);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gboolean
|
||||
qof_query_core_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
|
||||
{
|
||||
QueryPredicateEqual pred_equal;
|
||||
|
@@ -23,7 +23,7 @@
|
||||
|
||||
/** @addtogroup Query
|
||||
@{ */
|
||||
|
||||
|
||||
/** @file qofquerycore.h
|
||||
@brief API for providing core Query data types
|
||||
@author Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
|
||||
@@ -42,7 +42,7 @@
|
||||
/**
|
||||
* PREDICATE DATA TYPES: All the predicate data types are rolled up into
|
||||
* the union type PredicateData. The "type" field specifies which type
|
||||
* the union is.
|
||||
* the union is.
|
||||
*/
|
||||
typedef struct _QofQueryPredData QofQueryPredData;
|
||||
|
||||
@@ -58,7 +58,7 @@ typedef enum {
|
||||
QOF_COMPARE_NEQ
|
||||
} QofQueryCompare;
|
||||
|
||||
/** List of known core query data-types...
|
||||
/** List of known core query data-types...
|
||||
* Each core query type defines it's set of optional "comparitor qualifiers".
|
||||
*/
|
||||
/* Comparisons for QOF_TYPE_STRING */
|
||||
@@ -67,15 +67,13 @@ typedef enum {
|
||||
QOF_STRING_MATCH_CASEINSENSITIVE
|
||||
} QofStringMatch;
|
||||
|
||||
/** Comparisons for QOF_TYPE_DATE
|
||||
/** Comparisons for QOF_TYPE_DATE
|
||||
* The QOF_DATE_MATCH_DAY comparison rounds the two time
|
||||
* values to mid-day and then compares these rounded values.
|
||||
* The QOF_DATE_MATCH_NORMAL comparison matches the time values,
|
||||
* down to the second.
|
||||
*/
|
||||
/* XXX remove these deprecated old names .. */
|
||||
//#define QOF_DATE_MATCH_ROUNDED QOF_DATE_MATCH_DAY
|
||||
//#define QOF_DATE_MATCH_NORMAL QOF_DATE_MATCH_TIME
|
||||
|
||||
typedef enum {
|
||||
QOF_DATE_MATCH_NORMAL = 1,
|
||||
QOF_DATE_MATCH_DAY
|
||||
@@ -83,11 +81,11 @@ typedef enum {
|
||||
|
||||
/** Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED
|
||||
*
|
||||
* XXX Should be deprecated, or at least wrapped up as a convnience
|
||||
* function, this is based on the old bill gribble code, which assumed
|
||||
* the amount was always positive, and then specified a funds-flow
|
||||
* XXX Should be deprecated, or at least wrapped up as a convenience
|
||||
* function, this is based on the old bill gribble code, which assumed
|
||||
* the amount was always positive, and then specified a funds-flow
|
||||
* direction (credit, debit, or either).
|
||||
*
|
||||
*
|
||||
* The point being that 'match credit' is equivalent to the compound
|
||||
* predicate (amount >= 0) && (amount 'op' value) while the 'match
|
||||
* debit' predicate is equivalent to (amount <= 0) && (abs(amount) 'op' value)
|
||||
@@ -101,7 +99,7 @@ typedef enum {
|
||||
|
||||
/* Comparisons for QOF_TYPE_GUID */
|
||||
typedef enum {
|
||||
/** These expect a single object and expect the
|
||||
/** These expect a single object and expect the
|
||||
* QofAccessFunc returns GUID* */
|
||||
QOF_GUID_MATCH_ANY = 1,
|
||||
QOF_GUID_MATCH_NONE,
|
||||
@@ -114,12 +112,12 @@ typedef enum {
|
||||
QOF_GUID_MATCH_LIST_ANY,
|
||||
} QofGuidMatch;
|
||||
|
||||
/** A CHAR type is for a RECNCell, Comparisons for QOF_TYPE_CHAR
|
||||
/** A CHAR type is for a RECNCell, Comparisons for QOF_TYPE_CHAR
|
||||
* 'ANY' will match any charagter in the string.
|
||||
*
|
||||
* Match 'ANY' is a convenience/performance-enhanced predicate
|
||||
* Match 'ANY' is a convenience/performance-enhanced predicate
|
||||
* for the compound statement (value==char1) || (value==char2) || etc.
|
||||
* Match 'NONE' is equivalent to
|
||||
* Match 'NONE' is equivalent to
|
||||
* (value != char1) && (value != char2) && etc.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -138,15 +136,15 @@ struct _QofQueryPredData {
|
||||
};
|
||||
|
||||
|
||||
/** @name Core Data Type Predicates
|
||||
/** @name Core Data Type Predicates
|
||||
@{ */
|
||||
QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
|
||||
QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
|
||||
const char *str,
|
||||
QofStringMatch options,
|
||||
gboolean is_regex);
|
||||
|
||||
QofQueryPredData *qof_query_date_predicate (QofQueryCompare how,
|
||||
QofDateMatch options,
|
||||
QofDateMatch options,
|
||||
Timespec date);
|
||||
|
||||
QofQueryPredData *qof_query_numeric_predicate (QofQueryCompare how,
|
||||
@@ -169,13 +167,13 @@ QofQueryPredData *qof_query_choice_predicate (QofGuidMatch options, GList *guid
|
||||
* sense, the 'path' is handled as if it were a paramter.
|
||||
*/
|
||||
QofQueryPredData *qof_query_kvp_predicate (QofQueryCompare how,
|
||||
GSList *path,
|
||||
GSList *path,
|
||||
const KvpValue *value);
|
||||
|
||||
/** Same predicate as above, except that 'path' is assumed to be
|
||||
/** Same predicate as above, except that 'path' is assumed to be
|
||||
* a string containing slash-separated pathname. */
|
||||
QofQueryPredData *qof_query_kvp_predicate_path (QofQueryCompare how,
|
||||
const char *path,
|
||||
const char *path,
|
||||
const KvpValue *value);
|
||||
|
||||
/** Copy a predicate. */
|
||||
|
@@ -41,17 +41,11 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include "qofla-dir.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-event.h"
|
||||
#include "qofsession.h"
|
||||
#include "qof.h"
|
||||
#include "qofbackend-p.h"
|
||||
#include "qof-be-utils.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofbook-p.h"
|
||||
#include "qofobject.h"
|
||||
#include "qofsession-p.h"
|
||||
#include "qofobject-p.h"
|
||||
|
||||
/** \deprecated should not be static */
|
||||
static QofSession * current_session = NULL;
|
||||
@@ -325,7 +319,7 @@ qof_book_set_partial(QofBook *book)
|
||||
partial =
|
||||
(gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
|
||||
if(!partial) {
|
||||
qof_book_set_data(book, PARTIAL_QOFBOOK, (gboolean*)TRUE);
|
||||
qof_book_set_data(book, PARTIAL_QOFBOOK, GINT_TO_POINTER(TRUE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,8 +344,13 @@ qof_entity_param_cb(QofParam *param, gpointer data)
|
||||
g_return_if_fail(data != NULL);
|
||||
qecd = (QofEntityCopyData*)data;
|
||||
g_return_if_fail(param != NULL);
|
||||
/* KVP doesn't need a set routine to be copied. */
|
||||
if(0 == safe_strcmp(param->param_type, QOF_TYPE_KVP)) {
|
||||
qecd->param_list = g_slist_prepend(qecd->param_list, param);
|
||||
return;
|
||||
}
|
||||
if((param->param_getfcn != NULL)&&(param->param_setfcn != NULL)) {
|
||||
qecd->param_list = g_slist_prepend(qecd->param_list, param);
|
||||
qecd->param_list = g_slist_prepend(qecd->param_list, param);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,10 +476,18 @@ qof_entity_foreach_copy(gpointer data, gpointer user_data)
|
||||
if(boolean_setter != NULL) { boolean_setter(targetEnt, cm_boolean); }
|
||||
registered_type = TRUE;
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) {
|
||||
cm_kvp = kvp_frame_copy((KvpFrame*)cm_param->param_getfcn(importEnt,cm_param));
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) {
|
||||
cm_kvp = (KvpFrame*)cm_param->param_getfcn(importEnt,cm_param);
|
||||
kvp_frame_setter = (void(*)(QofEntity*, KvpFrame*))cm_param->param_setfcn;
|
||||
if(kvp_frame_setter != NULL) { kvp_frame_setter(targetEnt, cm_kvp); }
|
||||
else
|
||||
{
|
||||
QofInstance *target_inst;
|
||||
|
||||
target_inst = (QofInstance*)targetEnt;
|
||||
kvp_frame_delete(target_inst->kvp_data);
|
||||
target_inst->kvp_data = kvp_frame_copy(cm_kvp);
|
||||
}
|
||||
registered_type = TRUE;
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_CHAR) == 0) {
|
||||
@@ -535,8 +542,19 @@ qof_entity_list_foreach(gpointer data, gpointer user_data)
|
||||
qecd = (QofEntityCopyData*)user_data;
|
||||
if(qof_entity_guid_match(qecd->new_session, original)) { return; }
|
||||
qecd->from = original;
|
||||
if(!qof_object_compliance(original->e_type, FALSE))
|
||||
{
|
||||
qecd->error = TRUE;
|
||||
return;
|
||||
}
|
||||
book = qof_session_get_book(qecd->new_session);
|
||||
inst = (QofInstance*)qof_object_new_instance(original->e_type, book);
|
||||
if(!inst)
|
||||
{
|
||||
PERR (" failed to create new entity type=%s.", original->e_type);
|
||||
qecd->error = TRUE;
|
||||
return;
|
||||
}
|
||||
qecd->to = &inst->entity;
|
||||
g = qof_entity_get_guid(original);
|
||||
qof_entity_set_guid(qecd->to, g);
|
||||
@@ -580,6 +598,7 @@ qof_entity_coll_copy(QofEntity *original, gpointer user_data)
|
||||
g_return_if_fail(user_data != NULL);
|
||||
qecd = (QofEntityCopyData*)user_data;
|
||||
book = qof_session_get_book(qecd->new_session);
|
||||
if(!qof_object_compliance(original->e_type, TRUE)) { return; }
|
||||
inst = (QofInstance*)qof_object_new_instance(original->e_type, book);
|
||||
qecd->to = &inst->entity;
|
||||
qecd->from = original;
|
||||
@@ -590,7 +609,8 @@ qof_entity_coll_copy(QofEntity *original, gpointer user_data)
|
||||
qof_commit_edit(inst);
|
||||
}
|
||||
|
||||
gboolean qof_entity_copy_to_session(QofSession* new_session, QofEntity* original)
|
||||
gboolean
|
||||
qof_entity_copy_to_session(QofSession* new_session, QofEntity* original)
|
||||
{
|
||||
QofEntityCopyData qecd;
|
||||
QofInstance *inst;
|
||||
@@ -598,6 +618,7 @@ gboolean qof_entity_copy_to_session(QofSession* new_session, QofEntity* original
|
||||
|
||||
if(!new_session || !original) { return FALSE; }
|
||||
if(qof_entity_guid_match(new_session, original)) { return FALSE; }
|
||||
if(!qof_object_compliance(original->e_type, TRUE)) { return FALSE; }
|
||||
gnc_engine_suspend_events();
|
||||
qecd.param_list = NULL;
|
||||
book = qof_session_get_book(new_session);
|
||||
@@ -630,12 +651,17 @@ gboolean qof_entity_copy_list(QofSession *new_session, GList *entity_list)
|
||||
qof_book_set_partial(qof_session_get_book(new_session));
|
||||
g_list_foreach(entity_list, qof_entity_list_foreach, qecd);
|
||||
gnc_engine_resume_events();
|
||||
if(qecd->error)
|
||||
{
|
||||
PWARN (" some/all entities in the list could not be copied.");
|
||||
}
|
||||
g_free(qecd);
|
||||
LEAVE (" ");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean qof_entity_copy_coll(QofSession *new_session, QofCollection *entity_coll)
|
||||
gboolean
|
||||
qof_entity_copy_coll(QofSession *new_session, QofCollection *entity_coll)
|
||||
{
|
||||
QofEntityCopyData qecd;
|
||||
|
||||
@@ -644,7 +670,8 @@ gboolean qof_entity_copy_coll(QofSession *new_session, QofCollection *entity_col
|
||||
qecd.new_session = new_session;
|
||||
qof_book_set_partial(qof_session_get_book(qecd.new_session));
|
||||
qof_collection_foreach(entity_coll, qof_entity_coll_foreach, &qecd);
|
||||
qof_class_param_foreach(qof_collection_get_type(entity_coll), qof_entity_param_cb, &qecd);
|
||||
qof_class_param_foreach(qof_collection_get_type(entity_coll),
|
||||
qof_entity_param_cb, &qecd);
|
||||
qof_collection_foreach(entity_coll, qof_entity_coll_copy, &qecd);
|
||||
if(qecd.param_list != NULL) { g_slist_free(qecd.param_list); }
|
||||
gnc_engine_resume_events();
|
||||
@@ -789,7 +816,7 @@ gboolean qof_entity_copy_one_r(QofSession *new_session, QofEntity *ent)
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* Programs that use their own backends also need to call
|
||||
/** Programs that use their own backends also need to call
|
||||
the default QOF ones. The backends specified here are
|
||||
loaded only by applications that do not have their own. */
|
||||
struct backend_providers
|
||||
@@ -802,11 +829,11 @@ struct backend_providers
|
||||
/* All available QOF backends need to be described here
|
||||
and the last entry must be three NULL's.
|
||||
Remember: Use the libdir from the current build environment
|
||||
and use the .la NOT the .so - .so is not portable! */
|
||||
and use JUST the module name without .so - .so is not portable! */
|
||||
struct backend_providers backend_list[] = {
|
||||
{ QOF_LIB_DIR, "libqof-backend-qsf.la", "qsf_provider_init" },
|
||||
{ QOF_LIB_DIR, QSF_BACKEND_LIB, QSF_MODULE_INIT },
|
||||
#ifdef HAVE_DWI
|
||||
{ QOF_LIB_DIR, "libqof_backend_dwi.la", "dwiend_provider_init" },
|
||||
{ QOF_LIB_DIR, "libqof_backend_dwi", "dwiend_provider_init" },
|
||||
#endif
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
@@ -59,7 +59,7 @@
|
||||
* to and open this datastore?
|
||||
*
|
||||
* A brief note about books & sessions:
|
||||
* A book encapsulates the datasets manipulated by GnuCash. A book
|
||||
* A book encapsulates the datasets manipulated by QOF. A book
|
||||
* holds the actual data. By contrast, the session mediates the
|
||||
* connection between a book (the thing that lives in virtual memory
|
||||
* in the local process) and the datastore (the place where book
|
||||
@@ -75,6 +75,8 @@
|
||||
* make that assumption, in order to store the different accounting
|
||||
* periods in a clump so that one can be found, given another.
|
||||
*
|
||||
If you want multiple books that are unrelated to each other,
|
||||
use multiple sessions.
|
||||
|
||||
The session now calls QofBackendProvider->check_data_type
|
||||
to check that the incoming path contains data that the
|
||||
@@ -119,21 +121,12 @@ void qof_session_swap_data (QofSession *session_1, QofSession *session_2);
|
||||
|
||||
/** The qof_session_begin () method begins a new session.
|
||||
* It takes as an argument the book id. The book id must be a string
|
||||
* in the form of a URI/URL.
|
||||
* In the current implementation, the following URL's are supported
|
||||
* -- File URI of the form
|
||||
* "file:/home/somewhere/somedir/file.xac"
|
||||
* The path part must be a valid path. The file-part must be
|
||||
* a valid old-style-xacc or new-style-gnucash-format file. Paths
|
||||
* may be relative or absolute. If the path is relative; that is,
|
||||
* if the argument is "file:somefile.xac" then a sequence of
|
||||
* search paths are checked for a file of this name.
|
||||
*
|
||||
* -- Postgres URI of the form
|
||||
* "postgres://hostname.com/dbname"
|
||||
* See the src/backend/postgres subdirectory for more info.
|
||||
*
|
||||
* -- RPC URI of the form rpc://hostname.com/rpcserver.
|
||||
* in the form of a URI/URL. The access method specified depends
|
||||
* on the loaded backends. In the absence of a customised backend,
|
||||
* only QSF XML would be accepted). Paths may be relative or absolute.
|
||||
* If the path is relative; that is, if the argument is "file:somefile.xml"
|
||||
* then the current working directory is assumed. Customised backends can
|
||||
* choose to search other, application-specific, directories as well.
|
||||
*
|
||||
* The 'ignore_lock' argument, if set to TRUE, will cause this routine
|
||||
* to ignore any global-datastore locks (e.g. file locks) that it finds.
|
||||
@@ -216,7 +209,7 @@ QofBook * qof_session_get_book (QofSession *session);
|
||||
* filepath is derived from the url by substituting commas for
|
||||
* slashes).
|
||||
*
|
||||
* The qof_session_get_url() routine returns the url that was opened.
|
||||
* The qof_session_get_url() routine returns the url that was opened.
|
||||
* URL's for local files take the form of
|
||||
* file:/some/where/some/file.gml
|
||||
*/
|
||||
@@ -243,7 +236,7 @@ void qof_session_save (QofSession *session,
|
||||
QofPercentageFunc percentage_func);
|
||||
/**
|
||||
* The qof_session_end() method will release the session lock. For the
|
||||
* file backend, it will *not* save the account group to a file. Thus,
|
||||
* file backend, it will *not* save the data to a file. Thus,
|
||||
* this method acts as an "abort" or "rollback" primitive. However,
|
||||
* for other backends, such as the sql backend, the data would have
|
||||
* been written out before this, and so this routines wouldn't
|
||||
@@ -347,9 +340,7 @@ no support for handling collisions - instead, use \ref BookMerge
|
||||
Objects can be defined solely in terms of QOF data types or
|
||||
as a mix of data types and other objects, which may in turn
|
||||
include other objects. These references can be copied recursively
|
||||
down to the third level. e.g. ::GncInvoice refers to ::GncOwner which
|
||||
refers to ::GncCustomer which refers to ::GncAddress. See
|
||||
::QofEntityReference.
|
||||
down to the third level. See ::QofEntityReference.
|
||||
|
||||
\note This is a deep recursive copy - every referenced entity is copied
|
||||
to the new session, including all parameters. The starting point is all
|
||||
@@ -402,12 +393,12 @@ QofIdType and GUID so that when the book is written out, the
|
||||
reference can be included. See ::qof_book_get_data.
|
||||
|
||||
When the file is imported back in, the list needs to be rebuilt.
|
||||
The QSF backend rebuilds the references by linking to real entities. Other
|
||||
backends can process the hash table in similar ways.
|
||||
The QSF backend rebuilds the references by linking to real entities.
|
||||
Other backends can process the hash table in similar ways.
|
||||
|
||||
The list stores the QofEntityReference to the referenced entity -
|
||||
a struct that contains the GUID and the QofIdType of the referenced entity
|
||||
as well as the parameter used to obtain the reference.
|
||||
a struct that contains the GUID and the QofIdType of the referenced
|
||||
entity as well as the parameter used to obtain the reference.
|
||||
|
||||
Partial books need to be differentiated in the backend, the
|
||||
flag in the book data is used by qof_session_save to prevent a partial
|
||||
@@ -425,8 +416,8 @@ repeated references for a single entity.
|
||||
*/
|
||||
typedef struct qof_entity_reference {
|
||||
QofIdType choice_type;/**< When the reference is a different type.*/
|
||||
QofIdType type; /**< The type of entity */
|
||||
GUID *ref_guid; /**< The GUID of the REFERENCE entity */
|
||||
QofIdType type; /**< The type of entity */
|
||||
GUID *ref_guid; /**< The GUID of the REFERENCE entity */
|
||||
const QofParam *param; /**< The parameter name and type. */
|
||||
const GUID *ent_guid; /**< The GUID of the original entity. */
|
||||
}QofEntityReference;
|
||||
@@ -465,7 +456,8 @@ qof_entity_get_reference_from(QofEntity *ent, const QofParam *param);
|
||||
|
||||
Retrieves any existing reference list and appends the new reference.
|
||||
|
||||
If the book is not already marked as partial, it will be marked as partial.
|
||||
If the book is not already marked as partial, it will be marked as
|
||||
partial.
|
||||
*/
|
||||
void
|
||||
qof_session_update_reference_list(QofSession *session, QofEntityReference *reference);
|
||||
@@ -512,34 +504,19 @@ backends may return a ::QofBackendError.
|
||||
/** @name Event Handling
|
||||
|
||||
@{ */
|
||||
/** The qof_session_events_pending() method will return TRUE if the backend
|
||||
* has pending events which must be processed to bring the engine
|
||||
* up to date with the backend.
|
||||
/** The qof_session_events_pending() method will return TRUE if the
|
||||
* backend has pending events which must be processed to bring
|
||||
* the engine up to date with the backend.
|
||||
*/
|
||||
gboolean qof_session_events_pending (QofSession *session);
|
||||
|
||||
/** The qof_session_process_events() method will process any events indicated
|
||||
* by the qof_session_events_pending() method. It returns TRUE if the
|
||||
* engine was modified while engine events were suspended.
|
||||
/** The qof_session_process_events() method will process any events
|
||||
* indicated by the qof_session_events_pending() method. It returns
|
||||
* TRUE if the engine was modified while engine events were suspended.
|
||||
*/
|
||||
gboolean qof_session_process_events (QofSession *session);
|
||||
/** @} */
|
||||
|
||||
#ifdef GNUCASH_MAJOR_VERSION
|
||||
/** Run the RPC Server
|
||||
* @deprecated will go away */
|
||||
void gnc_run_rpc_server (void);
|
||||
|
||||
/** XXX session_export really doesn't belong here .
|
||||
* This functino exports the list of accounts to a file. Its a stop-gap
|
||||
* measure until full book-closing is implemented.
|
||||
*/
|
||||
gboolean qof_session_export (QofSession *tmp_session,
|
||||
QofSession *real_session,
|
||||
QofPercentageFunc percentage_func);
|
||||
|
||||
#endif /* GNUCASH_MAJOR_VERSION */
|
||||
|
||||
/** Register a function to be called just before a session is closed.
|
||||
*
|
||||
* @param fn The function to be called. The function definition must
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
/**
|
||||
@file qofsql.c
|
||||
@brief QOF client-side SQL parser.
|
||||
@brief QOF client-side SQL parser - interfaces with libgda.
|
||||
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
|
||||
*/
|
||||
@@ -38,18 +38,8 @@
|
||||
#include "sql_parser.h"
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include "kvp_frame.h"
|
||||
#include "gnc-date.h"
|
||||
#include "gnc-numeric.h"
|
||||
#include "gnc-trace.h"
|
||||
#include "guid.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofquery.h"
|
||||
#include "qofquerycore.h"
|
||||
#include "qofsql.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "qofinstance-p.h"
|
||||
#include "qofobject.h"
|
||||
|
||||
#include "qof.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QUERY;
|
||||
|
||||
@@ -72,7 +62,7 @@ QofSqlQuery *
|
||||
qof_sql_query_new(void)
|
||||
{
|
||||
QofSqlQuery * sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
|
||||
|
||||
|
||||
sqn->qof_query = NULL;
|
||||
sqn->parse_result = NULL;
|
||||
sqn->book = NULL;
|
||||
@@ -171,7 +161,7 @@ handle_single_condition (QofSqlQuery *query, sql_condition * cond)
|
||||
Timespec ts;
|
||||
QofType param_type;
|
||||
QofGuidMatch gm;
|
||||
|
||||
|
||||
pred_data = NULL;
|
||||
if (NULL == cond)
|
||||
{
|
||||
@@ -484,7 +474,7 @@ handle_where (QofSqlQuery *query, sql_where *swear)
|
||||
{
|
||||
QofQueryOp qop;
|
||||
QofQuery * qq;
|
||||
|
||||
|
||||
switch (swear->type)
|
||||
{
|
||||
case SQL_pair:
|
||||
@@ -536,7 +526,7 @@ handle_sort_order (QofSqlQuery *query, GList *sorder_list)
|
||||
int i;
|
||||
sql_order_field *sorder;
|
||||
char * qparam_name;
|
||||
|
||||
|
||||
if (!sorder_list) return;
|
||||
|
||||
for (i=0; i<3; i++)
|
||||
@@ -576,79 +566,15 @@ handle_sort_order (QofSqlQuery *query, GList *sorder_list)
|
||||
direction[1], direction[2]);
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
static void
|
||||
qof_queryForeachParam( QofParam* param, gpointer user_data)
|
||||
{
|
||||
QofSqlQuery *q;
|
||||
|
||||
g_return_if_fail(user_data != NULL);
|
||||
q = (QofSqlQuery*)user_data;
|
||||
g_return_if_fail(param != NULL);
|
||||
if((param->param_getfcn != NULL)&&(param->param_setfcn != NULL)) {
|
||||
q->param_list = g_list_append(q->param_list, param);
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
qof_sql_get_value(sql_insert_statement *insert)
|
||||
{
|
||||
GList *walk, *cur;
|
||||
const char *insert_string;
|
||||
sql_field *field;
|
||||
sql_field_item * item;
|
||||
|
||||
/* how to cope with multiple results? */
|
||||
if (insert->values == NULL) { return NULL; }
|
||||
insert_string = NULL;
|
||||
for (walk = insert->values; walk != NULL; walk = walk->next)
|
||||
{
|
||||
field = walk->data;
|
||||
item = field->item;
|
||||
for (cur = item->d.name; cur != NULL; cur = cur->next)
|
||||
{
|
||||
insert_string = g_strdup_printf("%s", (char*)cur->data);
|
||||
}
|
||||
}
|
||||
return insert_string;
|
||||
}
|
||||
|
||||
static const QofParam*
|
||||
qof_sql_get_param(QofIdTypeConst type, sql_insert_statement *insert)
|
||||
{
|
||||
GList *walk, *cur;
|
||||
const char *param_name;
|
||||
const QofParam *param;
|
||||
sql_field *field;
|
||||
sql_field_item *item;
|
||||
|
||||
param = NULL;
|
||||
param_name = NULL;
|
||||
if (insert->fields == NULL) { return NULL; }
|
||||
for (walk = insert->fields; walk != NULL; walk = walk->next)
|
||||
{
|
||||
field = walk->data;
|
||||
item = field->item;
|
||||
for (cur = item->d.name; cur != NULL; cur = cur->next)
|
||||
{
|
||||
param_name = g_strdup_printf("%s", (char*)cur->data);
|
||||
}
|
||||
}
|
||||
param = qof_class_get_parameter(type, param_name);
|
||||
return param;
|
||||
}
|
||||
/* INSERT INTO handlers =================================================== */
|
||||
|
||||
static void
|
||||
qof_sql_insertCB( gpointer value, gpointer data)
|
||||
qof_sql_insertCB(const QofParam *param, const gchar *insert_string, QofSqlQuery *query)
|
||||
{
|
||||
GList *param_list;
|
||||
QofSqlQuery *q;
|
||||
QofIdTypeConst type;
|
||||
sql_insert_statement *sis;
|
||||
const char *insert_string;
|
||||
gboolean registered_type;
|
||||
QofEntity *ent;
|
||||
QofParam *param;
|
||||
struct tm query_time;
|
||||
time_t query_time_t;
|
||||
/* cm_ prefix used for variables that hold the data to commit */
|
||||
@@ -663,7 +589,6 @@ qof_sql_insertCB( gpointer value, gpointer data)
|
||||
/* KvpFrame *cm_kvp;
|
||||
KvpValue *cm_value;
|
||||
KvpValueType cm_type;*/
|
||||
const QofParam *cm_param;
|
||||
void (*string_setter) (QofEntity*, const char*);
|
||||
void (*date_setter) (QofEntity*, Timespec);
|
||||
void (*numeric_setter) (QofEntity*, gnc_numeric);
|
||||
@@ -674,126 +599,186 @@ qof_sql_insertCB( gpointer value, gpointer data)
|
||||
void (*char_setter) (QofEntity*, char);
|
||||
/* void (*kvp_frame_setter) (QofEntity*, KvpFrame*);*/
|
||||
|
||||
q = (QofSqlQuery*)data;
|
||||
ent = q->inserted_entity;
|
||||
param = (QofParam*)value;
|
||||
sis = q->parse_result->statement;
|
||||
g_return_if_fail(param || insert_string || query);
|
||||
ent = query->inserted_entity;
|
||||
sis = query->parse_result->statement;
|
||||
type = g_strdup_printf("%s", sis->table->d.simple);
|
||||
insert_string = g_strdup(qof_sql_get_value(sis));
|
||||
cm_param = qof_sql_get_param(type, sis);
|
||||
param_list = g_list_copy(q->param_list);
|
||||
while(param_list != NULL) {
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_STRING) == 0) {
|
||||
string_setter = (void(*)(QofEntity*, const char*))cm_param->param_setfcn;
|
||||
if(string_setter != NULL) { string_setter(ent, insert_string); }
|
||||
registered_type = TRUE;
|
||||
|
||||
ENTER (" param=%s param_type=%s type=%s content=%s",
|
||||
param->param_name, param->param_type, type, insert_string);
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_STRING) == 0) {
|
||||
string_setter = (void(*)(QofEntity*, const char*))param->param_setfcn;
|
||||
if(string_setter != NULL) { string_setter(ent, insert_string); }
|
||||
registered_type = TRUE;
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_DATE) == 0) {
|
||||
date_setter = (void(*)(QofEntity*, Timespec))param->param_setfcn;
|
||||
strptime(insert_string, QOF_UTC_DATE_FORMAT, &query_time);
|
||||
query_time_t = mktime(&query_time);
|
||||
timespecFromTime_t(&cm_date, query_time_t);
|
||||
if(date_setter != NULL) { date_setter(ent, cm_date); }
|
||||
}
|
||||
if((safe_strcmp(param->param_type, QOF_TYPE_NUMERIC) == 0) ||
|
||||
(safe_strcmp(param->param_type, QOF_TYPE_DEBCRED) == 0)) {
|
||||
numeric_setter = (void(*)(QofEntity*, gnc_numeric))param->param_setfcn;
|
||||
string_to_gnc_numeric(insert_string, &cm_numeric);
|
||||
if(numeric_setter != NULL) { numeric_setter(ent, cm_numeric); }
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_GUID) == 0) {
|
||||
cm_guid = g_new(GUID, 1);
|
||||
if(TRUE != string_to_guid(insert_string, cm_guid))
|
||||
{
|
||||
LEAVE (" string to guid failed for %s", insert_string);
|
||||
return;
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_DATE) == 0) {
|
||||
date_setter = (void(*)(QofEntity*, Timespec))cm_param->param_setfcn;
|
||||
strptime(insert_string, QOF_UTC_DATE_FORMAT, &query_time);
|
||||
query_time_t = mktime(&query_time);
|
||||
timespecFromTime_t(&cm_date, query_time_t);
|
||||
if(date_setter != NULL) { date_setter(ent, cm_date); }
|
||||
}
|
||||
if((safe_strcmp(cm_param->param_type, QOF_TYPE_NUMERIC) == 0) ||
|
||||
(safe_strcmp(cm_param->param_type, QOF_TYPE_DEBCRED) == 0)) {
|
||||
numeric_setter = (void(*)(QofEntity*, gnc_numeric))cm_param->param_setfcn;
|
||||
string_to_gnc_numeric(insert_string, &cm_numeric);
|
||||
if(numeric_setter != NULL) { numeric_setter(ent, cm_numeric); }
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_GUID) == 0) {
|
||||
cm_guid = g_new(GUID, 1);
|
||||
if(TRUE != string_to_guid(insert_string, cm_guid))
|
||||
{
|
||||
LEAVE (" string to guid failed for %s", insert_string);
|
||||
return;
|
||||
}
|
||||
/* reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
|
||||
if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
|
||||
{
|
||||
qof_entity_set_guid(qsf_ent, cm_guid);
|
||||
}
|
||||
else {
|
||||
reference = qof_entity_get_reference_from(qsf_ent, cm_param);
|
||||
if(reference) {
|
||||
params->referenceList = g_list_append(params->referenceList, reference);
|
||||
}
|
||||
}*/
|
||||
if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
|
||||
{
|
||||
qof_entity_set_guid(qsf_ent, cm_guid);
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_INT32) == 0) {
|
||||
errno = 0;
|
||||
cm_i32 = (gint32)strtol (insert_string, &tail, 0);
|
||||
if(errno == 0) {
|
||||
i32_setter = (void(*)(QofEntity*, gint32))cm_param->param_setfcn;
|
||||
if(i32_setter != NULL) { i32_setter(ent, cm_i32); }
|
||||
else {
|
||||
reference = qof_entity_get_reference_from(qsf_ent, cm_param);
|
||||
if(reference) {
|
||||
params->referenceList = g_list_append(params->referenceList, reference);
|
||||
}
|
||||
// else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
|
||||
}*/
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_INT32) == 0) {
|
||||
errno = 0;
|
||||
cm_i32 = (gint32)strtol (insert_string, &tail, 0);
|
||||
if(errno == 0) {
|
||||
i32_setter = (void(*)(QofEntity*, gint32))param->param_setfcn;
|
||||
if(i32_setter != NULL) { i32_setter(ent, cm_i32); }
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_INT64) == 0) {
|
||||
errno = 0;
|
||||
cm_i64 = strtoll(insert_string, &tail, 0);
|
||||
if(errno == 0) {
|
||||
i64_setter = (void(*)(QofEntity*, gint64))cm_param->param_setfcn;
|
||||
if(i64_setter != NULL) { i64_setter(ent, cm_i64); }
|
||||
}
|
||||
// else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
|
||||
else
|
||||
{
|
||||
QofBackend *backend;
|
||||
QofBook *book;
|
||||
|
||||
book = qof_instance_get_book((QofInstance*)ent);
|
||||
backend = qof_book_get_backend(book);
|
||||
qof_backend_set_error(backend, ERR_QSF_OVERFLOW);
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_DOUBLE) == 0) {
|
||||
errno = 0;
|
||||
cm_double = strtod(insert_string, &tail);
|
||||
if(errno == 0) {
|
||||
double_setter = (void(*)(QofEntity*, double))cm_param->param_setfcn;
|
||||
if(double_setter != NULL) { double_setter(ent, cm_double); }
|
||||
}
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_INT64) == 0) {
|
||||
errno = 0;
|
||||
cm_i64 = strtoll(insert_string, &tail, 0);
|
||||
if(errno == 0) {
|
||||
i64_setter = (void(*)(QofEntity*, gint64))param->param_setfcn;
|
||||
if(i64_setter != NULL) { i64_setter(ent, cm_i64); }
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_BOOLEAN) == 0){
|
||||
if(0 == safe_strcmp(insert_string, "TRUE")) {
|
||||
cm_boolean = TRUE;
|
||||
}
|
||||
else { cm_boolean = FALSE; }
|
||||
boolean_setter = (void(*)(QofEntity*, gboolean))cm_param->param_setfcn;
|
||||
if(boolean_setter != NULL) { boolean_setter(ent, cm_boolean); }
|
||||
else
|
||||
{
|
||||
QofBackend *backend;
|
||||
QofBook *book;
|
||||
|
||||
book = qof_instance_get_book((QofInstance*)ent);
|
||||
backend = qof_book_get_backend(book);
|
||||
qof_backend_set_error(backend, ERR_QSF_OVERFLOW);
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) {
|
||||
|
||||
}
|
||||
if(safe_strcmp(cm_param->param_type, QOF_TYPE_CHAR) == 0) {
|
||||
cm_char = *insert_string;
|
||||
char_setter = (void(*)(QofEntity*, char))cm_param->param_setfcn;
|
||||
if(char_setter != NULL) { char_setter(ent, cm_char); }
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_DOUBLE) == 0) {
|
||||
errno = 0;
|
||||
cm_double = strtod(insert_string, &tail);
|
||||
if(errno == 0) {
|
||||
double_setter = (void(*)(QofEntity*, double))param->param_setfcn;
|
||||
if(double_setter != NULL) { double_setter(ent, cm_double); }
|
||||
}
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN) == 0) {
|
||||
gint b;
|
||||
b = qof_util_bool_to_int(insert_string);
|
||||
if(b == 1) {
|
||||
cm_boolean = TRUE;
|
||||
}
|
||||
else { cm_boolean = FALSE; }
|
||||
boolean_setter = (void(*)(QofEntity*, gboolean))param->param_setfcn;
|
||||
if(boolean_setter != NULL) { boolean_setter(ent, cm_boolean); }
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_KVP) == 0) {
|
||||
|
||||
}
|
||||
if(safe_strcmp(param->param_type, QOF_TYPE_CHAR) == 0) {
|
||||
cm_char = *insert_string;
|
||||
char_setter = (void(*)(QofEntity*, char))param->param_setfcn;
|
||||
if(char_setter != NULL) { char_setter(ent, cm_char); }
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static void
|
||||
qof_query_set_insert_table(QofSqlQuery *query)
|
||||
{
|
||||
sql_insert_statement *sis;
|
||||
sql_table *sis_t;
|
||||
sis = query->parse_result->statement;
|
||||
switch(sis->table->type) {
|
||||
case SQL_simple: {
|
||||
sis_t = sis->table;
|
||||
query->single_global_tablename = g_strdup_printf("%s", sis_t->d.simple);
|
||||
qof_query_search_for (query->qof_query, query->single_global_tablename);
|
||||
PINFO (" insert set to table: %s", sis_t->d.simple);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PWARN ("SQL insert only handles simple statements");
|
||||
}
|
||||
param_list = param_list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static QofEntity*
|
||||
qof_query_insert(QofSqlQuery *query)
|
||||
{
|
||||
GList *field_list, *value_list, *cur;
|
||||
const gchar *param_name;
|
||||
gchar *value;
|
||||
QofIdType type;
|
||||
const QofParam *param;
|
||||
QofInstance *inst;
|
||||
sql_insert_statement *sis;
|
||||
sql_table *sis_t;
|
||||
sql_field *field;
|
||||
sql_field_item *item;
|
||||
|
||||
ENTER (" ");
|
||||
query->param_list = NULL;
|
||||
type = NULL;
|
||||
param = NULL;
|
||||
value = NULL;
|
||||
field_list = NULL;
|
||||
value_list = NULL;
|
||||
param_name = NULL;
|
||||
sis = query->parse_result->statement;
|
||||
switch(sis->table->type) {
|
||||
case SQL_simple: {
|
||||
sis_t = sis->table;
|
||||
query->single_global_tablename = g_strdup_printf("%s", sis_t->d.simple);
|
||||
type = g_strdup(query->single_global_tablename);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "default");
|
||||
}
|
||||
}
|
||||
if (!sis->fields || !sis->values) { LEAVE (" NULL insert statement"); return NULL; }
|
||||
type = g_strdup(query->single_global_tablename);
|
||||
inst = (QofInstance*)qof_object_new_instance(type, query->book);
|
||||
if(inst == NULL) { return NULL; }
|
||||
query->param_list = NULL;
|
||||
if(inst == NULL)
|
||||
{
|
||||
LEAVE (" unable to create instance of type %s", type);
|
||||
return NULL;
|
||||
}
|
||||
query->inserted_entity = &inst->entity;
|
||||
qof_class_param_foreach((QofIdTypeConst)type, qof_queryForeachParam, query);
|
||||
g_list_foreach(query->param_list, qof_sql_insertCB, query);
|
||||
value_list = sis->values;
|
||||
for (field_list = sis->fields; field_list != NULL; field_list = field_list->next)
|
||||
{
|
||||
field = value_list->data;
|
||||
item = field->item;
|
||||
for (cur = item->d.name; cur != NULL; cur = cur->next)
|
||||
{
|
||||
value = g_strdup_printf("%s", dequote_string((char*)cur->data));
|
||||
}
|
||||
field = field_list->data;
|
||||
item = field->item;
|
||||
for (cur = item->d.name; cur != NULL; cur = cur->next)
|
||||
{
|
||||
param_name = g_strdup_printf("%s", (char*)cur->data);
|
||||
param = qof_class_get_parameter(type, param_name);
|
||||
}
|
||||
if(param && value) {
|
||||
qof_sql_insertCB(param, value, query);
|
||||
}
|
||||
value_list = g_list_next(value_list);
|
||||
}
|
||||
LEAVE (" ");
|
||||
return query->inserted_entity;
|
||||
}
|
||||
|
||||
@@ -817,9 +802,9 @@ qof_sql_query_parse (QofSqlQuery *query, const char *str)
|
||||
char *buf;
|
||||
sql_select_statement *sss;
|
||||
sql_where *swear;
|
||||
|
||||
if (!query) return;
|
||||
|
||||
if (!query) return;
|
||||
ENTER (" ");
|
||||
/* Delete old query, if any */
|
||||
if (query->qof_query)
|
||||
{
|
||||
@@ -835,13 +820,13 @@ qof_sql_query_parse (QofSqlQuery *query, const char *str)
|
||||
|
||||
if (!query->parse_result)
|
||||
{
|
||||
PWARN ("parse error");
|
||||
LEAVE ("parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((SQL_select != query->parse_result->type)&&(SQL_insert != query->parse_result->type))
|
||||
{
|
||||
PWARN("currently, only SELECT or INSERT statements are supported, "
|
||||
LEAVE ("currently, only SELECT or INSERT statements are supported, "
|
||||
"got type=%s", sql_type_as_string(query->parse_result->type));
|
||||
return;
|
||||
}
|
||||
@@ -859,6 +844,8 @@ qof_sql_query_parse (QofSqlQuery *query, const char *str)
|
||||
/* if this is an insert, we're done with the parse. */
|
||||
if(SQL_insert == query->parse_result->type) {
|
||||
query->qof_query = qof_query_create();
|
||||
qof_query_set_insert_table(query);
|
||||
LEAVE (" insert statement parsed OK");
|
||||
return;
|
||||
}
|
||||
sss = query->parse_result->statement;
|
||||
@@ -867,7 +854,7 @@ qof_sql_query_parse (QofSqlQuery *query, const char *str)
|
||||
{
|
||||
/* Walk over the where terms, turn them into QOF predicates */
|
||||
query->qof_query = handle_where (query, swear);
|
||||
if (NULL == query->qof_query) return;
|
||||
if (NULL == query->qof_query) { LEAVE (" no query found"); return; }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -877,11 +864,11 @@ qof_sql_query_parse (QofSqlQuery *query, const char *str)
|
||||
handle_sort_order (query, sss->order);
|
||||
|
||||
/* We also want to set the type of thing to search for.
|
||||
* If the user said SELECT * FROM ... then we should return
|
||||
* a list of QofEntity. Otherwise, we return ... ?
|
||||
* XXX all this needs fixing.
|
||||
* SELECT * FROM table1, table2, ... is not supported.
|
||||
* Use sequential queries and build a partial book.
|
||||
*/
|
||||
qof_query_search_for (query->qof_query, query->single_global_tablename);
|
||||
LEAVE (" success");
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
@@ -902,7 +889,12 @@ qof_sql_query_run (QofSqlQuery *query, const char *str)
|
||||
results = g_list_append(results, qof_query_insert(query));
|
||||
return results;
|
||||
}
|
||||
qof_query_print (query->qof_query);
|
||||
/* Maybe log this sucker */
|
||||
if (gnc_should_log (log_module, GNC_LOG_DETAIL))
|
||||
{
|
||||
qof_query_print (query->qof_query);
|
||||
}
|
||||
|
||||
results = qof_query_run (query->qof_query);
|
||||
|
||||
return results;
|
||||
@@ -919,7 +911,12 @@ qof_sql_query_rerun (QofSqlQuery *query)
|
||||
|
||||
qof_query_set_book (query->qof_query, query->book);
|
||||
|
||||
// qof_query_print (query->qof_query);
|
||||
/* Maybe log this sucker */
|
||||
if (gnc_should_log (log_module, GNC_LOG_DETAIL))
|
||||
{
|
||||
qof_query_print (query->qof_query);
|
||||
}
|
||||
|
||||
results = qof_query_run (query->qof_query);
|
||||
|
||||
return results;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************\
|
||||
* qofsql.h -- QOF client-side SQL parser *
|
||||
* qofsql.h -- QOF client-side SQL parser using libgda *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
@@ -24,7 +24,7 @@
|
||||
@{ */
|
||||
/**
|
||||
@file qofsql.h
|
||||
@brief QOF client-side SQL parser.
|
||||
@brief QOF client-side SQL parser, interfacing with libgda.
|
||||
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
@@ -197,5 +197,5 @@ GList * qof_sql_query_rerun (QofSqlQuery *query);
|
||||
void qof_sql_query_set_kvp (QofSqlQuery *, KvpFrame *);
|
||||
|
||||
/** @} */
|
||||
#endif /* QOF_SQL_QUERY_H */
|
||||
/** @} */
|
||||
#endif /* QOF_SQL_QUERY_H */
|
||||
|
Reference in New Issue
Block a user