[Gnucash-changes] r13797 - gnucash/trunk - Final changes for QOF 0.6.4 - Improvements in map handling.

Neil Williams codehelp at cvs.gnucash.org
Mon Apr 17 09:06:35 EDT 2006


Author: codehelp
Date: 2006-04-17 09:06:33 -0400 (Mon, 17 Apr 2006)
New Revision: 13797
Trac: http://svn.gnucash.org/trac/changeset/13797

Modified:
   gnucash/trunk/ChangeLog
   gnucash/trunk/configure.in
   gnucash/trunk/lib/libqof/backend/file/pilot-qsf-gncCustomer.xml
   gnucash/trunk/lib/libqof/backend/file/qof-backend-qsf.h
   gnucash/trunk/lib/libqof/backend/file/qsf-backend.c
   gnucash/trunk/lib/libqof/backend/file/qsf-xml-map.c
   gnucash/trunk/lib/libqof/backend/file/qsf-xml.c
   gnucash/trunk/lib/libqof/backend/file/qsf-xml.h
   gnucash/trunk/lib/libqof/qof/deprecated.h
   gnucash/trunk/lib/libqof/qof/kvp_frame.c
   gnucash/trunk/lib/libqof/qof/kvp_frame.h
   gnucash/trunk/lib/libqof/qof/qofbookmerge.c
   gnucash/trunk/lib/libqof/qof/qofchoice.c
   gnucash/trunk/lib/libqof/qof/qofutil.c
   gnucash/trunk/lib/libqof/qof/qofutil.h
Log:
Final changes for QOF 0.6.4 - Improvements in map handling.

Modified: gnucash/trunk/ChangeLog
===================================================================
--- gnucash/trunk/ChangeLog	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/ChangeLog	2006-04-17 13:06:33 UTC (rev 13797)
@@ -1,3 +1,23 @@
+2006-04-17  Neil Williams <linux at 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 at wilddev.net>
 
 	* NEWS: Added some text about the release.

Modified: gnucash/trunk/configure.in
===================================================================
--- gnucash/trunk/configure.in	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/configure.in	2006-04-17 13:06:33 UTC (rev 13797)
@@ -472,8 +472,8 @@
 	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])

Modified: gnucash/trunk/lib/libqof/backend/file/pilot-qsf-gncCustomer.xml
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/pilot-qsf-gncCustomer.xml	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/backend/file/pilot-qsf-gncCustomer.xml	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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>

Modified: gnucash/trunk/lib/libqof/backend/file/qof-backend-qsf.h
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/qof-backend-qsf.h	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/backend/file/qof-backend-qsf.h	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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

Modified: gnucash/trunk/lib/libqof/backend/file/qsf-backend.c
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/qsf-backend.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/backend/file/qsf-backend.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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 @@
 	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 @@
 	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 @@
 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 @@
 	}
 	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 @@
 		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 @@
 /* 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 @@
 		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 @@
 			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 @@
 			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 @@
 				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 @@
 			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 @@
 	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 @@
 	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 @@
 	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);
+	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;
 		}
-		break;
-	  case KVP_TYPE_DOUBLE:
-  		errno = 0;
-		cm_double = strtod(content, &tail);
-		if(errno == 0) {
-			return kvp_value_new_double(cm_double);
+		case KVP_TYPE_DOUBLE:
+		{
+			errno = 0;
+			cm_double = strtod(content, &tail);
+			if(errno == 0) {
+				return kvp_value_new_double(cm_double);
+			}
+			break;
 		}
-		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))
+		case KVP_TYPE_NUMERIC:
 		{
-			return kvp_value_new_guid(cm_guid);
+			string_to_gnc_numeric(content, &cm_numeric);
+			return kvp_value_new_gnc_numeric(cm_numeric);
+			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_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 @@
 	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 @@
 		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 @@
 {
 	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";

Modified: gnucash/trunk/lib/libqof/backend/file/qsf-xml-map.c
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/qsf-xml-map.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/backend/file/qsf-xml-map.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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 @@
 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 */
 			{
+				/* 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++;
-				PINFO (" %s is to be calculated", obj_type);
+				/* store the result */
+				g_hash_table_insert(valid->map_table, obj_type, GINT_TO_POINTER(type));
+				break;
 			}
