Final changes for QOF 0.6.4 - Improvements in map handling.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13797 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Neil Williams 2006-04-17 13:06:33 +00:00
parent c8cffa2094
commit 293e60d88f
15 changed files with 446 additions and 315 deletions

View File

@ -1,3 +1,23 @@
2006-04-17 Neil Williams <linux@codehelp.co.uk>
* configure.in : Bump versions of QOF libraries.
* lib/libqof/backend/file/qsf-xml-map.c : Refactoring common
code and fixing QOF_VERSION check.
* lib/libqof/backend/file/pilot-qsf-gncCustomer.xml :
remove gncBillTerm - isn't possible to create from
pilot data.
* lib/libqof/backend/file/qsf-backend.c :
* lib/libqof/backend/file/qsf-xml-map.c :
* lib/libqof/backend/file/qsf-xml.c :
* lib/libqof/backend/file/qsf-xml.h : Add control over status of
various objects during mapping.
* lib/libqof/qof/test/Makefile.am : Remove unwanted include.
* lib/libqof/qof/deprecated.h : Retain glib.h in QOF, not
deprecated.
2006-04-16 Chris Lyttle <chris@wilddev.net>
* NEWS: Added some text about the release.

View File

@ -472,8 +472,8 @@ if test x$QOF_XML_DIR = x; then
QOF_VERSION="internal"
QOF_PREFIX="internal"
QOF_XML_DIR='${datadir}/xml/qsf'
LIBQOF_LIBRARY_VERSION=1:4:0
LIBQOF_BACKEND_QSF_LIBRARY_VERSION=0:3:0
LIBQOF_LIBRARY_VERSION=1:5:0
LIBQOF_BACKEND_QSF_LIBRARY_VERSION=0:4:0
AC_SUBST(LIBQOF_LIBRARY_VERSION)
AC_SUBST(LIBQOF_BACKEND_QSF_LIBRARY_VERSION)
AC_DEFINE(HAVE_LIBQOF,,[We will use the internal QOF code])

View File

@ -1,71 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<qsf-map xmlns="http://qof.sourceforge.net/">
<definition qof_version="3">
<define e_type="pilot_address"/>
<define e_type="gncBillTerm"/>
<define e_type="pilot_address" foreach="true"/>
<define e_type="gncCustomer"/>
<define e_type="gncAddress" foreach="true"/>
</definition>
<object type="gncCustomer">
<calculate type="string" value="id"/>
<calculate type="string" value="notes">
<set>entryNote</set>
<set object="pilot_address">entryNote</set>
</calculate>
<calculate type="string" value="name">
<set>entryCompany</set>
<set object="pilot_address">entryCompany</set>
</calculate>
<calculate type="guid" value="guid"/>
<calculate type="guid" value="addr">
<set>guid</set>
<set object="pilot_address">guid</set>
</calculate>
<calculate type="guid" value="customer_terms"/>
<calculate type="guid" value="shipaddr"/>
<calculate type="boolean" value="active">
<set>true</set>
</calculate>
<calculate type="boolean" value="active"/>
<calculate type="boolean" value="tax table override"/>
<calculate type="numeric" value="amount of discount"/>
<calculate type="numeric" value="amount of credit"/>
</object>
<object type="gncAddress">
<calculate type="string" value="city">
<set>entryZip</set>
<set object="pilot_address">entryCity</set>
</calculate>
<calculate type="string" value="street">
<set>entryAddress</set>
<set object="pilot_address">entryAddress</set>
</calculate>
<calculate type="string" value="fax">
<set>entryPhone2</set>
<set object="pilot_address">entryPhone2</set>
</calculate>
<calculate type="string" value="number"/>
<calculate type="string" value="name">
<set>entryFirstname</set>
<set>entryLastname</set>
<set object="pilot_address">entryFirstname</set>
<set object="pilot_address">entryLastname</set>
</calculate>
<calculate type="string" value="email">
<set>entryPhone5</set>
<set object="pilot_address">entryPhone5</set>
</calculate>
<calculate type="string" value="locality">
<set>entryState</set>
<set object="pilot_address">entryState</set>
</calculate>
<calculate type="string" value="phone">
<set>entryPhone1</set>
<set object="pilot_address">entryPhone1</set>
</calculate>
<calculate type="guid" value="guid"/>
<calculate type="guid" value="owner">
<set>guid</set>
<set object="pilot_address">guid</set>
</calculate>
</object>
<object type="gncBillTerm">
<calculate type="string" value="description"/>
<calculate type="string" value="name"/>
<calculate type="string" value="bill type"/>
<calculate type="guid" value="guid"/>
<calculate type="numeric" value="amount of discount"/>
<calculate type="gint32" value="cut off"/>
<calculate type="gint32" value="number of days due"/>
<calculate type="gint32" value="number of discounted days"/>
</object>
<object type="pilot_address">
<calculate type="string" value="entryCity">
<set object="gncAddress">city</set>

View File

@ -14,7 +14,7 @@
* 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 Library General Public License for more details.
* 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

View File

