[Gnucash-changes] r11622 - in gnucash/branches/cashutil: . cashutil cashutil/po cashutil/src - Add cashutil source to cashutil branch [temp]

Neil Williams codehelp at cvs.gnucash.org
Mon Oct 31 18:42:22 EST 2005


Author: codehelp
Date: 2005-10-31 18:42:19 -0500 (Mon, 31 Oct 2005)
New Revision: 11622

Added:
   gnucash/branches/cashutil/cashutil/
   gnucash/branches/cashutil/cashutil/AUTHORS
   gnucash/branches/cashutil/cashutil/ChangeLog
   gnucash/branches/cashutil/cashutil/HACKING
   gnucash/branches/cashutil/cashutil/Makefile.am
   gnucash/branches/cashutil/cashutil/NEWS
   gnucash/branches/cashutil/cashutil/README
   gnucash/branches/cashutil/cashutil/README.cvs
   gnucash/branches/cashutil/cashutil/TODO
   gnucash/branches/cashutil/cashutil/cashutil-autogen.sh
   gnucash/branches/cashutil/cashutil/configure.ac
   gnucash/branches/cashutil/cashutil/debian/
   gnucash/branches/cashutil/cashutil/make-potfiles.in
   gnucash/branches/cashutil/cashutil/po/
   gnucash/branches/cashutil/cashutil/po/ChangeLog
   gnucash/branches/cashutil/cashutil/po/Makevars
   gnucash/branches/cashutil/cashutil/po/POTFILES.in
   gnucash/branches/cashutil/cashutil/po/en_GB.po
   gnucash/branches/cashutil/cashutil/src/
   gnucash/branches/cashutil/cashutil/src/Makefile.am
   gnucash/branches/cashutil/cashutil/src/README
   gnucash/branches/cashutil/cashutil/src/backend-bus.c
   gnucash/branches/cashutil/cashutil/src/backend-bus.h
   gnucash/branches/cashutil/cashutil/src/cashutil.c
   gnucash/branches/cashutil/cashutil/src/cashutil.h
   gnucash/branches/cashutil/cashutil/src/qof-main.c
   gnucash/branches/cashutil/cashutil/src/qof-main.h
   gnucash/branches/cashutil/cashutil/src/qofundo-p.h
   gnucash/branches/cashutil/cashutil/src/qofundo.c
   gnucash/branches/cashutil/cashutil/src/qofundo.h
Log:
Add cashutil source to cashutil branch [temp]

Added: gnucash/branches/cashutil/cashutil/AUTHORS
===================================================================
--- gnucash/branches/cashutil/cashutil/AUTHORS	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/AUTHORS	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,3 @@
+
+Neil Williams <linux at codehelp.co.uk>
+

Added: gnucash/branches/cashutil/cashutil/ChangeLog
===================================================================
--- gnucash/branches/cashutil/cashutil/ChangeLog	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/ChangeLog	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,137 @@
+2005-09-12  Neil Williams <linux at codehelp.co.uk>
+	* configure.ac: Check for setenv, use GModule,
+	and remove redundant notice.
+	* po/en_GB.po: tweak.
+	* src/Makefile.am: Use GModule.
+	* src/cashutil.c: Keep GnuCash options specific
+	to CashUtil.
+	* src/cashutil.h.in: Imitate the setenv code in
+	GnuCash - will be removed when folded in.
+	* src/qof-main.h: Input is not a generic function,
+	move to CashUtil only.
+	* src/backend/Makefile.am: tweak.
+	* src/backend/gnc-backend-file.c: GnuCash tweak.
+	* src/objects/Makefile.am: tweak.
+
+2005-08-14 Neil Williams <linux at codehelp.co.uk>
+	Sync with GnuCash 
+
+2005-08-12 Neil Williams <linux at codehelp.co.uk>
+	* src/test/test-address.c: Test-address without Guile 
+
+2005-08-10 Neil Williams <linux at codehelp.co.uk>
+	* src/cashutil.c: Sample QOF undo 
+
+2005-08-07 Neil Williams <linux at codehelp.co.uk>
+	* src/objects/Account.c:
+	* src/objects/cap-gains.c:
+	* src/objects/FreSpec.c:
+	* src/objects/Group.c:
+	* src/objectsSchedXaction.c:
+	* src/objects/Scrub2.c:
+	* src/objects/Scrub.c:
+	* src/objects/SX-book.c:
+	* src/objects/Transaction.c:
+	G2 sync and cast changes, removing unnecessary headers.
+
+2005-08-07 Neil Williams <linux at codehelp.co.uk>
+	* src/backend/gnc-account-xml-v2.c:
+	* src/backend/gnc-address-xml-v2.c:
+	* src/backend/gnc-commodity-xml-v2.c:
+	* src/backend/gnc-customer-xml-v2.c:
+	* src/backend/gnc-bill-term-xml-v2.c:
+	* src/backend/gnc-book-xml-v2.c:
+	* src/backend/gnc-employee-xml-v2.c:
+	* src/backend/gnc-entry-xml-v2.c:
+	* src/backend/gnc-invoice-xml-v2.c:
+	* src/backend/gnc-job-xml-v2.c:
+	* src/backend/gnc-order-xml-v2.c:
+	* src/backend/gnc-owner-xml-v2.c:
+	* src/backend/gnc-pricedb-xml-v2.c: 
+	* src/backend/gnc-transaction-xml-v2.c:
+	* src/backend/io-gncbin-r.c:
+	* src/backend/io-gncxml-v2.c:
+	* src/backend/sixtp-dom-generators.c:
+	* src/backend/sixtp-dom-parsers.c:
+	 Sync with G2 and more cast changes 
+	* src/backend/gnc-backend-file.c: 
+	* src/backend/gnc-backend-file.h: QofBackendProvider handling 
+
+2005-07-28  gettextize  <bug-gnu-gettext at gnu.org>
+
+	* m4/codeset.m4: New file, from gettext-0.14.5.
+	* m4/gettext.m4: New file, from gettext-0.14.5.
+	* m4/glibc2.m4: New file, from gettext-0.14.5.
+	* m4/glibc21.m4: New file, from gettext-0.14.5.
+	* m4/iconv.m4: New file, from gettext-0.14.5.
+	* m4/intdiv0.m4: New file, from gettext-0.14.5.
+	* m4/intmax.m4: New file, from gettext-0.14.5.
+	* m4/inttypes.m4: New file, from gettext-0.14.5.
+	* m4/inttypes_h.m4: New file, from gettext-0.14.5.
+	* m4/inttypes-pri.m4: New file, from gettext-0.14.5.
+	* m4/isc-posix.m4: New file, from gettext-0.14.5.
+	* m4/lcmessage.m4: New file, from gettext-0.14.5.
+	* m4/lib-ld.m4: New file, from gettext-0.14.5.
+	* m4/lib-link.m4: New file, from gettext-0.14.5.
+	* m4/lib-prefix.m4: New file, from gettext-0.14.5.
+	* m4/longdouble.m4: New file, from gettext-0.14.5.
+	* m4/longlong.m4: New file, from gettext-0.14.5.
+	* m4/nls.m4: New file, from gettext-0.14.5.
+	* m4/po.m4: New file, from gettext-0.14.5.
+	* m4/printf-posix.m4: New file, from gettext-0.14.5.
+	* m4/progtest.m4: New file, from gettext-0.14.5.
+	* m4/signed.m4: New file, from gettext-0.14.5.
+	* m4/size_max.m4: New file, from gettext-0.14.5.
+	* m4/stdint_h.m4: New file, from gettext-0.14.5.
+	* m4/uintmax_t.m4: New file, from gettext-0.14.5.
+	* m4/ulonglong.m4: New file, from gettext-0.14.5.
+	* m4/wchar_t.m4: New file, from gettext-0.14.5.
+	* m4/wint_t.m4: New file, from gettext-0.14.5.
+	* m4/xsize.m4: New file, from gettext-0.14.5.
+	* m4/Makefile.am: New file.
+	* Makefile.am (ACLOCAL_AMFLAGS): New variable.
+	(EXTRA_DIST): Add config.rpath.
+	* configure.ac (AC_OUTPUT): Add m4/Makefile.
+
+2005-07-24  Neil Williams <linux at codehelp.co.uk>
+	* NEWS: news of test routines.
+	* README: How GnuCash will use CashUtil.
+	* TODO: Changes needed to fit with GnuCash.
+	* src/Account.h: Cannot search if the parameter
+	has a hyphen - this may need to be changed in GnuCash.
+	* src/README:
+	* src/backend/.cvsignore:
+	* src/backend/README: Where the GnuCash XML v2 backend
+	will live during further testing.
+	* src/cashutil.c: Moving the QOF_SQL_SUPPORTED regexp
+	handling to the standard qof-main to be used by all 
+	projects.
+	* src/cashutil.h:
+	* src/gnc-lot-p.h: Removing private QOF header.
+	* src/gnc-lot.c: Removing private QOF header.
+	* src/gncEmployee.c: Experimental. May be reverted.
+	* src/gncEmployee.h:
+	* src/gncEmployeeP.h:
+	* src/gncOrder.c: tweaks.
+	* src/objects/.cvsignore:
+	* src/objects/README: Where all the objects will live
+	during further testing.
+	* src/qof-main.c: regexp support.
+	* src/qof-main.h:
+	* src/test/test-book-merge.c: Imported from GnuCash.
+	* src/test/test-cash.c: Basis of a test routine, incomplete.
+	* website/gnucash.html: Setting out how CashUtil relates to
+	GnuCash.
+	* website/index.html: new page link.
+
+2005-07-17  Neil Williams <linux at codehelp.co.uk>
+
+	* src/website: Added prototype website content.
+	* src/cashutil.c: 
+	* src/cashutil.h: 
+	* src/qof-main.c:
+	* src/qof-main.h: Added shell handling
+
+2005-07-10  Neil Williams <linux at codehelp.co.uk>
+
+	* Initial project creation: based on Pilot-QOF

Added: gnucash/branches/cashutil/cashutil/HACKING
===================================================================
--- gnucash/branches/cashutil/cashutil/HACKING	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/HACKING	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,115 @@
+Hacking on CashUtil
+===================
+
+Make and make install:
+=====================
+
+CashUtil relies on installed versions of the QOF, libcashobjects and libgnc-backend-file libraries. 
+If you change any source files for these libraries, 
+ensure you run 'make install' rather than just 'make' 
+or your changes will have no effect. There is no support 
+for loading local or 'test' versions of the libraries. 
+You can usually run cashutil against a freshly installed set of QOF libraries without recompiling cashutil, depending on 
+the level of changes in QOF.
+
+Debug output:
+=============
+
+#define PRINT_DEBUG is set to 0 in src/cashutil.c prior to packaging. Set to non-zero to print lots of debug information.
+
+IDEs:
+====
+
+KDevelop has some problems with CashUtil build frameworks when you select the debug build. It tends to continually 
+complain about lack of configure.in - it seems to simply 
+ignore configure.ac and autogen.sh and complains that no Makefiles exist when the files are fine.
+
+Do NOT attempt to run configure (with or without arguments) on the CVS code from within KDevelop - it will completely 
+break your Makefiles and you'll need to run ./autogen.sh with 
+the usual parameters all over again (plus make and then make 
+install).
+
+Instead, ignore the debug build and select 'default', entering the ./autogen.sh options for --with-qof and 
+--prefix as normal.
+
+--with-qof=<path to qof> --prefix=<prefix for install>
+
+Check your distribution for the updated KDevelop3 which does support code folding.
+
+CVS support seemed fragile - if KDevelop or Cervisia do not connect to existing repositories, try loading cervisia with a 
+known local working copy directory on the command line:
+$ cervisia <path to checked out project>
+
+If KDevelop also complains about not setting a local working 
+copy, set CVS handling in KDevelop Project Options | Version 
+Control. Close the Options dialog and re-open it to see the 
+CvsService options at the very end of the list. Set the 
+repository name (as displayed by Cervisia or as given in 
+CVS/Root in each directory) as the CVS server location. Close 
+the Options dialog, *close the project* and re-open the 
+project. Suddenly, CVS should become available.
+
+Anjuta has none of these problems. Anjuta also incorporates 
+CVS handling and displays line numbers in the edit window 
+without any special configuration or problems.
+
+Synchronising CashUtil CVS with QOF and GnuCash.
+===============================================
+
+CVS is fine for single trees and branches but it can be hard 
+to keep two or more projects in sync when they use the same 
+files and being developed in both trees. This kind of
+inter-operability between CVS trees tends to become an 
+intensely manual chore.
+
+CashUtil CVS includes a set of MANIFEST files that are intended to help with this problem by using a feature of the 
+makepatch package. By specifying customised MANIFEST files to
+makepatch, only the files mentioned in the manifest are 
+compared. This makes things much easier when dealing with 
+trees that have common files but where those files are not 
+restricted to dedicated directories. e.g. in GnuCash, files 
+in src/engine are a mixture of files from QOF and files from 
+src/objects in CashUtil. By using a manifest file, makepatch 
+can be instructed to only compare the files that are listed 
+in the manifest. Default behaviour is to assume that all
+files in the directory are part of the package (subject to 
+build/CVS exclusion patterns). Making a patch for such a 
+directory would include the missing files in the patch in 
+their entirety and  applying such a patch with applypatch 
+would create the unwanted files in the other tree! Naturally,
+the MANIFEST files need to be kept updated.
+
+Example: To fold changes from GnuCash into CashUtil.
+makepatch -description "cashutil sync" \
+-manifest OBJ_MANIFEST_ENG \
+cashutil/src/objects/ gnucash-gnome2/src/engine/ \
+> ../patches/cashutil_g2_sync.patch
+
+#(Reverse the pathnames to fold changes from CashUtil into GnuCash - old files first).
+# gnucash-gnome2/src/engine/ cashutil/src/objects/ \
+
+Output:
+Manifest OBJ_MANIFEST_ENG for src/objects/ contains 54 files.
+Manifest OBJ_MANIFEST_ENG for /opt/working/gnucash-gnome2/src/engine/ contains 54 files.
+Processing the filelists ...
+Collecting patches ...
+  10 files need to be patched.
+
+Paths to use with each MANIFEST
+-------------------------------
+
+-manifest OBJ_MANIFEST_ENG \
+cashutil/src/objects/ gnucash-gnome2/src/engine/ \
+
+-manifest OBJ_MANIFEST_BUS \
+cashutil/src/objects/ gnucash-gnome2/src/business/business-core/ \
+
+-manifest BACK_MANIFEST_ENG \
+cashutil/src/backend/ gnucash-gnome2/src/backend/file \
+
+-manifest BACK_MANIFEST_BUS \
+cashutil/src/backend/ gnucash-gnome2/src/business/business-core/file/ \
+
+See the makepatch man page for information on generating new manifest files.
+(e.g. QOF_MANIFEST_ENG for qof/qof/ gnucash-gnome2/src/engine/ )
+

Added: gnucash/branches/cashutil/cashutil/Makefile.am
===================================================================
--- gnucash/branches/cashutil/cashutil/Makefile.am	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/Makefile.am	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,24 @@
+
+SUBDIRS = src . po doc
+
+noinst_DATA = make-potfiles
+
+ACLOCAL_AMFLAGS = -I m4
+
+make-potfiles: make-potfiles.in Makefile
+	rm -f $@.tmp
+	 sed < $< > $@.tmp \
+             -e 's:@-PERL-@:${PERL}:g'
+	 chmod +x $@.tmp
+	 mv $@.tmp $@
+
+EXTRA_DIST =  \
+  make-potfiles.in \
+  intltool-extract.in \
+  intltool-merge.in \
+  intltool-update.in
+
+DISTCLEANFILES = \
+  intltool-extract intltool-update intltool-merge\
+  make-potfiles po/.intltool-merge-cache
+

Added: gnucash/branches/cashutil/cashutil/NEWS
===================================================================
--- gnucash/branches/cashutil/cashutil/NEWS	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/NEWS	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,11 @@
+
+This is very much pre-alpha - it compiles and certain
+basic functions do work but the objects and the interactive
+shell are not complete.
+
+Use the test-cash routine for examples of how each shell function
+can be built and to produce sample content.
+
+The test routine still fails and this is likely to continue until
+commodites can be harnessed.
+

Added: gnucash/branches/cashutil/cashutil/README
===================================================================
--- gnucash/branches/cashutil/cashutil/README	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/README	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,81 @@
+CASHUTIL - Command line GnuCash.
+========
+
+Most of the QOF processing is done in qof-main.c - the 
+specifics of making this general template into CashUtil are 
+expressed in cashutil.c which simply loads the particular 
+objects for this program and provides main().
+
+1.  CashUtil uses QSF XML which can be exported
+    from GnuCash v2 - the Gnome2 port which is
+    due for release in late 2005.
+
+2.  CashUtil will concentrate on the business
+    objects, gncInvoice, gncCustomer etc.
+    There are problems with currencies that mean
+    support is delayed.
+
+3.  CashUtil is now being steered towards full inclusion
+    in the GnuCash G2 source tree and using the full 
+    functionality of the GnuCash objects. 
+
+4.  The development of CashUtil is feeding back into
+    GnuCash in the separation of the financial objects
+    into a shared library, together with ancillary
+    logic from the GnuCash UI.
+
+5.  CashUtil will also now link into the GnuCash v2 XML
+    backend to read existing user data files as well as
+    exported data.
+ 
+CashUtil needs QOF v0.6.0 (currently available at v0.6.0-pre1 
+and via CVS). For CVS, build QOF first and pass the location 
+to CashUtil using the --with-qof option to ./autogen.sh
+
+./autogen.sh --with-qof=<QOF path> --prefix=<cashutil test install path>
+
+If installed, omit the --with-qof option.
+
+SUPPORT
+-------
+
+Please send problems, bug reports and feedback to the mailing list:
+http://lists.sourceforge.net/lists/listinfo/qof-devel
+
+
+USING THE CLI WITH YOUR OWN OBJECTS
+-----------------------------------
+
+To alter this program for any other set of objects, most of the 
+changes are within cashutil.c:
+
+-# Amend the list of Register() calls in register_objects(),
+
+-# Amend the help_header_text in main(), 
+
+-# Edit the copyright notice printed by qof_op_vers, also in main()
+
+-# Add your details to the copyright notices in each file and
+change the name of this file and it's header. (Keep existing 
+copyright notices intact to comply with the GNU GPL.) You are 
+reminded that QOF is only licenced under the GNU GPL and any 
+program that is linked against it must also be licenced under 
+the GNU GPL.
+http://www.gnu.org/licenses/gpl-faq.html#IfLibraryIsGPL
+http://www.gnu.org/licenses/gpl-faq.html#TOCLinkingWithGPL
+
+-# Replace the list of object header files in cashutil.c
+
+-# Change the version numbers and name of the program in 
+configure.ac AM_INIT_AUTOMAKE(cashutil, [$VERSION]),
+
+-# Adjust the makefile: src/Makefile.am, to change the names, 
+replacing cashutil in each case, e.g. libcashutil_la_SOURCES
+
+-# List the object files under libmyprog_la_SOURCES, 
+
+-# Replace the object headers in the list in EXTRA_DIST
+
+-# Finally, rename and edit the DocBook XML in doc/xml to 
+reflect the new program.
+

Added: gnucash/branches/cashutil/cashutil/README.cvs
===================================================================
--- gnucash/branches/cashutil/cashutil/README.cvs	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/README.cvs	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,32 @@
+This file contains guidelines for using CashUtil from CVS.
+They have been adapted from the guidelines for GnuCash which 
+in turn were adapted from the guidelines for gnome-libs by
+Miguel de Icaza who adapted them from guidelines written by
+Owen Taylor.
+
+ + In order to build CashUtil from CVS, you need to run the 
+   autogen.sh command to generate and execute a configure 
+   script. When building from CVS you should ALWAYS pass your 
+   configure options directly to autogen.sh.  For example:
+
+   ./autogen.sh --prefix=/opt/cashutil
+
+   Autogen will automatically generate the configure script 
+   and then run it WITH SPECIAL ARGUMENTS to make sure 
+   certain files get built.
+   If you run "configure" without these special arguments, 
+   it is very likely that CashUtil will fail to build.  
+   Therefore, do not run configure by hand.
+
+   If in doubt, you can run autogen.sh, run 
+   ./configure --help,
+   then re-run autogen.sh with your options.
+
+Neil Williams
+Sep 03, 2005
+
+Dave Peticolas
+June 21, 2002
+
+Derek Atkins
+November 21, 2002

