From 1de3fe86d23906f14064d8d41fa5ea29a1c1a01e Mon Sep 17 00:00:00 2001 From: Neil Williams Date: Sun, 8 Jan 2006 17:51:29 +0000 Subject: [PATCH] QOF 0.6.1 release update git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@12299 57a11ea4-9604-0410-9ed3-97b8803252fd --- configure.in | 4 +- .../backend/file/pilot-qsf-GnuCashInvoice.xml | 42 +- lib/libqof/backend/file/qof-backend-qsf.h | 87 ++- lib/libqof/backend/file/qsf-backend.c | 604 ++++++++++-------- lib/libqof/backend/file/qsf-xml-map.c | 78 ++- lib/libqof/backend/file/qsf-xml.c | 45 +- lib/libqof/backend/file/qsf-xml.h | 601 +++++++---------- lib/libqof/qof/Makefile.am | 8 +- lib/libqof/qof/deprecated.c | 54 ++ lib/libqof/qof/deprecated.h | 75 +++ lib/libqof/qof/gnc-date.c | 170 +++-- lib/libqof/qof/gnc-date.h | 39 +- lib/libqof/qof/gnc-engine-util.h | 108 +++- lib/libqof/qof/gnc-event-p.h | 4 +- lib/libqof/qof/gnc-event.c | 12 +- lib/libqof/qof/gnc-event.h | 1 + lib/libqof/qof/gnc-numeric.c | 54 +- lib/libqof/qof/gnc-numeric.h | 5 +- lib/libqof/qof/gnc-trace.c | 370 ----------- lib/libqof/qof/gnc-trace.h | 274 -------- lib/libqof/qof/guid.c | 38 +- lib/libqof/qof/guid.h | 20 +- lib/libqof/qof/kvp-util.h | 2 +- lib/libqof/qof/kvp_frame.c | 98 +-- lib/libqof/qof/kvp_frame.h | 10 +- lib/libqof/qof/qof-be-utils.h | 30 +- lib/libqof/qof/qof.h | 10 +- lib/libqof/qof/qof_book_merge.c | 17 +- lib/libqof/qof/qof_book_merge.h | 7 +- lib/libqof/qof/qofbackend-p.h | 8 +- lib/libqof/qof/qofbackend.c | 34 +- lib/libqof/qof/qofbook-p.h | 54 +- lib/libqof/qof/qofbook.c | 35 +- lib/libqof/qof/qofbook.h | 52 +- lib/libqof/qof/qofchoice.c | 3 +- lib/libqof/qof/qofchoice.h | 3 +- lib/libqof/qof/qofclass-p.h | 3 +- lib/libqof/qof/qofclass.c | 147 +++-- lib/libqof/qof/qofgobj.c | 10 +- lib/libqof/qof/qofgobj.h | 1 - lib/libqof/qof/qofid-p.h | 5 +- lib/libqof/qof/qofid.c | 29 +- lib/libqof/qof/qofid.h | 31 +- lib/libqof/qof/qofinstance-p.h | 34 +- lib/libqof/qof/qofinstance.c | 24 +- lib/libqof/qof/qoflog.c | 363 +++++++++++ lib/libqof/qof/qoflog.h | 274 ++++++++ lib/libqof/qof/qofobject-p.h | 12 + lib/libqof/qof/qofobject.c | 33 +- lib/libqof/qof/qofquery-deserial.c | 16 +- lib/libqof/qof/qofquery-deserial.h | 3 + lib/libqof/qof/qofquery-serialize.c | 9 +- lib/libqof/qof/qofquery-serialize.h | 3 + lib/libqof/qof/qofquery.c | 148 ++--- lib/libqof/qof/qofquery.h | 27 +- lib/libqof/qof/qofquerycore.c | 163 +++-- lib/libqof/qof/qofquerycore.h | 40 +- lib/libqof/qof/qofsession.c | 65 +- lib/libqof/qof/qofsession.h | 75 +-- lib/libqof/qof/qofsql.c | 375 ++++++----- lib/libqof/qof/qofsql.h | 6 +- 61 files changed, 2607 insertions(+), 2345 deletions(-) create mode 100644 lib/libqof/qof/deprecated.c create mode 100644 lib/libqof/qof/deprecated.h delete mode 100644 lib/libqof/qof/gnc-trace.c delete mode 100644 lib/libqof/qof/gnc-trace.h create mode 100644 lib/libqof/qof/qoflog.c create mode 100644 lib/libqof/qof/qoflog.h diff --git a/configure.in b/configure.in index dc7e649dca..b1571d97ad 100644 --- a/configure.in +++ b/configure.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]) diff --git a/lib/libqof/backend/file/pilot-qsf-GnuCashInvoice.xml b/lib/libqof/backend/file/pilot-qsf-GnuCashInvoice.xml index 776599b82c..b9c1e59060 100644 --- a/lib/libqof/backend/file/pilot-qsf-GnuCashInvoice.xml +++ b/lib/libqof/backend/file/pilot-qsf-GnuCashInvoice.xml @@ -5,13 +5,13 @@ - Pilot-link QOF expenses - Pilot-link QOF datebook - Pilot-link QOF address - Invoice - Transaction - Order/Invoice/Bill Entry - + + + + + + + @@ -29,20 +29,28 @@ xmlns="http://qof.sourceforge.net/"> expense_date - + expense_vendor + + description + - + Material - + Hours - expense_note + + expense_note + + + note + @@ -54,20 +62,18 @@ xmlns="http://qof.sourceforge.net/"> - + mileage_rate - - - expense_amount - + + end_time-start_time - - 0/1 + + expense_amount diff --git a/lib/libqof/backend/file/qof-backend-qsf.h b/lib/libqof/backend/file/qof-backend-qsf.h index 19529ef67c..1b27e13cdc 100644 --- a/lib/libqof/backend/file/qof-backend-qsf.h +++ b/lib/libqof/backend/file/qof-backend-qsf.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. */ /** @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 */ #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" + +/** @} */ /** @} */ /** @} */ diff --git a/lib/libqof/backend/file/qsf-backend.c b/lib/libqof/backend/file/qsf-backend.c index 322881ad5a..6f0882af19 100644 --- a/lib/libqof/backend/file/qsf-backend.c +++ b/lib/libqof/backend/file/qsf-backend.c @@ -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 #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; diff --git a/lib/libqof/backend/file/qsf-xml-map.c b/lib/libqof/backend/file/qsf-xml-map.c index d417dcbb49..5ea69cfcd2 100644 --- a/lib/libqof/backend/file/qsf-xml-map.c +++ b/lib/libqof/backend/file/qsf-xml-map.c @@ -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 #include #include +#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; } diff --git a/lib/libqof/backend/file/qsf-xml.c b/lib/libqof/backend/file/qsf-xml.c index c691281453..e267c387f1 100644 --- a/lib/libqof/backend/file/qsf-xml.c +++ b/lib/libqof/backend/file/qsf-xml.c @@ -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 +#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 diff --git a/lib/libqof/backend/file/qsf-xml.h b/lib/libqof/backend/file/qsf-xml.h index 93b2e266c7..1cc0802cb2 100644 --- a/lib/libqof/backend/file/qsf-xml.h +++ b/lib/libqof/backend/file/qsf-xml.h @@ -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 */ @@ -39,15 +38,7 @@ #include #include #include -#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); - /** @} */ /** @} */ diff --git a/lib/libqof/qof/Makefile.am b/lib/libqof/qof/Makefile.am index 5d0130d325..45c09268a3 100644 --- a/lib/libqof/qof/Makefile.am +++ b/lib/libqof/qof/Makefile.am @@ -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 \ diff --git a/lib/libqof/qof/deprecated.c b/lib/libqof/qof/deprecated.c new file mode 100644 index 0000000000..b5079dfb3a --- /dev/null +++ b/lib/libqof/qof/deprecated.c @@ -0,0 +1,54 @@ +/* *****************************************************************\ + * deprecated.c -- QOF deprecated function replacements * + * Copyright (c) 2005 Neil Williams * + * * + * 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); +} diff --git a/lib/libqof/qof/deprecated.h b/lib/libqof/qof/deprecated.h new file mode 100644 index 0000000000..7ce239fad3 --- /dev/null +++ b/lib/libqof/qof/deprecated.h @@ -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 */ diff --git a/lib/libqof/qof/gnc-date.c b/lib/libqof/qof/gnc-date.c index 5c892b468a..71b9ba454a 100644 --- a/lib/libqof/qof/gnc-date.c +++ b/lib/libqof/qof/gnc-date.c @@ -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 * - * Copyright (C) 1998-2000, 20003 Linas Vepstas * + * Copyright (C) 1998-2000, 2003 Linas Vepstas * * * * 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 #ifdef HAVE_LANGINFO_D_FMT @@ -42,7 +43,7 @@ #include #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 *********************************\ \********************************************************************/ diff --git a/lib/libqof/qof/gnc-date.h b/lib/libqof/qof/gnc-date.h index 57d27e445d..51ceae05d6 100644 --- a/lib/libqof/qof/gnc-date.h +++ b/lib/libqof/qof/gnc-date.h @@ -1,3 +1,10 @@ +/*************************************************************************** + * gnc-date.h (to be renamed qofdate.h) + * + * Copyright (C) 1997 Robin D. Clark + * Copyright (C) 1998-2000, 2003 Linas Vepstas + * Copyright 2005 Neil Williams + ****************************************************************************/ /********************************************************************\ * 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 @author Copyright (C) 1998-2001,2003 Linas Vepstas */ -/* @{ +/** @{ @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 */ - diff --git a/lib/libqof/qof/gnc-engine-util.h b/lib/libqof/qof/gnc-engine-util.h index 73d757debf..31f9ab6ffc 100644 --- a/lib/libqof/qof/gnc-engine-util.h +++ b/lib/libqof/qof/gnc-engine-util.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 @author Copyright (C) 2000 Bill Gribble @author Copyright (C) 1997-2002,2004 Linas Vepstas @@ -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)); diff --git a/lib/libqof/qof/gnc-event-p.h b/lib/libqof/qof/gnc-event-p.h index 02ace21545..714c0a0508 100644 --- a/lib/libqof/qof/gnc-event-p.h +++ b/lib/libqof/qof/gnc-event-p.h @@ -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 diff --git a/lib/libqof/qof/gnc-event.c b/lib/libqof/qof/gnc-event.c index 806982b0e1..7b82fc0c7f 100644 --- a/lib/libqof/qof/gnc-event.c +++ b/lib/libqof/qof/gnc-event.c @@ -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, diff --git a/lib/libqof/qof/gnc-event.h b/lib/libqof/qof/gnc-event.h index 2289d282a7..b163e38a51 100644 --- a/lib/libqof/qof/gnc-event.h +++ b/lib/libqof/qof/gnc-event.h @@ -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 */ diff --git a/lib/libqof/qof/gnc-numeric.c b/lib/libqof/qof/gnc-numeric.c index 7713575b58..dc2372dc79 100644 --- a/lib/libqof/qof/gnc-numeric.c +++ b/lib/libqof/qof/gnc-numeric.c @@ -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 diff --git a/lib/libqof/qof/gnc-numeric.h b/lib/libqof/qof/gnc-numeric.h index ca03724607..1b1f1b53c9 100644 --- a/lib/libqof/qof/gnc-numeric.h +++ b/lib/libqof/qof/gnc-numeric.h @@ -53,7 +53,7 @@ this may not be good enough. For example, @verbatim #include -#include "gnc-numeric.h" +#include #include 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 */ @@ -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: */ diff --git a/lib/libqof/qof/gnc-trace.c b/lib/libqof/qof/gnc-trace.c deleted file mode 100644 index 8b4b2a9a5d..0000000000 --- a/lib/libqof/qof/gnc-trace.c +++ /dev/null @@ -1,370 +0,0 @@ -/* *****************************************************************\ - * gnc-trace.c -- QOF error logging and tracing facility * - * Copyright (C) 1997-2003 Linas Vepstas * - * Copyright (c) 2005 Neil Williams * - * * - * 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 -*/ - -#include "config.h" - -#include -#ifdef HAVE_UNISTD_H -# include -#else - /* What to do? */ -#endif -#include -#include -#include -#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 ******************************\ -\********************************************************************/ diff --git a/lib/libqof/qof/gnc-trace.h b/lib/libqof/qof/gnc-trace.h deleted file mode 100644 index 143ce4436d..0000000000 --- a/lib/libqof/qof/gnc-trace.h +++ /dev/null @@ -1,274 +0,0 @@ -/********************************************************************\ - * gnc-trace.h -- QOF error logging and tracing facility * - * Copyright (C) 1998-2003 Linas Vepstas * - * Copyright (c) 2005 Neil Williams * - * * - * 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 - */ - -#ifndef GNC_TRACE_H -#define GNC_TRACE_H - -#include -#include -#include -#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 */ -/* @} */ diff --git a/lib/libqof/qof/guid.c b/lib/libqof/qof/guid.c index 526b7748a4..b424d0025a 100644 --- a/lib/libqof/qof/guid.c +++ b/lib/libqof/qof/guid.c @@ -38,23 +38,20 @@ #include #include #include - -#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); diff --git a/lib/libqof/qof/guid.h b/lib/libqof/qof/guid.h index aa61233f11..c4725523a1 100644 --- a/lib/libqof/qof/guid.h +++ b/lib/libqof/qof/guid.h @@ -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 */ diff --git a/lib/libqof/qof/kvp-util.h b/lib/libqof/qof/kvp-util.h index be8b156a06..fdd058f1e2 100644 --- a/lib/libqof/qof/kvp-util.h +++ b/lib/libqof/qof/kvp-util.h @@ -24,7 +24,7 @@ @{ */ /** @file kvp-util.h - @brief GnuCash KVP utility functions + @brief QOF KVP utility functions */ /** @name Hash Utilities @{ diff --git a/lib/libqof/qof/kvp_frame.c b/lib/libqof/qof/kvp_frame.c index ebe8ea9867..2ba039a7e9 100644 --- a/lib/libqof/qof/kvp_frame.c +++ b/lib/libqof/qof/kvp_frame.c @@ -31,20 +31,12 @@ #include #include -#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; diff --git a/lib/libqof/qof/kvp_frame.h b/lib/libqof/qof/kvp_frame.h index 553bb76584..f0b4dae060 100644 --- a/lib/libqof/qof/kvp_frame.h +++ b/lib/libqof/qof/kvp_frame.h @@ -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); /** @} */ diff --git a/lib/libqof/qof/qof-be-utils.h b/lib/libqof/qof/qof-be-utils.h index fa10cd2574..8c039cc181 100644 --- a/lib/libqof/qof/qof-be-utils.h +++ b/lib/libqof/qof/qof-be-utils.h @@ -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) \ { \ diff --git a/lib/libqof/qof/qof.h b/lib/libqof/qof/qof.h index 7f52183f4f..4d18149e7a 100644 --- a/lib/libqof/qof/qof.h +++ b/lib/libqof/qof/qof.h @@ -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_ */ diff --git a/lib/libqof/qof/qof_book_merge.c b/lib/libqof/qof/qof_book_merge.c index 41204dff72..3ad03b55e6 100644 --- a/lib/libqof/qof/qof_book_merge.c +++ b/lib/libqof/qof/qof_book_merge.c @@ -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) diff --git a/lib/libqof/qof/qof_book_merge.h b/lib/libqof/qof/qof_book_merge.h index d7df139b8e..4e6e2aee7c 100644 --- a/lib/libqof/qof/qof_book_merge.h +++ b/lib/libqof/qof/qof_book_merge.h @@ -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. diff --git a/lib/libqof/qof/qofbackend-p.h b/lib/libqof/qof/qofbackend-p.h index f81456b22d..ca5fd4c61e 100644 --- a/lib/libqof/qof/qofbackend-p.h +++ b/lib/libqof/qof/qofbackend-p.h @@ -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 }; diff --git a/lib/libqof/qof/qofbackend.c b/lib/libqof/qof/qofbackend.c index 11d8c141f6..8719d046e2 100644 --- a/lib/libqof/qof/qofbackend.c +++ b/lib/libqof/qof/qofbackend.c @@ -31,8 +31,8 @@ #include #include #include -#include #include +#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 ()); diff --git a/lib/libqof/qof/qofbook-p.h b/lib/libqof/qof/qofbook-p.h index 40cfca3dde..02d30a5616 100644 --- a/lib/libqof/qof/qofbook-p.h +++ b/lib/libqof/qof/qofbook-p.h @@ -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) diff --git a/lib/libqof/qof/qofbook.c b/lib/libqof/qof/qofbook.c index 553310b8b3..6a76f9cebb 100644 --- a/lib/libqof/qof/qofbook.c +++ b/lib/libqof/qof/qofbook.c @@ -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 -#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 diff --git a/lib/libqof/qof/qofbook.h b/lib/libqof/qof/qofbook.h index e075890eb5..31c45284ec 100644 --- a/lib/libqof/qof/qofbook.h +++ b/lib/libqof/qof/qofbook.h @@ -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); diff --git a/lib/libqof/qof/qofchoice.c b/lib/libqof/qof/qofchoice.c index 4adc7ffadc..ca5f6240cd 100644 --- a/lib/libqof/qof/qofchoice.c +++ b/lib/libqof/qof/qofchoice.c @@ -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 diff --git a/lib/libqof/qof/qofchoice.h b/lib/libqof/qof/qofchoice.h index 6e12e17293..b28837a958 100644 --- a/lib/libqof/qof/qofchoice.h +++ b/lib/libqof/qof/qofchoice.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 diff --git a/lib/libqof/qof/qofclass-p.h b/lib/libqof/qof/qofclass-p.h index 7722343554..d7a35e6212 100644 --- a/lib/libqof/qof/qofclass-p.h +++ b/lib/libqof/qof/qofclass-p.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 * * * * 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 @{ */ diff --git a/lib/libqof/qof/qofclass.c b/lib/libqof/qof/qofclass.c index d19e7c0215..b2a83a46b0 100644 --- a/lib/libqof/qof/qofclass.c +++ b/lib/libqof/qof/qofclass.c @@ -1,5 +1,5 @@ /********************************************************************\ - * qofclass.c -- provide QOF paramterized data objects * + * qofclass.c -- provide QOF parameterized data objects * * Copyright (C) 2002 Derek Atkins * * * * This program is free software; you can redistribute it and/or * @@ -25,11 +25,8 @@ #include -#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); } diff --git a/lib/libqof/qof/qofgobj.c b/lib/libqof/qof/qofgobj.c index 971ffe6e3b..bee63423df 100644 --- a/lib/libqof/qof/qofgobj.c +++ b/lib/libqof/qof/qofgobj.c @@ -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 diff --git a/lib/libqof/qof/qofgobj.h b/lib/libqof/qof/qofgobj.h index f49d7f6fe0..65f0f151cf 100644 --- a/lib/libqof/qof/qofgobj.h +++ b/lib/libqof/qof/qofgobj.h @@ -84,4 +84,3 @@ void qof_gobject_register_instance (QofBook *book, QofType, GObject *); #endif /* QOF_GOBJ_H */ /** @} */ /** @} */ - diff --git a/lib/libqof/qof/qofid-p.h b/lib/libqof/qof/qofid-p.h index a0d71e0c49..c94351d583 100644 --- a/lib/libqof/qof/qofid-p.h +++ b/lib/libqof/qof/qofid-p.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); diff --git a/lib/libqof/qof/qofid.c b/lib/libqof/qof/qofid.c index 326e23ba41..e8737c4c45 100644 --- a/lib/libqof/qof/qofid.c +++ b/lib/libqof/qof/qofid.c @@ -27,10 +27,8 @@ #include #include -#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; diff --git a/lib/libqof/qof/qofid.h b/lib/libqof/qof/qofid.h index 6e8b26cb76..016cb36755 100644 --- a/lib/libqof/qof/qofid.h +++ b/lib/libqof/qof/qofid.h @@ -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 * diff --git a/lib/libqof/qof/qofinstance-p.h b/lib/libqof/qof/qofinstance-p.h index 46bc67a723..b83f917d8d 100644 --- a/lib/libqof/qof/qofinstance-p.h +++ b/lib/libqof/qof/qofinstance-p.h @@ -26,20 +26,12 @@ * Copyright (C) 2003 Linas Vepstas */ -/** @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 */ diff --git a/lib/libqof/qof/qofinstance.c b/lib/libqof/qof/qofinstance.c index d236e1f70f..4b27090619 100644 --- a/lib/libqof/qof/qofinstance.c +++ b/lib/libqof/qof/qofinstance.c @@ -23,18 +23,14 @@ /* * Object instance holds many common fields that most * gnucash objects use. - * + * * Copyright (C) 2003 Linas Vepstas */ -#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; diff --git a/lib/libqof/qof/qoflog.c b/lib/libqof/qof/qoflog.c new file mode 100644 index 0000000000..62fb51fafd --- /dev/null +++ b/lib/libqof/qof/qoflog.c @@ -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 + * 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 +#ifdef HAVE_UNISTD_H +#include +#else +#warning unistd required. +#endif +#include +#include +#include +#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 **************************** */ diff --git a/lib/libqof/qof/qoflog.h b/lib/libqof/qof/qoflog.h new file mode 100644 index 0000000000..617144358a --- /dev/null +++ b/lib/libqof/qof/qoflog.h @@ -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 + * 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 +#include +#include +#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 */ + +/** @} */ diff --git a/lib/libqof/qof/qofobject-p.h b/lib/libqof/qof/qofobject-p.h index 17bc6b5908..eec5f40f02 100644 --- a/lib/libqof/qof/qofobject-p.h +++ b/lib/libqof/qof/qofobject-p.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_ */ /** @} */ /** @} */ diff --git a/lib/libqof/qof/qofobject.c b/lib/libqof/qof/qofobject.c index 612f5f1eb6..3f6bcb5ec5 100644 --- a/lib/libqof/qof/qofobject.c +++ b/lib/libqof/qof/qofobject.c @@ -28,11 +28,8 @@ #include -#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; } diff --git a/lib/libqof/qof/qofquery-deserial.c b/lib/libqof/qof/qofquery-deserial.c index f98c9b00de..c4fcf23857 100644 --- a/lib/libqof/qof/qofquery-deserial.c +++ b/lib/libqof/qof/qofquery-deserial.c @@ -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 #include #include @@ -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 (); diff --git a/lib/libqof/qof/qofquery-deserial.h b/lib/libqof/qof/qofquery-deserial.h index 131952dc06..80bffe4de3 100644 --- a/lib/libqof/qof/qofquery-deserial.h +++ b/lib/libqof/qof/qofquery-deserial.h @@ -40,6 +40,9 @@ author Copyright (C) 2004 Linas Vepstas 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); diff --git a/lib/libqof/qof/qofquery-serialize.c b/lib/libqof/qof/qofquery-serialize.c index 898ad65f7f..66dff5b756 100644 --- a/lib/libqof/qof/qofquery-serialize.c +++ b/lib/libqof/qof/qofquery-serialize.c @@ -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 (); diff --git a/lib/libqof/qof/qofquery-serialize.h b/lib/libqof/qof/qofquery-serialize.h index 8f38618e72..04d7b5639a 100644 --- a/lib/libqof/qof/qofquery-serialize.h +++ b/lib/libqof/qof/qofquery-serialize.h @@ -25,6 +25,9 @@ Copyright (C) 2001,2002,2004 Linas Vepstas */ +/* 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 diff --git a/lib/libqof/qof/qofquery.c b/lib/libqof/qof/qofquery.c index 02f2366584..0e1260abb8 100644 --- a/lib/libqof/qof/qofquery.c +++ b/lib/libqof/qof/qofquery.c @@ -29,18 +29,11 @@ #include #include -#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 =================== */ diff --git a/lib/libqof/qof/qofquery.h b/lib/libqof/qof/qofquery.h index 97f8224686..28f13c242d 100644 --- a/lib/libqof/qof/qofquery.h +++ b/lib/libqof/qof/qofquery.h @@ -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); diff --git a/lib/libqof/qof/qofquerycore.c b/lib/libqof/qof/qofquerycore.c index 21d6e994bb..6a960656cd 100644 --- a/lib/libqof/qof/qofquerycore.c +++ b/lib/libqof/qof/qofquerycore.c @@ -25,10 +25,7 @@ #include -#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; diff --git a/lib/libqof/qof/qofquerycore.h b/lib/libqof/qof/qofquerycore.h index 26b84b5df7..14793f0ba8 100644 --- a/lib/libqof/qof/qofquerycore.h +++ b/lib/libqof/qof/qofquerycore.h @@ -23,7 +23,7 @@ /** @addtogroup Query @{ */ - + /** @file qofquerycore.h @brief API for providing core Query data types @author Copyright (C) 2002 Derek Atkins @@ -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. */ diff --git a/lib/libqof/qof/qofsession.c b/lib/libqof/qof/qofsession.c index 4445af807d..ecf93c353a 100644 --- a/lib/libqof/qof/qofsession.c +++ b/lib/libqof/qof/qofsession.c @@ -41,17 +41,11 @@ #include #include -#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 } }; diff --git a/lib/libqof/qof/qofsession.h b/lib/libqof/qof/qofsession.h index 6131ce7cd3..12858108d9 100644 --- a/lib/libqof/qof/qofsession.h +++ b/lib/libqof/qof/qofsession.h @@ -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 diff --git a/lib/libqof/qof/qofsql.c b/lib/libqof/qof/qofsql.c index 9882a1bed1..e57051edfd 100644 --- a/lib/libqof/qof/qofsql.c +++ b/lib/libqof/qof/qofsql.c @@ -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 */ @@ -38,18 +38,8 @@ #include "sql_parser.h" #endif #include -#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; diff --git a/lib/libqof/qof/qofsql.h b/lib/libqof/qof/qofsql.h index 01bf53606c..4e5850da8e 100644 --- a/lib/libqof/qof/qofsql.h +++ b/lib/libqof/qof/qofsql.h @@ -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 */ @@ -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 */