@ -14,7 +14,7 @@
* 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 Library General Public License for more details.
* 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
@ -24,23 +24,24 @@
#define _GNU_SOURCE
#include "config.h"
#include <errno.h>
#include <sys/stat.h>
#include <glib.h>
#include "qof.h"
#include "qof-backend-qsf.h"
#include <libxml/xmlmemory.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlschemas.h>
#include "qof.h"
#include "qof-backend-qsf.h"
#include "qsf-xml.h"
#include "qsf-dir.h"
#include <errno.h>
#include <sys/stat.h>
#define QSF_TYPE_BINARY "binary"
#define QSF_TYPE_GLIST "glist"
#define QSF_TYPE_FRAME "frame"
static QofLogModule log_module = QOF_MOD_QSF;
static void qsf_object_commitCB(gpointer key, gpointer value, gpointer data);
struct QSFBackend_s
@ -60,14 +61,14 @@ static void option_cb (QofBackendOption *option, gpointer data)
g_return_if_fail(params);
if(0 == safe_strcmp(QSF_COMPRESS, option->option_name)) {
params->use_gz_level = (*(gint64*)option->value);
DEBUG (" gz=%" G_GINT64_FORMAT,params->use_gz_level);
PINFO (" compression=%" G_GINT64_FORMAT,params->use_gz_level);
}
if (0 == safe_strcmp(QSF_MAP_FILES, option->option_name)) {
params->map_files = g_list_copy((GList*)option->value);
}
if (0 == safe_strcmp(QSF_ENCODING, option->option_name)) {
params->encoding = g_strdup(option->value);
DEBUG (" encoding=%s", params->encoding);
PINFO (" encoding=%s", params->encoding);
}
}
@ -104,6 +105,7 @@ qsf_get_config(QofBackend *be)
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;
/* GINT_TO_POINTER can only be used for 32bit values. */
option->value = (gpointer)&params->use_gz_level;
qof_backend_prepare_option(be, option);
g_free(option);
@ -132,6 +134,8 @@ qsf_get_config(QofBackend *be)
GList**
qsf_map_prepare_list(GList **maps)
{
/* Add new map filenames here. */
/** \todo Automate this once map support is stable */
*maps = g_list_prepend(*maps, "pilot-qsf-GnuCashInvoice.xml");
*maps = g_list_prepend(*maps, "pilot-qsf-gncCustomer.xml");
return maps;
@ -246,10 +250,10 @@ qsf_session_begin(QofBackend *be, QofSession *session, const gchar *book_path,
}
if(create_if_nonexistent)
{
FILE *f;
f = fopen(qsf_be->fullpath, "a+");
if(f) {fclose(f); }
FILE *f;
f = fopen(qsf_be->fullpath, "a+");
if(f) {fclose(f); }
else
{
qof_backend_set_error(be, ERR_BACKEND_READONLY);
@ -364,11 +368,13 @@ qsfdoc_to_qofbook(xmlDocPtr doc, qsf_param *params)
object_list = g_list_next(object_list);
params->qsf_parameter_hash = params->object_set->parameters;
if(!qof_class_is_registered(params->object_set->object_type)) { continue; }
inst = (QofInstance*)qof_object_new_instance(params->object_set->object_type, book);
inst = (QofInstance*)qof_object_new_instance(params->object_set->object_type,
book);
g_return_val_if_fail(inst != NULL, FALSE);
params->qsf_ent = &inst->entity;
qof_begin_edit(inst);
g_hash_table_foreach(params->qsf_parameter_hash, qsf_object_commitCB, params);
g_hash_table_foreach(params->qsf_parameter_hash, qsf_object_commitCB,
params);
qof_commit_edit(inst);
}
qof_object_foreach_type(insert_ref_cb, params);
@ -437,24 +443,25 @@ load_our_qsf_object(QofBook *book, const gchar *fullpath, qsf_param *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.
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
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.
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;
QofBackendError err;
qsf_param *params;
FILE *f;
gchar *path;
@ -487,7 +494,16 @@ qsf_file_type(QofBackend *be, QofBook *book)
if(!result) { qof_backend_set_error(be, ERR_FILEIO_PARSE_ERROR); }
return;
}
if(result == FALSE) {
err = qof_backend_get_error(be);
if(err == ERR_QSF_WRONG_MAP)
{
/* usable QSF object but no map available */
params->file_type = IS_QSF_OBJ;
result = TRUE;
}
/* pop the error back on the stack. */
qof_backend_set_error(params->be, err);
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);
@ -608,7 +624,8 @@ qsf_from_kvp_helper(const gchar *path, KvpValue *content, gpointer data)
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_TYPE, BAD_CAST
qof_param->param_name);
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,
@ -792,11 +809,13 @@ qsf_entity_foreach(QofEntity *ent, gpointer data)
if(!own_guid)
{
cm_guid = qof_entity_get_guid(ent);
node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST QOF_TYPE_GUID));
node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST
QOF_TYPE_GUID));
guid_to_string_buff(cm_guid, cm_sa);
string_buffer = g_strdup(cm_sa);
xmlNodeAddContent(node, BAD_CAST string_buffer);
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE , BAD_CAST QOF_PARAM_GUID);
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE , BAD_CAST
QOF_PARAM_GUID);
g_free(string_buffer);
own_guid = TRUE;
}
@ -828,12 +847,14 @@ qsf_entity_foreach(QofEntity *ent, gpointer data)
param_list = g_slist_next(param_list);
continue;
}
node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST qof_param->param_type));
node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST
qof_param->param_type));
cm_guid = qof_entity_get_guid(choice_ent);
guid_to_string_buff(cm_guid, cm_sa);
string_buffer = g_strdup(cm_sa);
xmlNodeAddContent(node, BAD_CAST string_buffer);
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST
qof_param->param_name);
xmlNewProp(node, BAD_CAST "name", BAD_CAST choice_ent->e_type);
g_free(string_buffer);
param_list = g_slist_next(param_list);
@ -852,12 +873,16 @@ qsf_entity_foreach(QofEntity *ent, gpointer data)
for( supported = g_slist_copy(params->supported_types);
supported != NULL; supported = g_slist_next(supported))
{
if(0 == safe_strcmp((const gchar*)supported->data, (const gchar*)qof_param->param_type))
if(0 == safe_strcmp((const gchar*)supported->data,
(const gchar*)qof_param->param_type))
{
node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST qof_param->param_type));
string_buffer = g_strdup(qof_book_merge_param_as_string(qof_param, ent));
node = xmlAddChild(object_node,
xmlNewNode(ns, BAD_CAST qof_param->param_type));
string_buffer = g_strdup(qof_book_merge_param_as_string(qof_param,
ent));
xmlNodeAddContent(node, BAD_CAST string_buffer);
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST
qof_param->param_name);
g_free(string_buffer);
}
}
@ -932,13 +957,14 @@ 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;
DEBUG (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
params->use_gz_level, params->encoding);
if((params->use_gz_level > 0) && (params->use_gz_level <= 9))
{
xmlSetDocCompressMode(qsf_doc, params->use_gz_level);
}
g_return_if_fail(qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
g_return_if_fail(
qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
write_result = xmlSaveFormatFileEnc(path, qsf_doc, params->encoding, 1);
if(write_result < 0)
{
@ -954,8 +980,9 @@ write_qsf_to_stdout(QofBook *book, qsf_param *params)
xmlDocPtr qsf_doc;
qsf_doc = qofbook_to_qsf(book, params);
g_return_if_fail(qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
DEBUG (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
g_return_if_fail(
qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
params->use_gz_level, params->encoding);
xmlSaveFormatFileEnc("-", qsf_doc, params->encoding, 1);
fprintf(stdout, "\n");
@ -993,49 +1020,62 @@ string_to_kvp_value(const gchar *content, KvpValueType type)
time_t kvp_time_t;
Timespec cm_date;
switch(type) {
case KVP_TYPE_GINT64:
errno = 0;
cm_i64 = strtoll(content, &tail, 0);
if(errno == 0) {
return kvp_value_new_gint64(cm_i64);
}
break;
case KVP_TYPE_DOUBLE:
errno = 0;
cm_double = strtod(content, &tail);
if(errno == 0) {
return kvp_value_new_double(cm_double);
}
break;
case KVP_TYPE_NUMERIC:
string_to_gnc_numeric(content, &cm_numeric);
return kvp_value_new_gnc_numeric(cm_numeric);
break;
case KVP_TYPE_STRING:
return kvp_value_new_string(content);
break;
case KVP_TYPE_GUID:
cm_guid = g_new(GUID, 1);
if(TRUE == string_to_guid(content, cm_guid))
switch(type)
{
case KVP_TYPE_GINT64:
{
return kvp_value_new_guid(cm_guid);
errno = 0;
cm_i64 = strtoll(content, &tail, 0);
if(errno == 0) {
return kvp_value_new_gint64(cm_i64);
}
break;
}
break;
case KVP_TYPE_TIMESPEC:
strptime(content, QSF_XSD_TIME, &kvp_time);
kvp_time_t = mktime(&kvp_time);
timespecFromTime_t(&cm_date, kvp_time_t);
return kvp_value_new_timespec(cm_date);
break;
case KVP_TYPE_BINARY:
case KVP_TYPE_DOUBLE:
{
errno = 0;
cm_double = strtod(content, &tail);
if(errno == 0) {
return kvp_value_new_double(cm_double);
}
break;
}
case KVP_TYPE_NUMERIC:
{
string_to_gnc_numeric(content, &cm_numeric);
return kvp_value_new_gnc_numeric(cm_numeric);
break;
}
case KVP_TYPE_STRING:
{
return kvp_value_new_string(content);
break;
}
case KVP_TYPE_GUID:
{
cm_guid = g_new(GUID, 1);
if(TRUE == string_to_guid(content, cm_guid))
{
return kvp_value_new_guid(cm_guid);
}
break;
}
case KVP_TYPE_TIMESPEC:
{
strptime(content, QSF_XSD_TIME, &kvp_time);
kvp_time_t = mktime(&kvp_time);
timespecFromTime_t(&cm_date, kvp_time_t);
return kvp_value_new_timespec(cm_date);
break;
}
case KVP_TYPE_BINARY:
// return kvp_value_new_binary(value->value.binary.data,
// value->value.binary.datasize);
break;
case KVP_TYPE_GLIST:
case KVP_TYPE_GLIST:
// return kvp_value_new_glist(value->value.list);
break;
case KVP_TYPE_FRAME:
case KVP_TYPE_FRAME:
// return kvp_value_new_frame(value->value.frame);
break;
}
@ -1099,12 +1139,14 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
object_set = params->object_set;
if(safe_strcmp(qof_type, QOF_TYPE_STRING) == 0) {
string_setter = (void(*)(QofEntity*, const gchar*))cm_setter;
if(string_setter != NULL) { string_setter(qsf_ent, (gchar*)xmlNodeGetContent(node)); }
if(string_setter != NULL) { string_setter(qsf_ent,
(gchar*)xmlNodeGetContent(node)); }
}
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);
timechk = strptime((char*)xmlNodeGetContent(node), QSF_XSD_TIME,
&qsf_time);
g_return_if_fail(timechk != NULL);
qsf_time_t = mktime(&qsf_time);
if(qsf_time_t != -3600)
@ -1136,7 +1178,8 @@ qsf_object_commitCB(gpointer key, gpointer value, gpointer data)
else {
reference = qof_entity_get_reference_from(qsf_ent, cm_param);
if(reference) {
params->referenceList = g_list_append(params->referenceList, reference);
params->referenceList = g_list_append(params->referenceList,
reference);
}
}
}
@ -1276,12 +1319,6 @@ qsf_provider_init(void)
{
QofBackendProvider *prov;
/* #ifdef ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
#endif*/
prov = g_new0 (QofBackendProvider, 1);
prov->provider_name = "QSF Backend Version 0.2";
prov->access_method = "file";

View File

@ -14,7 +14,7 @@
* 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 Library General Public License for more details.
* 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
@ -72,61 +72,161 @@ qsf_string_default_handler(const gchar *default_name, GHashTable *qsf_default_ha
static void
qsf_map_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid)
{
xmlChar *qof_version, *match;
GString *buff;
xmlChar *qof_version, *obj_type;
gboolean match, is_registered;
gchar *buff;
xmlNodePtr child_node;
QofIdType obj_type;
QsfStatus type, incoming_type;
match = FALSE;
buff = NULL;
is_registered = FALSE;
type = QSF_NO_OBJECT;
if (qsf_is_element(child, ns, MAP_DEFINITION_TAG)) {
qof_version = xmlGetProp(child, BAD_CAST MAP_QOF_VERSION);
buff = g_string_new(" ");
g_string_printf(buff, "%i", QSF_QOF_VERSION);
if(xmlStrcmp(qof_version, BAD_CAST buff->str) != 0)
buff = g_strdup_printf("%i", QSF_QOF_VERSION);
if(xmlStrcmp(qof_version, BAD_CAST buff) != 0)
{
PERR (" Wrong QOF_VERSION in map '%s', should be %s",
qof_version, buff);
valid->error_state = ERR_QSF_BAD_QOF_VERSION;
g_free(buff);
return;
}
g_free(buff);
for(child_node = child->children; child_node != NULL;
child_node = child_node->next)
{
if (qsf_is_element(child_node, ns, MAP_DEFINE_TAG)) {
g_hash_table_insert(valid->validation_table,
xmlGetProp(child_node, BAD_CAST MAP_E_TYPE),
xmlNodeGetContent(child_node));
obj_type = xmlGetProp(child_node, MAP_E_TYPE);
type = QSF_DEFINED_OBJECT;
is_registered = qof_class_is_registered(obj_type);
if(is_registered) { type = QSF_REGISTERED_OBJECT; }
g_hash_table_insert(valid->map_table, obj_type,
GINT_TO_POINTER(type));
}
}
}
if(qsf_is_element(child, ns, MAP_OBJECT_TAG)) {
match = NULL;
obj_type = xmlGetProp(child, BAD_CAST MAP_TYPE_ATTR);
match = BAD_CAST g_hash_table_lookup( valid->validation_table, obj_type);
if(match) {
valid->map_calculated_count++;
if(TRUE == qof_class_is_registered((QofIdTypeConst) obj_type))
/* check each listed object is either registered or calculated. */
type = GPOINTER_TO_INT(g_hash_table_lookup(valid->map_table, obj_type));
switch(type)
{
case QSF_DEFINED_OBJECT :
/* we have a calculation for an unregistered object. */
/* Ignore the calculation that exists to support bidirectional maps. */
/* Check that the incoming QSF contains data for this object */
{
valid->qof_registered_count++;
PINFO (" %s is to be calculated", obj_type);
/* lookup the same object in QSF object_table */
incoming_type = GPOINTER_TO_INT(g_hash_table_lookup(valid->object_table,
obj_type));
switch (incoming_type)
{
case QSF_DEFINED_OBJECT :
{
valid->incoming_count++;
g_hash_table_insert(valid->map_table, obj_type,
GINT_TO_POINTER(type));
break; /* good, proceed. */
}
default :
{
PERR (" Missing data: %s", obj_type);
type = QSF_INVALID_OBJECT; break;
}
}
break;
}
case QSF_REGISTERED_OBJECT : /* use this calculation. */
{
type = QSF_CALCULATED_OBJECT;
valid->map_calculated_count++;
valid->qof_registered_count++;
/* store the result */
g_hash_table_insert(valid->map_table, obj_type, GINT_TO_POINTER(type));
break;
}
default :
{
type = QSF_INVALID_OBJECT;
break;
}
else { PINFO (" %s to be mapped", obj_type); }
}
PINFO (" final type=%s result=%d", obj_type, type);
if(type == QSF_INVALID_OBJECT) { valid->error_state = ERR_QSF_WRONG_MAP; }
}
}
static QofBackendError
check_qsf_object_with_map_internal(xmlDocPtr map_doc, xmlDocPtr doc)
{
xmlNodePtr map_root, object_root;
struct qsf_node_iterate iter;
qsf_validator valid;
xmlNsPtr map_ns;
valid.map_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.object_table = g_hash_table_new(g_str_hash, g_str_equal);
map_root = xmlDocGetRootElement(map_doc);
object_root = xmlDocGetRootElement(doc);
valid.map_calculated_count = 0;
valid.valid_object_count = 0;
valid.qof_registered_count = 0;
valid.incoming_count = 0;
valid.error_state = ERR_BACKEND_NO_ERR;
map_ns = map_root->ns;
iter.ns = object_root->ns;
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
iter.ns = map_ns;
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
if (valid.error_state != ERR_BACKEND_NO_ERR) {
PINFO (" Map is wrong. Trying the next map.");
g_hash_table_destroy(valid.object_table);
g_hash_table_destroy(valid.map_table);
return valid.error_state;
}
/* check all counted objects are valid:
Objects to be calculated must also be registered
so that new objects can be created and populated
from the incoming data: qof_registered_count > 0
The incoming data must contain valid objects -
not an empty QofBook: valid_object_count > 0
The map must contain at least some calculations:
map_calculated_count > 0
*/
if((valid.qof_registered_count < 1)
|| (valid.map_calculated_count < 1)
|| (valid.valid_object_count < 1)
|| (valid.incoming_count < g_hash_table_size(valid.object_table)))
{
PINFO (" Map is wrong. map:%d object:%d reg:%d incoming:%d size:%d",
valid.map_calculated_count, valid.valid_object_count,
valid.qof_registered_count, valid.incoming_count,
g_hash_table_size(valid.object_table));
if(valid.error_state != ERR_BACKEND_NO_ERR)
{
valid.error_state = ERR_QSF_WRONG_MAP;
}
g_hash_table_destroy(valid.object_table);
g_hash_table_destroy(valid.map_table);
return valid.error_state;
}
g_hash_table_destroy(valid.object_table);
g_hash_table_destroy(valid.map_table);
return ERR_BACKEND_NO_ERR;
}
gboolean is_qsf_object_with_map_be(gchar *map_file, qsf_param *params)
{
xmlDocPtr doc, map_doc;
gint valid_count, calc_count;
struct qsf_node_iterate iter;
xmlNodePtr map_root, object_root;
xmlNsPtr map_ns;
qsf_validator valid;
gchar *path;
gchar *map_path;
QofBackendError result;
gchar *path, *map_path;
g_return_val_if_fail((params != NULL),FALSE);
PINFO (" mapfile=%s", map_file);
path = g_strdup(params->filepath);
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
PINFO (" checking map file '%s'", map_path);
if(path == NULL) {
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
return FALSE;
@ -140,73 +240,24 @@ gboolean is_qsf_object_with_map_be(gchar *map_file, qsf_param *params)
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
return FALSE;
}
object_root = xmlDocGetRootElement(doc);
if(map_path == NULL) {
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
return FALSE;
}
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
map_doc = xmlParseFile(map_path);
if(map_doc == NULL) {
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)) {
qof_backend_set_error(params->be, ERR_QSF_INVALID_MAP);
return FALSE;
}
map_root = xmlDocGetRootElement(map_doc);
valid.map_calculated_count = 0;
valid.valid_object_count = 0;
valid.qof_registered_count = 0;
valid.error_state = ERR_BACKEND_NO_ERR;
map_ns = map_root->ns;
iter.ns = object_root->ns;
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
iter.ns = map_ns;
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
if (valid.error_state != ERR_BACKEND_NO_ERR) {
qof_backend_set_error(params->be, valid.error_state);
g_hash_table_destroy(valid.validation_table);
return FALSE;
}
/* check all counted objects are valid */
/* Should be:
the same number of valid object calculations as there are defined in the map.
And the number of calculations must match the number of unregistered
objects plus the number of registered objects defined. */
valid_count = g_hash_table_size(valid.validation_table) - valid.map_calculated_count;
calc_count = valid.map_calculated_count -
(valid.valid_object_count + valid.qof_registered_count);
if(valid_count == 0 && calc_count == 0) {
g_hash_table_destroy(valid.validation_table);
qof_backend_get_error(params->be);
return TRUE;
}
qof_backend_set_error(params->be, ERR_QSF_WRONG_MAP);
/* the object is OK, only the map is wrong. */
PINFO (" Map is wrong. map:%d object:%d reg:%d size:%d result:%d",
valid.map_calculated_count, valid.valid_object_count,
valid.qof_registered_count,
g_hash_table_size(valid.validation_table), valid_count);
if(valid_count != 0) {
PINFO (" size - map != 0. actual: %d.", valid_count);
}
if(calc_count != 0) {
PINFO (" map - (object + registered) != 0. Actual: %d.", calc_count);
}
g_hash_table_destroy(valid.validation_table);
return TRUE;
result = check_qsf_object_with_map_internal(map_doc, doc);
qof_backend_set_error(params->be, result);
return (result == ERR_BACKEND_NO_ERR) ? TRUE : FALSE;
}
gboolean is_qsf_object_with_map(const gchar *path, gchar *map_file)
{
xmlDocPtr doc, map_doc;
gint valid_count;
struct qsf_node_iterate iter;
xmlNodePtr map_root, object_root;
xmlNsPtr map_ns;
qsf_validator valid;
QofBackendError result;
gchar *map_path;
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
@ -220,39 +271,12 @@ gboolean is_qsf_object_with_map(const gchar *path, gchar *map_file)
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) {
return FALSE;
}
object_root = xmlDocGetRootElement(doc);
if(map_path == NULL) {
return FALSE;
}
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
map_doc = xmlParseFile(map_path);
if(map_doc == NULL) {
return FALSE;
}
if(TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, map_doc)) {
return FALSE;
}
map_root = xmlDocGetRootElement(map_doc);
valid.map_calculated_count = 0;
valid.valid_object_count = 0;
valid.error_state = ERR_BACKEND_NO_ERR;
map_ns = map_root->ns;
iter.ns = map_ns;
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
iter.ns = object_root->ns;
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
if (valid.error_state != ERR_BACKEND_NO_ERR) {
g_hash_table_destroy(valid.validation_table);
return FALSE;
}
valid_count = 0 - g_hash_table_size(valid.validation_table);
valid_count += valid.map_calculated_count;
valid_count += valid.valid_object_count;
g_hash_table_destroy(valid.validation_table);
if(valid_count == 0) {
return TRUE;
}
return FALSE;
result = check_qsf_object_with_map_internal(map_doc, doc);
return (result == ERR_BACKEND_NO_ERR) ? TRUE : FALSE;
}
gboolean is_qsf_map_be(qsf_param *params)
@ -283,16 +307,17 @@ gboolean is_qsf_map_be(qsf_param *params)
map_root = xmlDocGetRootElement(doc);
map_ns = map_root->ns;
iter.ns = map_ns;
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.object_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.map_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.error_state = ERR_BACKEND_NO_ERR;
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
if (valid.error_state != ERR_BACKEND_NO_ERR) {
qof_backend_set_error(params->be, valid.error_state);
g_hash_table_destroy(valid.validation_table);
g_hash_table_destroy(valid.object_table);
return FALSE;
}
qof_backend_get_error(params->be);
g_hash_table_destroy(valid.validation_table);
g_hash_table_destroy(valid.object_table);
return TRUE;
}
@ -315,17 +340,16 @@ gboolean is_qsf_map(const gchar *path)
map_ns = map_root->ns;
iter.ns = map_ns;
valid.error_state = ERR_BACKEND_NO_ERR;
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.map_table = g_hash_table_new(g_str_hash, g_str_equal);
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
if (valid.error_state != ERR_BACKEND_NO_ERR) {
g_hash_table_destroy(valid.validation_table);
g_hash_table_destroy(valid.map_table);
return FALSE;
}
g_hash_table_destroy(valid.validation_table);
g_hash_table_destroy(valid.map_table);
return TRUE;
}
static void
qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
{
@ -335,11 +359,13 @@ qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
g_return_if_fail(params->qsf_define_hash != NULL);
iterate = NULL;
if (qsf_is_element(child, ns, MAP_DEFINE_TAG)) {
iterate = xmlGetProp(child, MAP_ITERATE_ATTR);
if(qof_util_bool_to_int(iterate) == 1)
{
params->qof_foreach = xmlGetProp(child, BAD_CAST MAP_E_TYPE);
}
iterate = xmlGetProp(child, MAP_ITERATE_ATTR);
if((qof_util_bool_to_int(iterate) == 1) &&
(qof_class_is_registered(xmlGetProp(child, BAD_CAST MAP_E_TYPE))))
{
params->qof_foreach = xmlGetProp(child, BAD_CAST MAP_E_TYPE);
PINFO (" iterating over '%s' objects", params->qof_foreach);
}
if(NULL == g_hash_table_lookup(params->qsf_define_hash,
xmlGetProp(child, BAD_CAST MAP_E_TYPE)))
{
@ -398,17 +424,17 @@ static void
qsf_map_top_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
{
xmlChar *qof_version;
GString *buff;
gchar *buff;
struct qsf_node_iterate iter;
if(!params->qsf_define_hash) return;
if(!params->qsf_default_hash) return;
ENTER (" child=%s", child->name);
ENTER (" map top node child=%s", child->name);
buff = NULL;
if(qsf_is_element(child, ns, MAP_DEFINITION_TAG)) {
qof_version = xmlGetProp(child, BAD_CAST MAP_QOF_VERSION);
buff = g_string_new(" ");
g_string_printf(buff, "%i", QSF_QOF_VERSION);
if(xmlStrcmp(qof_version, BAD_CAST buff->str) != 0) {
buff = g_strdup_printf("%i", QSF_QOF_VERSION);
if(xmlStrcmp(qof_version, BAD_CAST buff) != 0) {
qof_backend_set_error(params->be, ERR_QSF_BAD_QOF_VERSION);
LEAVE (" ERR_QSF_BAD_QOF_VERSION set");
return;
@ -453,7 +479,8 @@ qsf_set_handler(xmlNodePtr parent, GHashTable *default_hash,
if(qsf_is_element(cur_node, params->map_ns, QSF_CONDITIONAL_SET))
{
content = (gchar*)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,
xmlNodeGetContent(cur_node));
@ -565,8 +592,7 @@ qsf_set_format_value(xmlChar *format, gchar *qsf_time_now_as_string,
result = regexec(&reg, (gchar*)format,(size_t)0,NULL,0);
if(result == REG_NOMATCH) { format = BAD_CAST "%F"; }
regfree(&reg);
/** QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats.
*/
/* 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");
}
@ -609,7 +635,8 @@ qsf_calculate_conditional(xmlNodePtr param_node, xmlNodePtr child, qsf_param *pa
/* Is the default set to true? */
if( 0 == qsf_compare_tag_strings(output_content, QSF_XML_BOOLEAN_TEST))
{
qsf_boolean_set_value(param_node, params, (gchar*)output_content, params->map_ns);
qsf_boolean_set_value(param_node, params, (gchar*)output_content,
params->map_ns);
export_node = xmlAddChild(params->lister, xmlNewNode(params->qsf_ns,
xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE)));
xmlNewProp(export_node, BAD_CAST QSF_OBJECT_TYPE,
@ -644,6 +671,8 @@ qsf_add_object_tag(qsf_param *params, gint count)
static gint
identify_source_func(gconstpointer qsf_object, gconstpointer map)
{
PINFO (" qsf_object=%s, map=%s",
((qsf_objects*)qsf_object)->object_type, (QofIdType)map);
return safe_strcmp(((qsf_objects*)qsf_object)->object_type, (QofIdType)map);
}
@ -652,22 +681,27 @@ qsf_map_calculate_output(xmlNodePtr param_node, xmlNodePtr child, qsf_param *par
{
xmlNodePtr export_node;
xmlChar *output_content;
xmlNodePtr node;
xmlNodePtr input_node;
GList *source;
DEBUG (" %s", xmlNodeGetContent(param_node));
output_content = xmlNodeGetContent(param_node);
DEBUG (" %s", output_content);
/* source refers to the source object that provides the data */
source = g_list_find_custom(params->qsf_object_list,
BAD_CAST xmlGetProp(param_node, MAP_OBJECT_ATTR), identify_source_func);
if(!source) return;
PINFO (" checking %s", BAD_CAST xmlGetProp(param_node, MAP_OBJECT_ATTR));
if(!source) { DEBUG (" no source found in list."); return; }
params->object_set = source->data;
node = g_hash_table_lookup(params->object_set->parameters, output_content);
input_node = g_hash_table_lookup(params->object_set->parameters,
output_content);
DEBUG (" node_value=%s, content=%s",
xmlGetProp(child, BAD_CAST MAP_VALUE_ATTR),
xmlNodeGetContent(input_node));
export_node = xmlAddChild(params->lister, xmlNewNode(params->qsf_ns,
xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE)));
xmlNewProp(export_node, BAD_CAST QSF_OBJECT_TYPE,
xmlGetProp(child, BAD_CAST MAP_VALUE_ATTR));
if(node) { xmlNodeAddContent(export_node, xmlNodeGetContent(node)); }
xmlNodeAddContent(export_node, xmlNodeGetContent(input_node));
}
static void
@ -712,7 +746,7 @@ qsf_map_object_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
qsf_string_default_handler("qsf_time_string",
params->qsf_default_hash, params->lister, child, qsf_ns);
}
qsf_map_calculate_output(param_node, child, params);
qsf_map_calculate_output(param_node, child, params);
}
qsf_calculate_conditional( param_node, child, params);
qsf_calculate_else(param_node, child, params);
@ -776,11 +810,12 @@ qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
map_root = xmlDocGetRootElement(mapDoc);
params->foreach_limit = 0;
iter.ns = params->map_ns;
/* sets qof_foreach iterator, defines and defaults. */
qsf_node_foreach(map_root, qsf_map_top_node_handler, &iter, params);
/* identify the entities of iterator type. */
iter.ns = params->qsf_ns;
qsf_node_foreach(qsf_root->children->next, iterator_cb, &iter, params);
PINFO (" counted %d records", params->foreach_limit);
params->count = 0;
for(cur_node = map_root->children; cur_node != NULL; cur_node = cur_node->next)
{
@ -790,24 +825,25 @@ qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
gint i;
params->lister = NULL;
PINFO (" found an object tag. starting calculation");
/* cur_node describes the target object */
if(!qof_class_is_registered(BAD_CAST
if(!qof_class_is_registered(BAD_CAST
xmlGetProp(cur_node, MAP_TYPE_ATTR))) { continue; }
qsf_add_object_tag(params, params->count);
params->count++;
iter.ns = params->map_ns;
for(i = 0; i < params->foreach_limit; i++)
PINFO (" params->foreach_limit=%d", params->foreach_limit);
for(i = -1; i < params->foreach_limit; i++)
{
qsf_node_foreach(cur_node, qsf_map_object_handler, &iter, params);
params->qsf_object_list = g_list_next(params->qsf_object_list);
qsf_add_object_tag(params, params->count);
params->count++;
}
}
}
params->file_type = OUR_QSF_OBJ;
/* use for debugging */
/* xmlSaveFormatFileEnc("-", output_doc, "UTF-8", 1);*/
xmlSaveFormatFileEnc("-", output_doc, "UTF-8", 1);
LEAVE (" ");
return output_doc;
}

View File

@ -14,7 +14,7 @@
* 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 Library General Public License for more details.
* 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
@ -122,22 +122,28 @@ qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *vali
xmlNodePtr cur_node;
xmlChar *object_declaration;
guint count;
QsfStatus type;
gboolean is_registered;
count = 0;
type = QSF_NO_OBJECT;
is_registered = FALSE;
for(cur_node = child->children; cur_node != NULL;
cur_node = cur_node->next)
{
if(qsf_is_element(cur_node, ns, QSF_OBJECT_TAG)) {
object_declaration = xmlGetProp(cur_node, BAD_CAST QSF_OBJECT_TYPE);
count = g_hash_table_size(valid->validation_table);
g_hash_table_insert(valid->validation_table, object_declaration, xmlNodeGetContent(cur_node));
if(g_hash_table_size(valid->validation_table) > count)
is_registered = qof_class_is_registered(object_declaration);
if(is_registered) { type = QSF_REGISTERED_OBJECT; }
else { type = QSF_DEFINED_OBJECT; }
count = g_hash_table_size(valid->object_table);
g_hash_table_insert(valid->object_table, object_declaration,
GINT_TO_POINTER(type));
/* if insert was successful - i.e. object is unique so far */
if(g_hash_table_size(valid->object_table) > count)
{
valid->valid_object_count++;
if(TRUE == qof_class_is_registered((QofIdTypeConst) object_declaration))
{
valid->qof_registered_count++;
}
if(is_registered) { valid->qof_registered_count++; }
}
}
}
@ -161,13 +167,13 @@ gboolean is_our_qsf_object(const gchar *path)
}
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.object_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);
table_count = g_hash_table_size(valid.object_table);
g_hash_table_destroy(valid.object_table);
if(table_count == valid.qof_registered_count) { return TRUE; }
return FALSE;
}
@ -214,18 +220,18 @@ gboolean is_our_qsf_object_be(qsf_param *params)
}
params->file_type = IS_QSF_OBJ;
object_root = xmlDocGetRootElement(doc);
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.object_table = g_hash_table_new(g_str_hash, g_str_equal);
valid.qof_registered_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);
table_count = g_hash_table_size(valid.object_table);
if(table_count == valid.qof_registered_count)
{
g_hash_table_destroy(valid.validation_table);
g_hash_table_destroy(valid.object_table);
qof_backend_set_error(params->be, ERR_BACKEND_NO_ERR);
return TRUE;
}
g_hash_table_destroy(valid.validation_table);
g_hash_table_destroy(valid.object_table);
qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
return FALSE;
}
@ -262,17 +268,17 @@ gboolean is_qsf_object_be(qsf_param *params)
/* retrieve list of maps from config frame. */
for(maps = params->map_files; maps; maps=maps->next)
{
QofBackendError err;
QofBackendError err;
result = is_qsf_object_with_map_be(maps->data, params);
err = qof_backend_get_error(params->be);
if((err == ERR_BACKEND_NO_ERR) && result)
{
params->map_path = maps->data;
PINFO ("map chosen = %s", params->map_path);
break;
}
/* pop the error back on the stack. */
else { qof_backend_set_error(params->be, err); }
err = qof_backend_get_error(params->be);
if((err == ERR_BACKEND_NO_ERR) && result)
{
params->map_path = maps->data;
PINFO ("map chosen = %s", params->map_path);
break;
}
/* pop the error back on the stack. */
else { qof_backend_set_error(params->be, err); }
}
return result;
}
@ -364,5 +370,5 @@ qsf_book_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
}
qsf_node_foreach(child, qsf_object_node_handler, &iter, params);
}
LEAVE (" ");
LEAVE (" ");
}