-			else { PINFO (" %s to be mapped", obj_type); }
+			default :
+			{
+				type = QSF_INVALID_OBJECT;
+				break;
+			}
 		}
+		PINFO (" final type=%s result=%d", obj_type, type);
+		if(type == QSF_INVALID_OBJECT) { valid->error_state = ERR_QSF_WRONG_MAP; }
 	}
 }
 
-gboolean is_qsf_object_with_map_be(gchar *map_file, qsf_param *params)
+static QofBackendError
+check_qsf_object_with_map_internal(xmlDocPtr map_doc, xmlDocPtr doc)
 {
-	xmlDocPtr doc, map_doc;
-	gint valid_count, calc_count;
+	xmlNodePtr map_root, object_root;
 	struct qsf_node_iterate iter;
-	xmlNodePtr map_root, object_root;
+	qsf_validator valid;
 	xmlNsPtr map_ns;
-	qsf_validator valid;
-	gchar *path;
-	gchar *map_path;
 
+	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;
+	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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 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 @@
 		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 @@
 	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 @@
 			/* 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 @@
 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 @@
 {
 	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_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 @@
 	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 @@
 			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;
 }

Modified: gnucash/trunk/lib/libqof/backend/file/qsf-xml.c
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/qsf-xml.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/backend/file/qsf-xml.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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 @@
 	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 @@
 	}
 	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 @@
 	}
 	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 @@
 	/* 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_node_foreach(child, qsf_object_node_handler, &iter, params);
 	}
-    LEAVE (" ");
+	LEAVE (" ");
 }

Modified: gnucash/trunk/lib/libqof/backend/file/qsf-xml.h
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/qsf-xml.h	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/backend/file/qsf-xml.h	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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 @@
 
 #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 @@
 	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 @@
 	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

Modified: gnucash/trunk/lib/libqof/qof/deprecated.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/deprecated.h	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/deprecated.h	2006-04-17 13:06:33 UTC (rev 13797)
@@ -24,7 +24,6 @@
  
 #ifndef _DEPRECATED_H
 #define _DEPRECATED_H
-#include <glib.h> /* deprecated */
 #include "qof.h"
 
 /** @file deprecated.h

Modified: gnucash/trunk/lib/libqof/qof/kvp_frame.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/kvp_frame.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/kvp_frame.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -868,7 +868,7 @@
   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;

Modified: gnucash/trunk/lib/libqof/qof/kvp_frame.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/kvp_frame.h	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/kvp_frame.h	2006-04-17 13:06:33 UTC (rev 13797)
@@ -183,7 +183,7 @@
  * 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 @@
 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 @@
    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);

Modified: gnucash/trunk/lib/libqof/qof/qofbookmerge.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofbookmerge.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/qofbookmerge.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -297,9 +297,11 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 	}
 	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 @@
 	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);

Modified: gnucash/trunk/lib/libqof/qof/qofchoice.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofchoice.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/qofchoice.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -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

Modified: gnucash/trunk/lib/libqof/qof/qofutil.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofutil.c	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/qofutil.c	2006-04-17 13:06:33 UTC (rev 13797)
@@ -54,6 +54,7 @@
   return NULL;
 }
 
+#ifndef HAVE_STRCASESTR
 /* Search for str2 in str1, ignore case.  Return pointer to first
  * match, or null.  */
 gchar *
@@ -63,6 +64,7 @@
    gchar * retval = strncasestr (str1, str2, len);
    return retval;
 }
+#endif
 
 gint 
 safe_strcmp (const gchar * da, const gchar * db)

Modified: gnucash/trunk/lib/libqof/qof/qofutil.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofutil.h	2006-04-17 09:05:19 UTC (rev 13796)
+++ gnucash/trunk/lib/libqof/qof/qofutil.h	2006-04-17 13:06:33 UTC (rev 13797)
@@ -197,6 +197,7 @@
  * 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



More information about the gnucash-changes mailing list