Added: gnucash/branches/cashutil/cashutil/TODO
===================================================================
--- gnucash/branches/cashutil/cashutil/TODO	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/TODO	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,19 @@
+The shell is incomplete. The Doxygen output contains
+the list of todo items for completion. To build the docs:
+cd doc
+make doc
+Build the rest of the tree first, using:
+./autogen.sh --with-qof=<QOF location> --prefix=<cashutil prefix>
+
+The website template needs extending but keep to a GnuCash style.
+
+gncCommodity is the biggest problem outstanding. Until
+this is overhauled to be a genuine QOF object, currencies
+and probably stocks will be off-limits.
+
+Later, the GnuCash v2 XML backend will be linked to CashUtil
+in preparation for full inclusion into the GnuCash tree and the
+completed spin-out of QOF (which will have an interim location
+of lib/qof/ in the GnuCash source tree while remaining issues
+are being resolved.
+

Added: gnucash/branches/cashutil/cashutil/cashutil-autogen.sh
===================================================================
--- gnucash/branches/cashutil/cashutil/cashutil-autogen.sh	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/cashutil-autogen.sh	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,251 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+PKG_NAME=cashutil
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+DIE=0
+
+INTLTOOLIZE=${INTLTOOLIZE:-intltoolize}
+LIBTOOLIZE=${LIBTOOLIZE:-libtoolize}
+LIBTOOL=${LIBTOOL:-libtool}
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: You must have \`autoconf' installed to compile $PKG_NAME."
+  echo "Download the appropriate package for your distribution or get the source."
+  echo "Get ftp://ftp.gnu.org/pub/gnu/autoconf/autoconf-2.50.tar.gz"
+  echo "(or a newer version if it is available)"
+  DIE=1
+}
+
+(grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && {
+  (glibtool --version) < /dev/null > /dev/null 2>&1 ||
+  (libtool --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`libtool' installed to compile $PKG_NAME."
+    echo "Get ftp://ftp.gnu.org/pub/gnu/libtool/libtool-1.5.tar.gz"
+    echo "(or a newer version if it is available)"
+    DIE=1
+  }
+}
+
+(grep "^AC_PROG_INTLTOOL" $srcdir/configure.ac >/dev/null) && {
+  (intltoolize --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`intltool' installed."
+    echo "You can get it from:"
+    echo "  ftp://ftp.gnome.org/pub/GNOME/"
+    DIE=1
+  }
+}
+
+(grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.ac >/dev/null) && {
+  (grep "sed.*POTFILES" $srcdir/configure.ac) > /dev/null || \
+  (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`glib' installed."
+    echo "You can get it from: ftp://ftp.gtk.org/pub/gtk"
+    DIE=1
+  }
+}
+
+# usage: test_version program version
+# returns 0 if program >= version; returns 1 if not.
+test_version()
+{
+    this_prog="$1"
+    want_vers="$2"
+
+    testv=`"$this_prog" --version 2>/dev/null | head -1 | awk '{print $NF}'`
+    if test -z "$testv" ; then return 1 ; fi
+
+    testv_major=`echo "$testv" | sed 's/\([0-9]*\).\([0-9]*\).*$/\1/'`
+    testv_minor=`echo "$testv" | sed 's/\([0-9]*\).\([0-9]*\).*$/\2/'`
+
+    vers_major=`echo "$want_vers" | sed 's/\([0-9]*\).\([0-9]*\).*$/\1/'`
+    vers_minor=`echo "$want_vers" | sed 's/\([0-9]*\).\([0-9]*\).*$/\2/'`
+
+    # if wanted_major > found_major, this isn't good enough
+    if test $vers_major -gt $testv_major ; then
+        return 1
+    # if wanted_major < found_major, then this is fine
+    elif test $vers_major -lt $testv_major ; then
+        return 0
+    # if we get here, then the majors are equal, so test the minor version
+    # we want found_minor >= want_minor.
+    # So, if want_minor > found_minor, this is bad.
+    elif test $vers_minor -gt $testv_minor ; then
+        return 1
+    # this is it.
+    else
+        return 0
+    fi
+}
+
+# usage: find_program preset program version "<other versions>"
+# sets "program" to the name of the program to use.
+# if preset is set, then use that regardless,
+#  otherwise check if "program" is of a good enough version and use that,
+#  otherwise check if "program-version" is of a good enough version and use that.
+#  otherwise return an error.
+find_program()
+{
+    find="$1"
+    prog="$2"
+    vers="$3"
+    extravers="$4"
+
+    if test -n "$find" ; then
+        test_version "$find" "$vers"
+        status="$?"
+        if test "$status" = 0 ; then
+            program="$find"
+            return 0
+        fi
+        echo "**Error**: cannot use $find"
+    else
+
+        test_version "$prog" "$vers"
+        status=$?
+        if test "$status" = 0 ; then
+            program="$prog"
+            return 0
+        fi
+
+        for test_vers in $vers $extravers ; do
+            test_version "$prog-$test_vers" "$vers"
+            status=$?
+            if test "$status" = 0 ; then
+                program="$prog-$test_vers"
+                return 0
+            fi
+        done
+    fi
+
+    echo
+    echo "**Warning**: Could not find a $prog that identifies itself >= $vers."
+    echo
+    program="$prog"
+}
+
+# These statics should really be defined at the top
+find_program "$AUTOCONF" autoconf "2.53"
+AUTOCONF="$program"
+find_program "$AUTOHEADER" autoheader "2.53"
+AUTOHEADER="$program"
+find_program "$AUTOMAKE" automake "1.5 1.6 1.7 1.8"
+AUTOMAKE="$program"
+find_program "$ACLOCAL" aclocal "1.5 1.6 1.7 1.8"
+ACLOCAL="$program"
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: You must have \`automake' installed to compile $PKG_NAME."
+  echo "Get ftp://ftp.gnu.org/pub/gnu/automake/automake-1.7.tar.gz"
+  echo "(or a newer version if it is available)"
+  DIE=1
+  NO_AUTOMAKE=yes
+}
+
+# if no automake, don't bother testing for aclocal
+test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: Missing \`aclocal'.  The version of \`automake'"
+  echo "installed doesn't appear recent enough."
+  echo "Get ftp://ftp.gnu.org/pub/gnu/automake/automake-1.7.tar.gz"
+  echo "(or a newer version if it is available)"
+  DIE=1
+}
+
+if test "$DIE" -eq 1; then
+  exit 1
+fi
+
+if test -z "$*"; then
+  echo "**Warning**: I am going to run \`configure' with no arguments."
+  echo "If you wish to pass any to it, please specify them on the"
+  echo \`$0\'" command line."
+  echo
+fi
+
+case $CC in
+xlc )
+  am_opt=--include-deps;;
+esac
+
+for coin in `find $srcdir -name configure.ac -print`
+do
+  dr=`dirname $coin`
+  if test -f $dr/NO-AUTO-GEN; then
+    echo skipping $dr -- flagged as no auto-gen
+  else
+    echo processing $dr
+    ( cd $dr
+      aclocalinclude="$ACLOCAL_FLAGS -I m4"
+
+      if grep "^AM_GLIB_GNU_GETTEXT" configure.ac >/dev/null; then
+	if grep "sed.*POTFILES" configure.ac >/dev/null; then
+	  : do nothing -- we still have an old unmodified configure.ac
+	else
+	  echo "Creating $dr/aclocal.m4 ..."
+	  test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+	  echo "Running glib-gettextize...  Ignore non-fatal messages."
+	  echo "no" | glib-gettextize --force --copy
+	  echo "Making $dr/aclocal.m4 writable ..."
+	  test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+        fi
+      fi
+      if grep "^AM_PROG_LIBTOOL" configure.ac >/dev/null; then
+	if test -z "$NO_LIBTOOLIZE" ; then
+	    case "$OSTYPE" in
+		*darwin*)
+		    echo "Running glibtoolize... ($MACHTYPE)"
+		    glibtoolize --force --copy
+		;;
+		    *)
+		    echo "Running libtoolize..."
+		    libtoolize --force --copy
+		;;
+	    esac
+	fi
+      fi
+     if grep "^AC_PROG_INTLTOOL" configure.ac >/dev/null; then
+        echo "Running intltoolize ..."
+        intltoolize --force --copy --automake
+      fi
+
+      echo "Running aclocal $aclocalinclude ..."
+      $ACLOCAL $aclocalinclude || {
+	echo
+	echo "**Error**: aclocal failed. This may mean that you have not"
+	echo "installed all of the packages you need, or you may need to"
+	echo "set ACLOCAL_FLAGS to include \"-I \$prefix/share/aclocal\""
+	echo "for the prefix where you installed the packages whose"
+	echo "macros were not found"
+	exit 1
+      }
+
+      if grep "^AM_CONFIG_HEADER" configure.ac >/dev/null; then
+	echo "Running autoheader..."
+	$AUTOHEADER || { echo "**Error**: autoheader failed."; exit 1; }
+      fi
+      echo "Running automake --gnu $am_opt ..."
+      $AUTOMAKE --add-missing --gnu $am_opt ||
+	{ echo "**Error**: automake failed."; exit 1; }
+      echo "Running autoconf ..."
+      $AUTOCONF || { echo "**Error**: autoconf failed."; exit 1; }
+    ) || exit 1
+  fi
+done
+
+conf_flags="--enable-maintainer-mode " #--enable-compile-warnings --enable-iso-c
+
+if test x$NOCONFIGURE = x; then
+  echo Running $srcdir/configure $conf_flags "$@" ...
+  $srcdir/configure $conf_flags "$@" \
+  && echo Now type \`make\' to compile $PKG_NAME || exit 1
+else
+  echo Skipping configure process.
+fi


Property changes on: gnucash/branches/cashutil/cashutil/cashutil-autogen.sh
___________________________________________________________________
Name: svn:executable
   + *

Added: gnucash/branches/cashutil/cashutil/configure.ac
===================================================================
--- gnucash/branches/cashutil/cashutil/configure.ac	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/configure.ac	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,430 @@
+# This is free software, licensed under the GNU Public License V2.
+# See the file COPYING for details.
+
+AC_INIT(cashutil, 0.1.0, http://lists.sourceforge.net/lists/listinfo/qof-devel)
+
+AM_MAINTAINER_MODE
+AC_PREFIX_DEFAULT(/usr/local)
+AC_PREREQ(2.53)
+AM_CONFIG_HEADER(config.h)
+
+dnl ******************************
+dnl CashUtil Version
+dnl ******************************
+CASHUTIL_VERS=0
+CASHUTIL_MAJOR=1
+CASHUTIL_MINOR=0
+
+AC_SUBST(CASHUTIL_VERS)
+AC_SUBST(CASHUTIL_MAJOR)
+AC_SUBST(CASHUTIL_MINOR)
+VERSION="$CASHUTIL_VERS.$CASHUTIL_MAJOR.$CASHUTIL_MINOR"
+
+AC_CANONICAL_HOST
+AC_CANONICAL_SYSTEM
+AC_DEFINE_UNQUOTED(HOST_OS, "$host", [Host type])
+AM_INIT_AUTOMAKE(cashutil, [$VERSION])
+AC_PROG_INTLTOOL
+INTLTOOLIZE=${INTLTOOLIZE:-intltoolize}
+
+dnl ******************************
+dnl Checks for basic programs.
+dnl ******************************
+AC_PROG_CC
+AC_PROG_INSTALL
+AM_PROG_LIBTOOL
+AC_PROG_YACC
+
+dnl ******************************
+dnl Platform-specific things
+dnl ******************************
+
+dnl PIC_LIBS is flags needed to compile PIC, for shared libs
+dnl where some linker offsets are not allowed. Currently set
+dnl for FreeBSD-amd64 only.
+PIC_LIBS=""
+
+dnl null_device is the default NULL device on your system
+dnl (usually /dev/null or NUL). If yours is _not_ /dev/null,
+dnl set it in the platform-specific section below.
+null_device="/dev/null"
+
+case "$host" in
+        *darwin*)
+        dnl Use fink under MacOS X
+        AC_MSG_CHECKING(for fink support)
+        if test -d "/sw/lib" -a -d "/sw/include"; then
+            CPPFLAGS="$CPPFLAGS -I/sw/include"
+            LDFLAGS="$LDFLAGS -L/sw/lib"
+            AC_MSG_RESULT(yes)
+        else
+            AC_MSG_RESULT(no)
+        fi
+        AC_CHECK_HEADERS(popt.h)
+        AC_MSG_RESULT([yes, patching libtool to always build dylibs])
+        mv libtool libtool.old
+        sed -e 's/^deplibs_check_method.*/deplibs_check_method=pass_all/g' \
+            -e 's|^archive_cmds.*|archive_cmds="$CC -dynamiclib \\$allow_undefined_flag -o \\$lib \\$libobjs \\$deplibs\\$linker_flags -install_name \\$rpath/\\$soname \\$verstring"|g' \
+            -e 's|^library_names_spec.*|library_names_spec="\\$libname\\$release\\$versuffix.dylib \\$libname\\$release\\${major}.dylib \\$libname.dylib"|g' \
+            -e 's|^soname_spec.*|soname_spec="\\$libname\\$release\\$major.dylib"|g' \
+        < libtool.old > libtool
+        rm libtool.old
+        AC_MSG_RESULT([yes, patching libtool to avoid the libtool bug on MacOSX])
+        mv libtool libtool.old
+        sed -e 's|^old_archive_cmds.*|old_archive_cmds="\\$AR \\$AR_FLAGS \\$oldlib\\$oldobjs\\$old_deplibs \&\& \\$RANLIB \\$oldlib"|g' \
+            -e 's|^old_postinstall_cmds.*|old_postinstall_cmds="\\$RANLIB \\$oldlib \&\& chmod 644 \\$oldlib"|g' \
+       < libtool.old > libtool
+        rm libtool.old
+    ;;
+        amd64*freebsd*)
+                dnl Need -fPIC for shared libs
+                PIC_LIBS="-fPIC"
+    ;;
+        *solaris*)
+                dnl Check if we need -lresolv for inet_pton
+                AC_CHECK_FUNC(inet_pton,,
+                        [AC_CHECK_LIB(resolv,inet_pton,LIBS="-lresolv $LIBS")])
+                AC_CHECK_FUNC(pow,,
+                        [AC_CHECK_LIB(m,pow,LIBS="-lm $LIBS")])
+    ;;
+    *)
+    ;;
+esac
+AC_DEFINE_UNQUOTED(NULL_DEVICE, "$null_device",
+         [Your system's bitbucket (usually /dev/null or NUL)])
+AC_SUBST(PIC_LIBS)
+
+dnl ******************************
+dnl Check if this was CVS source
+dnl ******************************
+if test -f "${srcdir}/README.cvs" ; then
+       PL_FROM_CVS=yes
+fi
+
+### --------------------------------------------------------------------------
+### popt
+
+AC_CHECK_LIB(popt, poptStrippedArgv,, [AC_MSG_ERROR([
+
+  popt 1.5 or newer is required to build cashutil. You can download
+  the latest version from ftp://people.redhat.com/sopwith/popt/, or if
+  you're running Debian, install the libpopt-dev package.
+])])
+
+dnl ******************************
+dnl readline checking
+dnl ******************************
+VL_LIB_READLINE
+
+dnl ******************************
+dnl Cashutil Checks
+dnl ******************************
+AC_HEADER_STDC
+AC_C_CONST
+AC_HEADER_TIME
+AC_TYPE_SIZE_T
+AC_C_INLINE
+AC_HEADER_TIME
+AC_STRUCT_TM
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_MALLOC
+AC_FUNC_MKTIME
+AC_FUNC_CHOWN
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_FORK
+AC_FUNC_STAT
+AC_FUNC_STRFTIME
+AC_FUNC_STRTOD
+AC_FUNC_VPRINTF
+AC_HEADER_DIRENT
+AC_TYPE_PID_T
+
+AC_CHECK_HEADERS(
+	dirent.h errno.h fcntl.h inttypes.h memory.h netdb.h 	  \
+	netinet/in.h regex.h stdint.h stdlib.h string.h strings.h \
+	sys/ioctl_compat.h sys/ioctl.h 	sys/malloc.h sys/select.h \
+	sys/sockio.h sys/time.h sys/utsname.h unistd.h popt.h     \
+	ifaddrs.h inttypes.h langinfo.h libintl.h limits.h )
+
+AC_CHECK_FUNCS(
+	malloc memcpy memmove memset mkdir setenv putenv \
+	sigaction snprintf strchr strdup getline stpcpy  \
+	strtoul strerror getcwd gettimeofday localtime_r \
+	regcomp setlocale strcasecmp strcspn strrchr \
+	strspn strstr strtol strtok)
+
+dnl *************************************
+dnl QOF
+dnl *************************************
+AC_DEFUN([AS_SCRUB_INCLUDE],
+[
+  GIVEN_CFLAGS=$[$1]
+  INCLUDE_DIRS=`echo | cpp -v 2>&1`
+
+  dnl remove everything from this output between the "starts here" and "End of"
+  dnl line
+  INCLUDE_DIRS=`echo $INCLUDE_DIRS | sed -e 's/.*<...> search starts here://' | sed -e 's/End of search list.*//'`
+  for dir in $INCLUDE_DIRS; do
+    GIVEN_CFLAGS=$(echo $GIVEN_CFLAGS | sed -e "s;-I$dir ;;" | sed -e "s;-I$dir$;;")
+  done
+  [$1]=$GIVEN_CFLAGS
+])
+
+AC_ARG_WITH(qof, [  --with-qof=path         prefix for Query Object Framework - QOF (auto)])
+QOF_REQUIRED=0.6.0
+AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+if test pkg-config = no; then
+	AC_MSG_ERROR([Please install pkgconfig])
+	exit 1
+fi
+AC_MSG_CHECKING([for QOF, version >= $QOF_REQUIRED])
+if test "$withval" != "yes"; then
+	QOF=`$PKG_CONFIG --exists '$withval/lib/pkgconfig/qof-1.pc >= $QOF_REQUIRED'`
+	QOF_LIBS=`$PKG_CONFIG --libs $withval/lib/pkgconfig/qof-1.pc`
+	QOF_CFLAGS=`$PKG_CONFIG --cflags $withval/lib/pkgconfig/qof-1.pc`
+	QOF_VERSION=`$PKG_CONFIG --modversion $withval/lib/pkgconfig/qof-1.pc`
+	QOF_PREFIX=`$PKG_CONFIG --variable=prefix $withval/lib/pkgconfig/qof-1.pc`
+	QOF_LIB_DIR=`$PKG_CONFIG --variable=libdir $withval/lib/pkgconfig/qof-1.pc`
+	QOF_XML_DIR=`$PKG_CONFIG --variable=xmldir $withval/lib/pkgconfig/qof-1.pc`
+else
+	QOF=`$PKG_CONFIG --exists 'qof-1 >= $QOF_REQUIRED'`
+	QOF_LIBS=`$PKG_CONFIG --libs qof-1`
+	QOF_CFLAGS=`$PKG_CONFIG --cflags qof-1`
+	QOF_VERSION=`$PKG_CONFIG --modversion qof-1`
+	QOF_PREFIX=`$PKG_CONFIG --variable=prefix qof-1`
+	QOF_LIB_DIR=`$PKG_CONFIG --variable=libdir qof-1`
+	QOF_XML_DIR=`$PKG_CONFIG --variable=xmldir qof-1`
+fi
+AC_SUBST(QOF_CFLAGS)
+AC_SUBST(QOF_LIBS)
+AS_SCRUB_INCLUDE(QOF_PREFIX)
+AC_SUBST(QOF_PREFIX)
+AC_SUBST(QOF_LIB_DIR)
+AC_SUBST(QOF_XML_DIR)
+if test x$QOF_XML_DIR = x; then
+	AC_MSG_RESULT([no])
+	AC_MSG_ERROR([
+	CashUtil requires the Query Object Framework: QOF.
+	You need to install libqof1 >= 0.6.0
+	You can find it at http://qof.sourceforge.net/
+])
+	exit 1
+else
+	AC_MSG_RESULT([yes])
+fi
+
+dnl *************************************
+dnl GLib
+dnl *************************************
+
+AC_PATH_PROG(PKG_CONFIG,pkg-config)
+AM_PATH_GLIB_2_0("2.0.0", , ,gobject)
+if test "x$PKG_CONFIG" != x; then
+	GLIB_LIBS=`$PKG_CONFIG --libs glib-2.0`
+	GLIB_CFLAGS=`$PKG_CONFIG --cflags glib-2.0`
+	GOBJECT_LIBS=`$PKG_CONFIG --libs gobject-2.0`
+	GMODULE_LIBS=`$PKG_CONFIG --libs gmodule-2.0`
+fi
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+AC_SUBST(GOBJECT_LIBS)
+AC_SUBST(GMODULE_LIBS)
+
+dnl *************************************
+dnl Check for xsltproc
+dnl *************************************
+AM_CONDITIONAL(BUILD_XML,[test ! -f "${srcdir}/doc/man/cashutil.1"])
+if test ! -f "${srcdir}/doc/man/cashutil.1" ; then
+
+# It's just rude to go over the net to build
+XSLTPROC_FLAGS=--nonet
+DOCBOOK_ROOT=
+XSLTROOT="../../doc/xml"
+case "$host" in
+        *darwin*)
+	DOCBOOK_ROOT="/sw/share/xml/xsl/docbook-xsl"
+	XSLTROOT="/sw/share/xml/xsl/docbook-xsl/manpages/"
+	XSLTPROC_FLAGS="$XSLTPROC_FLAGS --novalid"
+	;;
+esac
+AC_SUBST(XSLTROOT)
+if test ! -f /etc/xml/catalog; then
+for i in /usr/share/sgml/docbook/stylesheet/xsl/nwalsh /usr/share/docbook2X/xslt/man/ /usr/share/xml/docbook/stylesheet/nwalsh/manpages/ /sw/share/xml/xsl/docbook-xsl;
+	do
+		if test -d "$i"; then
+		DOCBOOK_ROOT=$i
+        fi
+	done
+# Last resort - try net
+if test -z "$DOCBOOK_ROOT"; then
+   XSLTPROC_FLAGS=
+fi
+else
+   XML_CATALOG=/etc/xml/catalog
+   CAT_ENTRY_START='<!--'
+   CAT_ENTRY_END='-->'
+fi
+
+AC_CHECK_PROG(XSLTPROC,xsltproc,xsltproc,)
+XSLTPROC_WORKS=no
+if test -n "$XSLTPROC"; then
+    AC_MSG_CHECKING([whether xsltproc works])
+
+    if test -n "$XML_CATALOG"; then
+       DB_FILE="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"
+    else
+       DB_FILE="$XSLTROOT/docbook.xsl"
+    fi
+   $XSLTPROC $XSLTPROC_FLAGS $DB_FILE << END
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+<book id="test">
+</book>
+END
+        if test "$?" = 0; then
+           XSLTPROC_WORKS=yes
+        fi
+        AC_MSG_RESULT($XSLTPROC_WORKS)
+fi
+fi
+AM_CONDITIONAL(have_xsltproc, test "$XSLTPROC_WORKS" = "yes")
+
+AC_SUBST(XML_CATALOG)
+AC_SUBST(XSLTPROC_FLAGS)
+AC_SUBST(DOCBOOK_ROOT)
+AC_SUBST(CAT_ENTRY_START)
+AC_SUBST(CAT_ENTRY_END)
+AC_SUBST(XSLTPROC)
+
+### --------------------------------------------------------------------------
+### Check for perl
+
+# Check for perl, force version 5
+AC_ARG_WITH(perl,
+  [  --with-perl=FILE        which perl executable to use ],
+  PERL="${with_perl}")
+
+# If the user didn't specify a perl, then go fetch.
+if test x"$PERL" = x;
+then
+  AC_PATH_PROG(PERL, perl)
+fi
+
+# Make sure Perl was found
+if test x"$PERL" = x; then
+    AC_MSG_ERROR([Cannot find Perl. Try using the --with-perl flag.])
+fi
+
+# Make sure it's version 5 or later
+if "$PERL" -e 'exit 1 if $] < 5.0'; then
+        :
+else
+    AC_MSG_ERROR([Found ${PERL} reports version ]
+                 [`${PERL} -e 'print $]'`, need version 5.*])
+fi
+AC_SUBST(PERL)
+
+dnl *******************************
+dnl Internationalization
+dnl *******************************
+
+ALL_LINGUAS="en_GB "
+GETTEXT_PACKAGE=cashutil
+AC_SUBST(GETTEXT_PACKAGE)
+AM_GLIB_GNU_GETTEXT
+AC_SUBST(INTLTOOL_XGETTEXT)
+AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["${GETTEXT_PACKAGE}"], [gettext domain])
+
+dnl *************************************
+dnl Locate the backend library 
+dnl *************************************
+
+GNC_LIB_DIR=`eval echo $libdir | sed "s%^NONE%$prefix%"`
+GNC_LIB_DIR=`eval echo $GNC_LIB_DIR | sed "s%^NONE%$prefix%"`
+AC_SUBST(GNC_LIB_DIR)
+
+dnl ******************************
+dnl Defaults for GCC
+dnl ******************************
+AC_MSG_CHECKING(what extra warning flags to pass to the C compiler)
+if test ${GCC}x = yesx; then
+  warnFLAGS=
+  CFLAGS="${CFLAGS} -g2 -Wall"
+  AC_ARG_ENABLE(error-on-warning,
+        [  --disable-error-on-warning    disable treating compile warnings as errors],
+        [case "${enableval}" in
+        yes) warnFLAGS="${warnFLAGS} -Werror" ;;
+        no)  ;;
+        *) AC_MSG_ERROR(bad value ${enableval} for --enable-error-on-warning) ;;
+        esac],
+        [  warnFLAGS="${warnFLAGS} -Werror" ])
+  GCC_VERSION=`${CC} -dumpversion`
+  if test `echo ${GCC_VERSION} | cut -d. -f1` -ge 3; then
+     # This is gcc >= 3.x.x
+     if test `echo ${GCC_VERSION} | cut -d. -f2` -ge 4; then
+        # This is gcc >= 3.4.x
+        warnFLAGS="${warnFLAGS} -Wdeclaration-after-statement"
+     fi
+  fi
+  CFLAGS="${CFLAGS} ${warnFLAGS}"
+else
+  warnFLAGS=
+fi
+AC_MSG_RESULT($warnFLAGS)
+
+case "$host" in
+	*bsd*)
+		AC_DEFINE(TTYPrompt, "/dev/cua[<0..n>]", [Define verbose tty device])
+	;;
+	*)
+		AC_DEFINE(TTYPrompt, "/dev/tty[<0..n>]", [Define verbose tty device])
+	;;
+esac
+
+AC_OUTPUT([ po/Makefile.in
+  Makefile
+  src/Makefile
+  src/cashutil.h
+  src/gncla-dir.h
+  src/objects/Makefile
+  src/backend/Makefile
+  src/test/Makefile
+  doc/Makefile
+  doc/doxygen.cfg
+  doc/man/Makefile
+  doc/xml/Makefile
+  doc/xml/catalog.xml
+  doc/xml/docbook.xsl
+])
+
+AC_MSG_RESULT([
+  Options detected/selected
+  -------------------------
+  cashutil version ..... : $VERSION
+  Build for host ....... : $host
+  Extra Warnings ....... : $warnFLAGS
+  CPPFLAGS ............. : $CPPFLAGS
+  CFLAGS ............... : $CFLAGS
+  LDFLAGS .............. : $LDFLAGS
+  xsltproc flags ........: $XSLTPROC_FLAGS
+  QOF support ...........: $QOF_VERSION
+  QOF location ..........: $QOF_PREFIX
+  QOF library dir .......: $QOF_LIB_DIR
+  QOF backend config ....: $QOF_XML_DIR
+  GNC Backend location ..: $GNC_LIB_DIR
+])
+
+if [[ x"$PL_FROM_CVS" = xyes ]]; then
+  echo " .----- NOTICE ------------------------------------------------."
+  echo " |         You are using Cashutil from CVS source.             |"
+  echo " |                                                             |"
+  echo " | This is likely to be unstable, or contain some incomplete   |"
+  echo " | features, or just plain not work at all. Use it at your own |"
+  echo " | risk. Please help me to fix any bugs you find, by reporting |"
+  echo " | them back to me via the QOF-devel mailing list.             |"
+  echo " | http://lists.sourceforge.net/lists/listinfo/qof-devel       |"
+  echo " \`-------------------------------------------------------------'"
+  echo ""
+fi

Added: gnucash/branches/cashutil/cashutil/make-potfiles.in
===================================================================
--- gnucash/branches/cashutil/cashutil/make-potfiles.in	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/make-potfiles.in	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,53 @@
+#!@-PERL-@ -w
+# -*- perl -*-
+#
+# This perl script is used to make po/POTFILES.in, the list
+# of C files to be searched for translatable strings.
+#
+# Author: Dave Peticolas <dave at krondo.com>
+
+use strict;
+
+use File::Basename;
+
+my @cvsignores = `find src -name '.cvsignore'`;
+my @possible_files = `find src -name '*.c' -o -name '*.desktop.in' -o -name '*.keys.in' -o -name '*.pl'`;
+
+chomp(my $cwd = `pwd`);
+
+my %ignores;
+
+foreach my $one_ignore (@cvsignores) {
+  chomp($one_ignore);
+  my ($name, $path) = fileparse($one_ignore);
+  $path =~ s/^\.\///;
+  open (IG, $one_ignore);
+  chdir $path;
+  foreach my $fl (<IG>) {
+    chomp $fl;
+    next unless $fl;
+    my @matches = glob ($fl);
+    foreach my $match (@matches) {
+      chomp($match);
+      next unless $match;
+      $ignores{$path . $match} = 1;
+    }
+  }
+  close (IG);
+  chdir $cwd;
+}
+
+print "# List of files which containing translatable strings.\n";
+print "# This file was generated by ../make-potfiles.in.\n";
+print "\n";
+
+foreach my $file (@possible_files) {
+  chomp($file);
+  my ($name, $path) = fileparse($file);
+  $path =~ s/^\.\///;
+
+  next if $ignores{$path . $name};
+
+  print $path . $name . "\n";
+}
+

Added: gnucash/branches/cashutil/cashutil/po/ChangeLog
===================================================================
--- gnucash/branches/cashutil/cashutil/po/ChangeLog	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/po/ChangeLog	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,15 @@
+2005-08-14  Neil Williams <linux at codehelp.co.uk>
+
+	* po/en_GB.po: Started the simplest translation.
+
+2005-07-28  gettextize  <bug-gnu-gettext at gnu.org>
+
+	* Makefile.in.in: Upgrade to gettext-0.14.5.
+	* boldquot.sed: New file, from gettext-0.14.5.
+	* en at boldquot.header: New file, from gettext-0.14.5.
+	* en at quot.header: New file, from gettext-0.14.5.
+	* insert-header.sin: New file, from gettext-0.14.5.
+	* quot.sed: New file, from gettext-0.14.5.
+	* remove-potcdate.sin: New file, from gettext-0.14.5.
+	* Rules-quot: New file, from gettext-0.14.5.
+

Added: gnucash/branches/cashutil/cashutil/po/Makevars
===================================================================
--- gnucash/branches/cashutil/cashutil/po/Makevars	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/po/Makevars	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,25 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
+# package.  (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.)  Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright.  The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = Neil Williams linux at codehelp.co.uk
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =

Added: gnucash/branches/cashutil/cashutil/po/POTFILES.in
===================================================================
--- gnucash/branches/cashutil/cashutil/po/POTFILES.in	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/po/POTFILES.in	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,84 @@
+# List of files which containing translatable strings.
+# This file was generated by ../make-potfiles.in.
+
+src/backend/gnc-account-xml-v2.c
+src/backend/gnc-address-xml-v2.c
+src/backend/gnc-backend-file.c
+src/backend/gnc-bill-term-xml-v2.c
+src/backend/gnc-book-xml-v2.c
+src/backend/gnc-commodity-xml-v2.c
+src/backend/gnc-customer-xml-v2.c
+src/backend/gnc-employee-xml-v2.c
+src/backend/gnc-entry-xml-v2.c
+src/backend/gnc-freqspec-xml-v2.c
+src/backend/gnc-invoice-xml-v2.c
+src/backend/gnc-job-xml-v2.c
+src/backend/gnc-lot-xml-v2.c
+src/backend/gnc-order-xml-v2.c
+src/backend/gnc-owner-xml-v2.c
+src/backend/gnc-pricedb-xml-v2.c
+src/backend/gnc-schedxaction-xml-v2.c
+src/backend/gnc-tax-table-xml-v2.c
+src/backend/gnc-transaction-xml-v2.c
+src/backend/gnc-vendor-xml-v2.c
+src/backend/io-example-account.c
+src/backend/io-gncbin-r.c
+src/backend/io-gncxml-gen.c
+src/backend/io-gncxml-v1.c
+src/backend/io-gncxml-v2.c
+src/backend/io-utils.c
+src/backend/sixtp-dom-generators.c
+src/backend/sixtp-dom-parsers.c
+src/backend/sixtp-stack.c
+src/backend/sixtp-to-dom-parser.c
+src/backend/sixtp-utils.c
+src/backend/sixtp.c
+src/cashutil.c
+src/qof-main.c
+src/objects/Account.c
+src/objects/FreqSpec.c
+src/objects/Group.c
+src/objects/SX-book.c
+src/objects/SchedXaction.c
+src/objects/TransLog.c
+src/objects/Transaction.c
+src/objects/gnc-commodity.c
+src/objects/gnc-filepath-utils.c
+src/objects/gnc-lot.c
+src/objects/gnc-pricedb.c
+src/objects/gncAddress.c
+src/objects/gncBillTerm.c
+src/objects/gncCustomer.c
+src/objects/gncEmployee.c
+src/objects/gncEntry.c
+src/objects/gncInvoice.c
+src/objects/gncJob.c
+src/objects/gncOrder.c
+src/objects/gncOwner.c
+src/objects/gncTaxTable.c
+src/objects/gncVendor.c
+src/objects/iso-4217-currencies.c
+src/objects/SX-ttinfo.c
+src/objects/Scrub2.c
+src/objects/Scrub.c
+src/objects/Scrub3.c
+src/objects/cap-gains.c
+src/objects/policy.c
+src/objects/messages.c
+src/objects/Query.c
+src/objects/cashobjects.c
+src/test/test-book-merge.c
+src/test/test-cash.c
+src/test/test-engine-stuff.c
+src/test/test-stuff.c
+src/test/test-address.c
+src/test/test-customer.c
+src/test/test-employee.c
+src/test/test-job.c
+src/test/test-vendor.c
+src/test/test-numeric.c
+src/test/test-commodities.c
+src/test/test-freq-spec.c
+src/test/test-transaction-reversal.c
+src/test/test-transaction-voiding.c
+src/qofundo.c

Added: gnucash/branches/cashutil/cashutil/po/en_GB.po
===================================================================
--- gnucash/branches/cashutil/cashutil/po/en_GB.po	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/po/en_GB.po	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,1248 @@
+# English(GB) for CashUtil
+# Copyright (C) 2005 Neil Williams <linux at codehelp.co.uk>
+# This file is distributed under the same license as the CashUtil package.
+# Neil Williams <linx at codehelp.co.uk>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: CashUtil 0.0.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-09-22 00:08+0100\n"
+"PO-Revision-Date: 2005-08-14 20:41+0100\n"
+"Last-Translator: Neil Williams <linux at codehelp.co.uk>\n"
+"Language-Team: English (British) <en_gb at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: src/backend/gnc-backend-file.c:108
+msgid "Number of days to retain old files"
+msgstr "Number of days to retain old files"
+
+#: src/backend/gnc-backend-file.c:109
+msgid ""
+"GnuCash keeps backups of old files, this setting dictates how long each is "
+"kept"
+msgstr ""
+"GnuCash keeps backups of old files, this setting dictates how long each is "
+"kept"
+
+#: src/backend/gnc-backend-file.c:117
+msgid "Compress output files?"
+msgstr ""
+
+#: src/backend/gnc-backend-file.c:118
+msgid ""
+"GnuCash can save data files with compression. Enable this option to compress "
+"your data file. "
+msgstr ""
+
+#: src/backend/io-gncbin-r.c:514
+msgid "Lost Accounts"
+msgstr "Lost Accounts"
+
+#: src/cashutil.c:111
+msgid "Load a GnuCash or QSF book from <filename>"
+msgstr ""
+
+#: src/cashutil.c:132
+msgid ""
+"\n"
+"   Command line query interface to GnuCash using QOF - the Query Object "
+"Framework.\n"
+"   Supports reading personal and business GnuCash data and running \n"
+"   SQL-type queries on the live data or XML file. \n"
+"   Data can be added, edited, removed, printed, merged and written \n"
+"   out in the QOF interactive shell.\n"
+"   QSF XML can be imported into other QOF applications.\n"
+"\n"
+"   Use exactly one of -i -l --explain --shell; \n"
+"   options are -tde, with either -s or -f, then -w.\n"
+"\n"
+msgstr ""
+"\n"
+"   Command line query interface to GnuCash using QOF - the Query Object "
+"Framework.\n"
+"   Supports reading personal and business GnuCash data and running \n"
+"   SQL-type queries on the live data or XML file. \n"
+"   Data can be added, edited, removed, printed, merged and written \n"
+"   out in the QOF interactive shell.\n"
+"   QSF XML can be imported into other QOF applications.\n"
+"\n"
+"   Use exactly one of -i -l --explain --shell; \n"
+"   options are -tde, with either -s or -f, then -w.\n"
+"\n"
+
+#: src/cashutil.c:163
+#, c-format
+msgid ""
+"Fatal error: Cannot initialise QOF.\n"
+"\n"
+msgstr ""
+"Fatal error: Cannot initialise QOF.\n"
+"\n"
+
+#: src/cashutil.c:189
+#, c-format
+msgid "%s: ERROR. Specify only one command out of -i, -l."
+msgstr "%s: ERROR. Specify only one command out of -i, -l."
+
+#: src/cashutil.c:190 src/cashutil.c:250
+#, c-format
+msgid "--explain or --shell\n"
+msgstr "--explain or --shell\n"
+
+#: src/cashutil.c:200
+#, c-format
+msgid " For CashUtil support, join the QOF-devel mailing list at\n"
+msgstr " For CashUtil support, join the QOF-devel mailing list at\n"
+
+#: src/cashutil.c:202
+#, c-format
+msgid ""
+"\n"
+" This is CashUtil v%s\n"
+msgstr ""
+"\n"
+" This is CashUtil v%s\n"
+
+#: src/cashutil.c:203
+#, c-format
+msgid " The GnuCash Command Line Interface.\n"
+msgstr " The GnuCash Command Line Interface.\n"
+
+#: src/cashutil.c:204
+#, c-format
+msgid " Build target..: %s\n"
+msgstr " Build target..: %s\n"
+
+#: src/cashutil.c:205
+#, c-format
+msgid ""
+" Build date....: %s %s\n"
+"\n"
+msgstr ""
+" Build date....: %s %s\n"
+"\n"
+
+#: src/cashutil.c:206
+#, c-format
+msgid ""
+"   Please use --help for more detailed options.\n"
+"\n"
+msgstr ""
+"   Please use --help for more detailed options.\n"
+"\n"
+
+#: src/cashutil.c:242
+#, c-format
+msgid "%s: ERROR. Unknown option %d, argument: %s\n"
+msgstr "%s: ERROR. Unknown option %d, argument: %s\n"
+
+#: src/cashutil.c:249
+#, c-format
+msgid "%s: Please specify only one command out of -i, -l."
+msgstr "%s: Please specify only one command out of -i, -l."
+
+#: src/cashutil.c:256
+#, c-format
+msgid "%s: Sorry, %s cannot yet read STDIN.\n"
+msgstr "%s: Sorry, %s cannot yet read STDIN.\n"
+
+#: src/cashutil.c:290
+#, c-format
+msgid ""
+"%s: Error. please specify the database to explain.\n"
+"\n"
+msgstr ""
+"%s: Error. please specify the database to explain.\n"
+"\n"
+
+#: src/qof-main.c:161
+#, c-format
+msgid "Choose the %s to edit: (1 - %d): "
+msgstr ""
+
+#: src/qof-main.c:166
+#, c-format
+msgid "Choose the %s to DELETE: (1 - %d): "
+msgstr ""
+
+#: src/qof-main.c:171
+#, c-format
+msgid "Choose the %s to print: (1 - %d): "
+msgstr ""
+
+#: src/qof-main.c:184
+#, fuzzy, c-format
+msgid "Only %d objects are available of type '%s'.\n"
+msgstr "%s: No objects of type '%s' found.\n"
+
+#: src/qof-main.c:186
+#, c-format
+msgid "Choose the %s to use: (1 - %d): "
+msgstr ""
+
+#: src/qof-main.c:246
+#, c-format
+msgid "%s: No objects of type '%s' found.\n"
+msgstr "%s: No objects of type '%s' found.\n"
+
+#: src/qof-main.c:262
+#, c-format
+msgid "No parameter named '%s' found for object '%s'\n"
+msgstr "No parameter named '%s' found for object '%s'\n"
+
+#: src/qof-main.c:336
+#, c-format
+msgid "%s: Cannot add '%s' - object name not found\n"
+msgstr "%s: Cannot add '%s' - object name not found\n"
+
+#: src/qof-main.c:345
+#, c-format
+msgid "Failed to add an instance of %s\n"
+msgstr "Failed to add an instance of %s\n"
+
+#: src/qof-main.c:348
+#, c-format
+msgid ""
+"Added an instance of %s\n"
+"\n"
+msgstr ""
+"Added an instance of %s\n"
+"\n"
+
+#: src/qof-main.c:349
+#, c-format
+msgid "Now edit the parameter details of this instance.\n"
+msgstr "Now edit the parameter details of this instance.\n"
+
+#: src/qof-main.c:350 src/qof-main.c:381 src/qof-main.c:391 src/qof-main.c:423
+#: src/qof-main.c:807
+#, c-format
+msgid ""
+"Type 'help' for available commands or parameters.\n"
+"\n"
+msgstr ""
+"Type 'help' for available commands or parameters.\n"
+"\n"
+
+#: src/qof-main.c:373
+#, c-format
+msgid "%s: Cannot edit '%s' - object name not found\n"
+msgstr "%s: Cannot edit '%s' - object name not found\n"
+
+#: src/qof-main.c:380
+#, c-format
+msgid "Select an instance of %s to edit:\n"
+msgstr "Select an instance of %s to edit:\n"
+
+#: src/qof-main.c:390 src/qof-main.c:806
+#, c-format
+msgid "Edit the parameter details of the selected instance.\n"
+msgstr "Edit the parameter details of the selected instance.\n"
+
+#: src/qof-main.c:415
+#, c-format
+msgid "%s: Cannot delete '%s' - object name not found\n"
+msgstr "%s: Cannot delete '%s' - object name not found\n"
+
+#: src/qof-main.c:422
+#, c-format
+msgid "Select the instance of %s to delete\n"
+msgstr "Select the instance of %s to delete\n"
+
+#: src/qof-main.c:436
+#, c-format
+msgid ""
+"The instance has been DELETED. Type 'quit' to exit and undo. The file will "
+"not be changed until you type 'write'.\n"
+msgstr ""
+
+#: src/qof-main.c:449
+#, fuzzy, c-format
+msgid ""
+"\n"
+"The QOF shell supports these object names:\n"
+"You can use the names with 'edit', 'print' or 'delete'\n"
+"and in SQL queries (as the table name) with 'sql'\n"
+"Descriptions are shown only for readability.\n"
+"\n"
+msgstr ""
+"\n"
+"The QOF shell supports these database names:\n"
+"You can use the names with 'edit'\n"
+"and in SQL queries (as the table name) with 'sql'\n"
+"Descriptions are shown only for readability.\n"
+"\n"
+
+#: src/qof-main.c:453
+msgid "Object Name"
+msgstr ""
+
+#: src/qof-main.c:453
+#, fuzzy
+msgid "Description\n"
+msgstr "Name%sDescription"
+
+#: src/qof-main.c:455
+#, c-format
+msgid ""
+"\n"
+"Use 'explain <database>' to see the list of fields within\n"
+"any supported database.\n"
+msgstr ""
+"\n"
+"Use 'explain <database>' to see the list of fields within\n"
+"any supported database.\n"
+
+#: src/qof-main.c:469
+#, c-format
+msgid "%-24s %-12s %s\n"
+msgstr ""
+
+#: src/qof-main.c:480
+#, c-format
+msgid "%s: Cannot print '%s' - object name not found\n"
+msgstr "%s: Cannot print '%s' - object name not found\n"
+
+#: src/qof-main.c:488
+#, c-format
+msgid "Select the instance of '%s' to print.\n"
+msgstr "Select the instance of '%s' to print.\n"
+
+#: src/qof-main.c:489
+#, c-format
+msgid ""
+" Type 'help' for available commands or parameters.\n"
+"\n"
+msgstr ""
+" Type 'help' for available commands or parameters.\n"
+"\n"
+
+#: src/qof-main.c:495 src/qof-main.c:882
+msgid "Name"
+msgstr "Name"
+
+#: src/qof-main.c:495 src/qof-main.c:882
+msgid "Type"
+msgstr "Type"
+
+#: src/qof-main.c:495 src/qof-main.c:882
+msgid "Value"
+msgstr "Value"
+
+#: src/qof-main.c:506
+#, c-format
+msgid "Type: %-12s\tName: %-12s\n"
+msgstr "Type: %-12s\tName: %-12s\n"
+
+#: src/qof-main.c:514 src/qof-main.c:1696
+#, c-format
+msgid ""
+"\n"
+"Parameters of the %s database:\n"
+"\n"
+msgstr ""
+"\n"
+"Parameters of the %s database:\n"
+"\n"
+
+#: src/qof-main.c:519
+#, c-format
+msgid ""
+"\n"
+"%s: %s object not found.\n"
+msgstr ""
+"\n"
+"%s: %s object not found.\n"
+
+#: src/qof-main.c:535
+#, c-format
+msgid ""
+"%s: The current book has not been saved.\n"
+"Do you still want to overwrite it? [y/n]\n"
+msgstr ""
+"%s: The current book has not been saved.\n"
+"Do you still want to overwrite it? [y/n]\n"
+
+#: src/qof-main.c:624
+#, c-format
+msgid "%i:Parameter name: %s "
+msgstr "%i:Parameter name: %s "
+
+#: src/qof-main.c:627
+#, c-format
+msgid "Import data : %s "
+msgstr "Import data : %s "
+
+#: src/qof-main.c:629
+#, c-format
+msgid "Original data : %s\n"
+msgstr "Original data : %s\n"
+
+#: src/qof-main.c:635
+#, c-format
+msgid ""
+"\n"
+"Please resolve this conflict. Enter\n"
+"    1 to use the import data or \n"
+"    2 to keep the original data or"
+msgstr ""
+"\n"
+"Please resolve this conflict. Enter\n"
+"    1 to use the import data or \n"
+"    2 to keep the original data or"
+
+#: src/qof-main.c:639
+#, c-format
+msgid ""
+"\n"
+"    3 to import the data as a NEW object or"
+msgstr ""
+"\n"
+"    3 to import the data as a NEW object or"
+
+#: src/qof-main.c:641
+#, c-format
+msgid ""
+"\n"
+"    9 to abort the entire merge operation.\n"
+msgstr ""
+"\n"
+"    9 to abort the entire merge operation.\n"
+
+#: src/qof-main.c:646
+#, c-format
+msgid "or 9) : "
+msgstr "or 9) : "
+
+#: src/qof-main.c:672
+#, c-format
+msgid ""
+"Are you sure you want to abort the entire merge operation?\n"
+"The rest of the import data will not be processed.\n"
+"Your original data will not be modified. Abort? y/n : "
+msgstr ""
+"Are you sure you want to abort the entire merge operation?\n"
+"The rest of the import data will not be processed.\n"
+"Your original data will not be modified. Abort? y/n : "
+
+#: src/qof-main.c:676
+msgid "y"
+msgstr "y"
+
+#: src/qof-main.c:677
+#, c-format
+msgid ""
+"Aborting . . \n"
+"\n"
+msgstr ""
+"Aborting . . \n"
+"\n"
+
+#: src/qof-main.c:725
+#, c-format
+msgid ""
+"The current book has not been saved.\n"
+"Do you still want to quit without saving? %s"
+msgstr ""
+"The current book has not been saved.\n"
+"Do you still want to quit without saving? %s"
+
+#: src/qof-main.c:740
+#, c-format
+msgid ""
+"\n"
+"Thank you for using %s.\n"
+msgstr ""
+"\n"
+"Thank you for using %s.\n"
+
+#: src/qof-main.c:746
+#, c-format
+msgid ""
+"Commands available in the shell are:\n"
+"\n"
+msgstr ""
+"Commands available in the shell are:\n"
+"\n"
+
+#: src/qof-main.c:748
+msgid "Add a new instance of the object.\n"
+msgstr "Add a new instance of the object.\n"
+
+#: src/qof-main.c:750
+msgid "Select one instance and edit (set) the parameter values.\n"
+msgstr "Select one instance and edit (set) the parameter values.\n"
+
+#: src/qof-main.c:752
+msgid "Select one instance for deletion.\n"
+msgstr "Select one instance for deletion.\n"
+
+#: src/qof-main.c:754
+msgid "Synonym for the --list command outside the shell.\n"
+msgstr "Synonym for the --list command outside the shell.\n"
+
+#: src/qof-main.c:756
+msgid "Select one instance and print the parameter values.\n"
+msgstr "Select one instance and print the parameter values.\n"
+
+#: src/qof-main.c:758
+msgid "Synonym for the --explain command outside the shell.\n"
+msgstr "Synonym for the --explain command outside the shell.\n"
+
+#: src/qof-main.c:760
+msgid "Replace the current book with data from the file.\n"
+msgstr "Replace the current book with data from the file.\n"
+
+#: src/qof-main.c:762
+msgid "Prompts to save the current book, if any.\n"
+msgstr "Prompts to save the current book, if any.\n"
+
+#: src/qof-main.c:764
+msgid "Write out the current book. If no filename is given,\n"
+msgstr "Write out the current book. If no filename is given,\n"
+
+#: src/qof-main.c:765
+msgid "write to the original file.\n"
+msgstr "write to the original file.\n"
+
+#: src/qof-main.c:766
+msgid "(uses STDOUT if STDIN is used.)\n"
+msgstr "(uses STDOUT if STDIN is used.)\n"
+
+#: src/qof-main.c:768
+msgid "Merge data from the file into the current book.\n"
+msgstr "Merge data from the file into the current book.\n"
+
+#: src/qof-main.c:770
+msgid "Run a \"quoted\" SQL statement.\n"
+msgstr "Run a \"quoted\" SQL statement.\n"
+
+#: src/qof-main.c:771 src/qof-main.c:908
+msgid "This screen.\n"
+msgstr "This screen.\n"
+
+#: src/qof-main.c:772
+msgid "Quit the shell\n"
+msgstr "Quit the shell\n"
+
+#: src/qof-main.c:814
+#, c-format
+msgid "Query returned %d entities\n"
+msgstr "Query returned %d entities\n"
+
+#: src/qof-main.c:843
+#, c-format
+msgid "%s: parameter name '%s' of object '%s' not recognised.\n"
+msgstr "%s: parameter name '%s' of object '%s' not recognised.\n"
+
+#: src/qof-main.c:845
+#, c-format
+msgid "Type 'explain' for more information.\n"
+msgstr "Type 'explain' for more information.\n"
+
+#: src/qof-main.c:862
+#, c-format
+msgid ""
+"\n"
+"Editable parameters of the %s object:\n"
+"\n"
+msgstr ""
+"\n"
+"Editable parameters of the %s object:\n"
+"\n"
+
+#: src/qof-main.c:884
+#, c-format
+msgid ""
+"\n"
+"Not all parameters are editable, use 'explain' to see the list of editable "
+"parameters for the object '%s'.\n"
+"\n"
+msgstr ""
+"\n"
+"Not all parameters are editable, use 'explain' to see the list of editable "
+"parameters for the object '%s'.\n"
+"\n"
+
+#: src/qof-main.c:893
+#, c-format
+msgid ""
+"Commands available in this sub-shell are:\n"
+"\n"
+msgstr ""
+"Commands available in this sub-shell are:\n"
+"\n"
+
+#: src/qof-main.c:895
+msgid "Edit the parameter 'Name' to have the 'Value' given.\n"
+msgstr "Edit the parameter 'Name' to have the 'Value' given.\n"
+
+#: src/qof-main.c:898
+msgid "Boolean values accept TRUE|true, 1, Y|y or yes|YES\n"
+msgstr "Boolean values accept TRUE|true, 1, Y|y or yes|YES\n"
+
+#: src/qof-main.c:899
+msgid "String values that include spaces should be quoted\n"
+msgstr "String values that include spaces should be quoted\n"
+
+#: src/qof-main.c:900
+msgid "Synonym for edit.\n"
+msgstr "Synonym for edit.\n"
+
+#: src/qof-main.c:901
+#, c-format
+msgid "Print the current values for this '%s' instance.\n"
+msgstr "Print the current values for this '%s' instance.\n"
+
+#: src/qof-main.c:904
+#, c-format
+msgid "Show the editable parameters for '%s'\n"
+msgstr "Show the editable parameters for '%s'\n"
+
+#: src/qof-main.c:907
+msgid "Set the edited parameter values.\n"
+msgstr "Set the edited parameter values.\n"
+
+#: src/qof-main.c:910
+msgid "Return to the top shell without setting changes.\n"
+msgstr "Return to the top shell without setting changes.\n"
+
+#: src/qof-main.c:1045 src/qof-main.c:1063
+#, c-format
+msgid "%s: bad option - %s, available commands are:\n"
+msgstr "%s: bad option - %s, available commands are:\n"
+
+#: src/qof-main.c:1050 src/qof-main.c:1068
+#, c-format
+msgid ""
+"\n"
+"Use help for more information.\n"
+"\n"
+msgstr ""
+"\n"
+"Use help for more information.\n"
+"\n"
+
+#: src/qof-main.c:1098 src/qof-main.c:1614
+#, c-format
+msgid ""
+"%s: Error: Cannot exclude database \"%s\" with option -e\n"
+"    because option -d is set to the include the same database: \"%s\"\n"
+"Use the '-l' command to see the full list of supported databases.\n"
+msgstr ""
+"%s: Error: Cannot exclude database \"%s\" with option -e\n"
+"    because option -d is set to the include the same database: \"%s\"\n"
+"Use the '-l' command to see the full list of supported databases.\n"
+
+#: src/qof-main.c:1117
+#, c-format
+msgid ""
+"\n"
+"Welcome to the QOF interactive shell ...\n"
+msgstr ""
+"\n"
+"Welcome to the QOF interactive shell ...\n"
+
+#: src/qof-main.c:1118
+#, c-format
+msgid ""
+" Type 'help' for additional information\n"
+"\n"
+msgstr ""
+" Type 'help' for additional information\n"
+"\n"
+
+#: src/qof-main.c:1126
+#, c-format
+msgid ""
+"\n"
+"\n"
+"Thank you for using %s.\n"
+msgstr ""
+"\n"
+"\n"
+"Thank you for using %s.\n"
+
+#: src/qof-main.c:1173
+#, c-format
+msgid "%s: No suitable backend was found for %s.\n"
+msgstr "%s: No suitable backend was found for %s.\n"
+
+#: src/qof-main.c:1178
+#, c-format
+msgid "%s: The URL '%s' is not supported by this version of %s.\n"
+msgstr "%s: The URL '%s' is not supported by this version of %s.\n"
+
+#: src/qof-main.c:1184
+#, c-format
+msgid "%s: Cannot parse the URL '%s'\n"
+msgstr "%s: Cannot parse the URL '%s'\n"
+
+#: src/qof-main.c:1189
+#, c-format
+msgid ""
+"%s: Cannot connect to '%s'. The host, username or password were incorrect.\n"
+msgstr ""
+"%s: Cannot connect to '%s'. The host, username or password were incorrect.\n"
+
+#: src/qof-main.c:1195
+#, c-format
+msgid "%s: Cannot connect to '%s'. Connection was lost, unable to send data.\n"
+msgstr ""
+"%s: Cannot connect to '%s'. Connection was lost, unable to send data.\n"
+
+#: src/qof-main.c:1201
+#, c-format
+msgid "%s: This file/URL appears to be from a newer version of %s.\n"
+msgstr "%s: This file/URL appears to be from a newer version of %s.\n"
+
+#: src/qof-main.c:1207
+#, c-format
+msgid "%s: The database '%s' does not seem to exist.\n"
+msgstr "%s: The database '%s' does not seem to exist.\n"
+
+#: src/qof-main.c:1212
+#, c-format
+msgid "%s: Could not obtain the lock for '%s'.\n"
+msgstr "%s: Could not obtain the lock for '%s'.\n"
+
+#: src/qof-main.c:1217
+#, c-format
+msgid ""
+"%s could not write to '%s'. That database may be on a read-only file system, "
+"or you may not have write permission for the directory.\n"
+msgstr ""
+"%s could not write to '%s'. That database may be on a read-only file system, "
+"or you may not have write permission for the directory.\n"
+
+#: src/qof-main.c:1224
+#, c-format
+msgid ""
+"%s: The file/URL '%s' does not contain %s data or the data is corrupt.\n"
+msgstr ""
+"%s: The file/URL '%s' does not contain %s data or the data is corrupt.\n"
+
+#: src/qof-main.c:1230
+#, c-format
+msgid ""
+"%s: The server at URL '%s' experienced an error or encountered bad or "
+"corrupt data.\n"
+msgstr ""
+"%s: The server at URL '%s' experienced an error or encountered bad or "
+"corrupt data.\n"
+
+#: src/qof-main.c:1236
+#, c-format
+msgid "%s: You do not have permission to access '%s'.\n"
+msgstr "%s: You do not have permission to access '%s'.\n"
+
+#: src/qof-main.c:1241
+#, c-format
+msgid "%s: An error occurred while processing '%s'.\n"
+msgstr "%s: An error occurred while processing '%s'.\n"
+
+#: src/qof-main.c:1247
+#, c-format
+msgid ""
+"%s: Invalid QSF Object file! The QSF object file '%s'  failed to validate  "
+"against the QSF object schema. The XML structure of the file is either not "
+"well-formed or the file contains illegal data.\n"
+msgstr ""
+"%s: Invalid QSF Object file! The QSF object file '%s'  failed to validate  "
+"against the QSF object schema. The XML structure of the file is either not "
+"well-formed or the file contains illegal data.\n"
+
+#: src/qof-main.c:1255
+#, c-format
+msgid ""
+"%s: Invalid QSF Map file! The QSF map file failed to validate against the "
+"QSF map schema. The XML structure of the file is either not well-formed or "
+"the file contains illegal data.\n"
+msgstr ""
+"%s: Invalid QSF Map file! The QSF map file failed to validate against the "
+"QSF map schema. The XML structure of the file is either not well-formed or "
+"the file contains illegal data.\n"
+
+#: src/qof-main.c:1263
+#, c-format
+msgid ""
+"%s: The QSF Map file '%s' was written for a different version of QOF. It may "
+"need to be modified to work with your current QOF installation.\n"
+msgstr ""
+"%s: The QSF Map file '%s' was written for a different version of QOF. It may "
+"need to be modified to work with your current QOF installation.\n"
+
+#: src/qof-main.c:1270
+#, c-format
+msgid ""
+"%s: The selected QSF map '%s' contains unusable or missing data. This is "
+"usually because not all the required parameters for the defined objects have "
+"calculations described in the map.\n"
+msgstr ""
+"%s: The selected QSF map '%s' contains unusable or missing data. This is "
+"usually because not all the required parameters for the defined objects have "
+"calculations described in the map.\n"
+
+#: src/qof-main.c:1277
+#, c-format
+msgid ""
+"%s: The selected QSF object file '%s' contains one or more invalid GUIDs. "
+"The file cannot be processed - please check the source of the file and try "
+"again.\n"
+msgstr ""
+"%s: The selected QSF object file '%s' contains one or more invalid GUIDs. "
+"The file cannot be processed - please check the source of the file and try "
+"again.\n"
+
+#: src/qof-main.c:1284
+#, c-format
+msgid ""
+"%s: The selected QSF Object file '%s' requires a mapbut it was not "
+"provided.\n"
+msgstr ""
+"%s: The selected QSF Object file '%s' requires a mapbut it was not "
+"provided.\n"
+
+#: src/qof-main.c:1290
+#, c-format
+msgid ""
+"%s: Wrong QSF map selected. The selected map, validates but was written for "
+"different QOF objects. The list of objects defined in this map does not "
+"include all the objects described in the current QSF object file.\n"
+msgstr ""
+"%s: Wrong QSF map selected. The selected map, validates but was written for "
+"different QOF objects. The list of objects defined in this map does not "
+"include all the objects described in the current QSF object file.\n"
+
+#: src/qof-main.c:1298
+#, c-format
+msgid ""
+"%s: The selected file '%s' is a QSF map and cannotbe opened as a QSF "
+"object.\n"
+msgstr ""
+"%s: The selected file '%s' is a QSF map and cannotbe opened as a QSF "
+"object.\n"
+
+#: src/qof-main.c:1304
+#, c-format
+msgid ""
+"%s: When converting XML strings into numbers, an overflow has been detected. "
+"The QSF object file '%s' contains invalid data in a field that is meant to "
+"hold a number.\n"
+msgstr ""
+"%s: When converting XML strings into numbers, an overflow has been detected. "
+"The QSF object file '%s' contains invalid data in a field that is meant to "
+"hold a number.\n"
+
+#: src/qof-main.c:1311
+#, c-format
+msgid "%s: The QSF object file '%s' should be merged, not opened directly.\n"
+msgstr "%s: The QSF object file '%s' should be merged, not opened directly.\n"
+
+#: src/qof-main.c:1317
+#, c-format
+msgid "%s: There was an error reading the file '%s'.\n"
+msgstr "%s: There was an error reading the file '%s'.\n"
+
+#: src/qof-main.c:1322
+#, c-format
+msgid "%s: There was an error parsing the file '%s'.\n"
+msgstr "%s: There was an error parsing the file '%s'.\n"
+
+#: src/qof-main.c:1327
+#, c-format
+msgid "%s: The file '%s' is empty.\n"
+msgstr "%s: The file '%s' is empty.\n"
+
+#: src/qof-main.c:1332
+#, c-format
+msgid "%s: The file '%s' could not be found.\n"
+msgstr "%s: The file '%s' could not be found.\n"
+
+#: src/qof-main.c:1337
+#, c-format
+msgid "%s: This file is from an older version.\n"
+msgstr "%s: This file is from an older version.\n"
+
+#: src/qof-main.c:1342
+#, c-format
+msgid "%s: Unknown file type, '%s'.\n"
+msgstr "%s: Unknown file type, '%s'.\n"
+
+#: src/qof-main.c:1347
+#, c-format
+msgid "%s: Could not make a backup of '%s'.\n"
+msgstr "%s: Could not make a backup of '%s'.\n"
+
+#: src/qof-main.c:1352
+#, c-format
+msgid ""
+"%s: Could not write to '%s'. Check that you have permission to write to this "
+"file and that there is sufficient space to create it.\n"
+msgstr ""
+"%s: Could not write to '%s'. Check that you have permission to write to this "
+"file and that there is sufficient space to create it.\n"
+
+#: src/qof-main.c:1359
+#, c-format
+msgid "%s: This database is from an older version.\n"
+msgstr "%s: This database is from an older version.\n"
+
+#: src/qof-main.c:1364
+#, c-format
+msgid "%s: The SQL database is in use by other users.\n"
+msgstr "%s: The SQL database is in use by other users.\n"
+
+#: src/qof-main.c:1369
+#, c-format
+msgid "%s: An unknown I/O error occurred.\n"
+msgstr "%s: An unknown I/O error occurred.\n"
+
+#: src/qof-main.c:1664
+#, c-format
+msgid ""
+"\n"
+"%s currently supports these database names:\n"
+"You can use the names with %s -d\n"
+"and in SQL queries (as the table name) with %s -s|f\n"
+"Descriptions are shown only for readability.\n"
+"\n"
+"Name                    Description\n"
+"\n"
+msgstr ""
+"\n"
+"%s currently supports these database names:\n"
+"You can use the names with %s -d\n"
+"and in SQL queries (as the table name) with %s -s|f\n"
+"Descriptions are shown only for readability.\n"
+"\n"
+"Name                    Description\n"
+"\n"
+
+#: src/qof-main.c:1672
+#, c-format
+msgid ""
+"\n"
+"Use '-d <database> --explain' to see the list of fields within\n"
+"any supported database.\n"
+msgstr ""
+"\n"
+"Use '-d <database> --explain' to see the list of fields within\n"
+"any supported database.\n"
+
+#: src/qof-main.c:1674 src/qof-main.c:1698
+#, c-format
+msgid ""
+"\n"
+"Thank you for using %s\n"
+"\n"
+msgstr ""
+"\n"
+"Thank you for using %s\n"
+"\n"
+
+#: src/objects/Account.c:2276
+msgid "Bank"
+msgstr "Bank"
+
+#: src/objects/Account.c:2277
+msgid "Cash"
+msgstr "Cash"
+
+#: src/objects/Account.c:2278
+msgid "Asset"
+msgstr "Asset"
+
+#: src/objects/Account.c:2279
+msgid "Credit Card"
+msgstr "Credit Card"
+
+#: src/objects/Account.c:2280
+msgid "Liability"
+msgstr "Liability"
+
+#: src/objects/Account.c:2281
+msgid "Stock"
+msgstr "Stock"
+
+#: src/objects/Account.c:2282
+msgid "Mutual Fund"
+msgstr "Mutual Fund"
+
+#: src/objects/Account.c:2283
+msgid "Currency"
+msgstr "Currency"
+
+#: src/objects/Account.c:2284
+msgid "Income"
+msgstr "Income"
+
+#: src/objects/Account.c:2285 src/objects/gncInvoice.c:608
+msgid "Expense"
+msgstr "Expense"
+
+#: src/objects/Account.c:2286
+msgid "Equity"
+msgstr "Equity"
+
+#: src/objects/Account.c:2287
+msgid "A/Receivable"
+msgstr "A/Receivable"
+
+#: src/objects/Account.c:2288
+msgid "A/Payable"
+msgstr "A/Payable"
+
+#. This is displayed instead of the number of the day of month.
+#: src/objects/FreqSpec.c:691
+msgid "last day"
+msgstr "last day"
+
+#: src/objects/FreqSpec.c:729
+#, c-format
+msgid "None"
+msgstr "None"
+
+#. %s is the strftime-string of the one-time date.
+#: src/objects/FreqSpec.c:739
+#, c-format
+msgid "Once: %s"
+msgstr "Once: %s"
+
+#. %u is the number of intervals
+#: src/objects/FreqSpec.c:748
+#, c-format
+msgid "Daily (x%u)"
+msgstr "Daily (x%u)"
+
+#: src/objects/FreqSpec.c:753
+#, c-format
+msgid "Daily"
+msgstr "Daily"
+
+#. %u is the number of intervals
+#: src/objects/FreqSpec.c:773
+#, c-format
+msgid "Weekdays: (x%u)"
+msgstr "Weekdays: (x%u)"
+
+#: src/objects/FreqSpec.c:778
+#, c-format
+msgid "Weekdays"
+msgstr "Weekdays"
+
+#. %d are the number of intervals; %s is
+#. the name of the weekday
+#: src/objects/FreqSpec.c:817
+#, c-format
+msgid "Weekly (x%d): %s"
+msgstr "Weekly (x%d): %s"
+
+#. Translators: %s is the name of the weekday
+#: src/objects/FreqSpec.c:823
+#, c-format
+msgid "Weekly: %s"
+msgstr "Weekly: %s"
+
+#. %s is the name of the weekday
+#: src/objects/FreqSpec.c:830
+#, c-format
+msgid "Bi-Weekly, %ss"
+msgstr "Bi-Weekly, %ss"
+
+#. Translators: %u is the number of intervals;
+#. %s is the day of month of the starting month
+#. (or the string "last day"); %s is the day of
+#. month of the ending month
+#: src/objects/FreqSpec.c:853
+#, c-format
+msgid "Semi-monthly (x%u): %s, %s"
+msgstr "Semi-monthly (x%u): %s, %s"
+
+#. Translators: %s is the day of month of the
+#. starting month (or the string "last day"); %s
+#. is the day of month of the ending month
+#: src/objects/FreqSpec.c:864
+#, c-format
+msgid "Semi-monthly: %s, %s"
+msgstr "Semi-monthly: %s, %s"
+
+#. %u is the number of intervals; %u is
+#. the day of month
+#: src/objects/FreqSpec.c:880
+#, c-format
+msgid "Monthly (x%u): %u"
+msgstr "Monthly (x%u): %u"
+
+#. %u is the day of month
+#: src/objects/FreqSpec.c:888
+#, c-format
+msgid "Monthly: %u"
+msgstr "Monthly: %u"
+
+#. %u is the number of intervals; %u is
+#. the day of month
+#: src/objects/FreqSpec.c:898
+#, c-format
+msgid "Quarterly (x%u): %u"
+msgstr "Quarterly (x%u): %u"
+
+#. %u is the day of month
+#: src/objects/FreqSpec.c:906
+#, c-format
+msgid "Quarterly: %u"
+msgstr "Quarterly: %u"
+
+#. %u is the number of intervals; %u is
+#. the day of month
+#: src/objects/FreqSpec.c:917
+#, c-format
+msgid "Tri-Yearly (x%u): %u"
+msgstr "Tri-Yearly (x%u): %u"
+
+#. %u is the day of month
+#: src/objects/FreqSpec.c:925
+#, c-format
+msgid "Tri-Yearly: %u"
+msgstr "Tri-Yearly: %u"
+
+#. %u is the number of intervals; %u
+#. is the day of month
+#: src/objects/FreqSpec.c:940
+#, c-format
+msgid "Semi-Yearly (x%u): %u"
+msgstr "Semi-Yearly (x%u): %u"
+
+#. %u is the day of month
+#: src/objects/FreqSpec.c:948
+#, c-format
+msgid "Semi-Yearly: %u"
+msgstr "Semi-Yearly: %u"
+
+#. FIXME: This string *must* be translated for
+#. en_GB, en_AU and everywhere else with the
+#. sensible ordering of ddmmyy.  Translators
+#. note: to switch the last two arguments,
+#. write "Yearly (x%1$u): %3$u of month %2$s"
+#.
+#. %u is the number of intervals; %s is the
+#. abbreviated name of the month; %u is the
+#. day of month.
+#: src/objects/FreqSpec.c:971
+#, c-format
+msgid "Yearly (x%u): %s/%u"
+msgstr "Yearly (x%1$u): %3%u of month %s$s"
+
+#. %s is the abbreviated name of the
+#. month; %u is the day of month
+#: src/objects/FreqSpec.c:981
+#, c-format
+msgid "Yearly: %s/%u"
+msgstr "Yearly: %s/%u"
+
+#: src/objects/FreqSpec.c:988
+#, c-format
+msgid "Unknown"
+msgstr "Unknown"
+
+#: src/objects/Transaction.c:2219 src/objects/Transaction.c:2240
+msgid "-- Split Transaction --"
+msgstr "-- Split Transaction --"
+
+#: src/objects/Transaction.c:2261
+msgid "Split"
+msgstr "Split"
+
+#: src/objects/Transaction.c:3118
+msgid "Voided transaction"
+msgstr "Voided transaction"
+
+#: src/objects/Transaction.c:3143
+msgid "Transaction Voided"
+msgstr "Transaction Voided"
+
+#: src/objects/gncInvoice.c:604
+msgid "Invoice"
+msgstr "Invoice"
+
+#: src/objects/gncInvoice.c:606
+msgid "Bill"
+msgstr "Bill"
+
+#. Set memo.  action?
+#: src/objects/gncInvoice.c:1039
+msgid "Extra to Charge Card"
+msgstr "Extra to Charge Card"
+
+#: src/objects/gncInvoice.c:1078
+msgid "Generated from an invoice.  Try unposting the invoice."
+msgstr "Generated from an invoice.  Try unposting the invoice."
+
+#. Translators: This is the memo of an auto-created split
+#: src/objects/gncInvoice.c:1096
+msgid "Automatic Payment Forward"
+msgstr "Automatic Payment Forward"
+
+#: src/objects/gncInvoice.c:1097
+msgid "Auto Split"
+msgstr "Auto Split"
+
+#: src/objects/gncInvoice.c:1288 src/objects/gncInvoice.c:1350
+msgid "Payment"
+msgstr "Payment"
+
+#: src/objects/gncInvoice.c:1377
+msgid "Pre-Payment"
+msgstr "Pre-Payment"
+
+#: src/objects/gncInvoice.c:1474
+msgid " (posted)"
+msgstr " (posted)"
+
+#: src/objects/gncOrder.c:416
+msgid " (closed)"
+msgstr " (closed)"
+
+#: src/objects/Scrub.c:105
+msgid "Orphan"
+msgstr "Orphan"
+
+#: src/objects/Scrub.c:411
+msgid "Imbalance"
+msgstr "Imbalance"
+
+#: src/objects/cap-gains.c:230
+msgid "Orphaned Gains"
+msgstr "Orphaned Gains"
+
+#: src/objects/cap-gains.c:244 src/objects/cap-gains.c:916
+#: src/objects/cap-gains.c:921 src/objects/cap-gains.c:922
+msgid "Realized Gain/Loss"
+msgstr "Realized Gain/Loss"
+
+#: src/objects/cap-gains.c:246
+msgid ""
+"Realized Gains or Losses from\n"
+"Commodity or Trading Accounts\n"
+"that haven't been recorded elsewhere.\n"
+msgstr ""
+"Realized Gains or Losses from\n"
+"Commodity or Trading Accounts\n"
+"that have not been recorded elsewhere.\n"
+
+#: src/objects/cap-gains.c:574
+#, fuzzy
+msgid "Lot"
+msgstr "Lot %"
+
+#: src/qofundo.c:126 src/qofundo.c:138
+#, c-format
+msgid "%s: Cannot convert %s into a number: an overflow has been detected."
+msgstr "%s: Cannot convert %s into a number: an overflow has been detected."
+
+#~ msgid "Return to the top shell\n"
+#~ msgstr "Return to the top shell\n"

Added: gnucash/branches/cashutil/cashutil/src/Makefile.am
===================================================================
--- gnucash/branches/cashutil/cashutil/src/Makefile.am	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/Makefile.am	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,38 @@
+#SUBDIRS = objects . test backend
+
+AM_CFLAGS = \
+  -I.. -I../..  \
+  -DLOCALE_DIR=\""$(datadir)/locale"\" \
+  -I${top_srcdir}/src/backend/file \
+  -I${top_srcdir}/src/business/business-core \
+  -I${top_srcdir}/src/engine \
+  ${GOBJECT_CFLAGS} \
+  ${GLIB_CFLAGS}  \
+  ${QOF_CFLAGS}
+
+bin_PROGRAMS= \
+  cashutil
+
+cashutil_SOURCES = \
+  qof-main.c \
+  qofundo.c \
+  cashutil.c 
+
+EXTRA_DIST = \
+  qof-main.h \
+  qofundo.h \
+  gncla-dir.h.in
+
+noinst_HEADERS = qofundo-p.h
+
+cashutil_LDADD =   \
+  ${top_builddir}/src/objects/libcashobjects.la  \
+  ${top_builddir}/src/objects/libcashbusobjects.la  \
+  -lltdl  \
+  ${QOF_LIBS}  \
+  ${GLIB_LIBS}  \
+  ${GOBJECT_LIBS} \
+  ${GMODULE_LIBS} \
+  ${RL_LIBS} \
+  -lltdl  \
+  -lpopt

Added: gnucash/branches/cashutil/cashutil/src/README
===================================================================
--- gnucash/branches/cashutil/cashutil/src/README	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/README	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,29 @@
+CashUtil source readme
+======================
+
+CashUtil is intended to be built separately from
+GnuCash whilst being developed in the same CVS tree.
+
+The modifications within GnuCash mean that the object
+files and the backend files need to be reorganised. 
+Also, the translation files, man page and configuration
+scripts are just for CashUtil.
+
+CashUtil also uses QOF as an external library, requiring
+libqof1 (>= 0.6.0).
+
+A lot of the translatable strings are similar to GnuCash
+but have to be formatted slightly differently for a command
+line interface.
+
+Important: When debugging this code, remember that CashUtil
+is linked against an installed version of QOF, AND it *only*
+uses the installed copies of libcashobjects.la and 
+libgnc-backend-file.la. You must 'make install' to test any
+changes in the source files for these libraries. If you
+change any QOF files, run 'make install' in QOF and then
+run 'make install' in CashUtil.
+
+If you have your own books to test during development, CVS 
+will ignore a src/books directory as a convenience.
+

Added: gnucash/branches/cashutil/cashutil/src/backend-bus.c
===================================================================
--- gnucash/branches/cashutil/cashutil/src/backend-bus.c	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/backend-bus.c	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *            backend-bus.c
+ *
+ *  Sun Sep 25 15:59:50 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xmlschemas.h>
+
+#include "gnc-address-xml-v2.h"
+#include "gnc-bill-term-xml-v2.h"
+#include "gnc-customer-xml-v2.h"
+#include "gnc-employee-xml-v2.h"
+#include "gnc-entry-xml-v2.h"
+#include "gnc-invoice-xml-v2.h"
+#include "gnc-job-xml-v2.h"
+#include "gnc-order-xml-v2.h"
+#include "gnc-owner-xml-v2.h"
+#include "gnc-tax-table-xml-v2.h"
+#include "gnc-vendor-xml-v2.h"
+
+void
+backend_business_add (void)
+{
+	gnc_address_xml_initialize ();
+	gnc_billterm_xml_initialize ();
+	gnc_customer_xml_initialize ();
+	gnc_employee_xml_initialize ();
+	gnc_entry_xml_initialize ();
+	gnc_invoice_xml_initialize ();
+	gnc_job_xml_initialize ();
+	gnc_order_xml_initialize ();
+	gnc_owner_xml_initialize ();
+	gnc_taxtable_xml_initialize ();
+	gnc_vendor_xml_initialize ();
+}
+
+
+gboolean bus_cashobjects_register(void)
+{
+	g_return_val_if_fail(gncInvoiceRegister(), FALSE);
+	g_return_val_if_fail ( gncJobRegister (),  FALSE);
+	g_return_val_if_fail(gncBillTermRegister(), FALSE);
+	g_return_val_if_fail(gncCustomerRegister(), FALSE);
+	g_return_val_if_fail(gncAddressRegister(), FALSE);
+	g_return_val_if_fail(gncEmployeeRegister(), FALSE);
+	g_return_val_if_fail ( gncEntryRegister (), FALSE);
+	g_return_val_if_fail (gncVendorRegister (), FALSE);
+	g_return_val_if_fail(gncTaxTableRegister(), FALSE);
+	g_return_val_if_fail ( gncOrderRegister (), FALSE);
+	return TRUE;
+}

Added: gnucash/branches/cashutil/cashutil/src/backend-bus.h
===================================================================
--- gnucash/branches/cashutil/cashutil/src/backend-bus.h	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/backend-bus.h	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,28 @@
+/***************************************************************************
+ *            backend-bus.h
+ *
+ *  Sun Sep 25 16:02:07 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+void backend_business_add (void);
+
+gboolean bus_cashobjects_register (void);
+

Added: gnucash/branches/cashutil/cashutil/src/cashutil.c
===================================================================
--- gnucash/branches/cashutil/cashutil/src/cashutil.c	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/cashutil.c	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,364 @@
+/***************************************************************************
+ *            cashutil.c
+ *
+ *   Sat Feb  5 10:40:03 GMT 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/** @addtogroup QOFCLI
+    @{ */
+
+/** @addtogroup cashutil A command line interface for GnuCash data
+
+cashutil provides an executable interface to GnuCash data
+It supports writing the QSF XML files and SQL-type queries.
+
+The types of SQL queries that are allowed at this point are a little limited.
+In general, only the following types of queries are supported: \n
+SELECT * FROM SomeObj WHERE (param_a < 10.0) AND (param_b = "asdf") SORT BY param_c DESC;\n
+INSERT INTO SomeObj (param_a, param_b, param_c) VALUES ("value_a", true, "0/1");
+
+Joins are not supported directly.\n
+SELECT * FROM ObjA,ObjB WHERE (ObjA.param_id = ObjB.param_other_id);\n
+The problem with the above is that the search requires a nested search loop, aka a 'join',
+which is not currently supported in the underlying QofQuery code.
+
+However, by repeating queries and adding the entities to a new session using
+::qof_entity_copy_list, a series of queries can be added to a single book.
+e.g. You can insert multiple entities and save out as a QSF XML file or use multiple
+SELECT queries to build a precise list - this can be used to replicate most of the
+functionality of a SQL join.
+
+SELECT * from ObjA where param_id = value; SELECT * from ObjB where param_other_id = value;
+
+Equivalent to:\n
+SELECT * from ObjA,ObjB where param_id = param_other_id and param_id = value;
+
+When combined with a foreach callback on the value of param_id for each entity in the
+QofBook, you can produce the effect of a join from running the two SELECT queries for each
+value of param_id held in 'value'.
+
+See ::QofEntityForeachCB and ::qof_object_foreach.
+
+SELECT a,b,c FROM ...
+
+Used to convert QOF objects between applications by using the returned parameter values
+to create a second object. One application using QOF could register objects from two
+applications and convert data from one to the other by using\n
+SELECT a,b,c FROM ObjA; SELECT d,f,k FROM ObjB; qof_object_new_instance();
+ObjC_set_a(value_c); ObjC_set_b(value_k) etc.
+
+What's needed is for the SELECT to return a complete object that only contains the
+parameters selected.
+
+Unsupported: UPDATE, DELETE.
+
+It will not be possible to support CREATE, AMEND or DROP for understandable reasons.
+
+@{
+*/
+/** @file cashutil.c
+    @brief Command line interface.
+    @author Copyright (c) 2005 Neil Williams <linux at codehelp.co.uk>
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <locale.h>
+#include <errno.h>
+#include <gmodule.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "qof-main.h"
+#include "cashutil.h"
+#include "cashobjects.h"
+#include "gncla-dir.h"
+#include "qofundo-p.h"
+#include "backend-bus.h"
+
+static gchar* log_module = CU_MOD_CLI;
+static gboolean debug_on = FALSE;
+
+static gboolean
+load_bus_backend (const char *directory)
+{
+	typedef void (* bus_backend_init) (void);
+	GModule *bus_backend;
+	gchar *fullpath;
+	struct stat sbuf;
+	bus_backend_init bus_init;
+	gpointer g;
+
+	g_return_val_if_fail(bus_cashobjects_register(), FALSE);
+	g_return_val_if_fail(g_module_supported(), FALSE);
+	fullpath = g_module_build_path(directory, "libgnc-backend-bus.la");
+	g_return_val_if_fail((stat(fullpath, &sbuf) == 0), FALSE);
+	bus_backend = g_module_open(fullpath, G_MODULE_BIND_LAZY);
+	if(!bus_backend) { 
+		PWARN ("%s: %s\n", PACKAGE, g_module_error ()); 
+		return FALSE;
+	}
+	g = &bus_init;
+	if (!g_module_symbol (bus_backend, "backend_business_add", g))
+	{
+		PWARN ("%s: %s\n", PACKAGE, g_module_error ());
+		return FALSE;
+	}
+	g_module_make_resident(bus_backend);
+	bus_init();
+	return TRUE;
+}
+
+int
+main (int argc, const char *argv[])
+{
+	const char *exclude, *date_time, *database;
+	const char *sql_file, *write_file, *sql_query, *filename;
+	const char *help_header_text;
+	gboolean use_stdin;
+	qof_data *context;
+	int optc, gz_level;
+	poptContext pc;
+	qof_op_type command;
+	QofSession *session;
+	FILE *f;
+
+	struct poptOption options[] = {
+		QOF_CLI_OPTIONS
+		{"input", 'i', POPT_ARG_STRING, &filename, qof_op_input,
+		 _("Load a GnuCash or QSF book from <filename>"), "filename"},
+		POPT_TABLEEND
+	};
+	#ifdef ENABLE_NLS
+	setlocale (LC_ALL, "");
+	bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+	#endif
+	use_stdin = TRUE;
+	command = qof_op_noop;
+	exclude = NULL;
+	database = NULL;
+	sql_file = NULL;
+	write_file = NULL;
+	sql_query = NULL;
+	filename = NULL;
+	f = NULL;
+	gnc_set_log_level_global(1);
+
+	help_header_text = _(
+		"\n"
+		"   Command line query interface to GnuCash using QOF -\n"
+		"   the Query Object Framework.\n"
+		"   Supports reading personal and business GnuCash data and running \n"
+		"   SQL-type queries on the live data or XML file. \n"
+		"   Data can be added, edited, removed, printed, merged and written \n"
+		"   out in the QOF interactive shell.\n"
+		"   QSF XML can be imported into other QOF applications.\n\n"
+		"   Use exactly one of -i -l --explain --shell; \n"
+		"   options are -tde, with either -s or -f, then -w.\n\n");
+
+	pc = poptGetContext (PACKAGE, argc, argv, options, 0);
+
+	poptSetOtherOptionHelp (pc, help_header_text);
+
+	if (argc < 2)
+	{
+		poptPrintUsage (pc, stderr, 0);
+		return 1;
+	}
+	qof_init();
+	g_return_val_if_fail(cashobjects_register(), -1);
+	context = qof_create();
+	if(!context) {
+		fprintf(stderr, _("Fatal error: Cannot initialise QOF.\n\n"));
+		return -1; 
+	}
+	session = qof_session_new ();
+	context->book = qof_session_get_book(session);
+	/* Read user alias settings */
+	poptReadDefaultConfig(pc, 0);
+	/* could use poptAddAlias(poptContext pc, struct poptAlias alias, 0) to specify
+	 * a default alias, perhaps to ease GnuCash or PilotQOF usage. */
+	while ((optc = poptGetNextOpt (pc)) >= 0)
+	{
+		switch (optc)
+		{
+			/* commands - mutually exclusive */
+			case qof_op_input:
+			case qof_op_list:
+			case qof_op_explain:
+			case qof_op_shell:
+			{
+				if (qof_op_noop != command)
+				{
+					fprintf (stderr, 
+						_("%s: ERROR. Specify only one command out of -i, -l."), PACKAGE);
+					fprintf (stderr, _("--explain or --shell\n"));
+					return 1;
+				}
+				command = optc;
+				use_stdin = FALSE;
+				break;
+			}
+			case qof_op_vers :
+			{
+				fprintf (stdout, "\n (c) Copyright 2005 Neil Williams <linux at codehelp.co.uk>\n");
+				fprintf (stdout, _(" For CashUtil support, join the QOF-devel mailing list at\n"));
+				fprintf (stdout, " http://lists.sourceforge.net/mailman/listinfo/qof-devel\n");
+				fprintf (stdout, _("\n This is CashUtil v%s\n"), VERSION);
+				fprintf (stdout, _(" The GnuCash Command Line Interface.\n"));
+//				fprintf (stdout, _(" Build target..: %s\n"), HOST_OS);
+				fprintf (stdout, _(" Build date....: %s %s\n\n"), __DATE__, __TIME__);
+				fprintf (stdout, _("   Please use --help for more detailed options.\n\n"));
+				return 0;
+			}
+			/* optional modifiers - store to act on later. */
+			case qof_op_database:
+			{
+				qof_mod_database (database, context);
+				break;
+			}
+			case qof_op_timespec:
+			{
+				qof_mod_timespec (date_time, context);
+				break;
+			}
+			case qof_op_exclude:
+			{
+				qof_mod_exclude (exclude, context);
+				break;
+			}
+			case qof_op_sql:
+			{
+				qof_mod_sql (sql_query, context);
+				break;
+			}
+			case qof_op_sql_file:
+			{
+				qof_mod_sql_file (sql_file, context);
+				break;
+			}
+			case qof_op_write:
+			{
+				qof_mod_write (write_file, context);
+				break;
+			}
+			case qof_op_compress:
+			{
+				context->gz_level = gz_level;
+				break;
+			}
+			case qof_op_debug:
+			{
+				debug_on = TRUE;
+				break;
+			}
+			default:
+			{
+				fprintf (stderr, _("%s: ERROR. Unknown option %d, argument: %s\n"),
+					 PACKAGE, optc, poptGetOptArg (pc));
+				return 1;
+			}
+		}
+	}
+	if (use_stdin && command == qof_op_noop) {
+		fprintf (stderr, _("%s: Please specify only one command out of -i, -l."), PACKAGE);
+		fprintf (stderr, _("--explain or --shell\n"));
+		poptPrintUsage(pc, stderr, 0);
+		return 1;
+
+	}
+	if (use_stdin) {
+		fprintf (stderr, _("%s: Sorry, %s cannot yet read STDIN.\n"), PACKAGE, PACKAGE);
+		poptPrintUsage(pc, stderr, 0);
+		return 1;
+	}
+	if (optc < -1)
+	{
+		fprintf(stderr, "%s: %s %s\n\n", PACKAGE,
+		poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+		poptStrerror(optc));
+		poptPrintUsage(pc, stderr, 0);
+		return 1;
+	}
+	/* If we get this far, we should have sensible options: start the work. */
+	if(debug_on) {
+		f = fopen("/tmp/cashutil.trace", "w");
+		gnc_set_logfile(f);
+		gnc_log_init();
+		qof_log_set_default(GNC_LOG_DETAIL);
+		gnc_set_log_level(CU_MOD_CLI, GNC_LOG_DETAIL);
+		gnc_set_log_level(CU_MOD_ENGINE, GNC_LOG_DETAIL);
+	}
+	g_return_val_if_fail((qof_load_backend_library 
+		(QOF_LIB_DIR, "libqof-backend-qsf.la", "qsf_provider_init")), -1);
+	g_return_val_if_fail((qof_load_backend_library
+		(GNC_LIBDIR, GNC_LIB_NAME, GNC_LIB_INIT)), -1);
+	g_return_val_if_fail(load_bus_backend(GNC_LIBDIR), -1);
+	context->input_session = session;
+	qof_book_clear_undo(context->book);
+	qof_object_foreach_type(qof_select_all, context);
+	switch (command)
+	{
+		case qof_op_input:
+		{
+			context->filename = g_strdup(filename);
+			qof_cmd_offline (context);
+			break;
+		}
+		case qof_op_list:
+		{
+			qof_cmd_list ();
+			break;
+		}
+		case qof_op_explain:
+		{
+			if(!context->database)
+			{
+				fprintf (stderr, 
+					_("%s: Error. please specify the database to explain.\n\n"), 
+					PACKAGE);
+				break;
+			}
+			qof_cmd_explain(context);
+			break;
+		}
+		case qof_op_shell:
+		{
+			qof_cmd_shell(context);
+			break;
+		}
+		default:
+		{
+			/* should be impossible */
+			break;
+		}
+	}
+	poptFreeContext(pc);
+	qof_data_free(context);
+	qof_close();
+	if(f) { fclose(f); }
+	return 0;
+}
+
+/** @} */
+/** @} */

Added: gnucash/branches/cashutil/cashutil/src/cashutil.h
===================================================================
--- gnucash/branches/cashutil/cashutil/src/cashutil.h	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/cashutil.h	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *            cashutil.h
+ *
+ *  Sun Apr 17 17:56:17 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CASHUTIL_H
+#define _CASHUTIL_H
+
+#include "qof-main.h"
+
+#define CU_MOD_CLI "cashutil-cli"
+
+#endif /* _PILOT_QOF_H */

Added: gnucash/branches/cashutil/cashutil/src/qof-main.c
===================================================================
--- gnucash/branches/cashutil/cashutil/src/qof-main.c	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/qof-main.c	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,1875 @@
+/***************************************************************************
+ *            qof-main.c
+ *
+ *  Thu Jan 13 10:55:44 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/** @addtogroup QOFCLI
+
+Includes common functions for all QOF CLI programs and provides generic
+functions to implement command line and interactive shell options.
+@{
+*/
+/** @file qof-main.c
+    @brief Common functions for the QOF external framework
+    @author Copyright (c) 2005 Neil Williams <linux at codehelp.co.uk>
+*/
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include "qof-main.h"
+/** \todo temporary until undo goes into QofBook */
+#include "qofundo-p.h"
+
+#ifdef HAVE_LIBREADLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+static GHashTable *backend_extensions;
+static gchar* log_module = CU_MOD_ENGINE;
+
+#define QSF_COMPRESS "compression_level"
+
+/** standardise tab output to help output line up nicely. */
+#define QOF_TAB "    "
+
+/** the maximum number of entities to offer for a single selection.
+
+\todo Improve the maximum to allow scrolling / next page.
+*/
+#define CLI_MAX_SELECT 20
+
+/** Relate the command to the function. */
+typedef int (*cmd_fcn) (qof_data *context);
+/** \todo Reorganise the C into multiple files. */
+static int qof_parse_command (const char *cmd, qof_data *context);
+
+/** Provide a simple numerical index for selectable objects.
+
+ at param ent  each entity in turn of the selected type.
+ at param data The qof_data context for the CLI.
+
+Ensure counter is reset to zero between runs.
+*/
+static void
+cli_select_cb (QofEntity *ent, gpointer data)
+{
+	qof_data *context;
+	gchar *temp;
+
+	context = (qof_data*)data;
+	g_return_if_fail(context);
+	context->counter++;
+	if(context->counter >= CLI_MAX_SELECT) { return; }
+	fprintf (stdout, "%d    %s\n", context->counter, 
+		qof_object_printable(context->inst_type, (QofInstance*)ent));
+	temp = g_strdup_printf("%d", context->counter);
+	g_hash_table_insert(context->select_table, temp, ent);
+}
+
+/** \brief Relate the commands to the functions within the shell. */
+struct shell_cmd
+{
+	const char *name;     /**< Name of the command. */
+	cmd_fcn func;         /**< Name of function to execute the command. */
+};
+
+/** command object param value */
+struct search_helper
+{
+	QofInstance *inst;
+	QofParam *param;  /**< the parameter in argv[2] */
+	const char *term; /**< argv[3] */
+	char *value;      /**< argv[4] */
+};
+
+/** check_for_single_instance */
+struct count_helper
+{
+	gint count;
+	QofInstance *first_inst;
+};
+
+/** pre-selects if only one entity of this type exists. */
+static void
+count_cb (QofEntity *ent, gpointer user_data)
+{
+	struct count_helper *ch;
+
+	ch = (struct count_helper*)user_data;
+	ch->count++;
+	if(ch->count == 1)
+	{
+		ch->first_inst = (QofInstance*)ent;
+	}
+}
+
+/** select_table helper
+
+The select_table hashtable relies on a conversion from
+the integer counter to a string. This frees the temporary
+conversion string when the hashtable is no longer needed.
+*/
+static void
+cli_free_select (gpointer key, gpointer value, gpointer data)
+{
+	g_free(key);	
+}
+
+static void option_cb (QofBackendOption *option, gpointer data)
+{
+	gint gz_level;
+
+	gz_level = *(gint*)data;
+	if(0 == safe_strcmp(QSF_COMPRESS, option->option_name)) {
+		option->value = (gpointer)&gz_level;
+	}
+}
+
+static void
+qof_mod_compression (gint gz_level, qof_data *data)
+{
+	KvpFrame *be_config;
+	QofBook *book;
+	QofBackend *be;
+
+	if((gz_level > 0) && (gz_level <= 9))
+	{
+		book = qof_session_get_book(data->export_session);
+		be = qof_book_get_backend(book);
+		be_config = qof_backend_get_config(be);
+		qof_backend_option_foreach(be_config, option_cb, &gz_level);
+		qof_backend_load_config(be, be_config);
+	}
+}
+
+/** select an instance
+
+Offers multiple entities for selection. Ensure that
+check_for_single_instance has been run first.
+
+\todo Offer multiple listings of CLI_MAX_SELECT each.
+*/
+static int select_fcn (qof_data *context)
+{
+	gint choice, max;
+	gchar *temp;
+
+	if(!context->inst_type) { return -1; }
+	choice = 0;
+	context->counter = 0;
+	context->instance = NULL;
+	context->select_table = g_hash_table_new(g_str_hash, g_str_equal);
+	qof_object_foreach(context->inst_type, context->book, cli_select_cb, context);
+	max = g_hash_table_size(context->select_table);
+	if(max > CLI_MAX_SELECT) { max = CLI_MAX_SELECT; }
+	/* Translators: %s is an object name, %d the number of objects in the book. */
+	switch (context->cli_mode)
+	{
+		case EDIT_MODE : {
+			fprintf (stdout, _("Choose the %s to edit: (1 - %d): "), 
+				context->inst_type, max);
+			break;
+		}
+		case DELETE_MODE : {
+			fprintf (stdout, _("Choose the %s to DELETE: (1 - %d): "), 
+				context->inst_type, max);
+			break;
+		}
+		case PRINT_MODE : {
+			fprintf (stdout, _("Choose the %s to print: (1 - %d): "), 
+				context->inst_type, max);
+			break;
+		}
+		case NO_OP : { break; }
+	}
+	scanf("%2i", &choice);
+	fprintf (stdout, "\n");
+	while(choice <= 0 || choice > max)
+	{
+		char c;
+		c = getchar();
+		while (c != '\n') { c = getchar(); }
+		fprintf (stdout, _("Only %d objects are available of type '%s'.\n"), 
+			max, context->inst_type);
+		fprintf (stdout, _("Choose the %s to use: (1 - %d): "), context->inst_type, max);
+		scanf("%2i", &choice);
+		fprintf (stdout, "\n");
+	}
+	temp = g_strdup_printf("%d", choice);
+	context->instance = (QofInstance*)g_hash_table_lookup(context->select_table, temp);
+	g_free(temp);
+	g_hash_table_foreach(context->select_table, cli_free_select, NULL);
+	g_hash_table_destroy(context->select_table);
+	return 0;
+}
+
+/** \brief Shorthand search routine.
+
+Rather than using a QofQuery, this shorthand version uses a
+string for all parameter types. It will support the existing
+-t --date shorthand versions for compatibility with the non-interactive
+command set by actually using an underlying QofQuery.
+
+If this quick search fails, an interactive QofQuery could be used.
+A new query would have been needed anyway, with options enabled to
+isolate only one match. QofQuery relies on the term being the same
+type as the param_type. SQL queries will also be supported via the
+sql command in the shell. */
+
+static void
+cli_search_cb (QofEntity * ent, gpointer data)
+{
+	struct search_helper *sh;
+	gchar *value;
+	const QofParam *param;
+	gboolean found;
+
+	found = FALSE;
+	sh = (struct search_helper*)data;
+	param = sh->param;
+/* if param_type == QOF_TYPE_DATE, process term as -t --date and skip to a QofQuery format. */
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_DATE)) { return; }
+	value = qof_book_merge_param_as_string((QofParam*)param, ent);
+	if(0 == safe_strcmp(value, sh->term))
+	{
+		 /* if term matches more than once, fallback to SQL */
+		if(found) { sh->inst = NULL; return; }
+		found = TRUE;
+		sh->inst = (QofInstance*)ent;
+	}
+}
+
+/** Shortcut if only one entity of this type exists. */
+static gboolean
+check_for_single_instance (qof_data *context)
+{
+	QofCollection *coll;
+	struct count_helper ch;
+	struct search_helper sh;
+
+	ch.count = 0;
+	qof_object_foreach(context->inst_type, context->book, count_cb, &ch);
+	if(!ch.count)
+	{
+		fprintf (stderr, _("%s: No objects of type '%s' found.\n"),
+			PACKAGE, context->inst_type);
+		context->inst_type = NULL;
+		return FALSE;
+	}
+	if(ch.count == 1) 
+	{ 
+		context->instance = ch.first_inst; 
+		if(!context->argv[2] || !context->argv[3]) { return TRUE; }
+	}
+	if(!context->argv[2] || !context->argv[3]) { return FALSE; }
+	sh.inst = NULL;
+	sh.param = NULL;
+	sh.term = context->argv[3];
+	sh.param = (QofParam*)qof_class_get_parameter(context->inst_type, context->argv[2]);
+	if(sh.param == NULL) { 
+		fprintf (stderr, _("No parameter named '%s' found for object '%s'\n"), 
+			sh.term, sh.param->param_name);
+		return FALSE;
+	}
+	coll = qof_book_get_collection(context->book, context->inst_type);
+	if(!coll) { return FALSE; }
+	qof_collection_foreach(coll, cli_search_cb, &sh);
+	if(sh.inst)
+	{
+		context->instance = sh.inst;
+		if(context->argv[4]) {
+			g_message("argv[4]=%s param=%s", context->argv[4], sh.param->param_name);
+			sh.value = g_strdup(context->argv[4]);
+			qof_begin_edit(context->instance);
+			undo_edit_record(context->instance, sh.param);
+			qof_entity_set_param(&context->instance->entity, (QofParam*)sh.param, sh.value);
+			qof_commit_edit(context->instance);
+			undo_edit_commit(context->instance, sh.param);
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/** @name Top level shell functions.
+@{
+*/
+
+/** Run a sub-shell to either select or edit an instance. */
+static int
+qof_sub_shell (qof_data *context)
+{
+#ifdef HAVE_LIBREADLINE
+	char *line;
+	char *prompt;
+
+	if(!context->inst_type) { return 0; }
+	line = (char*)malloc(256 * sizeof(char));
+	prompt = g_strdup_printf("%s/%s> ", context->shortname, context->inst_type);
+#else
+	char buf[256];
+
+	if(!context->inst_type) { return 0; }
+#endif
+	for (;;) {
+		fflush (stdout);
+#ifdef HAVE_LIBREADLINE
+		line = readline(prompt);
+		if (line == NULL) { break; }
+		if (*line) { add_history(line); }
+		if (qof_parse_command(line, context) < 0) { break; }
+		g_free (line);
+#else
+		fprintf (stdout, "%s/%s> ", context->shortname, context->inst_type);
+		if (qof_parse_command(buf, context) < 0) { break; }
+#endif
+	}
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+/** \brief add a new instance and edit the values
+
+Expects the second argument (context->argv[1]) to be the name of a registed object.
+*/
+static int add_fcn(qof_data *context)
+{
+	QofInstance *inst;
+	gint result;
+	gchar *temp;
+
+	result = 0;
+	if(!qof_class_is_registered(context->argv[1]))
+	{
+		fprintf (stdout, _("%s: Cannot add '%s' - object name not found\n"),
+			PACKAGE, context->argv[1]);
+		return 0;
+	}
+	context->inst_type = g_strdup(context->argv[1]);
+	temp = g_strdup_printf("add-%s", context->inst_type);
+	qof_book_start_operation(context->book, temp);
+	inst = (QofInstance*)qof_object_new_instance(context->inst_type, context->book);
+	if(!inst) {
+		fprintf (stdout, _("Failed to add an instance of %s\n"), context->inst_type);
+		return 0;
+	}
+	fprintf (stdout, _("Added an instance of %s\n\n"), context->inst_type);
+	fprintf (stdout, _("Now edit the parameter details of this instance.\n"));
+	fprintf (stdout, _("Type 'help' for available commands or parameters.\n\n"));
+	undo_create_record(inst);
+	qof_book_end_operation(context->book);
+	context->shell_type = EDIT_SHELL;
+	context->instance = inst;
+	result = qof_sub_shell(context);
+	context->shell_type = TOP_SHELL;
+	return result;
+}
+
+/** \brief edit [object]
+
+\todo skip over user-friendly forms that may use
+where or =.
+
+*/
+static int edit_fcn(qof_data *context)
+{
+	gint result;
+	gchar *temp;
+
+	if(!qof_class_is_registered(context->argv[1]))
+	{
+		fprintf (stdout, _("%s: Cannot edit '%s' - object name not found\n"),
+			PACKAGE, context->argv[1]);
+		return 0;
+	}
+	result = 0;
+	context->inst_type = g_strdup(context->argv[1]);
+	if(!check_for_single_instance(context)) {
+		fprintf (stdout, _("Select an instance of %s to edit:\n"), context->inst_type);
+		fprintf (stdout, _("Type 'help' for available commands or parameters.\n\n"));
+		context->cli_mode = EDIT_MODE;
+		result = select_fcn(context);
+		context->cli_mode = NO_OP;
+		if (result) { return result; }
+	}
+	context->shell_type = EDIT_SHELL;
+	temp = g_strdup_printf("modify-%s", context->inst_type);
+	qof_book_start_operation(context->book, temp);
+	fprintf (stdout, _("Edit the parameter details of the selected instance.\n"));
+	fprintf (stdout, _("Type 'help' for available commands or parameters.\n\n"));
+	if(context->instance) { result = qof_sub_shell(context); }
+	context->shell_type = TOP_SHELL;
+	context->inst_type = NULL;
+	qof_book_end_operation(context->book);
+	return result;
+}
+/** \brief delete an instance of an object.
+
+Selects one instance and frees the entity.
+Warns the user AFTER deletion. 
+
+\todo a bespoke undo command could be useful, rather
+than quitting the program completely! :-)
+*/
+static int delete_fcn(qof_data *context)
+{
+	gint result;
+	QofEntity *ent;
+	gchar *temp;
+
+	result = 0;
+	if(!qof_class_is_registered(context->argv[1]))
+	{
+		fprintf (stdout, _("%s: Cannot delete '%s' - object name not found\n"),
+		PACKAGE, context->argv[1]);
+		return 0;
+	}
+	context->inst_type = g_strdup(context->argv[1]);
+	if(!check_for_single_instance(context))
+	{
+		fprintf (stdout, _("Select the instance of %s to delete\n"), context->inst_type);
+		fprintf (stdout, _("Type 'help' for available commands or parameters.\n\n"));
+		context->cli_mode = DELETE_MODE;
+		result = select_fcn(context);
+		context->cli_mode = NO_OP;
+		if ((result)||(!context->instance)) { return result; }
+	}
+	temp = g_strdup_printf("delete_%s", context->inst_type);
+	qof_book_start_operation(context->book, temp);
+	undo_delete_record(context->instance);
+	ent = (QofEntity*)context->instance;
+	qof_collection_mark_dirty(qof_book_get_collection(context->book, ent->e_type));
+	qof_entity_release(ent);
+	qof_book_end_operation(context->book);
+	fprintf (stdout, _("The instance has been DELETED. Type 'quit' to exit and undo. "
+	"The file will not be changed until you type 'write'.\n"));
+	return 0;
+}
+
+static void
+qof_list_cb(QofObject *obj, gpointer data)
+{
+	fprintf(stdout, "%-20s\t%s\n", obj->e_type, obj->type_label);
+}
+
+static int list_fcn(qof_data *context)
+{
+	fprintf (stdout, _("\nThe QOF shell supports these object names:\n"
+	"You can use the names with 'edit', 'print' or 'delete'\n"
+	"and in SQL queries (as the table name) with 'sql'\n"
+	"Descriptions are shown only for readability.\n\n"));
+	fprintf (stdout, "%-20s%s", _("Object Name"), _("Description\n"));
+	qof_object_foreach_type(qof_list_cb, NULL);
+	fprintf (stdout, _("\nUse 'explain <database>' to see the list of fields within\n"
+	"any supported database.\n"));
+	return 0;
+}
+
+static void
+qof_print_cb (QofParam *param, gpointer data)
+{
+	gchar *str;
+	qof_data *context;
+
+	context = (qof_data*)data;
+	g_return_if_fail(context);
+	str = qof_book_merge_param_as_string(param, (QofEntity*)context->instance);
+	fprintf (stdout, _("%-24s %-12s %s\n"), param->param_name, param->param_type, str);
+}
+
+/** \brief print an instance to the terminal. */
+static int print_fcn(qof_data *context)
+{
+	gint result;
+
+	result = 0;
+	if(!qof_class_is_registered(context->argv[1]))
+	{
+		fprintf (stdout, _("%s: Cannot print '%s' - object name not found\n"),
+			PACKAGE, context->argv[1]);
+		return 0;
+	}
+	context->inst_type = g_strdup(context->argv[1]);
+	if(!check_for_single_instance(context))
+	{
+		if(!context->inst_type) { return 0; }
+		fprintf (stdout, _("Select the instance of '%s' to print.\n"), context->inst_type);
+		fprintf (stdout, _(" Type 'help' for available commands or parameters.\n\n"));
+		context->cli_mode = PRINT_MODE;
+		result = select_fcn(context);
+		context->cli_mode = NO_OP;
+		if ((result)||(!context->instance)) { return result; }
+	}
+	fprintf (stdout, "%-24s %-12s %s\n\n", _("Name"), _("Type"), _("Value"));
+	qof_class_param_foreach (context->inst_type, qof_print_cb, context);
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static void
+qof_explain_cb (QofParam* param, gpointer user_data)
+{
+	if(param->param_getfcn && param->param_setfcn)
+	{
+		fprintf (stdout, _("Type: %-12s\tName: %-12s\n"), param->param_type, param->param_name);
+	}
+}
+
+/** print a list of available parameters for this object type */
+static int explain_fcn(qof_data *context)
+{
+	if(qof_class_is_registered(context->argv[1])) {
+		fprintf (stdout, _("\nParameters of the %s database:\n\n"), context->argv[1]);
+		qof_class_param_foreach(context->argv[1], qof_explain_cb, NULL);
+		fprintf (stdout, "\n\n");
+	}
+	else {
+		fprintf (stderr, _("\n%s: %s object not found.\n"), PACKAGE, context->argv[1]);
+	}
+	return 0;
+}
+
+/** \brief load [filename]
+
+Expects a readable filename in context->argv[1]
+*/
+static int load_fcn(qof_data *context)
+{
+	char* answer;
+
+	answer = g_strdup(" ");
+	if(qof_book_not_saved(context->book))
+	{
+		fprintf (stderr, _("%s: The current book has not been saved.\n"
+		"Do you still want to overwrite it? [y/n]\n"), PACKAGE);
+		scanf("%1s", answer);
+		if((0 != safe_strcmp(answer, "y")) && (0 != safe_strcmp(answer, "Y"))) {
+			qof_session_save(context->input_session, NULL);
+		}
+	}
+	qof_session_end(context->input_session);
+	context->input_session = qof_session_new();
+	if(context->argv[1]) {
+		context->filename = g_strdup(context->argv[1]);
+	}
+	if(context->filename) {
+		qof_session_begin(context->input_session, context->filename, FALSE, TRUE);
+		qof_mod_compression(context->gz_level, context);
+	}
+	else {
+		qof_session_begin(context->input_session, QOF_STDOUT, FALSE, FALSE);
+	}
+	qof_session_load(context->input_session, NULL);
+	context->book = qof_session_get_book(context->input_session);
+	qof_show_error(context->input_session, context->filename);
+	/* implement in the backend eventually */
+	qof_book_clear_undo(context->book);
+	return 0;
+}
+/** \brief write [filename]
+
+write the current book to file.
+	If no filename is provided, save to the original file
+	(to STDOUT if STDIN used). Analagous to Save / Save As...
+
+\todo fix problems with writing to an alternative file.
+*/
+static int write_fcn(qof_data *context)
+{
+	QofSession *save_as;
+	gchar current_work[PATH_MAX];
+	gchar *temp;
+
+	if(context->argv[1])
+	{
+		save_as = qof_session_new();
+		if(*context->argv[1] != '/')
+		{
+			getcwd(current_work, PATH_MAX);
+			temp = g_strconcat(current_work, "/", context->argv[1], NULL);
+			context->argv[1] = temp;
+		}
+		qof_session_begin(save_as, context->argv[1], FALSE, TRUE);
+		qof_session_swap_data(save_as, context->input_session);
+		qof_session_save(save_as, NULL);
+		qof_show_error(save_as, context->argv[1]);
+		qof_session_end(save_as);
+		return 0;
+	}
+	if(context->write_file)
+	{
+		qof_session_save(context->export_session, NULL);
+		qof_show_error(context->export_session, context->write_file);
+	}
+	else {
+		qof_session_save(context->input_session, NULL);
+		qof_show_error(context->input_session, context->filename);
+	}
+	/* implement in the backend eventually */
+	if(qof_book_can_undo(context->book)) { qof_book_clear_undo(context->book); }
+	return 0;
+}
+
+/** \brief merge UI
+
+\todo the entire merge routine needs testing.
+*/
+static void
+qof_merge_loop (qof_book_mergeData *mergeData, qof_book_mergeRule *rule, guint remainder)
+{
+	GSList *user_reports;
+	QofParam *one_param;
+	gchar *importstring, *targetstring, *buffer;
+	gint count, resolution;
+	gboolean input_ok;
+	gchar y;
+
+	buffer = "";
+	count = 0;
+	input_ok = FALSE;
+	user_reports = rule->mergeParam;
+	while(user_reports != NULL) {
+		one_param = user_reports->data;
+		buffer = g_strconcat(buffer, g_strdup_printf(_("%i:Parameter name: %s "),
+			count, one_param->param_name), NULL);
+		importstring = qof_book_merge_param_as_string(one_param, rule->importEnt);
+		buffer = g_strconcat(buffer, g_strdup_printf(_("Import data : %s "), importstring), NULL);
+		targetstring = qof_book_merge_param_as_string(one_param, rule->targetEnt);
+		buffer = g_strconcat(buffer, g_strdup_printf(_("Original data : %s\n"), targetstring), NULL);
+		user_reports = g_slist_next(user_reports);
+		count++;
+	}
+	while(!input_ok) {
+		resolution = 0;
+		fprintf (stdout, _("\nPlease resolve this conflict. Enter\n"
+		"    1 to use the import data or \n"
+		"    2 to keep the original data or"));
+		if(rule->mergeAbsolute == FALSE) {
+			fprintf (stdout, _("\n    3 to import the data as a NEW object or"));
+		}
+		fprintf (stdout, _("\n    9 to abort the entire merge operation.\n"));
+		fprintf (stdout, "> (1, 2");
+		if(rule->mergeAbsolute == FALSE) {
+			fprintf (stdout, ", 3 ");
+		}
+		fprintf (stdout, _("or 9) : "));
+		scanf("%1i", &resolution);
+		switch(resolution) {
+			case 1 : {
+				mergeData = qof_book_mergeUpdateResult(mergeData, MERGE_UPDATE);
+				input_ok = TRUE;
+				break;
+				}
+			case 2 : {
+				if(rule->mergeAbsolute == FALSE) {
+					mergeData = qof_book_mergeUpdateResult(mergeData, MERGE_DUPLICATE);
+				}
+				if(rule->mergeAbsolute == TRUE) {
+					mergeData = qof_book_mergeUpdateResult(mergeData, MERGE_ABSOLUTE);
+				}
+				input_ok = TRUE;
+				break;
+			}
+			case 3 : {
+				if(rule->mergeAbsolute == FALSE) {
+					mergeData = qof_book_mergeUpdateResult(mergeData, MERGE_NEW);
+					input_ok = TRUE;
+				}
+				break;
+			}
+			case 9 : {
+				fprintf (stdout, _("Are you sure you want to abort the entire merge operation?\n"
+				"The rest of the import data will not be processed.\n"
+				"Your original data will not be modified. Abort? y/n : "));
+				scanf("%1s", &y);
+				if((safe_strcmp(_("y"),&y) == 0)||(safe_strcmp("",&y) == 0)) {
+					fprintf (stdout, _("Aborting . . \n\n"));
+					mergeData = qof_book_mergeUpdateResult(mergeData, MERGE_INVALID);
+					input_ok = TRUE;
+				}
+				break;
+			}
+			default : break;
+		}
+	}
+}
+
+/** \brief merge [filename]
+
+Accept a filename from the shell, check it is readable and
+load it, then if the book is valid, merge it into the
+current book.
+
+If the current book is NULL, this is equivalent to 'load' but
+a LOT more longwinded. (Not recommended.)
+*/
+static int merge_fcn(qof_data *context)
+{
+	qof_book_mergeData *mergeData;
+	QofBook *importBook, *targetBook;
+	gint result;
+
+	/** \todo check the filename can be read. */
+	if(!context->argv[1]) { return 0; }
+	qof_session_begin(context->export_session, context->argv[1], FALSE, FALSE);
+	qof_session_load(context->export_session, NULL);
+	qof_show_error(context->export_session, context->write_file);
+	importBook = qof_session_get_book(context->export_session);
+	targetBook = context->book;
+	mergeData = qof_book_mergeInit(importBook, targetBook);
+	g_return_val_if_fail((mergeData != NULL), -1);
+	qof_book_mergeRuleForeach(mergeData, qof_merge_loop, MERGE_REPORT);
+	result = qof_book_mergeCommit(mergeData);
+	return result;
+}
+
+/** check if book is dirty, show errors (if any) and exit */
+static int exit_fcn(qof_data *context)
+{
+	char* answer;
+
+	answer = g_strdup(" ");
+	if(qof_book_not_saved(context->book))
+	{
+		fprintf (stdout, _("The current book has not been saved.\n"
+		"Do you still want to quit without saving? %s"), "[y/n]");
+		scanf("%1s", answer);
+		fprintf (stdout, "\n");
+		if(0 != safe_strcmp(answer, "y") && (0 != safe_strcmp(answer, "Y"))) {
+			qof_session_save(context->input_session, NULL);
+		}
+	}
+	if(qof_book_not_saved(qof_session_get_book(context->export_session)))
+	{
+		qof_show_error(context->export_session, context->write_file);
+	}
+	qof_show_error(context->input_session, context->filename);
+	qof_session_end(context->input_session);
+	if(context->export_session) { qof_session_end(context->export_session); }
+	fprintf (stdout, _("\nThank you for using %s.\n"), PACKAGE);
+	return -1;
+}
+
+static int help_fcn(qof_data *context)
+{
+	fprintf (stdout, _("Commands available in the shell are:\n\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "add [object]", 
+		_("Add a new instance of the object.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "edit [object]",
+		_("Select one instance and edit (set) the parameter values.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "delete [object]", 
+		_("Select one instance for deletion.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "list", 
+		_("Synonym for the --list command outside the shell.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "print [object]", 
+		_("Select one instance and print the parameter values.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "explain [object]", 
+		_("Synonym for the --explain command outside the shell.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "load [filename]",
+		_("Replace the current book with data from the file.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, " ", 
+		_("Prompts to save the current book, if any.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "write [filename]", 
+		_("Write out the current book. If no filename is given,\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, " ", _("write to the original file.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, " ", _("(uses STDOUT if STDIN is used.)\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "merge [filename]", 
+		_("Merge data from the file into the current book.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "sql [sql_query]", 
+		_("Run a \"quoted\" SQL statement.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "help | ?", _("This screen.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "quit | q | exit", _("Quit the shell\n"));
+	fprintf (stdout, "\n");
+	return 0;
+}
+
+/** \brief sql - take a SQL statement.
+
+\todo improve the sql_parser - it is very noisy and
+yet not very helpful.
+*/
+static int sql_fcn(qof_data *context)
+{
+	QofSqlQuery *q;
+	gchar *sql, *temp;
+	gint result;
+	QofQuery *qq;
+	QofBook *book;
+	GList *results;
+
+	q = qof_sql_query_new();
+	sql = g_strdup(context->sql_str);
+	if(!sql) { sql = context->argv[1]; }
+	qof_sql_query_parse(q, sql);
+	qq = qof_sql_query_get_query(q);
+	book = qof_session_get_book(context->input_session);
+	qof_query_set_book(qq, book);
+	qof_query_set_sort_order(qq, NULL, NULL, NULL);
+	results = qof_query_run (qq);
+	if(!results) { return 0; }
+	if(g_list_length(results) == 1) { 
+		context->instance = (QofInstance*)results->data;
+		context->shell_type = EDIT_SHELL;
+		temp = g_strdup_printf("modify-%s", context->inst_type);
+		qof_book_start_operation(context->book, temp);
+		fprintf (stdout, _("Edit the parameter details of the selected instance.\n"));
+		fprintf (stdout, _("Type 'help' for available commands or parameters.\n\n"));
+		if(context->instance) { result = qof_sub_shell(context); }
+		context->shell_type = TOP_SHELL;
+		context->inst_type = NULL;
+		qof_book_end_operation(context->book);
+		return 0;
+	}
+	fprintf (stdout, _("Query returned %d entities\n"), g_list_length(results));
+	return 0;
+}
+
+/** @} */
+/** \name Edit shell functions
+@{
+*/
+
+/** \brief Set a value in a parameter
+
+\todo improve error handling - currently it is almost silent.
+
+Boolean values accept TRUE, 1, or translated values for Y, YES or TRUE
+and are matched case insensitively, so y, yes and true (and their translations)
+also match. If the match fails, false is set.
+
+*/
+static int set_edit_fcn (qof_data *context)
+{
+	QofParam *param;
+	QofType type;
+	gchar *value;
+
+	if(!context->instance || !context->argv[1] || !context->argv[2]) { return 0; }
+	value = g_strdup(context->argv[2]);
+	param = (QofParam*)qof_class_get_parameter(context->inst_type, context->argv[1]);
+	if(!param)
+	{
+		fprintf (stderr, _("%s: parameter name '%s' of object '%s' not recognised.\n"),
+			PACKAGE, context->argv[1], context->inst_type);
+		fprintf (stderr, _("Type 'explain' for more information.\n"));
+		return 0;
+	}
+	type = qof_class_get_parameter_type(context->inst_type, context->argv[1]);
+	qof_begin_edit(context->instance);
+	/* undo_edit_record will be called by begin_edit eventually. */
+	undo_edit_record(context->instance, param);
+	qof_entity_set_param(&context->instance->entity, param, value);
+	qof_commit_edit(context->instance);
+	undo_edit_commit(context->instance, param);
+	g_free(value);
+	return 0;
+}
+
+/** List the available parameters for this edit */
+static int explain_edit_fcn (qof_data *context)
+{
+	fprintf (stdout, _("\nEditable parameters of the %s object:\n\n"), context->inst_type);
+	qof_class_param_foreach(context->inst_type, qof_explain_cb, NULL);
+	fprintf (stdout, "\n\n");
+	return 0;
+}
+
+/** \brief Commit data to instance and leave the sub-shell.
+
+\todo Should this clear the undo??
+*/
+static int commit_edit_fcn (qof_data *context)
+{
+//	if(qof_book_can_undo(context->book)) { qof_book_clear_undo(context->book); }
+	return -1;
+}
+
+/** print the instance being edited.*/
+static int print_edit_fcn (qof_data *context)
+{
+	if(!context->inst_type) { return 0; }
+	fprintf (stdout, "%-24s %-12s %s\n\n", _("Name"), _("Type"), _("Value"));
+	qof_class_param_foreach (context->inst_type, qof_print_cb, context);
+	fprintf (stdout, _("\nNot all parameters are editable, use 'explain' "
+	"to see the list of editable parameters for the object '%s'.\n\n"), context->inst_type);
+	return 0;
+}
+
+static int help_edit_fcn (qof_data *context)
+{
+	gchar *temp;
+
+	fprintf (stdout, _("Commands available in this sub-shell are:\n\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "edit [Name] [Value]", 
+	_("Edit the parameter 'Name' to have the 'Value' given.\n"));
+	/* Translators: TRUE and numeral one are always acceptable for boolean values here. */
+	fprintf (stdout, QOF_SHELL_FORMAT, " ", 
+		_("Boolean values accept TRUE|true, 1, Y|y or yes|YES\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, " ", _("String values that include spaces should be quoted\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "set [Name] [Value]", _("Synonym for edit.\n"));
+	temp = g_strdup_printf(_("Print the current values for this '%s' instance.\n"), context->inst_type);
+	fprintf (stdout, QOF_SHELL_FORMAT, "print", temp);
+	g_free(temp);
+	temp = g_strdup_printf(_("Show the editable parameters for '%s'\n"), context->inst_type);
+	fprintf (stdout, QOF_SHELL_FORMAT, "explain", temp);
+	g_free(temp);
+	fprintf (stdout, QOF_SHELL_FORMAT, "commit",  _("Set the edited parameter values.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "help | ?", _("This screen.\n"));
+	fprintf (stdout, QOF_SHELL_FORMAT, "quit | q | exit", 
+		_("Return to the top shell without setting changes.\n"));
+	fprintf (stdout, "\n");
+	return 0;
+}
+
+static int quit_edit_fcn (qof_data *context)
+{
+	if(qof_book_can_undo(context->book)) { qof_book_undo(context->book); }
+	return -1;
+}
+
+/** @} */
+/** \name Shell control handlers
+@{
+*/
+struct shell_cmd shell_list[] = {
+	{ "add",     add_fcn          },
+	{ "edit",    edit_fcn         },
+	{ "delete",  delete_fcn       },
+	{ "list",    list_fcn         },
+	{ "print",   print_fcn        },
+	{ "explain", explain_fcn      },
+	{ "load",    load_fcn         },
+	{ "write",   write_fcn        },
+	{ "merge",   merge_fcn        },
+	{ "sql",     sql_fcn          },
+	{ "help",    help_fcn         },
+	{ "?",       help_fcn         },
+	{ "q",       exit_fcn         },
+	{ "quit",    exit_fcn         },
+	{ "exit",    exit_fcn         },
+	{ "bye",     exit_fcn         },
+	{ NULL, NULL }
+};
+
+struct shell_cmd edit_list[] = {
+	{ "edit",    set_edit_fcn     },
+	{ "set",     set_edit_fcn     },
+	{ "explain", explain_edit_fcn },
+	{ "commit",  commit_edit_fcn  },
+	{ "print",   print_edit_fcn   },
+	{ "quit",    quit_edit_fcn    },
+	{ "help",    help_edit_fcn    },
+	{ "?",       help_edit_fcn    },
+	{ "q",       quit_edit_fcn    },
+	{ "exit",    quit_edit_fcn    },
+	{ "bye",     quit_edit_fcn    },
+	{ NULL, NULL }
+};
+
+static char *strtoke(char *str, const char *ws, const char *delim)
+{
+	int inc;
+	static char *start, *s = NULL;
+
+	if (str != NULL) { s = str; }
+	inc = strspn(s, ws);
+	s += inc;
+	start = s;
+	if (*s == '\0') { return NULL; }
+	else if (strchr(delim, *s) != NULL) {
+		start++;
+		s = strchr(s + 1, *s);
+		*s = '\0';
+		s++;
+	}
+	else {
+		inc = strcspn(s, ws);
+		if (s[inc] == '\0') { s += inc; }
+		else {
+			s[inc] = '\0';
+			s += inc + 1;
+		}
+	}
+	return start;
+}
+
+gboolean
+qof_check_sql(const char *sql)
+{
+	regex_t *r;
+	int reg_exp_check;
+	static char *pattern = QOF_SQL_SUPPORTED;
+//	QofSqlQuery *q;
+	gboolean result;
+
+	result = FALSE;
+	r = g_new(regex_t, 1);
+	reg_exp_check = regcomp(r, pattern,
+		REG_ICASE | REG_NOSUB | REG_EXTENDED);
+	g_return_val_if_fail(reg_exp_check == 0, FALSE);
+	if(0 == regexec(r, sql, 0, NULL, 0)) { result = TRUE; }
+	regfree(r);
+	g_free(r);
+	return result;
+}
+
+/** \brief Relate the command to the function.
+
+\todo Stop changing the input with strtoke ?
+*/
+static int
+qof_parse_command (const char *cmd, qof_data *context)
+{
+	char *argv[32];
+	int inc, argc;
+	char *cmd_dup;
+	gboolean good;
+
+	argc = 0;
+	good = FALSE;
+	memset(argv, 0, sizeof(argv) / sizeof(char*));
+	cmd_dup = strdup(cmd);
+	argv[0] = strtoke(cmd_dup, " \t\n", "\"'");
+	while (argv[argc] != NULL) {
+		argc++;
+		argv[argc] = strtoke(NULL, " \t\n", "\"'");
+	}
+	if (argc == 0) {
+		free(cmd_dup);
+		return 0;
+	}
+	context->argc = argc;
+	context->argv = argv;
+	switch(context->shell_type)
+	{
+		case TOP_SHELL :
+		{
+			for (inc = 0; shell_list[inc].name != NULL; inc++) {
+				if (strcasecmp(argv[0], shell_list[inc].name) == 0) {
+					good = TRUE;
+					if((shell_list[inc].func(context)) < 0) { return -1; }
+				}
+			}
+			if(!good) {
+				fprintf(stderr, _("%s: bad option - %s, available commands are:\n"),
+					PACKAGE, argv[0]);
+				for (inc = 0; shell_list[inc].name != NULL; inc++) {
+					fprintf (stderr, "%s ", shell_list[inc].name);
+				}
+				fprintf (stderr, _("\nUse help for more information.\n\n"));
+			}
+			break;
+		}
+		case EDIT_SHELL :
+		{
+			for (inc = 0; edit_list[inc].name != NULL; inc++) {
+				if(strcasecmp(argv[0], edit_list[inc].name) == 0) {
+					good = TRUE;
+					if((edit_list[inc].func(context)) < 0) { return -1; }
+				}
+			}
+			if(!good) {
+				fprintf(stderr, _("%s: bad option - %s, available commands are:\n"),
+					PACKAGE, argv[0]);
+				for (inc = 0; edit_list[inc].name != NULL; inc++) {
+					fprintf (stderr, "%s ", edit_list[inc].name);
+				}
+				fprintf (stderr, _("\nUse help for more information.\n\n"));
+			}
+			break;
+		}
+		default : { break; }
+	}
+	free(cmd_dup);
+	return 0;
+}
+
+void
+qof_cmd_shell(qof_data *context)
+{
+	QofSession *input_session;
+#ifdef HAVE_LIBREADLINE
+	char *line;
+	char *prompt;
+
+	line = (char *)malloc(256*sizeof(char));
+	prompt = g_strdup_printf("%s> ", PACKAGE);
+#else
+	char buf[256];
+
+#endif
+	context->argc = 0;
+	context->argv = NULL;
+	input_session = context->input_session;
+	if(0 == safe_strcmp(context->exclude, context->database)
+		&&(context->exclude != NULL))
+	{
+		fprintf(stderr, _("%s: Error: Cannot exclude database \"%s\" with option -e\n"
+		"    because option -d is set to the include the same database: \"%s\"\n"
+		"Use the \'-l\' command to see the full list of supported databases.\n"),
+			PACKAGE, context->exclude, context->database);
+		qof_session_end(input_session);
+		return;
+	}
+	if(context->filename) {
+		qof_session_begin(input_session, context->filename, TRUE, TRUE);
+		qof_session_load(input_session, NULL);
+	}
+	else { qof_session_begin(input_session, QOF_STDOUT, TRUE, FALSE); }
+	qof_show_error(input_session, context->filename);
+	context->book = qof_session_get_book(context->input_session);
+	context->shell_type = TOP_SHELL;
+	context->inst_type = NULL;
+	context->instance = NULL;
+	if(!context->shortname) { context->shortname = g_strndup(PACKAGE, 4); }
+	context->argc = 0;
+	fprintf (stdout, _("\nWelcome to the QOF interactive shell ...\n"));
+	fprintf (stdout, _(" Type 'help' for additional information\n\n"));
+
+	for (;;) {
+		fflush(stdout);
+#ifdef HAVE_LIBREADLINE
+		line = readline(prompt);
+		/* user pressed ^d or so */
+		if (line == NULL) {
+			fprintf(stdout, _("\n\nThank you for using %s.\n"), PACKAGE);
+		       	break;
+		}
+		/* skip blanks */
+		if (*line) { add_history(line); }
+		if(qof_parse_command(line, context) != 0) { break; }
+		free(line);
+#else
+		fprintf (stdout, "%s> ", PACKAGE);
+		if(qof_parse_command(buf, context) != 0) { break; }
+		if (fgets(buf, 256, stdin) == NULL) { break; }
+#endif
+	}
+	fprintf(stdout, "\n");
+}
+/** @} */
+
+qof_data*
+qof_create(void)
+{
+	qof_data *context;
+
+	context = g_new0(qof_data, 1);
+	return context;
+}
+
+/** Prints helpful error messages
+
+\todo make sure the file is always available, some
+errors still print (null).
+*/
+void
+qof_show_error(QofSession *session, const char *newfile)
+{
+	QofBackendError io_error;
+	gboolean uh_oh;
+	const char *fmt;
+
+	uh_oh = TRUE;
+	io_error = qof_session_get_error(session);
+	switch (io_error)
+	{
+	case ERR_BACKEND_NO_ERR : {
+		uh_oh = FALSE;
+		return;
+	}
+	case ERR_BACKEND_NO_HANDLER: {
+		fmt = _("%s: No suitable backend was found for %s.\n");
+		fprintf(stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_NO_BACKEND: {
+		fmt = _("%s: The URL '%s' is not supported by this "
+		"version of %s.\n");
+		fprintf(stderr, fmt, PACKAGE, newfile, PACKAGE);
+		break;
+	}
+	case ERR_BACKEND_BAD_URL: {
+		fmt = _("%s: Cannot parse the URL '%s'\n");
+		fprintf(stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_CANT_CONNECT: {
+		fmt = _("%s: Cannot connect to '%s'. "
+		"The host, username or password were incorrect.\n");
+		fprintf(stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_CONN_LOST: {
+		fmt = _("%s: Cannot connect to '%s'. "
+		"Connection was lost, unable to send data.\n");
+		fprintf(stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_TOO_NEW: {
+		fmt = _("%s: This file/URL appears to be from a newer "
+		"version of %s.\n");
+		fprintf (stderr, fmt, PACKAGE, PACKAGE);
+		break;
+	}
+	case ERR_BACKEND_NO_SUCH_DB: {
+		fmt = _("%s: The database '%s' does not seem to exist.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_LOCKED: {
+		fmt = _("%s: Could not obtain the lock for '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_READONLY: {
+		fmt = _("%s could not write to '%s'. "
+		"That database may be on a read-only file system, "
+		"or you may not have write permission for the directory.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_DATA_CORRUPT: {
+		fmt = _("%s: The file/URL '%s' does not contain %s "
+		"data or the data is corrupt.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile, PACKAGE);
+		break;
+	}
+	case ERR_BACKEND_SERVER_ERR: {
+		fmt = _("%s: The server at URL '%s' "
+		"experienced an error or encountered bad or corrupt data.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_PERM: {
+		fmt = _("%s: You do not have permission to access '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_BACKEND_MISC: {
+		fmt = _("%s: An error occurred while processing '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	/* QSF additions */
+	case ERR_QSF_INVALID_OBJ: {
+		fmt = _("%s: Invalid QSF Object file! The QSF object file '%s' "
+		" failed to validate  against the QSF object schema. "
+		"The XML structure of the file is either not well-formed "
+		"or the file contains illegal data.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_INVALID_MAP: {
+		fmt = _("%s: Invalid QSF Map file! The QSF map file "
+		"failed to validate against the QSF map schema. "
+		"The XML structure of the file is either not well-formed "
+		"or the file contains illegal data.\n");
+		fprintf (stderr, fmt, PACKAGE);
+		break;
+	}
+	case ERR_QSF_BAD_QOF_VERSION: {
+		fmt = _("%s: The QSF Map file '%s' was written for a different "
+		"version of QOF. It may need to be modified to work with "
+		"your current QOF installation.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_BAD_MAP: {
+		fmt = _("%s: The selected QSF map '%s' contains unusable or missing data. "
+		"This is usually because not all the required parameters for "
+		"the defined objects have calculations described in the map.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_BAD_OBJ_GUID: {
+		fmt = _("%s: The selected QSF object file '%s' contains one or "
+		"more invalid GUIDs. The file cannot be processed - "
+		"please check the source of the file and try again.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_NO_MAP: {
+		fmt = _("%s: The selected QSF Object file '%s' requires a map"
+		"but it was not provided.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_WRONG_MAP: {
+		fmt = _("%s: Wrong QSF map selected. The selected map, validates "
+		"but was written for different QOF objects. "
+		"The list of objects defined in this map does not include "
+		"all the objects described in the current QSF object file.\n");
+		fprintf (stderr, fmt, PACKAGE);
+		break;
+	}
+	case ERR_QSF_MAP_NOT_OBJ: {
+		fmt = _("%s: The selected file '%s' is a QSF map and cannot"
+		"be opened as a QSF object.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_OVERFLOW : {
+		fmt = _("%s: When converting XML strings into numbers, an overflow "
+		"has been detected. The QSF object file '%s' contains invalid "
+		"data in a field that is meant to hold a number.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_QSF_OPEN_NOT_MERGE : {
+		fmt = _("%s: The QSF object file '%s' should be merged, "
+		"not opened directly.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_FILE_BAD_READ: {
+		fmt = _("%s: There was an error reading the file '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_PARSE_ERROR: {
+		fmt = _("%s: There was an error parsing the file '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_FILE_EMPTY: {
+		fmt = _("%s: The file '%s' is empty.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_FILE_NOT_FOUND: {
+		fmt = _("%s: The file '%s' could not be found.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_FILE_TOO_OLD: {
+		fmt = _("%s: This file is from an older version.\n");
+		fprintf (stderr, fmt, PACKAGE);
+		break;
+	}
+	case ERR_FILEIO_UNKNOWN_FILE_TYPE: {
+		fmt = _("%s: Unknown file type, '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_BACKUP_ERROR: {
+		fmt = _("%s: Could not make a backup of '%s'.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+		break;
+	}
+	case ERR_FILEIO_WRITE_ERROR: {
+		fmt = _("%s: Could not write to '%s'. Check that you have "
+		"permission to write to this file and that there is sufficient "
+		"space to create it.\n");
+		fprintf (stderr, fmt, PACKAGE, newfile);
+	  break;
+	}
+	case ERR_SQL_DB_TOO_OLD: {
+		fmt = _("%s: This database is from an older version.\n");
+		fprintf (stderr, fmt, PACKAGE);
+		break;
+	}
+	case ERR_SQL_DB_BUSY: {
+		fmt = _("%s: The SQL database is in use by other users.\n");
+		fprintf (stderr, fmt, PACKAGE);
+		break;
+	}
+	default:
+		fmt = _("%s: An unknown I/O error occurred.\n");
+		fprintf (stderr, fmt, PACKAGE);
+	break;
+	}
+	fprintf (stderr, "\n");
+}
+
+struct param_ref_list
+{
+	GSList *slist;
+	QofType param_type;
+	int i;
+};
+
+static void
+find_param_cb(QofParam *param, gpointer user_data)
+{
+	struct param_ref_list *b;
+	char *buf;
+
+	b = (struct param_ref_list*)user_data;
+	if((param->param_getfcn == NULL)||(param->param_setfcn == NULL)) { return; }
+	if(0 == safe_strcmp(b->param_type, param->param_type))
+	{
+		b->i++;
+		buf = g_strdup(param->param_name);
+		if(buf != NULL) {
+			b->slist = g_slist_append(b->slist, buf);
+		}
+		return;
+	}
+}
+
+GSList*
+qof_get_param_list(QofIdTypeConst object_type, QofType param_type)
+{
+	GSList *param_list;
+	char *i;
+	struct param_ref_list p;
+
+	param_list = NULL;
+	p.slist = NULL;
+	p.i = 0;
+	g_return_val_if_fail(object_type != NULL, NULL);
+	p.param_type = g_strdup(param_type);
+	qof_class_param_foreach(object_type, find_param_cb, &p);
+	param_list = g_slist_copy(p.slist);
+	i = g_strdup(object_type);
+	return param_list;
+}
+
+void
+qof_data_free(qof_data *data)
+{
+	g_free(data->filename);
+	g_free(data->write_file);
+	g_free(data->sql_file);
+	g_free(data->sql_str);
+	g_free(data->database);
+	g_free(data->shortname);
+}
+
+/** \name SQL handlers
+@{
+*/
+static QofQuery*
+qof_main_run_sql(qof_data *context)
+{
+	QofSqlQuery *q;
+	gchar *sql;
+	QofQuery *qq;
+
+	q = qof_sql_query_new();
+	sql = g_strdup(context->sql_str);
+	qof_sql_query_parse(q, sql);
+	qq = qof_sql_query_get_query(q);
+	return qq;
+}
+
+static void
+qof_main_run_query(QofQuery *qq, qof_data *context)
+{
+	QofBook *book;
+	GList *results;
+
+	g_return_if_fail(qq);
+	results = NULL;
+	book = qof_session_get_book(context->input_session);
+	qof_query_set_book(qq, book);
+	qof_query_set_sort_order(qq, NULL, NULL, NULL);
+	results = qof_query_run (qq);
+#ifdef PRINT_DEBUG
+	qof_query_print(qq);
+#endif
+	if(results == NULL) { return; }
+	if(results != NULL) {
+		qof_entity_copy_list(context->export_session, results);
+	}
+}
+
+/** \brief Assemble the components of the query.
+
+If any SQL statements are found, run
+separately from any -c, -d or -t options.
+
+All queries are additive: Successive queries add
+more entities to the result set but no entity is
+set more than once.
+*/
+static void
+qof_moderate_query(qof_data *context)
+{
+	Timespec min_ts;
+	Timespec max_ts;
+	QofQueryPredData *date_pred_data;
+//	QofQueryPredData *category_pred;
+	QofQuery *q;
+	QofIdTypeConst find;
+//	char *buf;
+	GSList *date_param_list, *category_param_list;
+	GList *f;
+	gboolean all;
+
+	all = TRUE;
+	q = qof_query_create();
+	date_param_list = NULL;
+	category_param_list = NULL;
+	for (f = context->sql_list; f ; f = context->sql_list->next)
+	{
+		context->sql_str = g_strdup(f->data);
+		q = qof_main_run_sql(context);
+		qof_main_run_query(q, context);
+		if(q) { qof_query_clear(q); }
+		g_free(context->sql_str);
+		all = FALSE;
+	}
+	if(0 < g_list_length(context->sql_list)) {
+		context->sql_str = NULL;
+		g_list_free(context->sql_list);
+		all = FALSE;
+	}
+	if(context->sql_str != NULL) {
+		q = qof_main_run_sql(context);
+		qof_main_run_query(q, context);
+		if(q) { qof_query_clear(q); }
+		all = FALSE;
+	}
+	if((context->database != NULL)&&(qof_class_is_registered(context->database)))
+	{
+		qof_query_search_for(q, context->database);
+		find = qof_query_get_search_for(q);
+		if(context->min_ts.tv_sec > 0) {
+			min_ts = context->min_ts;
+			max_ts = context->max_ts;
+			date_param_list = g_slist_copy(qof_get_param_list(find, QOF_TYPE_DATE));
+			if(!date_param_list) { qof_query_clear(q); return;}
+			date_pred_data = qof_query_date_predicate(QOF_COMPARE_GTE, QOF_DATE_MATCH_NORMAL, min_ts);
+			qof_query_add_term(q, date_param_list, date_pred_data, QOF_QUERY_AND);
+			date_param_list = qof_get_param_list(qof_query_get_search_for(q), QOF_TYPE_DATE);
+			date_pred_data = qof_query_date_predicate(QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, max_ts);
+			qof_query_add_term(q, date_param_list, date_pred_data, QOF_QUERY_AND);
+		}
+		qof_main_run_query(q, context);
+		if(q) { qof_query_clear(q); }
+		all = FALSE;
+	}
+	if(all == TRUE)
+	{
+		while(context->all_objects)
+		{
+			q = qof_query_create_for(context->all_objects->data);
+		find = qof_query_get_search_for(q);
+			if(context->min_ts.tv_sec > 0) {
+				min_ts = context->min_ts;
+				max_ts = context->max_ts;
+				date_param_list = g_slist_copy(qof_get_param_list(find, QOF_TYPE_DATE));
+				if(!date_param_list) {
+					if(q) { qof_query_clear(q); }
+					context->all_objects = context->all_objects->next;
+					continue;
+				}
+				date_pred_data = qof_query_date_predicate(QOF_COMPARE_GTE, QOF_DATE_MATCH_NORMAL, min_ts);
+				qof_query_add_term(q, date_param_list, date_pred_data, QOF_QUERY_AND);
+				date_param_list = qof_get_param_list(qof_query_get_search_for(q), QOF_TYPE_DATE);
+				date_pred_data = qof_query_date_predicate(QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, max_ts);
+				qof_query_add_term(q, date_param_list, date_pred_data, QOF_QUERY_AND);
+			}
+			qof_main_run_query(q, context);
+			if(q) { qof_query_clear(q); }
+			context->all_objects = context->all_objects->next;
+		}
+	}
+}
+/** @} */
+
+static void
+print_config_cb (QofBackendOption *option, gpointer data)
+{
+	fprintf (stdout, "option name=%s\n", option->option_name);
+	fprintf (stdout, "option desc=%s\n", option->description);
+	fprintf (stdout, "option tip =%s\n", option->tooltip);
+	switch(option->type) {
+		case KVP_TYPE_GINT64   : {
+			fprintf (stdout, "option value=%" G_GINT64_FORMAT,
+				*(gint64*)option->value);
+			fprintf (stdout, "\noption type=%s\n", QOF_TYPE_INT64);
+			break;
+		}
+		case KVP_TYPE_DOUBLE   : {
+			break; 
+		}
+		case KVP_TYPE_NUMERIC  : {
+			break; 
+		}
+		case KVP_TYPE_STRING   : {
+			fprintf (stdout, "option value=%s\n", (char*)option->value);
+			fprintf (stdout, "option type=%s\n", QOF_TYPE_STRING);
+			break;
+		}
+		case KVP_TYPE_GUID     : { break; } /* unsupported */
+		case KVP_TYPE_TIMESPEC : {
+			break;
+		}
+		case KVP_TYPE_BINARY   : { break; } /* unsupported */
+		case KVP_TYPE_GLIST    : { break; } /* unsupported */
+		case KVP_TYPE_FRAME    : { break; } /* unsupported */
+	}		
+}
+
+void
+qof_cmd_offline (qof_data *context)
+{
+	QofSession *input_session, *export_session;
+	gchar current_work[PATH_MAX];
+	gchar *temp;
+	QofBackend *be;
+	KvpFrame *backend_config;
+
+	backend_config = NULL;
+	input_session = context->input_session;
+	if(0 == safe_strcmp(context->exclude, context->database)
+		&&(context->exclude != NULL))
+	{
+		fprintf(stderr, _("%s: Error: Cannot exclude database \"%s\" with option -e\n"
+		"    because option -d is set to the include the same database: \"%s\"\n"
+		"Use the \'-l\' command to see the full list of supported databases.\n"),
+			PACKAGE, context->exclude, context->database);
+		qof_session_end(input_session);
+		return;
+	}
+	qof_session_begin(input_session, context->filename, FALSE, TRUE);
+	qof_session_load(input_session, NULL);
+	if(ERR_BACKEND_LOCKED == qof_session_get_error(input_session))
+	{
+		/** \todo ask the user if it is OK to ignore the lock. */
+		qof_session_begin(input_session, context->filename, TRUE, FALSE);
+		qof_session_load(input_session, NULL);
+	}
+	context->book = qof_session_get_book(input_session);
+	be = qof_book_get_backend(context->book);
+	backend_config = qof_backend_get_config(be);
+	PINFO (" trying to get backend config");
+	if(backend_config) 
+	{
+		qof_backend_option_foreach(backend_config, 
+			print_config_cb, context);
+	}
+	else { PINFO (" failed"); }
+	export_session = qof_session_new();
+	context->export_session = export_session;
+	if(context->write_file != NULL) {
+		if(*context->write_file != '/')
+		{
+			getcwd(current_work, PATH_MAX);
+			temp = g_strconcat(current_work, "/", context->write_file, NULL);
+			context->write_file = temp;
+		}
+		qof_session_begin(export_session, context->write_file, FALSE, TRUE);
+	}
+	else { qof_session_begin(export_session, QOF_STDOUT, TRUE, FALSE); }
+	qof_session_set_current_session(input_session);
+	qof_moderate_query(context);
+	qof_session_save(export_session, NULL);
+	qof_show_error(export_session, context->write_file);
+	qof_show_error(input_session, context->filename);
+	qof_session_end(input_session);
+	qof_session_end(export_session);
+}
+
+
+void
+qof_cmd_list (void)
+{
+	fprintf(stdout, _("\n%s currently supports these database names:\n"
+	"You can use the names with %s -d\n"
+	"and in SQL queries (as the table name) with %s -s|f\n"
+	"Descriptions are shown only for readability.\n\n"
+	"Name                    Description\n\n"
+	)
+	, PACKAGE, PACKAGE, PACKAGE);
+	qof_object_foreach_type(qof_list_cb, NULL);
+	fprintf(stdout, _("\nUse '-d <database> --explain' to see the list of fields within\n"
+	"any supported database.\n"));
+	fprintf(stdout, _("\nThank you for using %s\n\n"), PACKAGE);
+}
+
+void
+qof_select_all(QofObject *obj, gpointer data)
+{
+	qof_data *context;
+	char* type;
+
+	context = (qof_data*)data;
+	type = g_strdup(obj->e_type);
+	if(!qof_class_is_registered(type)) { return; }
+	context->all_objects = g_list_prepend(context->all_objects, type);
+}
+
+void
+qof_cmd_explain (gpointer user_data)
+{
+	qof_data *context;
+
+	context = (qof_data*)user_data;
+	if(context->error) { return; }
+	fprintf(stdout, _("\nParameters of the %s database:\n\n"), context->database);
+	qof_class_param_foreach(context->database, qof_explain_cb, NULL);
+	fprintf(stdout, _("\nThank you for using %s\n\n"), PACKAGE);
+}
+
+void
+qof_mod_database (const char *database, qof_data *data)
+{
+	if(qof_class_is_registered(database)) {
+		data->database = g_strdup(database);
+	}
+}
+
+void
+qof_mod_timespec (const char *date_time, qof_data *data)
+{
+	gchar *temp;
+	int year, month, day;
+	gboolean takemonth, takeyear, scanned;
+	char *first_field, *second_field, *third_field;
+	static char *delims = ".,-+/\\() ";
+
+	takemonth = takeyear = scanned = FALSE;
+	day = month = year = 0;
+	second_field = "";
+	third_field = "";
+	temp = g_strdup(date_time);
+	qof_date_format_set(QOF_DATE_FORMAT_UTC);
+	scanned = qof_scan_date(temp, &day, &month, &year);
+	if(scanned == FALSE)
+	{
+		first_field = strtok (temp, delims);
+		if (first_field)
+		{
+			second_field = strtok (NULL, delims);
+			if (second_field)
+			{
+				third_field = strtok (NULL, delims);
+			}
+		}
+		if (third_field && second_field)
+		{
+			year = atoi(first_field);
+			month = atoi(second_field);
+			day = atoi(third_field);
+		} else if (second_field)
+		{
+			year = atoi(first_field);
+			month = atoi(second_field);
+			takemonth = TRUE;
+		} else if (first_field)
+		{
+			year = atoi(first_field);
+			takeyear = TRUE;
+		}
+	}
+	if(takemonth) { day = 1; }
+	if(takeyear)  { day = 1; month = 1; }
+	data->min_ts = gnc_dmy2timespec(day, month, year);
+	if(takemonth) { day = gnc_date_my_last_mday(month, year); }
+	if(takeyear)  {
+		month = 12;
+		day = gnc_date_my_last_mday(month, year);
+	}
+	data->max_ts = gnc_dmy2timespec_end(day, month, year);
+}
+
+void
+qof_mod_exclude (const char *exclude, qof_data *data)
+{
+	if(qof_class_is_registered(exclude)) {
+		data->exclude = g_strdup(exclude);
+	}
+}
+
+void
+qof_mod_sql (const char *sql_query, qof_data *data)
+{
+	if(!qof_check_sql(sql_query)) { return; }
+	data->sql_str = g_strdup(sql_query);
+}
+
+void
+qof_mod_sql_file (const char *sql_file, qof_data *data)
+{
+	FILE *filehandle;
+#ifndef HAVE_GETLINE
+	char lineptr[1024];
+#else
+	char *lineptr;
+#endif
+	char *buf;
+	size_t n;
+	QofQuery *q;
+	struct stat sbuf;
+
+	data->sql_file = g_strdup(sql_file);
+	n = 0;
+	q = NULL;
+	data->sql_list = NULL;
+	if (stat(sql_file, &sbuf) <0) {
+		fprintf(stderr,"%s: ERROR. Unable to open %s (%s)\n\n",
+			PACKAGE, sql_file, strerror(errno));
+		return;
+		}
+	filehandle = fopen(sql_file, "r");
+#ifndef HAVE_GETLINE
+	while (NULL != (fgets(lineptr, sizeof(lineptr), filehandle)))
+#else
+	lineptr = NULL;
+	while (0 < getline(&lineptr, &n, filehandle))
+#endif
+	{
+		if(!qof_check_sql(lineptr)) { continue; }
+		if(0 == safe_strcmp(lineptr, "\n")) { continue; }
+		buf = g_strdup(lineptr);
+		data->sql_list = g_list_append(data->sql_list, buf);
+	}
+
+	fclose(filehandle);
+}
+
+void
+qof_mod_write (const char *write_file, qof_data *data)
+{
+	data->write_file = g_strdup(write_file);
+}
+
+void extensions_init(void)
+{
+	backend_extensions = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+void qof_backend_extension_add(char *IDstring, gpointer data)
+{
+	g_hash_table_insert(backend_extensions, IDstring, data);
+}
+
+gpointer qof_backend_extension(const char* IDstring)
+{
+	gpointer func;
+
+	func = g_hash_table_lookup(backend_extensions, IDstring);
+	if(func) { return func; }
+	return NULL;
+}
+
+/** @} */
+/** @} */

Added: gnucash/branches/cashutil/cashutil/src/qof-main.h
===================================================================
--- gnucash/branches/cashutil/cashutil/src/qof-main.h	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/qof-main.h	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,459 @@
+/***************************************************************************
+ *            qof-main.h
+ *
+ *  Thu Jan 13 12:15:41 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/** @addtogroup QOFCLI Query Object Framework Command Line Interface and shell.
+
+The CLI uses a top level shell and two sub shells. The top level shell provides
+general interactivity with object types, entire books and SQL support.
+
+The select sub-shell identifies a single instance of an object. e.g. the print 
+command in the top shell uses the select subshell to locate the instance to be
+printed and the delete command, the instance to be deleted. These commands then
+return to the top shell.
+
+The edit sub-shell allows data to be set in a selected instance. The edit command
+uses a select sub-shell to identify the instance then changes to an edit sub-shell
+to handle setting the individual parameters of that instance. Before returning to the
+top shell, the edited data can be saved to the instance using 'commit' or the edit can
+be aborted using 'quit'. 
+
+The add command creates a new instance and passes that instance, already selected,
+to the edit sub-shell for data entry.
+
+\note CashUtil relies on installed versions of the QOF, libcashobjects and
+libgnc-backend-file libraries. If you change any source files for these libraries,
+ensure you run 'make install' rather than just 'make' or your changes will have no
+effect. There is no support for loading local or 'test' versions of the libraries.
+You can usually run cashutil against a freshly installed set of QOF libraries without
+recompiling cashutil, depending on the level of changes in QOF.
+
+@{
+*/
+/** @file qof-main.h
+  @brief Common functions for the QOF external framework
+  @author Copyright (c) 2005 Neil Williams <linux at codehelp.co.uk>
+*/
+
+#define _GNU_SOURCE
+#include "config.h"
+#ifndef _QOF_MAIN_H
+#define _QOF_MAIN_H
+#include <popt.h>
+#include "qof.h"
+#include "qofundo.h"
+
+#if defined(HAVE_GETTEXT)             /* HAVE_GETTEXT */
+
+#include <libintl.h>
+#include <locale.h>
+
+#undef _
+#undef Q_
+
+#ifdef DISABLE_GETTEXT_UNDERSCORE
+#define _(String) (String)
+#define Q_(String) gnc_qualifier_prefix_noop(String)
+#else                                 /* ENABLE_GETTEXT_UNDERSCORE */
+#define _(String) gettext(String)
+#define Q_(String) gnc_qualifier_prefix_gettext(String)
+#endif                                /* End ENABLE_GETTEXT_UNDERSCORE */
+
+#else                                 /* Not HAVE_GETTEXT */
+#if !defined(__USE_GNU_GETTEXT)
+
+#undef _
+#undef Q_
+#define _(String)       (String)
+#define Q_(String) gnc_qualifier_prefix_noop(String)
+#define gettext(String) (String)
+#define ngettext(msgid, msgid_plural, n) (((n)==1) ? \
+                                            (msgid) : (msgid_plural))
+
+#endif                                /* End not__USE_GNU_GETTEXT */
+#endif                                /* End Not HAVE_GETTEXT */
+
+#undef  N_
+#define N_(String) (String)
+
+/** gnc file backend library name */
+#define GNC_LIB_NAME "libgnc-backend-file.la"
+/** init_fcn for gnc file backend library. */
+#define GNC_LIB_INIT "gnc_provider_init"
+
+#define CU_MOD_ENGINE "cashutil-engine"
+
+gpointer qof_backend_extension(const char* IDstring);
+
+/** \name Control functions.
+@{
+*/
+/** \brief List of all parameters for this object of one type.
+
+Return a GSList of all parameters of this object that are a
+particular QOF type, QOF_TYPE_STRING, QOF_TYPE_BOOLEAN etc.
+
+The returned GSList should be freed by the caller.
+
+\note The return list is a singly linked list - GSList -
+\b not the doubly-linked list - GList - returned by
+::qof_class_get_referenceList.
+
+\param object_type  object->e_type for the relevant object.
+\param param_type  The type of parameter to match, QOF_TYPE_STRING etc.
+
+\return GSList of all matching parameters or NULL if none exist.
+*/
+GSList*
+qof_get_param_list(QofIdTypeConst object_type, QofType param_type);
+
+#define QOF_DATE_STRING_LENGTH  31 /**< Inherited from QSF */
+#define QOF_UTC_DATE_FORMAT     "%Y-%m-%dT%H:%M:%SZ" /**< Inherited from QSF */
+
+/**  \brief The SQL commands supported by QOF
+
+A regular expression used to exclude unsupported commands
+from SQL files. Anything that does \b not match the expression
+will be silently ignored by cashutil. This allows genuine
+SQL dump files to be parsed by cashutil without errors.
+
+ A QOF object is similar to a definition of a SQL table.\n
+ A QOF entity is similar to an instance of a SQL record.\n
+ A QOF parameter is similar to data in a SQL field.
+
+Certain SQL commands have no QOF equivalent and should
+always be ignored silently:
+ - ALTER (the object parameters cannot be changed at runtime)
+ - CREATE (new tables - new objects - cannot be created at runtime)
+ - DROP  (an object cannot be "de-registered" without re-compiling)
+ - FLUSH (QOF has no permissions system)
+ - GRANT
+ - KILL
+ - LOCK
+ - OPTIMIZE
+ - REVOKE
+ - USE (QOF only has one database, itself.)
+*/
+#define QOF_SQL_SUPPORTED  "^SELECT|INSERT"
+
+/** Indent and pad the shell output nicely.*/
+#define QOF_SHELL_FORMAT "    %-30s%s"
+
+/** \brief Common QOF CLI options
+
+ * These are definitions for popt support in the CLI. Every program's
+ * popt table should start with QOF_CLI_OPTIONS to insert
+ * the standard options into it. Also enables autohelp.
+ */
+#define QOF_CLI_OPTIONS POPT_AUTOHELP \
+	{"list", 'l', POPT_ARG_NONE, NULL, qof_op_list, \
+	 _("List all databases supported by the current QOF framework and exit."), \
+	 NULL}, \
+	{"explain", 0, POPT_ARG_NONE, NULL, qof_op_explain, \
+	 _("List the fields within the specified database and exit, requires -d."), \
+	 NULL}, \
+	{"date", 't', POPT_ARG_STRING, &date_time, qof_op_timespec, \
+	 _("Shorthand to only query objects that contain the specified date."), \
+	 "string"}, \
+	{"database", 'd', POPT_ARG_STRING, &database, qof_op_database, \
+	 _("Shorthand to only query objects within a specific supported database. "), \
+	 "string"}, \
+	{"exclude", 'e', POPT_ARG_STRING, &exclude, qof_op_exclude, \
+	 _("Shorthand to exclude a supported database from the query."), \
+	 "string"}, \
+	{"sql", 's', POPT_ARG_STRING, &sql_query, qof_op_sql, \
+	 _("Specify a SQL query on the command line."), "string"}, \
+	{"sql-file", 'f', POPT_ARG_STRING, &sql_file, qof_op_sql_file, \
+	 _("Specify one or more SQL queries contained in a file."), \
+	 "filename"}, \
+	{"write", 'w', POPT_ARG_STRING, &write_file, qof_op_write, \
+	 _("Write the results of any query to the file"), "filename"}, \
+	{"compress", 0, POPT_ARG_INT, &gz_level, qof_op_compress, \
+	 _("Compress output files, 0 for none, 9 for maximum"), "integer"}, \
+	{"debug", 0, POPT_ARG_NONE, NULL, qof_op_debug, \
+	 _("Print debugging information to a temporary file."), NULL}, \
+	{"shell", 0, POPT_ARG_NONE, NULL, qof_op_shell, \
+	 _("Enter the QOF interactive shell"), NULL}, \
+	{"version", 0, POPT_ARG_NONE, NULL, qof_op_vers, \
+	 _("Display version information"), NULL},
+
+/** \brief Output error messages from QOF
+
+QOF will set errors in the QofSession. The
+application determines how to output those
+messages and for CLI programw, this will be to
+stderr. Some of these error messages are not used in
+all CLI programs.
+*/
+void qof_show_error(QofSession *session, const char *file);
+
+/** \brief Handle the type of each subshell. */
+typedef enum {
+	NO_SHELL,
+	TOP_SHELL,     /**< the first, top level shell. */
+	EDIT_SHELL,    /**< Edit the selected instance */
+}qof_subshell;
+
+typedef enum {
+	NO_OP,
+	PRINT_MODE,
+	DELETE_MODE,
+	EDIT_MODE,
+}qof_cli_mode;
+
+/** \brief The QOF CLI context struct */
+typedef struct qofdata_s {
+	gchar *filename;            /**< Input filename containing QSF XML, if any.*/
+	gchar *write_file;          /**< Export filename, if any.*/
+	gchar *sql_file;            /**< SQL file, if any. */
+	gchar *sql_str;             /**< The current SQL, overwritten each iteration if using a file.*/
+	gchar *database;            /**< The database to include with -d. */
+	gchar *exclude;             /**< The database to exclude with -e. */
+	gchar *shortname;           /**< A shortname for this program if truncation to first 4 characters is not suitable. */
+	Timespec min_ts;            /**< Matches objects above minimum time_t value. */
+	Timespec max_ts;            /**< Matches objects below maximum time_t value. */
+	QofSession *input_session;  /**< The input session. */
+	QofSession *export_session; /**< The query results session, for STDOUT or -w. */
+	gboolean error;             /**< general error, abort. */
+	GList *all_objects;         /**< List of all supported databases. */
+	GList *sql_list;            /**< List of sql commands from a file. */
+	int argc;                   /**< Shell copy of argc */
+	char **argv;                /**< Shell copy of commands */
+	QofBook *book;              /**< the current book for the shell function. */
+	qof_subshell shell_type;    /**< the type of subshell, top or edit */
+	qof_cli_mode cli_mode;          /**< current operation mode. */
+	QofIdTypeConst inst_type;   /**< The current registered QofObject type. */
+	QofInstance *instance;      /**< The currently selected instance. */
+	gint counter;
+	GHashTable *select_table;
+	gint gz_level;
+}qof_data;
+
+/** \brief Register all QOF objects.
+
+If new objects are added, call the register func()
+here.
+
+qof_init must be called by any program wanting to
+use the QOF framework with GnuCash objects.
+
+\return A usable qof_data* context.
+*/
+void  qof_init (void);
+
+/** \brief initialise the QOF CLI context. 
+
+All QOF CLI programs must create a context.
+*/
+qof_data* qof_create(void);
+
+/** \brief Shutdown the QOF framework
+*/
+void qof_close(void);
+
+/* \brief Clear up the qof_data context */
+void qof_data_free(qof_data *data);
+
+/** \brief Check that the SQL command is supported.*/
+gboolean qof_check_sql(const char *sql);
+
+/** \enum qof_op_type
+
+main operator enum
+*/
+/** \enum qof_op_type::qof_op_noop
+
+undefined check value
+*/
+/**\enum qof_op_type::qof_op_input
+
+execute input command
+*/
+/** \enum qof_op_type::qof_op_list
+
+List supported databases command.
+*/
+
+/** \brief command line command options.*/
+typedef enum {
+	qof_op_noop = 0,
+	qof_op_input,
+	qof_op_list,
+	qof_op_shell,
+	qof_op_vers,
+	qof_op_database,
+	qof_op_timespec,
+	qof_op_exclude,
+	qof_op_sql,
+	qof_op_sql_file,
+	qof_op_write,
+	qof_op_explain,
+	qof_op_compress,
+	qof_op_debug
+}qof_op_type;
+
+/** \brief Build a list of all available objects */
+void qof_select_all(QofObject *obj, gpointer data);
+
+/** @} */
+/** @name Command handlers.
+@{
+*/
+
+/** \brief load the QOF interactive shell
+
+Where available, uses READLINE to store a history of
+previous shell commands.
+*/
+void qof_cmd_shell(qof_data *context);
+
+/** \brief List each parameter for the selected object. */
+void qof_cmd_explain (gpointer user_data);
+
+/** \brief List the supported databases.
+
+Uses a callback to ::qof_class_is_registered.
+*/
+void qof_cmd_list (void);
+
+/** \brief query a QSF XML file
+
+Query the QSF XML in <filename>.
+*/
+void qof_cmd_offline (qof_data *context);
+
+/** \brief Lists all databases supported by the current QOF framework.
+
+Prints the name and description for each object type
+registered with this instance of QOF. No options are used.
+*/
+void qof_cmd_list (void);
+/** @} */
+
+/** @name Command modulators.
+@{
+*/
+
+/** \brief Shorthand to only query objects within one specific supported database.
+
+Used to only query objects within the specified
+database. In a hotsync, all other supported databases are skipped
+and data is only read from the named database. Without a HotSync (using
+offline storage), only objects of this type are queried.
+*/
+void qof_mod_database (const char *database, qof_data *data);
+
+/** \brief Shorthand to only query objects that contain the specified date.
+
+Used to modify the QOF query to only query objects that contain
+at least one parameter containing a QOF_TYPE_DATE that
+matches the range specified. Dates need to be specified as YY-MM-DD.
+
+You can specify a UTC timestring, just as normally output by QSF,
+but the time will not be matched when using the shorthand option,
+only the year, month and day.
+
+For more precise time matches or to set a defined period that doesn't follow
+whole calendar months, (e.g. the UK financial year) use a SQL statement:
+
+Partial matches are allowed, so YY-MM matches
+any object where a date is within the specified month and year,
+YY matches any object where a date is within the specified year.
+
+The query range starts at midnight on the first day of the range
+and ends at 1 second to midnight on the last day of the range.
+*/
+void qof_mod_timespec (const char *date_time, qof_data *data);
+
+/** \brief Shorthand to exclude a supported database from the query.
+
+Excludes the (single) specified database from the query.
+During a hotsync, data in that database is not read from the Palm.
+When working offline, the objects of that type are not queried.
+*/
+void qof_mod_exclude (const char *exclude, qof_data *data);
+
+/** \brief Specify a SQL query on the command line.
+
+For SELECT, the returned list is a list of all of the instances of 'SomeObj' that
+match the query. The 'SORT' term is optional. The 'WHERE' term is optional; but
+if you don't include 'WHERE', you will get a list of all of the object instances.
+The Boolean operations 'AND' and 'OR' together with parenthesis can be used to construct
+arbitrarily nested predicates.
+
+For INSERT, the returned list is a list containing the newly created instance of 'SomeObj'.
+
+Date queries handle full date and time strings, using the format exported by the QSF
+backend. To query dates and times, convert user input into UTC time using the
+QOF_UTC_DATE_FORMAT string. e.g. set the UTC date format and call qof_print_time_buff
+with a time_t obtained via timespecToTime_t.
+
+If the param is a KVP frame, then we use a special markup to indicate frame values.
+The markup should look like /some/kvp/path:value. Thus, for example,\n
+SELECT * FROM SomeObj WHERE (param_a < '/some/kvp:10.0')\n
+will search for the object where param_a is a KVP frame, and this KVP frame contains
+a path '/some/kvp' and the value stored at that path is floating-point and that float
+value is less than 10.0.
+
+ at param sql_query Examples:
+
+"select * from gncAddress"
+
+*/
+void qof_mod_sql (const char *sql_query, qof_data *data);
+
+/** \brief Specify one or more SQL queries contained in a file.
+
+The rules for single SQL commands also apply with regard to the lack of explicit
+support for joins and the pending support for selecting only certain parameters
+from a certain object.
+
+See ::qof_mod_sql for information on the queries supported.
+
+\note Where possible, this function uses the safer GNU extension: getline().
+On Mac OSX and other platforms that do not provide getline, the call uses
+the less reliable fgets(). If the input file contains a NULL, fgets will
+get confused and the read may terminate early on such platforms.\n
+http://www.gnu.org/software/libc/manual/html_node/Line-Input.html
+
+*/
+void qof_mod_sql_file (const char *sql_file, qof_data *data);
+
+/** \brief Write the results of any query to the file
+
+Sets the \a filename of the file to be written out using 
+the QSF XML QofBackend.
+
+*/
+void qof_mod_write (const char *write_file, qof_data *data);
+
+void extensions_init(void);
+
+void qof_backend_extension_add(char *IDstring, gpointer data);
+
+gpointer qof_backend_extension(const char* IDstring);
+
+
+/** @} */
+/** @} */
+
+#endif				/* _QOF_MAIN_H */

Added: gnucash/branches/cashutil/cashutil/src/qofundo-p.h
===================================================================
--- gnucash/branches/cashutil/cashutil/src/qofundo-p.h	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/qofundo-p.h	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *            qofundo-p.h
+ *
+ *  Thu Aug 25 09:20:14 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+#ifndef _QOFUNDO_P_H
+#define _QOFUNDO_P_H
+
+#include "qof.h"
+#include "qofundo.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Undo is limited, not infinite. */
+#define MAX_UNDO_LENGTH     300
+
+/* Free the entire undo list for this book. */
+void qof_book_clear_undo(QofBook *book);
+
+/* reads the data from this parameter to allow undo
+
+To be able to undo and then redo an action, QOF needs to know the
+before and after states. Initially, the before state is the same as
+the file but after that point, the state of the entity needs to be
+tracked whenever it is opened for editing.
+*/
+qof_undo_entity* qof_prepare_undo (QofEntity *ent, QofParam *param);
+
+/* Add the changes to be undone to the event.
+
+Designed to be used with g_list_foreach, simply adds
+any number of undo_entity pointers (representing the 
+entity changes relating to this event) to the list 
+of changes for this event.
+*/
+void qof_undo_new_entry(gpointer event, gpointer changes);
+
+/* Add an undo event to the list.
+
+type holds the type of event that has just occurred.
+
+If the event follows a successful qof_commit_edit, then the
+cached undo_entity changes are placed into this undo_event.
+*/
+qof_undo_operation* qof_undo_new_operation(char* label);
+
+/* dummy routines for testing only */
+void undo_edit_record(QofInstance *inst, QofParam *param);
+void undo_edit_commit(QofInstance *inst, QofParam *param);
+void undo_create_record(QofInstance *inst);
+void undo_delete_record(QofInstance *inst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _QOFUNDO_P_H */

Added: gnucash/branches/cashutil/cashutil/src/qofundo.c
===================================================================
--- gnucash/branches/cashutil/cashutil/src/qofundo.c	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/qofundo.c	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,473 @@
+/***************************************************************************
+ *            qofundo.c
+ *
+ *  Thu Aug 25 09:19:17 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <locale.h>
+#include <errno.h>
+#include "qofundo-p.h"
+#include "qofundo.h"
+/* for gettext support - change this later. */
+#include "qof-main.h"
+
+/* the undo list itself 
+ definition will later be placed within the QofBook opaque struct
+ GList of qof_undo_event*
+ */
+static GList *book_undo;
+/* list of undo_entity, pending commit */
+static GList *undo_cache;
+static gchar* undo_label;
+/* the current position within the undo list within this book */
+static gint index_position; 
+static gboolean undo_operation_open = FALSE;
+
+typedef enum
+{
+	UNDO_NOOP = 0,
+	UNDO_CREATE,
+	UNDO_DELETE,
+	UNDO_MODIFY
+}undo_action;
+
+struct qof_undo_entity_t
+{
+	QofParam *param;  /* static anyway so only store a pointer */
+	const GUID *guid; /* enable re-creation of this entity */
+	QofIdType type;   /* ditto param, static. */
+	char *value;      /* cached string? */
+	char *path;       /* for KVP */
+	QofIdType choice; /* For QOF_TYPE_CHOICE */
+	undo_action how;  /* how to act on the undo */
+};
+
+struct qof_undo_operation_t
+{
+	const char* label;
+	Timespec ts;
+	GList *entity_list; /* GList of qof_undo_entity* */
+};
+
+void
+qof_entity_set_param(QofEntity *ent, QofParam *param, char *value)
+{
+	gchar *tail;
+	gnc_numeric cli_numeric;
+	gboolean    cli_bool;
+	gint32      cli_i32;
+	gint64      cli_i64;
+	Timespec    cli_date;
+	GUID        *cm_guid;
+	struct tm   cli_time;
+	time_t      cli_time_t;
+	const char  *fmt;
+	void (*string_setter)   (QofEntity*, char*);
+	void (*date_setter)     (QofEntity*, Timespec);
+	void (*i32_setter)      (QofEntity*, gint32);
+	void (*i64_setter)      (QofEntity*, gint64);
+	void (*numeric_setter)  (QofEntity*, gnc_numeric);
+	void (*boolean_setter)  (QofEntity*, gboolean);
+	void (*guid_setter)     (QofEntity*, const GUID*);
+
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_STRING)) {
+		string_setter = (void(*)(QofEntity*, char*))param->param_setfcn;
+		if(string_setter) { param->param_setfcn(ent, value); }
+	}
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_GUID)) {
+		cm_guid = g_new(GUID, 1);
+		if(TRUE == string_to_guid(value, cm_guid))
+		{
+			guid_setter = (void(*)(QofEntity*, const GUID*))param->param_setfcn;
+			if(guid_setter != NULL) { guid_setter(ent, cm_guid); }
+		}
+	}
+	if((0 == safe_strcmp(param->param_type, QOF_TYPE_NUMERIC)) || 
+			(safe_strcmp(param->param_type, QOF_TYPE_DEBCRED) == 0)) {
+		numeric_setter = (void(*)(QofEntity*, gnc_numeric))param->param_setfcn;
+		string_to_gnc_numeric(value, &cli_numeric);
+		if(numeric_setter != NULL) { numeric_setter(ent, cli_numeric); }
+	}
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN)) {
+		cli_bool = FALSE;
+		if(qof_util_bool_to_int(value) == 1) { cli_bool = TRUE; }
+		boolean_setter = (void(*)(QofEntity*, gboolean))param->param_setfcn;
+		if(boolean_setter != NULL) { boolean_setter(ent, cli_bool); }
+	}
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT32)) {
+		errno = 0;
+		cli_i32 = (gint32)strtol (value, &tail, 0);
+		if(errno == 0) {
+			i32_setter = (void(*)(QofEntity*, gint32))param->param_setfcn;
+			if(i32_setter != NULL) { i32_setter(ent, cli_i32); }
+		}
+		 else { 
+		 	fmt = _("%s: Cannot convert %s into a number: an overflow has been detected.");
+			fprintf (stderr, fmt, PACKAGE, value);
+		}
+	}
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT64)) {
+		errno = 0;
+		cli_i64 = (gint64)strtol (value, &tail, 0);
+		if(errno == 0) {
+			i64_setter = (void(*)(QofEntity*, gint64))param->param_setfcn;
+			if(i64_setter != NULL) { i64_setter(ent, cli_i64); }
+		}
+		 else { 
+		 	fmt = _("%s: Cannot convert %s into a number: an overflow has been detected.");
+			fprintf (stderr, fmt, PACKAGE, value);
+		}
+	}
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_DATE)) {
+		date_setter = (void(*)(QofEntity*, Timespec))param->param_setfcn;
+		strptime(value, QOF_UTC_DATE_FORMAT, &cli_time);
+		cli_time_t = mktime(&cli_time);
+		timespecFromTime_t(&cli_date, cli_time_t);
+		if(date_setter != NULL) { date_setter(ent, cli_date); }
+	}
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_CHAR)) {
+		param->param_setfcn(ent, value);
+	}
+}
+
+static void
+undo_from_kvp_helper(const char *path, KvpValue *content, gpointer data)
+{
+	qof_undo_entity *undo_entity;
+
+	undo_entity = (qof_undo_entity*)data;
+	undo_entity->path = g_strdup(path);
+	undo_entity->value = kvp_value_to_bare_string(content);
+}
+
+qof_undo_entity* 
+qof_prepare_undo (QofEntity *ent, QofParam *param)
+{
+	qof_undo_entity *undo_entity;
+	KvpFrame *undo_frame;
+
+	undo_frame = NULL;
+	undo_entity = g_new0(qof_undo_entity, 1);
+	undo_entity->guid = qof_entity_get_guid(ent);
+	undo_entity->param = param;
+	undo_entity->how = UNDO_MODIFY;
+	undo_entity->type = ent->e_type;
+	undo_entity->value = qof_book_merge_param_as_string(param, ent);
+	if(0 == (safe_strcmp(param->param_type, QOF_TYPE_KVP)))
+	{
+		undo_frame = kvp_frame_copy(param->param_getfcn(ent,param));
+		kvp_frame_for_each_slot(undo_frame, undo_from_kvp_helper, undo_entity);
+	}
+	/* need to do COLLECT and CHOICE */
+	return undo_entity;
+}
+
+static void
+qof_reinstate_entity (qof_undo_entity *undo_entity, QofBook *book)
+{
+	QofParam *undo_param;
+	QofCollection *coll;
+	QofEntity *ent;
+
+	undo_param = undo_entity->param;
+	if(!undo_param) { return; }
+	g_message("reinstate:%s", undo_entity->type);
+	coll = qof_book_get_collection(book, undo_entity->type);
+	if(!coll) { return; }
+	ent = qof_collection_lookup_entity(coll, undo_entity->guid);
+	if(!ent) { return; }
+	g_message("undoing %s %s", undo_param->param_name, undo_entity->value);
+	qof_entity_set_param(ent, undo_param, undo_entity->value);
+}
+
+static void
+qof_recreate_entity (qof_undo_entity *undo_entity, QofBook *book)
+{
+	QofEntity *ent;
+	const GUID *guid;
+	QofIdType type;
+	QofInstance *inst;
+
+	guid = undo_entity->guid;
+	type = undo_entity->type;
+	g_return_if_fail(guid || type);
+	inst = (QofInstance*)qof_object_new_instance(type, book);
+	ent = (QofEntity*)inst;
+	qof_entity_set_guid(ent, guid);
+}
+
+static void
+qof_dump_entity (qof_undo_entity *undo_entity, QofBook *book)
+{
+	QofCollection *coll;
+	QofEntity *ent;
+	const GUID *guid;
+	QofIdType type;
+
+	type = undo_entity->type;
+	guid = undo_entity->guid;
+	g_return_if_fail(type || book);
+	coll = qof_book_get_collection(book, type);
+	ent = qof_collection_lookup_entity(coll, guid);
+	qof_entity_release(ent);
+}
+
+void 
+qof_book_undo(QofBook *book)
+{
+	qof_undo_operation *undo_operation;
+	qof_undo_entity *undo_entity;
+	GList *ent_list;
+	gint length;
+
+	length = g_list_length(book_undo);
+	if (index_position >1 ) { index_position--; }
+	else { index_position = 0; }
+	undo_operation = (qof_undo_operation*)(g_list_nth(book_undo, index_position))->data;
+	g_return_if_fail(undo_operation);
+	ent_list = undo_operation->entity_list;
+	while (ent_list != NULL)
+	{
+		undo_entity = (qof_undo_entity*)ent_list->data;
+		if(!undo_entity) { break; }
+		switch(undo_entity->how) {
+			case UNDO_MODIFY : { qof_reinstate_entity(undo_entity, book); break; }
+			case UNDO_CREATE : { qof_recreate_entity(undo_entity, book);  break; }
+			case UNDO_DELETE : { qof_dump_entity (undo_entity, book); break; }
+			case UNDO_NOOP : { break; }
+		}
+		ent_list = g_list_next(ent_list);
+	}
+}
+
+void 
+qof_book_redo(QofBook *book)
+{
+	qof_undo_operation *undo_operation;
+	qof_undo_entity *undo_entity;
+	GList *ent_list;
+	gint length;
+
+	undo_operation = (qof_undo_operation*)(g_list_nth(book_undo, index_position))->data;
+	if(!undo_operation) { return; }
+	ent_list = undo_operation->entity_list;
+	while (ent_list != NULL)
+	{
+		undo_entity = (qof_undo_entity*)ent_list->data;
+		if(!undo_entity) { break; }
+		switch(undo_entity->how) {
+			case UNDO_MODIFY : { qof_reinstate_entity(undo_entity, book); break; }
+			case UNDO_CREATE : { qof_dump_entity (undo_entity, book); break; }
+			case UNDO_DELETE : { qof_recreate_entity(undo_entity, book); break; }
+			case UNDO_NOOP : { break; }
+		}
+		ent_list = g_list_next(ent_list);
+	}
+	length = g_list_length(book_undo);
+	if (index_position < length ) { index_position++; }
+	else { index_position = length; }
+}
+
+void 
+qof_book_clear_undo(QofBook *book)
+{
+	qof_undo_operation *operation;
+
+	if(!book || !book_undo) { return; }
+	while (book_undo != NULL)
+	{
+		operation = (qof_undo_operation*)book_undo->data;
+		g_list_free(operation->entity_list);
+		book_undo = g_list_next(book_undo);
+	}
+	index_position = 0;
+	g_free(undo_label);
+	book_undo = NULL;
+	undo_cache = NULL;
+}
+
+gboolean 
+qof_book_can_undo(QofBook *book)
+{
+	gint length;
+	
+	length = g_list_length(book_undo);
+	if ((index_position == 0) || (length == 0)) { return FALSE; }
+	return TRUE;
+}
+
+gboolean 
+qof_book_can_redo(QofBook *book)
+{
+	gint length;
+
+	length = g_list_length(book_undo);
+	if ((index_position == length) || (length == 0)) { return FALSE; }
+	return TRUE;
+}
+
+qof_undo_operation* 
+qof_undo_new_operation(char* label)
+{
+	qof_undo_operation *undo_operation;
+	time_t t;
+	Timespec ts;
+
+	undo_operation = NULL;
+	t = time (NULL);
+	timespecFromTime_t(&ts, t);
+	undo_operation = g_new0(qof_undo_operation, 1);
+	undo_operation->label = label;
+	undo_operation->ts =  ts;
+	undo_operation->entity_list = NULL;
+	g_list_foreach(undo_cache, qof_undo_new_entry, undo_operation);
+	undo_cache = NULL;
+	return undo_operation;
+}
+
+void
+qof_undo_new_entry(gpointer cache, gpointer operation)
+{
+	qof_undo_operation *undo_operation;
+ 	qof_undo_entity *undo_entity;
+
+	g_return_if_fail(operation || cache);
+	undo_operation = (qof_undo_operation*)operation;
+	undo_entity = (qof_undo_entity*)cache;
+	g_return_if_fail(undo_operation || undo_entity);
+	undo_operation->entity_list = g_list_prepend(undo_operation->entity_list, undo_entity);
+}
+
+void
+undo_create_record (QofInstance *instance)
+{
+	qof_undo_entity *undo_entity;
+
+	if(!instance) { return; }
+	undo_entity = g_new0(qof_undo_entity, 1);
+	// to undo a create, use a delete.
+	undo_entity->how = UNDO_DELETE;
+	undo_entity->guid = qof_instance_get_guid(instance);
+	undo_entity->type = instance->entity.e_type;
+	undo_cache = g_list_prepend(undo_cache, undo_entity);
+}
+
+static void
+undo_get_entity (QofParam *param, gpointer data)
+{
+	QofInstance *instance;
+	qof_undo_entity *undo_entity;
+
+	instance = (QofInstance*)data;
+	g_return_if_fail(instance || param);
+	undo_entity = qof_prepare_undo(&instance->entity, param);
+	undo_cache = g_list_prepend(undo_cache, undo_entity);
+}
+
+void
+undo_delete_record (QofInstance *instance)
+{
+	qof_undo_entity *undo_entity;
+	QofIdType type;
+
+	if(!instance) { return; }
+	// now need to store each parameter in a second entity, MODIFY.
+	type = instance->entity.e_type;
+	qof_class_param_foreach(type, undo_get_entity, instance);
+	undo_entity = g_new0(qof_undo_entity, 1);
+	// to undo a delete, use a create.
+	undo_entity->how = UNDO_CREATE;
+	undo_entity->guid = qof_instance_get_guid(instance);
+	undo_entity->type = type;
+	undo_cache = g_list_prepend(undo_cache, undo_entity);
+}
+
+void 
+undo_edit_record (QofInstance *instance, QofParam *param)
+{
+	qof_undo_entity *undo_entity;
+
+	if(!instance || !param) { return; }
+	// handle if record is called without a commit.
+	undo_entity = qof_prepare_undo(&instance->entity, param);
+	// get book from the instance.
+	undo_cache = g_list_prepend(undo_cache, undo_entity);
+	// set the initial state that undo will reinstate.
+	if(index_position == 0)
+	{
+		book_undo = g_list_prepend(book_undo, qof_undo_new_operation("initial"));
+		index_position++;
+	}
+}
+
+void 
+undo_edit_commit (QofInstance *instance, QofParam *param)
+{
+	qof_undo_entity *undo_entity;
+
+	if(!instance || !param) { return; }
+	undo_entity = qof_prepare_undo(&instance->entity, param);
+	undo_cache = g_list_prepend(undo_cache, undo_entity);
+	// get book from the instance.
+}
+
+void 
+qof_book_start_operation(QofBook *book, char *label)
+{
+	if(undo_operation_open && undo_cache) { 
+		g_list_free(undo_cache);
+		undo_operation_open = FALSE;
+		if(undo_label) { g_free(undo_label); }
+	}
+	/** \todo handle the book parameter. */
+	undo_label = g_strdup(label);
+	undo_cache = NULL;
+	undo_operation_open = TRUE;
+}
+
+void
+qof_book_end_operation(QofBook *book)
+{
+	book_undo = g_list_prepend(book_undo, qof_undo_new_operation(undo_label));
+	index_position++;
+//	g_list_free(undo_cache);
+	undo_operation_open = FALSE;
+}
+
+Timespec 
+qof_book_undo_first_modified(QofBook *book)
+{
+	qof_undo_operation *undo_operation;
+
+	undo_operation = (qof_undo_operation*)g_list_last(book_undo);
+	return undo_operation->ts;
+}
+
+gint
+qof_book_undo_count(QofBook *book)
+{
+	return g_list_length(book_undo);
+}
+
+/* ====================== END OF FILE ======================== */

Added: gnucash/branches/cashutil/cashutil/src/qofundo.h
===================================================================
--- gnucash/branches/cashutil/cashutil/src/qofundo.h	2005-10-31 23:34:53 UTC (rev 11621)
+++ gnucash/branches/cashutil/cashutil/src/qofundo.h	2005-10-31 23:42:19 UTC (rev 11622)
@@ -0,0 +1,154 @@
+/***************************************************************************
+ *            qofundo.h
+ *
+ *  Thu Aug 25 09:19:25 2005
+ *  Copyright  2005  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+ /** @addtogroup UNDO Undo: track and undo or redo entity changes
+ @ingroup QOFCLI
+
+\b EXPERIMENTAL!
+
+ QOF Undo operates within a QofBook. In order to undo the changes to
+ the entity, the initial state of each parameter is cached when an operation
+ begins. If the entity changes are not successful, the lack of a
+ ::qof_book_end_operation call before a ::qof_book_start_operation will cause
+ the cached data to be freed. If the entity is changed successfully,
+ ::qof_book_end_operation will create the undo data using the operation
+ label and each of the entity changes that were successful.
+ 
+ Undo data consists of a list of operations that have changed data in this book and a
+ list of entity changes for each of those operations. Each operation can relate to
+ more than one entity change and cover more than one entity but must only relate to
+ one book.
+ 
+-# Only QOF parameter changes can be undone or redone. Data from structs that
+ are not QOF objects or which have no QofParam to get <b>and set</b> the data
+ will not be available to the undo process.
+-# Undo relates to 'user interface operations', not engine events. This is
+because an operation (like an import or voiding a transaction) can involve
+multiple, possibly conflicting, engine events - e.g. removing an entity from one
+reference and inserting it as another. Therefore, the UI developer alone can
+decide where an operation begins and ends. All changes between the two will be
+undone or redone in one call to qof_book_undo.
+-# Undo operations \b cannot be nested. Be careful where you start and end an undo operation,
+if your application calls qof_book_start_operation() before calling qof_book_end_operation(),
+the undo cache will be freed and QOF Undo will not notify you of this. The API is designed to
+silently handle user aborts during a user operation. As undo data is cached as soon as editing
+begins, if the edit is never completed the cache must be cleared before the next operation.
+i.e. if the user starts to edit an entity but then cancels the operation, there are no changes
+to undo. It follows that any one book can only be the subject of one operation at a time.
+
+\todo Change operations to return a handler that can distinguish each operation then
+make it: QofOperation qof_book_start_operation(QofBook* book, char *label) and
+void qof_book_end_operation(QofOperation oper);
+
+@{
+ */
+/** @file  qofundo.h
+    @brief Experimental QOF undo handling
+	@author Copyright (c) 2005  Neil Williams <linux at codehelp.co.uk>
+*/
+#ifndef _QOFUNDO_H
+#define _QOFUNDO_H
+
+/** @brief The parameter changes, >=1 per affected entity 
+
+One per parameter change - the bottom level of any undo. A single click of 
+Undo could use the data from one or many parameter changes - as determined by 
+the event. Each parameter change can be for any entity of any registered type 
+in the book and parameter changes can be repeated for the multiple changes to 
+different parameters of the same entity. The combination of param, guid and 
+type will be unique per event. (i.e. no event will ever set the same 
+parameter of the same entity twice (with or without different data) in one 
+undo operation.)
+*/
+typedef struct qof_undo_entity_t qof_undo_entity;
+
+/** @brief The affected entities, >=1 per operation 
+
+The top level of any undo. Contains a GList that keeps the type of operation and 
+the GList of qof_undo_entity* instances relating to that operation. Some form of 
+index / counter probably too in order to speed up freeing unwanted operations and 
+undo data upon resumption of editing and in controlling the total number of 
+operations that can be undone.
+
+Each qof_undo_event.entity_list can contain data about >1 type of entity.
+*/
+typedef struct qof_undo_operation_t qof_undo_operation;
+
+/** \brief Set a value in this parameter of the entity.
+
+Setting an arbitrary parameter in an entity can involve
+repetitive string comparisons and setter function prototypes.
+This function accepts a QofParam (which determines the type of 
+value) and a string representing the value. e.g. for a boolean,
+pass "TRUE", for a GUID pass the result of guid_to_string_buff.
+
+It's a convenience wrapper for routines that take values from 
+files (e.g. XML) and need to convert into real data in the entity.
+
+ at param ent An initialized QofEntity from an accessible QofBook.
+ at param param The QofParam that needs to be set, including the 
+get_fcn, set_fcn, param_type and param_name.
+ at param value A string representation of the required value - original
+type as specified in param->param_type.
+
+*/
+void qof_entity_set_param(QofEntity *ent, QofParam *param, char *value);
+
+/** @brief Set parameter values from before the previous event. */
+void qof_book_undo(QofBook *book);
+
+/** @brief Set parameter values from after the previous event. */
+void qof_book_redo(QofBook *book);
+
+/** @brief event handler for undo widget 
+
+ @return FALSE if length == 0 or index_position == 0,
+ otherwise TRUE.
+*/
+gboolean qof_book_can_undo(QofBook *book);
+
+/** @brief event handler for redo widget
+
+ at return FALSE if index_position == 0 or index_position == length
+otherwise TRUE.
+*/
+gboolean qof_book_can_redo(QofBook *book);
+
+/** \brief Start recording operation.
+
+*/
+void qof_book_start_operation(QofBook *book, char *label);
+
+/** \brief End recording the current operation. */
+void qof_book_end_operation(QofBook *book);
+
+/** \brief HIG compliance aid to report time of first change. */
+Timespec qof_book_undo_first_modified(QofBook *book);
+
+/** \brief Number of undo operations available. */
+gint qof_book_undo_count(QofBook *book);
+
+#endif /* _QOFUNDO_H */
+
+/** @} */



More information about the gnucash-changes mailing list