View File

@ -14,7 +14,7 @@
* 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 Library General Public License for more details.
* 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
@ -331,6 +331,35 @@ Both defaults use UTC.
#define QSF_OBJECT_SCHEMA "qsf-object.xsd.xml" /**< Name of the QSF Object Schema. */
#define QSF_MAP_SCHEMA "qsf-map.xsd.xml" /**< Name of the QSF Map Schema. */
/** \brief Status of various object during mapping.
When handling a map, the incoming QSF objects are not registered with this
instance of QOF - they originate from another QOF user. Each object in a map
needs to be defined. If the object is registered, the map is checked to locate
a calculation that can be used to generate this object. If the object is not
registered, the incoming QSF is checked to ensure it provides the object data
for the calculation. If anything goes wrong, QSF_INVALID_OBJECT is used.
Maps can be unidirectional or bidirectional so QOF registration is used to
determine which calculations should be used and which should be ignored.
All QSF_REGISTERED_OBJECT types need a calculation - if any types remain tagged
as QSF_REGISTERED_OBJECT when the map validation is complete, the validation
must fail. The only acceptable end values for QsfStatus are QSF_DEFINED_OBJECT,
QSF_CALCULATED_OBJECT or QSF_INVALID_OBJECT.
*/
typedef enum {
QSF_NO_OBJECT = 0, /**< Init value only. */
QSF_DEFINED_OBJECT, /**< The object is unregistered but defined.
Objects of this type must exist in the incoming QSF and must
provide data for the calculation of registered objects. */
QSF_REGISTERED_OBJECT, /**< Temporary value. The object is registered
and defined - a calculation is needed but has not been found, yet. */
QSF_CALCULATED_OBJECT, /**< The object is registered, defined and can be calculated. */
QSF_INVALID_OBJECT /**< Oops value. */
}QsfStatus;
/** \brief QSF Parameters
This struct is a catch-all for all parameters required
@ -347,26 +376,27 @@ 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 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 gchar *qof_type; /**< Holds details of the QOF_TYPE */
QofIdType qof_obj_type; /**< current QofObject type (e_type) for the parameters. */
QofIdType qof_foreach; /**< How to iterate over hierarchical entities. */
gint foreach_limit; /**< How many iterations are found in the QSF */
QofEntity *qsf_ent; /**< Current entity in the book. */
QofBackend *be; /**< the current QofBackend for this operation. */
gboolean knowntype; /**< detect references by comparing with known QOF types. */
QofParam *qof_param; /**< used by kvp to handle the frame hash table */
QofBook *book; /**< the current QofBook.
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 gchar *qof_type; /**< Holds details of the QOF_TYPE */
QofIdType qof_obj_type; /**< current QofObject type (e_type) for the parameters. */
QofIdType qof_foreach; /**< How to iterate over hierarchical entities. */
gint foreach_limit; /**< How many iterations are found in the QSF */
QofEntity *qsf_ent; /**< Current entity in the book. */
QofBackend *be; /**< the current QofBackend for this operation. */
gboolean knowntype; /**< detect references by comparing with known QOF types. */
QofParam *qof_param; /**< used by kvp to handle the frame hash table */
QofBook *book; /**< the current QofBook.
Theoretically, QSF can handle multiple QofBooks - currently limited to 1.
*/
@ -392,10 +422,19 @@ typedef struct qsf_validates
QofBackendError error_state;
const gchar *object_path;
const gchar *map_path;
GHashTable *validation_table;
gint valid_object_count;
gint map_calculated_count;
gint qof_registered_count;
GHashTable *object_table; /**< Names of all incoming objects (from the
object_type) and status (QOF registration). */
GHashTable *map_table; /**< Names of all defined objects (from the
define tag) and status (presence of a calculation.)*/
/* Need to match object names, not just counts. */
gint valid_object_count; /**< Number of unique incoming objects as
defined in ::QSF_OBJECT_TAG tags in the QSF.*/
gint map_calculated_count; /**< Number of objects that can be calculated
by this map. ::MAP_OBJECT_TAG. */
gint qof_registered_count; /**< Number of objects (in either the QSF
or the map) that are registered with QofObject. */
gint incoming_count; /**< Number of unique objects in the incoming
QSF file. Used to ensure all incoming objects are used.*/
}qsf_validator;
/** \brief shorthand function

View File

@ -24,7 +24,6 @@
#ifndef _DEPRECATED_H
#define _DEPRECATED_H
#include <glib.h> /* deprecated */
#include "qof.h"
/** @file deprecated.h

View File

@ -868,7 +868,7 @@ kvp_frame_get_numeric(const KvpFrame *frame, const char *path)
return kvp_value_get_numeric(kvp_frame_get_slot (frame, key));
}
const char *
char *
kvp_frame_get_string(const KvpFrame *frame, const char *path)
{
char *key = NULL;

View File

@ -183,7 +183,7 @@ Use kvp_frame_set_string instead of kvp_frame_set_str
* The kvp_frame_set_frame_nc() routine works as above, but does
* *NOT* copy the frame.
*/
void kvp_frame_set_string(KvpFrame * frame, const gchar * path, const gchar* str);
void kvp_frame_set_string(KvpFrame * frame, const gchar * path, const char* str);
void kvp_frame_set_guid(KvpFrame * frame, const gchar * path, const GUID *guid);
void kvp_frame_set_frame(KvpFrame *frame, const gchar *path, KvpFrame *chld);
@ -348,7 +348,7 @@ KvpFrame * kvp_frame_add_value_nc(KvpFrame * frame, const gchar * path, KvpValue
gint64 kvp_frame_get_gint64(const KvpFrame *frame, const gchar *path);
double kvp_frame_get_double(const KvpFrame *frame, const gchar *path);
gnc_numeric kvp_frame_get_numeric(const KvpFrame *frame, const gchar *path);
const gchar * kvp_frame_get_string(const KvpFrame *frame, const gchar *path);
gchar * kvp_frame_get_string(const KvpFrame *frame, const gchar *path);
GUID * kvp_frame_get_guid(const KvpFrame *frame, const gchar *path);
void * kvp_frame_get_binary(const KvpFrame *frame, const gchar *path,
guint64 * size_return);
@ -677,7 +677,7 @@ gboolean kvp_value_binary_append(KvpValue *v, void *data, guint64 size);
slot values. You must handle that in proc, with a suitable
recursive call if desired. */
void kvp_frame_for_each_slot(KvpFrame *f,
void (*proc)(const gchar *key,
void (*proc)(const char *key,
KvpValue *value,
gpointer data),
gpointer data);

View File

@ -297,9 +297,11 @@ qof_book_merge_commit_foreach (
iter.fcn = cb;
subList = NULL;
iter.ruleList = NULL;
for (node = mergeData->mergeList; node != NULL; node = node->next) {
for (node = mergeData->mergeList; node != NULL; node = node->next)
{
currentRule = node->data;
if(currentRule->mergeResult == mergeResult) {
if(currentRule->mergeResult == mergeResult)
{
subList = g_list_prepend(subList, currentRule);
}
}
@ -746,7 +748,7 @@ qof_book_merge_init( QofBook *importBook, QofBook *targetBook)
{
QofBookMergeData *mergeData;
QofBookMergeRule *currentRule;
GList *node;
GList *check;
g_return_val_if_fail((importBook != NULL)&&(targetBook != NULL), NULL);
mergeData = g_new(QofBookMergeData, 1);
@ -762,12 +764,13 @@ qof_book_merge_init( QofBook *importBook, QofBook *targetBook)
mergeData->currentRule = currentRule;
qof_object_foreach_type(qof_book_merge_foreach_type, mergeData);
g_return_val_if_fail(mergeData->mergeObjectParams, NULL);
if(mergeData->orphan_list != NULL) {
if(mergeData->orphan_list != NULL)
{
qof_book_merge_match_orphans(mergeData);
}
for (node = mergeData->mergeList; node != NULL; node = node->next) {
currentRule = node->data;
for (check = mergeData->mergeList; check != NULL; check = check->next)
{
currentRule = check->data;
if(currentRule->mergeResult == MERGE_INVALID) {
mergeData->abort = TRUE;
return(NULL);
@ -948,7 +951,8 @@ qof_book_merge_commit(QofBookMergeData *mergeData )
if(mergeData->abort == TRUE) return -1;
check = g_list_copy(mergeData->mergeList);
g_return_val_if_fail(check != NULL, -1);
for (node = check; node != NULL; node = node->next) {
for (node = check; node != NULL; node = node->next)
{
currentRule = node->data;
if(currentRule->mergeResult == MERGE_INVALID) {
qof_book_merge_abort(mergeData);
@ -962,9 +966,9 @@ qof_book_merge_commit(QofBookMergeData *mergeData )
}
g_list_free(check);
qof_book_merge_commit_foreach(qof_book_merge_commit_rule_loop,
MERGE_NEW, mergeData);
MERGE_NEW, mergeData);
qof_book_merge_commit_foreach(qof_book_merge_commit_rule_loop,
MERGE_UPDATE, mergeData);
MERGE_UPDATE, mergeData);
/* Placeholder for QofObject merge_helper_cb - all objects
and all parameters set */
while(mergeData->mergeList != NULL) {
@ -1000,8 +1004,8 @@ qof_book_merge_rule_foreach(QofBookMergeData *mergeData,
iter.fcn = cb;
iter.data = mergeData;
matching_rules = NULL;
iter.ruleList = NULL;
for (node = mergeData->mergeList; node != NULL; node = node->next) {
for (node = mergeData->mergeList; node != NULL; node = node->next)
{
currentRule = node->data;
if(currentRule->mergeResult == mergeResult) {
matching_rules = g_list_prepend(matching_rules, currentRule);

View File

@ -14,7 +14,7 @@
* 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 Library General Public License for more details.
* 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

View File

@ -54,6 +54,7 @@ strncasestr(const guchar *str1, const guchar *str2, size_t len)
return NULL;
}
#ifndef HAVE_STRCASESTR
/* Search for str2 in str1, ignore case. Return pointer to first
* match, or null. */
gchar *
@ -63,6 +64,7 @@ strcasestr(const gchar *str1, const gchar *str2)
gchar * retval = strncasestr (str1, str2, len);
return retval;
}
#endif
gint
safe_strcmp (const gchar * da, const gchar * db)

View File

@ -197,6 +197,7 @@ gint null_strcmp (const gchar * da, const gchar * db);
* and the strstr functions, except that they ignore the case. */
extern gchar *strncasestr(const guchar *str1, const guchar *str2,
size_t len);
extern gchar *strcasestr(const gchar *str1, const gchar *str2);
/** The ultostr() subroutine is the inverse of strtoul(). It accepts a