mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Rob Browning's patch with price db & miscellany.
* first iteration of pricedb: we should preserve quotes from old binfiles now (rather than throwing it away during the conversion), and we can read/write the pricedb as XML. * added configure --enable-error-on-warning -- developers, please use this. * add fancier TAGS handling -- we now track file additions/deletions dynamically. * add g_hash_table_key_value_pairs: returns a GSList of all the key value pairs in a given hash table so you can manipulate them. add g_hash_table_kv_pair_free_gfunc: g_slist_foreach helper for deleting key value hash pairs when you're finished with the results from g_hash_table_key_value_pairs. You'll still need to call g_slist_free as well to delete the spine of the list. * continue migration to using backend for all IO and switching from top-level Group to top level GNCBook. * switch from const gnc_commodity to gnc_commodity in many places, after consultation with Bill. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3684 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
ce532a2a86
commit
e30a8bc509
238
ChangeLog
238
ChangeLog
@ -1,3 +1,241 @@
|
|||||||
|
2001-02-24 Rob Browning <rlb@cs.utexas.edu>
|
||||||
|
|
||||||
|
* configure.in (AC_ARG_ENABLE): add --enable-error-on-warning.
|
||||||
|
Enables -Werror and whatever else is needed for super-strict
|
||||||
|
checks. I'm compiling with this now, and I urge everyone else to
|
||||||
|
as well. We do have a few aggravating things we still ignore,
|
||||||
|
like unused variables, but as of today, the whole codebase
|
||||||
|
compiles successfully with this turned on.
|
||||||
|
(AC_CHECK_PROG): Add a check for etags.
|
||||||
|
(AC_ARG_WITH): --with-perl-includes - don't die if CORE not found.
|
||||||
|
I install modules in a local directory and use --perl-includes to
|
||||||
|
enable gnucash to find Finance::Quote at runtime, but there won't
|
||||||
|
be a CORE file.
|
||||||
|
(AC_CHECK_LIB): popt - note required Debian -dev package.
|
||||||
|
|
||||||
|
* macros/autogen.sh (conf_flags): omit --enable-compile-warnings.
|
||||||
|
This was adding flags that overrode our configure.in settings;
|
||||||
|
specifically, this kept --enable-error-on-warning from working.
|
||||||
|
|
||||||
|
* Makefile.am (noinst_DATA): add optional TAGS target.
|
||||||
|
(DISTCLEANFILES): add tags cleanup bits.
|
||||||
|
(TAGS): Add fancy TAGS handling. TAGS file is only built if you
|
||||||
|
have etags available, and now it takes into account
|
||||||
|
additions/deletions of files in addition to modifications.
|
||||||
|
|
||||||
|
* src/engine/gnc-engine-util.c
|
||||||
|
(g_hash_table_key_value_pairs): new - returns a GSList of all the
|
||||||
|
key value pairs in a given hash table so you can manipulate them.
|
||||||
|
(g_hash_table_kv_pair_free_gfunc): new - g_slist_foreach helper
|
||||||
|
for deleting key value hash pairs when you're finished with the
|
||||||
|
results from g_hash_table_key_value_pairs. You'll still need to
|
||||||
|
call g_slist_free as well to delete the spine of the list.
|
||||||
|
|
||||||
|
* src/engine/NetIO.c: comment out various bits of the code that's
|
||||||
|
incompatible with the recent gnc-book changes. Linas said he'd
|
||||||
|
fix it later.
|
||||||
|
|
||||||
|
* src/scm/price-quotes.scm: new file - not used yet.
|
||||||
|
|
||||||
|
* src/scm/price-quotes.scm: new file - launch a sub-process you
|
||||||
|
can talk to bidirectionally from scheme read/write.
|
||||||
|
|
||||||
|
* src/scm/command-line.scm: (disabled) support for getting prices.
|
||||||
|
|
||||||
|
* src/scm/command-line.scm
|
||||||
|
(gnc:group-map-accounts): implementation simplified dramatically,
|
||||||
|
probably should be dropped entirely, in favor of just calling (map
|
||||||
|
thunk (gnc:group-get-subaccounts group)) -- which is what's in the
|
||||||
|
replacement code.
|
||||||
|
|
||||||
|
* src/quotes/price-quote-helper.in: new file.
|
||||||
|
|
||||||
|
* src/Backend.h: Delete ERR_FILEIO_MISC (use ERR_BACKEND_MISC).
|
||||||
|
Replace ERR_FILEIO_ALLOC with ERR_BACKEND_ALLOC.
|
||||||
|
|
||||||
|
* src/engine/gnc-book.c: add support for GNCPriceDB element. Move
|
||||||
|
still relevant FileIO bits here. Add support for gnc-book
|
||||||
|
clean/dirty checking instead of just Group checking.
|
||||||
|
|
||||||
|
* src/engine/gnc-book.h: fixes for gnc-book marking, private
|
||||||
|
header, and addition of pricedb.
|
||||||
|
|
||||||
|
* src/engine/gnc-book-p.h: new file - private book functions.
|
||||||
|
|
||||||
|
* src/engine/Ledger-xml-parser-v1.c
|
||||||
|
(ledger_data_after_child_handler): new function to handle grabbing
|
||||||
|
the pricedb when we hit it.
|
||||||
|
|
||||||
|
* src/FileDialog.c: Various fixes to replace uses of the top level
|
||||||
|
AccountGroup with the parent GNCBook. Also add support for
|
||||||
|
reading/writing the GNCPriceDB. This file still needs a lot of
|
||||||
|
work. Much of it should become a proper file IO Backend.
|
||||||
|
|
||||||
|
* src/guile/gnc.gwp: Add <gnc:Book*>. Add gnc:get-current-book.
|
||||||
|
Add gnc:book-get-group. Add gnc:account-get-price-src.
|
||||||
|
|
||||||
|
* src/gnome/druid-commodity.c (finish_helper): add support for
|
||||||
|
GNCPriceDB.
|
||||||
|
|
||||||
|
* src/engine/sixtp-writers.h: add support for GNCPriceDB.
|
||||||
|
|
||||||
|
* src/engine/sixtp-to-dom-parser.c
|
||||||
|
(sixtp_dom_parser_new): change signature to add fail and result
|
||||||
|
cleanup functions. These can be NULL, in which case they're
|
||||||
|
ignored. Also modify overall scheme to clean internal garbage up
|
||||||
|
properly in case of failure.
|
||||||
|
|
||||||
|
* src/engine/sixtp-parsers.h
|
||||||
|
(sixtp_dom_parser_new): change signature.
|
||||||
|
|
||||||
|
* src/engine/sixtp-dom-parsers.c (dom_tree_to_text): minor fixes.
|
||||||
|
|
||||||
|
* src/engine/sixtp-dom-generators.c
|
||||||
|
(text_to_dom_tree): new function.
|
||||||
|
|
||||||
|
* src/engine/sixtp-dom-generators.h
|
||||||
|
(text_to_dom_tree): new prototype.
|
||||||
|
|
||||||
|
* src/engine/io-gncxml-w.c: add support for pricedb and using
|
||||||
|
GNCBook at top level rather than Group.
|
||||||
|
|
||||||
|
* src/engine/io-gncxml.h: support migration from top level Group
|
||||||
|
to top level GNCBook.
|
||||||
|
|
||||||
|
* src/engine/io-gncbin-r.c: add support for detecting legacy
|
||||||
|
prices and migrating them to the new pricedb. Replace top level
|
||||||
|
uses of a Group with a GNCBook.
|
||||||
|
|
||||||
|
* src/engine/io-gncbin.h: support pricedb and gnc-book changes.
|
||||||
|
|
||||||
|
* src/engine/io-gncxml-p.h: new file - private header.
|
||||||
|
|
||||||
|
* src/engine/io-gncxml-r.c: move bits to private header. Make
|
||||||
|
changes to support move from top level to Group to top level
|
||||||
|
GNCBook.
|
||||||
|
|
||||||
|
* src/gnome/druid-qif-import.c: -Werror fixes.
|
||||||
|
|
||||||
|
* src/engine/gnc-pricedb.h: new file.
|
||||||
|
|
||||||
|
* src/engine/gnc-pricedb-p.h: new file.
|
||||||
|
|
||||||
|
* src/engine/gnc-pricedb.c: new file.
|
||||||
|
|
||||||
|
* src/engine/gnc-pricedb-xml-v1.c: new file.
|
||||||
|
|
||||||
|
* src/engine/gnc-engine-util.h: accomodate new functions.
|
||||||
|
|
||||||
|
* src/engine/gnc-commodity-xml-v2.c
|
||||||
|
(gnc_commodity_sixtp_parser_create): fix sixtp_dom_parser_new call.
|
||||||
|
|
||||||
|
* src/engine/gnc-account-xml-v2.c
|
||||||
|
(gnc_account_end_handler): -Werror fixes.
|
||||||
|
(gnc_account_sixtp_parser_create): fix sixtp_dom_parser_new call.
|
||||||
|
|
||||||
|
* src/engine/date.h (timespec_equal): add back.
|
||||||
|
|
||||||
|
* src/engine/date.c (timespec_equal): add back.
|
||||||
|
|
||||||
|
* src/engine/Commodity-xml-parser-v1.c
|
||||||
|
(xml_add_commodity_ref): cleanup.
|
||||||
|
|
||||||
|
* src/FileIO.h: deleted.
|
||||||
|
|
||||||
|
* src/FileIOP.h: deleted.
|
||||||
|
|
||||||
|
* src/FileIO.c: deleted.
|
||||||
|
|
||||||
|
* src/test/test-dom-parser1.c: fixes for new sixtp_dom_parser_new.
|
||||||
|
|
||||||
|
* src/test/test-xml-account.c: fixes for new sixtp_dom_parser_new.
|
||||||
|
|
||||||
|
* src/test/test-xml-commodity.c: fixes for new sixtp_dom_parser_new.
|
||||||
|
|
||||||
|
* src/guile/option-util.h: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/guile/option-util.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/guile/guile-util.h: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/guile/guile-util.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/guile/global-options.h: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/guile/global-options.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/window-register.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/window-main.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/gnc-currency-edit.h: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/gnc-currency-edit.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/gnc-commodity-edit.h: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/gnc-commodity-edit.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/druid-commodity.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/dialog-account.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/dialog-options.c: remove consts from gnc_commoditities
|
||||||
|
(after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/dialog-commodity.h: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnome/dialog-commodity.c: remove consts from
|
||||||
|
gnc_commoditities (after consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnc-ui-util.h: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/gnc-ui-util.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/engine/Transaction.h: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/engine/Transaction.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/engine/Scrub.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/AccountP.h: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/Account.h: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/Account.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/SplitLedger.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/EuroUtils.h: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
|
* src/EuroUtils.c: remove consts from gnc_commoditities (after
|
||||||
|
consultation with Bill).
|
||||||
|
|
||||||
2001-02-23 Bill Gribble <grib@billgribble.com>
|
2001-02-23 Bill Gribble <grib@billgribble.com>
|
||||||
|
|
||||||
* src/scm/qif-import/qif-dialog-utils.scm: Be more flexible
|
* src/scm/qif-import/qif-dialog-utils.scm: Be more flexible
|
||||||
|
29
Makefile.am
29
Makefile.am
@ -3,7 +3,7 @@ SUBDIRS = macros debian doc-tools doc intl lib src po rpm accounts
|
|||||||
|
|
||||||
docdir = ${GNC_DOC_INSTALL_DIR}
|
docdir = ${GNC_DOC_INSTALL_DIR}
|
||||||
|
|
||||||
noinst_DATA = make-gnucash-patch
|
noinst_DATA = make-gnucash-patch @GNC_TAGS_FILE@
|
||||||
|
|
||||||
doc_DATA = \
|
doc_DATA = \
|
||||||
AUTHORS \
|
AUTHORS \
|
||||||
@ -43,7 +43,8 @@ make-gnucash-patch: make-gnucash-patch.in
|
|||||||
chmod +x $@.tmp
|
chmod +x $@.tmp
|
||||||
mv $@.tmp $@
|
mv $@.tmp $@
|
||||||
|
|
||||||
DISTCLEANFILES += cscope.files cscope.out etags.files make-gnucash-patch
|
DISTCLEANFILES += \
|
||||||
|
TAGS.stamp cscope.files cscope.out etags.files make-gnucash-patch
|
||||||
|
|
||||||
cscope.files:
|
cscope.files:
|
||||||
find . -name '*.[ch]' > cscope.files
|
find . -name '*.[ch]' > cscope.files
|
||||||
@ -51,8 +52,24 @@ cscope.files:
|
|||||||
cscope.out: cscope.files
|
cscope.out: cscope.files
|
||||||
cscope -b
|
cscope -b
|
||||||
|
|
||||||
TAGS: etags.files
|
if GNC_TAGS_FILE
|
||||||
etags `cat etags.files`
|
|
||||||
|
|
||||||
etags.files:
|
TAGS.stamp: etags.files $(shell cat etags.files)
|
||||||
find . -name '*.[ch]' -o -name '*.scm' > etags.files
|
etags `cat etags.files`
|
||||||
|
touch TAGS.stamp
|
||||||
|
|
||||||
|
TAGS:
|
||||||
|
find . -name '*.[ch]' -o -name '*.scm' | sort > etags.files.tmp
|
||||||
|
@if cmp --quiet etags.files etags.files.tmp; \
|
||||||
|
then \
|
||||||
|
echo "TAGS file list hasn't changed."; \
|
||||||
|
rm -f etags.files.tmp; \
|
||||||
|
else \
|
||||||
|
echo "TAGS file list has changed."; \
|
||||||
|
mv etags.files.tmp etags.files; \
|
||||||
|
fi
|
||||||
|
${MAKE} TAGS.stamp
|
||||||
|
|
||||||
|
.PHONY: TAGS
|
||||||
|
|
||||||
|
endif
|
||||||
|
26
configure.in
26
configure.in
@ -126,9 +126,18 @@ AC_SUBST(GNC_ACCOUNTS_DIR)
|
|||||||
# We should always see these errors...
|
# We should always see these errors...
|
||||||
CFLAGS="${CFLAGS} -Wall"
|
CFLAGS="${CFLAGS} -Wall"
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(error-on-warning,
|
||||||
|
[ --enable-error-on-warning treat compile warnings as errors],
|
||||||
|
[case "${enableval}" in
|
||||||
|
yes) CFLAGS="${CFLAGS} -Werror"; enable_compile_warnings=no ;;
|
||||||
|
no) ;;
|
||||||
|
*) AC_MSG_ERROR(bad value ${enableval} for --enable-error-on-warning) ;;
|
||||||
|
esac])
|
||||||
|
|
||||||
# This has to come after AC_PROG_CC
|
# This has to come after AC_PROG_CC
|
||||||
if test ${GCC}x = yesx
|
if test ${GCC}x = yesx
|
||||||
then
|
then
|
||||||
|
CFLAGS="${CFLAGS} -Wno-unused"
|
||||||
CFLAGS="${CFLAGS} -Werror-implicit-function-declaration"
|
CFLAGS="${CFLAGS} -Werror-implicit-function-declaration"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -173,11 +182,15 @@ AC_ARG_WITH( help-prefix,
|
|||||||
|
|
||||||
AC_SUBST(GNC_HELPDIR)
|
AC_SUBST(GNC_HELPDIR)
|
||||||
|
|
||||||
|
### --------------------------------------------------------------------------
|
||||||
|
### Check for etags
|
||||||
|
|
||||||
|
AC_CHECK_PROG(GNC_TAGS_FILE, etags, TAGS)
|
||||||
|
AM_CONDITIONAL(GNC_TAGS_FILE, test x${GNC_TAGS_FILE} = xTAGS)
|
||||||
|
|
||||||
### --------------------------------------------------------------------------
|
### --------------------------------------------------------------------------
|
||||||
### Check for glade
|
### Check for glade
|
||||||
|
|
||||||
# Check for glade
|
|
||||||
AC_ARG_WITH(glade,
|
AC_ARG_WITH(glade,
|
||||||
[ --with-glade=FILE which glade executable to use ],
|
[ --with-glade=FILE which glade executable to use ],
|
||||||
GLADE="${with_glade}")
|
GLADE="${with_glade}")
|
||||||
@ -233,10 +246,6 @@ PERLINCL=`$PERL -MConfig -e 'print $Config{"archlibexp"}'`
|
|||||||
AC_ARG_WITH( perl-includes,
|
AC_ARG_WITH( perl-includes,
|
||||||
[ --with-perl-includes=DIR specify where to look for perl includes],
|
[ --with-perl-includes=DIR specify where to look for perl includes],
|
||||||
PERLINCL="$with_perl_includes" )
|
PERLINCL="$with_perl_includes" )
|
||||||
|
|
||||||
if test ! -d ${PERLINCL}/CORE; then
|
|
||||||
AC_MSG_ERROR([Missing directory ${PERLINCL}/CORE in the perl include directory])
|
|
||||||
fi
|
|
||||||
AC_SUBST(PERLINCL)
|
AC_SUBST(PERLINCL)
|
||||||
|
|
||||||
|
|
||||||
@ -390,11 +399,12 @@ AC_SUBST(GTK_XIM_FLAGS)
|
|||||||
### --------------------------------------------------------------------------
|
### --------------------------------------------------------------------------
|
||||||
### popt
|
### popt
|
||||||
|
|
||||||
AC_CHECK_LIB(popt, poptStrippedArgv,, AC_MSG_ERROR([
|
AC_CHECK_LIB(popt, poptStrippedArgv,, [AC_MSG_ERROR([
|
||||||
|
|
||||||
popt 1.5 or newer is required to build gnucash. You can download
|
popt 1.5 or newer is required to build gnucash. You can download
|
||||||
the latest version from ftp://people.redhat.com/sopwith/popt/
|
the latest version from ftp://people.redhat.com/sopwith/popt/, or if
|
||||||
]))
|
you're running Debian, install the libpopt-dev pacakge.
|
||||||
|
])])
|
||||||
|
|
||||||
### --------------------------------------------------------------------------
|
### --------------------------------------------------------------------------
|
||||||
## For now, we just presume you're using the GNOME version. The other
|
## For now, we just presume you're using the GNOME version. The other
|
||||||
|
@ -168,7 +168,7 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c
|
conf_flags="--enable-maintainer-mode" # --enable-compile-warnings --enable-iso-c
|
||||||
|
|
||||||
if test x$NOCONFIGURE = x; then
|
if test x$NOCONFIGURE = x; then
|
||||||
echo Running $srcdir/configure $conf_flags "$@" ...
|
echo Running $srcdir/configure $conf_flags "$@" ...
|
||||||
|
@ -67,8 +67,7 @@ static gnc_euro_rate_struct _gnc_euro_rate_[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_gnc_euro_rate_compare_(const void * key,
|
_gnc_euro_rate_compare_(const void * key, const void * value)
|
||||||
const void * value)
|
|
||||||
{
|
{
|
||||||
const gnc_commodity * curr = key;
|
const gnc_commodity * curr = key;
|
||||||
const gnc_euro_rate_struct * euro = value;
|
const gnc_euro_rate_struct * euro = value;
|
||||||
@ -83,7 +82,8 @@ _gnc_euro_rate_compare_(const void * key,
|
|||||||
/* ------------------------------------------------------ */
|
/* ------------------------------------------------------ */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gnc_is_euro_currency(const gnc_commodity * currency) {
|
gnc_is_euro_currency(gnc_commodity * currency)
|
||||||
|
{
|
||||||
|
|
||||||
gnc_euro_rate_struct *result;
|
gnc_euro_rate_struct *result;
|
||||||
const char *namespace;
|
const char *namespace;
|
||||||
@ -113,7 +113,7 @@ gnc_is_euro_currency(const gnc_commodity * currency) {
|
|||||||
/* ------------------------------------------------------ */
|
/* ------------------------------------------------------ */
|
||||||
|
|
||||||
gnc_numeric
|
gnc_numeric
|
||||||
gnc_convert_to_euro(const gnc_commodity * currency, gnc_numeric value) {
|
gnc_convert_to_euro(gnc_commodity * currency, gnc_numeric value) {
|
||||||
|
|
||||||
gnc_euro_rate_struct *result;
|
gnc_euro_rate_struct *result;
|
||||||
const char *namespace;
|
const char *namespace;
|
||||||
@ -150,7 +150,7 @@ gnc_convert_to_euro(const gnc_commodity * currency, gnc_numeric value) {
|
|||||||
/* ------------------------------------------------------ */
|
/* ------------------------------------------------------ */
|
||||||
|
|
||||||
gnc_numeric
|
gnc_numeric
|
||||||
gnc_convert_from_euro(const gnc_commodity * currency, gnc_numeric value) {
|
gnc_convert_from_euro(gnc_commodity * currency, gnc_numeric value) {
|
||||||
|
|
||||||
gnc_euro_rate_struct * result;
|
gnc_euro_rate_struct * result;
|
||||||
const char *namespace;
|
const char *namespace;
|
||||||
@ -186,7 +186,7 @@ gnc_convert_from_euro(const gnc_commodity * currency, gnc_numeric value) {
|
|||||||
|
|
||||||
/* ------------------------------------------------------ */
|
/* ------------------------------------------------------ */
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_get_euro (void)
|
gnc_get_euro (void)
|
||||||
{
|
{
|
||||||
return gnc_commodity_table_lookup (gnc_engine_commodities (),
|
return gnc_commodity_table_lookup (gnc_engine_commodities (),
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
#include "gnc-commodity.h"
|
#include "gnc-commodity.h"
|
||||||
#include "gnc-numeric.h"
|
#include "gnc-numeric.h"
|
||||||
|
|
||||||
gboolean gnc_is_euro_currency (const gnc_commodity * currency);
|
gboolean gnc_is_euro_currency (gnc_commodity * currency);
|
||||||
gnc_numeric gnc_convert_to_euro (const gnc_commodity * currency,
|
gnc_numeric gnc_convert_to_euro (gnc_commodity * currency,
|
||||||
gnc_numeric value);
|
gnc_numeric value);
|
||||||
gnc_numeric gnc_convert_from_euro (const gnc_commodity * currency,
|
gnc_numeric gnc_convert_from_euro (gnc_commodity * currency,
|
||||||
gnc_numeric value);
|
gnc_numeric value);
|
||||||
|
|
||||||
const gnc_commodity * gnc_get_euro (void);
|
gnc_commodity * gnc_get_euro (void);
|
||||||
|
|
||||||
#endif /* __EURO_UTILS_H__ */
|
#endif /* __EURO_UTILS_H__ */
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "Backend.h"
|
#include "Backend.h"
|
||||||
#include "FileBox.h"
|
#include "FileBox.h"
|
||||||
#include "FileDialog.h"
|
#include "FileDialog.h"
|
||||||
#include "FileIO.h"
|
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "file-history.h"
|
#include "file-history.h"
|
||||||
#include "gnc-component-manager.h"
|
#include "gnc-component-manager.h"
|
||||||
@ -37,6 +36,8 @@
|
|||||||
#include "gnc-ui.h"
|
#include "gnc-ui.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
|
|
||||||
|
/* FIXME: this is wrong. This file should not need this include. */
|
||||||
|
#include "gnc-book-p.h"
|
||||||
|
|
||||||
/** GLOBALS *********************************************************/
|
/** GLOBALS *********************************************************/
|
||||||
/* This static indicates the debugging module that this .o belongs to. */
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
@ -113,11 +114,6 @@ show_book_error (GNCBackendError io_error, const char *newfile)
|
|||||||
if (gnc_verify_dialog (fmt, TRUE)) { uh_oh = FALSE; }
|
if (gnc_verify_dialog (fmt, TRUE)) { uh_oh = FALSE; }
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ERR_FILEIO_MISC:
|
|
||||||
fmt = _("There was an error during file I/O.");
|
|
||||||
gnc_error_dialog (fmt);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ERR_SQL_BAD_LOCATION:
|
case ERR_SQL_BAD_LOCATION:
|
||||||
fmt = _("Can't parse the database URL\n %s\n");
|
fmt = _("Can't parse the database URL\n %s\n");
|
||||||
buf = g_strdup_printf (fmt, newfile);
|
buf = g_strdup_printf (fmt, newfile);
|
||||||
@ -192,7 +188,6 @@ void
|
|||||||
gncFileNew (void)
|
gncFileNew (void)
|
||||||
{
|
{
|
||||||
GNCBook *book;
|
GNCBook *book;
|
||||||
AccountGroup *group;
|
|
||||||
|
|
||||||
/* If user attempts to start a new session before saving results of
|
/* If user attempts to start a new session before saving results of
|
||||||
* the last one, prompt them to clean up their act. */
|
* the last one, prompt them to clean up their act. */
|
||||||
@ -200,7 +195,6 @@ gncFileNew (void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
book = gncGetCurrentBook ();
|
book = gncGetCurrentBook ();
|
||||||
group = gnc_book_get_group (book);
|
|
||||||
|
|
||||||
/* close any ongoing file sessions, and free the accounts.
|
/* close any ongoing file sessions, and free the accounts.
|
||||||
* disable events so we don't get spammed by redraws. */
|
* disable events so we don't get spammed by redraws. */
|
||||||
@ -221,14 +215,8 @@ gncFileNew (void)
|
|||||||
gboolean
|
gboolean
|
||||||
gncFileQuerySave (void)
|
gncFileQuerySave (void)
|
||||||
{
|
{
|
||||||
GNCBook *book;
|
GNCBook *book = gncGetCurrentBook();
|
||||||
AccountGroup *group;
|
gncUIWidget app = gnc_get_ui_data();
|
||||||
gncUIWidget app;
|
|
||||||
|
|
||||||
book = gncGetCurrentBook ();
|
|
||||||
group = gnc_book_get_group (book);
|
|
||||||
|
|
||||||
app = gnc_get_ui_data ();
|
|
||||||
|
|
||||||
/* If user wants to mess around before finishing business with
|
/* If user wants to mess around before finishing business with
|
||||||
* the old file, give em a chance to figure out what's up.
|
* the old file, give em a chance to figure out what's up.
|
||||||
@ -236,8 +224,7 @@ gncFileQuerySave (void)
|
|||||||
* up the file-selection dialog, we don't blow em out of the water;
|
* up the file-selection dialog, we don't blow em out of the water;
|
||||||
* instead, give them another chance to say "no" to the verify box.
|
* instead, give them another chance to say "no" to the verify box.
|
||||||
*/
|
*/
|
||||||
while (xaccGroupNotSaved (group))
|
while (gnc_book_not_saved(book)) {
|
||||||
{
|
|
||||||
GNCVerifyResult result;
|
GNCVerifyResult result;
|
||||||
const char *message = _("Changes have been made since the last "
|
const char *message = _("Changes have been made since the last "
|
||||||
"Save. Save the data to file?");
|
"Save. Save the data to file?");
|
||||||
@ -386,7 +373,6 @@ gncPostFileOpen (const char * filename)
|
|||||||
gh_eval_str("gnc:*file-opened-hook*"),
|
gh_eval_str("gnc:*file-opened-hook*"),
|
||||||
gh_str02scm(newfile));
|
gh_str02scm(newfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (newfile);
|
g_free (newfile);
|
||||||
|
|
||||||
gnc_engine_resume_events ();
|
gnc_engine_resume_events ();
|
||||||
@ -469,7 +455,7 @@ gncFileSave (void)
|
|||||||
|
|
||||||
gnc_history_add_file (newfile);
|
gnc_history_add_file (newfile);
|
||||||
|
|
||||||
xaccGroupMarkSaved (gnc_book_get_group (book));
|
gnc_book_mark_saved(book);
|
||||||
LEAVE (" ");
|
LEAVE (" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,6 +465,7 @@ void
|
|||||||
gncFileSaveAs (void)
|
gncFileSaveAs (void)
|
||||||
{
|
{
|
||||||
AccountGroup *group;
|
AccountGroup *group;
|
||||||
|
GNCPriceDB *pdb;
|
||||||
GNCBook *new_book;
|
GNCBook *new_book;
|
||||||
GNCBook *book;
|
GNCBook *book;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
@ -510,7 +497,8 @@ gncFileSaveAs (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -- this session code is NOT identical in FileOpen and FileSaveAs -- */
|
/* -- this session code is NOT identical in FileOpen and FileSaveAs -- */
|
||||||
group = gnc_book_get_group (book);
|
group = gnc_book_get_group(book);
|
||||||
|
pdb = gnc_book_get_pricedb(book);
|
||||||
|
|
||||||
new_book = gnc_book_new ();
|
new_book = gnc_book_new ();
|
||||||
gnc_book_begin (new_book, newfile, FALSE, FALSE);
|
gnc_book_begin (new_book, newfile, FALSE, FALSE);
|
||||||
@ -552,7 +540,8 @@ gncFileSaveAs (void)
|
|||||||
|
|
||||||
/* if we got to here, then we've successfully gotten a new session */
|
/* if we got to here, then we've successfully gotten a new session */
|
||||||
/* close up the old file session (if any) */
|
/* close up the old file session (if any) */
|
||||||
gnc_book_set_group (book, NULL);
|
gnc_book_set_group(book, NULL);
|
||||||
|
gnc_book_set_pricedb(book, NULL);
|
||||||
gnc_book_destroy (book);
|
gnc_book_destroy (book);
|
||||||
current_book = new_book;
|
current_book = new_book;
|
||||||
|
|
||||||
@ -581,7 +570,8 @@ gncFileSaveAs (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* OK, save the data to the file ... */
|
/* OK, save the data to the file ... */
|
||||||
gnc_book_set_group (new_book, group);
|
gnc_book_set_group(new_book, group);
|
||||||
|
gnc_book_set_pricedb(new_book, pdb);
|
||||||
gncFileSave ();
|
gncFileSave ();
|
||||||
|
|
||||||
g_free (newfile);
|
g_free (newfile);
|
||||||
|
@ -426,7 +426,7 @@ gnc_find_split_in_trans_by_memo (Transaction *trans, const char *memo,
|
|||||||
if (safe_strcmp(memo, xaccSplitGetMemo(split)) == 0)
|
if (safe_strcmp(memo, xaccSplitGetMemo(split)) == 0)
|
||||||
{
|
{
|
||||||
Account *account = xaccSplitGetAccount(split);
|
Account *account = xaccSplitGetAccount(split);
|
||||||
const gnc_commodity *currency, *security;
|
gnc_commodity *currency, *security;
|
||||||
|
|
||||||
if (account == NULL)
|
if (account == NULL)
|
||||||
return split;
|
return split;
|
||||||
@ -611,7 +611,7 @@ gnc_split_get_value_denom (Split *split)
|
|||||||
denom = xaccAccountGetCurrencySCU (xaccSplitGetAccount (split));
|
denom = xaccAccountGetCurrencySCU (xaccSplitGetAccount (split));
|
||||||
if (denom == 0)
|
if (denom == 0)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity = gnc_locale_default_currency ();
|
gnc_commodity *commodity = gnc_locale_default_currency ();
|
||||||
denom = gnc_commodity_get_fraction (commodity);
|
denom = gnc_commodity_get_fraction (commodity);
|
||||||
if (denom == 0)
|
if (denom == 0)
|
||||||
denom = 100;
|
denom = 100;
|
||||||
@ -628,7 +628,7 @@ gnc_split_get_quantity_denom (Split *split)
|
|||||||
denom = xaccAccountGetSecuritySCU (xaccSplitGetAccount (split));
|
denom = xaccAccountGetSecuritySCU (xaccSplitGetAccount (split));
|
||||||
if (denom == 0)
|
if (denom == 0)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity = gnc_locale_default_currency ();
|
gnc_commodity *commodity = gnc_locale_default_currency ();
|
||||||
denom = gnc_commodity_get_fraction (commodity);
|
denom = gnc_commodity_get_fraction (commodity);
|
||||||
if (denom == 0)
|
if (denom == 0)
|
||||||
denom = 100;
|
denom = 100;
|
||||||
@ -660,7 +660,7 @@ sr_set_cell_fractions (SplitRegister *reg, Split *split)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
int fraction;
|
int fraction;
|
||||||
|
|
||||||
xaccSetPriceCellFraction (reg->sharesCell, 10000);
|
xaccSetPriceCellFraction (reg->sharesCell, 10000);
|
||||||
@ -3245,8 +3245,8 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
|||||||
|
|
||||||
if ((new_acc != NULL) && (old_acc != new_acc))
|
if ((new_acc != NULL) && (old_acc != new_acc))
|
||||||
{
|
{
|
||||||
const gnc_commodity * currency = NULL;
|
gnc_commodity * currency = NULL;
|
||||||
const gnc_commodity * security = NULL;
|
gnc_commodity * security = NULL;
|
||||||
|
|
||||||
currency = xaccAccountGetCurrency(new_acc);
|
currency = xaccAccountGetCurrency(new_acc);
|
||||||
currency = xaccTransIsCommonExclSCurrency(trans, currency, split);
|
currency = xaccTransIsCommonExclSCurrency(trans, currency, split);
|
||||||
@ -3319,8 +3319,8 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
|||||||
|
|
||||||
if ((new_acc != NULL) && (old_acc != new_acc))
|
if ((new_acc != NULL) && (old_acc != new_acc))
|
||||||
{
|
{
|
||||||
const gnc_commodity * currency = NULL;
|
gnc_commodity * currency = NULL;
|
||||||
const gnc_commodity * security = NULL;
|
gnc_commodity * security = NULL;
|
||||||
|
|
||||||
currency = xaccAccountGetCurrency(new_acc);
|
currency = xaccAccountGetCurrency(new_acc);
|
||||||
currency = xaccTransIsCommonExclSCurrency(trans,
|
currency = xaccTransIsCommonExclSCurrency(trans,
|
||||||
@ -4831,8 +4831,8 @@ xaccSRLoadRegister (SplitRegister *reg, GList * slist,
|
|||||||
static void
|
static void
|
||||||
LoadXferCell (ComboCell * cell,
|
LoadXferCell (ComboCell * cell,
|
||||||
AccountGroup * grp,
|
AccountGroup * grp,
|
||||||
const gnc_commodity * base_currency,
|
gnc_commodity * base_currency,
|
||||||
const gnc_commodity * base_security)
|
gnc_commodity * base_security)
|
||||||
{
|
{
|
||||||
gboolean load_everything;
|
gboolean load_everything;
|
||||||
GList *list;
|
GList *list;
|
||||||
@ -4853,8 +4853,8 @@ LoadXferCell (ComboCell * cell,
|
|||||||
for (node = list; node; node = node->next)
|
for (node = list; node; node = node->next)
|
||||||
{
|
{
|
||||||
Account *account = node->data;
|
Account *account = node->data;
|
||||||
const gnc_commodity * curr;
|
gnc_commodity * curr;
|
||||||
const gnc_commodity * secu;
|
gnc_commodity * secu;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
curr = xaccAccountGetCurrency (account);
|
curr = xaccAccountGetCurrency (account);
|
||||||
@ -4891,7 +4891,7 @@ xaccLoadXferCell (ComboCell *cell,
|
|||||||
AccountGroup *grp,
|
AccountGroup *grp,
|
||||||
Account *base_account)
|
Account *base_account)
|
||||||
{
|
{
|
||||||
const gnc_commodity * curr, * secu;
|
gnc_commodity * curr, * secu;
|
||||||
|
|
||||||
curr = xaccAccountGetCurrency (base_account);
|
curr = xaccAccountGetCurrency (base_account);
|
||||||
secu = xaccAccountGetSecurity (base_account);
|
secu = xaccAccountGetSecurity (base_account);
|
||||||
|
@ -132,14 +132,14 @@ account_restore_end_handler(gpointer data_for_children,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
account_restore_after_child_handler(gpointer data_for_children,
|
account_restore_after_child_handler(gpointer data_for_children,
|
||||||
GSList* data_from_children,
|
GSList* data_from_children,
|
||||||
GSList* sibling_data,
|
GSList* sibling_data,
|
||||||
gpointer parent_data,
|
gpointer parent_data,
|
||||||
gpointer global_data,
|
gpointer global_data,
|
||||||
gpointer *result,
|
gpointer *result,
|
||||||
const gchar *tag,
|
const gchar *tag,
|
||||||
const gchar *child_tag,
|
const gchar *child_tag,
|
||||||
sixtp_child_result *child_result)
|
sixtp_child_result *child_result)
|
||||||
{
|
{
|
||||||
Account *a = (Account *) data_for_children;
|
Account *a = (Account *) data_for_children;
|
||||||
g_return_val_if_fail(a, FALSE);
|
g_return_val_if_fail(a, FALSE);
|
||||||
@ -172,12 +172,12 @@ account_restore_after_child_handler(gpointer data_for_children,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
account_restore_fail_handler(gpointer data_for_children,
|
account_restore_fail_handler(gpointer data_for_children,
|
||||||
GSList* data_from_children,
|
GSList* data_from_children,
|
||||||
GSList* sibling_data,
|
GSList* sibling_data,
|
||||||
gpointer parent_data,
|
gpointer parent_data,
|
||||||
gpointer global_data,
|
gpointer global_data,
|
||||||
gpointer *result,
|
gpointer *result,
|
||||||
const gchar *tag)
|
const gchar *tag)
|
||||||
{
|
{
|
||||||
Account *acc = (Account *) *result;
|
Account *acc = (Account *) *result;
|
||||||
if(acc) xaccFreeAccount(acc);
|
if(acc) xaccFreeAccount(acc);
|
||||||
|
@ -1147,7 +1147,7 @@ update_split_currency(Account * acc)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
xaccAccountSetCommodity (Account * acc, const gnc_commodity * com)
|
xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
|
||||||
{
|
{
|
||||||
if ((!acc) || (!com)) return;
|
if ((!acc) || (!com)) return;
|
||||||
|
|
||||||
@ -1180,7 +1180,7 @@ xaccAccountSetCommodity (Account * acc, const gnc_commodity * com)
|
|||||||
/* below follow the old, deprecated currency/security routines. */
|
/* below follow the old, deprecated currency/security routines. */
|
||||||
|
|
||||||
void
|
void
|
||||||
xaccAccountSetCurrency (Account * acc, const gnc_commodity * currency) {
|
xaccAccountSetCurrency (Account * acc, gnc_commodity * currency) {
|
||||||
|
|
||||||
if ((!acc) || (!currency)) return;
|
if ((!acc) || (!currency)) return;
|
||||||
|
|
||||||
@ -1200,7 +1200,7 @@ xaccAccountSetCurrency (Account * acc, const gnc_commodity * currency) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xaccAccountSetSecurity (Account *acc, const gnc_commodity * security) {
|
xaccAccountSetSecurity (Account *acc, gnc_commodity * security) {
|
||||||
|
|
||||||
if ((!acc) || (!security)) return;
|
if ((!acc) || (!security)) return;
|
||||||
|
|
||||||
@ -1383,14 +1383,14 @@ xaccAccountGetNotes (Account *acc)
|
|||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccAccountGetCurrency (Account *acc)
|
xaccAccountGetCurrency (Account *acc)
|
||||||
{
|
{
|
||||||
if (!acc) return NULL;
|
if (!acc) return NULL;
|
||||||
return (acc->currency);
|
return (acc->currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccAccountGetEffectiveSecurity (Account *acc)
|
xaccAccountGetEffectiveSecurity (Account *acc)
|
||||||
{
|
{
|
||||||
if (!acc) return NULL;
|
if (!acc) return NULL;
|
||||||
@ -1401,7 +1401,7 @@ xaccAccountGetEffectiveSecurity (Account *acc)
|
|||||||
return (acc->security);
|
return (acc->security);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccAccountGetSecurity (Account *account)
|
xaccAccountGetSecurity (Account *account)
|
||||||
{
|
{
|
||||||
if (!account) return NULL;
|
if (!account) return NULL;
|
||||||
|
@ -215,23 +215,23 @@ const char * xaccAccountGetNotes (Account *account);
|
|||||||
* amount of the Account's commodity involved) into the Transaction's
|
* amount of the Account's commodity involved) into the Transaction's
|
||||||
* balancing currency. */
|
* balancing currency. */
|
||||||
#define xaccAccountGetCommodity xaccAccountGetEffectiveSecurity
|
#define xaccAccountGetCommodity xaccAccountGetEffectiveSecurity
|
||||||
void xaccAccountSetCommodity (Account *account, const gnc_commodity *comm);
|
void xaccAccountSetCommodity (Account *account, gnc_commodity *comm);
|
||||||
|
|
||||||
/* Soon-to-be-deprecated currency/security access routines.
|
/* Soon-to-be-deprecated currency/security access routines.
|
||||||
* The future API will associate only one thing with an account:
|
* The future API will associate only one thing with an account:
|
||||||
* the 'commodity'. Use xaccAccountGetCommodity() to fetch it.
|
* the 'commodity'. Use xaccAccountGetCommodity() to fetch it.
|
||||||
*/
|
*/
|
||||||
/* these two funcs take control of thier gnc_commodity args. Don't free */
|
/* these two funcs take control of thier gnc_commodity args. Don't free */
|
||||||
void xaccAccountSetCurrency (Account *account, const gnc_commodity *currency);
|
void xaccAccountSetCurrency (Account *account, gnc_commodity *currency);
|
||||||
void xaccAccountSetSecurity (Account *account, const gnc_commodity *security);
|
void xaccAccountSetSecurity (Account *account, gnc_commodity *security);
|
||||||
void xaccAccountSetCurrencySCU (Account *account, int frac);
|
void xaccAccountSetCurrencySCU (Account *account, int frac);
|
||||||
void xaccAccountSetSecuritySCU (Account *account, int frac);
|
void xaccAccountSetSecuritySCU (Account *account, int frac);
|
||||||
int xaccAccountGetCurrencySCU (Account *account);
|
int xaccAccountGetCurrencySCU (Account *account);
|
||||||
int xaccAccountGetSecuritySCU (Account *account);
|
int xaccAccountGetSecuritySCU (Account *account);
|
||||||
|
|
||||||
const gnc_commodity * xaccAccountGetCurrency (Account *account);
|
gnc_commodity * xaccAccountGetCurrency (Account *account);
|
||||||
const gnc_commodity * xaccAccountGetSecurity (Account *account);
|
gnc_commodity * xaccAccountGetSecurity (Account *account);
|
||||||
const gnc_commodity * xaccAccountGetEffectiveSecurity (Account *account);
|
gnc_commodity * xaccAccountGetEffectiveSecurity (Account *account);
|
||||||
|
|
||||||
AccountGroup * xaccAccountGetChildren (Account *account);
|
AccountGroup * xaccAccountGetChildren (Account *account);
|
||||||
AccountGroup * xaccAccountGetParent (Account *account);
|
AccountGroup * xaccAccountGetParent (Account *account);
|
||||||
|
@ -111,8 +111,8 @@ struct _account {
|
|||||||
* messages will print to the screen if things don't go well.
|
* messages will print to the screen if things don't go well.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
const gnc_commodity * currency;
|
gnc_commodity * currency;
|
||||||
const gnc_commodity * security;
|
gnc_commodity * security;
|
||||||
int currency_scu;
|
int currency_scu;
|
||||||
int security_scu;
|
int security_scu;
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ typedef enum {
|
|||||||
/* or no backend handler (ENOSYS) */
|
/* or no backend handler (ENOSYS) */
|
||||||
ERR_BACKEND_LOCKED, /* in use by another user (ETXTBSY) */
|
ERR_BACKEND_LOCKED, /* in use by another user (ETXTBSY) */
|
||||||
ERR_BACKEND_NO_SUCH_DB, /* the named database doesn't exist */
|
ERR_BACKEND_NO_SUCH_DB, /* the named database doesn't exist */
|
||||||
|
ERR_BACKEND_ALLOC, /* internal memory allocation failure */
|
||||||
ERR_BACKEND_MISC, /* undetermined error */
|
ERR_BACKEND_MISC, /* undetermined error */
|
||||||
|
|
||||||
/* fileio errors */
|
/* fileio errors */
|
||||||
@ -34,8 +35,6 @@ typedef enum {
|
|||||||
ERR_FILEIO_FILE_NOT_FOUND, /* not found / no such file */
|
ERR_FILEIO_FILE_NOT_FOUND, /* not found / no such file */
|
||||||
ERR_FILEIO_FILE_TOO_NEW, /* file version newer than what we can read */
|
ERR_FILEIO_FILE_TOO_NEW, /* file version newer than what we can read */
|
||||||
ERR_FILEIO_FILE_TOO_OLD, /* file version so old we can't read it */
|
ERR_FILEIO_FILE_TOO_OLD, /* file version so old we can't read it */
|
||||||
ERR_FILEIO_ALLOC, /* ?? */
|
|
||||||
ERR_FILEIO_MISC, /* unknown weird error */
|
|
||||||
|
|
||||||
/* network errors */
|
/* network errors */
|
||||||
ERR_NETIO_NO_CONNECTION, /* network failure, can't connect to server */
|
ERR_NETIO_NO_CONNECTION, /* network failure, can't connect to server */
|
||||||
|
@ -95,14 +95,14 @@ commodity_restore_start_handler(GSList* sibling_data, gpointer parent_data,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
commodity_restore_after_child_handler(gpointer data_for_children,
|
commodity_restore_after_child_handler(gpointer data_for_children,
|
||||||
GSList* data_from_children,
|
GSList* data_from_children,
|
||||||
GSList* sibling_data,
|
GSList* sibling_data,
|
||||||
gpointer parent_data,
|
gpointer parent_data,
|
||||||
gpointer global_data,
|
gpointer global_data,
|
||||||
gpointer *result,
|
gpointer *result,
|
||||||
const gchar *tag,
|
const gchar *tag,
|
||||||
const gchar *child_tag,
|
const gchar *child_tag,
|
||||||
sixtp_child_result *child_result)
|
sixtp_child_result *child_result)
|
||||||
{
|
{
|
||||||
CommodityParseInfo *cpi = (CommodityParseInfo *) data_for_children;
|
CommodityParseInfo *cpi = (CommodityParseInfo *) data_for_children;
|
||||||
|
|
||||||
@ -367,31 +367,37 @@ generic_gnc_commodity_lookup_parser_new(void)
|
|||||||
/* WRITING */
|
/* WRITING */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
xml_add_commodity_ref(xmlNodePtr p, const char *tag, const gnc_commodity *c) {
|
xml_add_commodity_ref(xmlNodePtr p, const char *tag, const gnc_commodity *c)
|
||||||
|
{
|
||||||
xmlNodePtr c_xml = NULL;
|
xmlNodePtr c_xml = NULL;
|
||||||
gboolean ok = FALSE;
|
xmlNodePtr tmp_xml = NULL;
|
||||||
|
const gchar *namestr;
|
||||||
|
const gchar *idstr;
|
||||||
|
|
||||||
if(p && tag) {
|
if (!(p && tag)) return FALSE;
|
||||||
if(!c) {
|
if (!c) return TRUE;
|
||||||
ok = TRUE;
|
|
||||||
} else {
|
namestr = gnc_commodity_get_namespace(c);
|
||||||
c_xml= xmlNewTextChild(p, NULL, tag, NULL);
|
idstr = gnc_commodity_get_mnemonic(c);
|
||||||
if(c_xml) {
|
|
||||||
const gchar *namestr = gnc_commodity_get_namespace(c);
|
|
||||||
if(namestr) {
|
|
||||||
xmlNodePtr namespace_xml = xmlNewTextChild(c_xml, NULL, "space", namestr);
|
|
||||||
if(namespace_xml) {
|
|
||||||
const gchar *idstr = gnc_commodity_get_mnemonic(c);
|
|
||||||
xmlNodePtr id_xml = xmlNewTextChild(c_xml, NULL, "id", idstr);
|
|
||||||
if(id_xml) ok = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ok && c_xml) xmlFreeNode(c_xml);
|
if(!(namestr && idstr)) return FALSE;
|
||||||
return(TRUE);
|
|
||||||
|
c_xml= xmlNewNode(NULL, tag);
|
||||||
|
if(!c_xml) return FALSE;
|
||||||
|
|
||||||
|
tmp_xml = xmlNewTextChild(c_xml, NULL, "space", namestr);
|
||||||
|
if(!tmp_xml) {
|
||||||
|
xmlFreeNode(c_xml);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
tmp_xml = xmlNewTextChild(c_xml, NULL, "id", idstr);
|
||||||
|
if(!tmp_xml) {
|
||||||
|
xmlFreeNode(c_xml);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlAddChild(p, c_xml);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ============================================================== */
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
/********************************************************************\
|
|
||||||
* FileIO.c -- read and write file wrappers (old and new format) *
|
|
||||||
* Copyright (C) 1997-2000 Linas Vepstas <linas@linas.org> *
|
|
||||||
* Copyright (C) 1999-2000 Rob Browning *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU General Public License as *
|
|
||||||
* published by the Free Software Foundation; either version 2 of *
|
|
||||||
* the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License*
|
|
||||||
* along with this program; if not, contact: *
|
|
||||||
* *
|
|
||||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
||||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
|
||||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
|
||||||
* *
|
|
||||||
\********************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "DateUtils.h"
|
|
||||||
#include "FileIO.h"
|
|
||||||
#include "io-gncxml.h"
|
|
||||||
#include "io-gncbin.h"
|
|
||||||
|
|
||||||
AccountGroup *
|
|
||||||
xaccReadAccountGroupFile(const gchar *name, GNCBackendError *error_result)
|
|
||||||
{
|
|
||||||
AccountGroup *result_grp;
|
|
||||||
|
|
||||||
if(is_gncxml_file(name)) {
|
|
||||||
if(gncxml_read(name, &result_grp)) {
|
|
||||||
if(error_result) *error_result = ERR_BACKEND_NO_ERR;
|
|
||||||
return result_grp;
|
|
||||||
} else {
|
|
||||||
if(error_result) *error_result = ERR_FILEIO_MISC;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* presume it's an old-style binary file */
|
|
||||||
result_grp = xaccReadGncBinAccountGroupFile(name);
|
|
||||||
|
|
||||||
if(result_grp) {
|
|
||||||
if(error_result) *error_result = ERR_BACKEND_NO_ERR;
|
|
||||||
return result_grp;
|
|
||||||
} else {
|
|
||||||
if(error_result) *error_result = xaccGetGncBinFileIOError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Should never get here */
|
|
||||||
if(error_result) *error_result = ERR_FILEIO_MISC;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
xaccWriteAccountGroupFile(const char *datafile,
|
|
||||||
AccountGroup *grp,
|
|
||||||
gboolean make_backup,
|
|
||||||
GNCBackendError *error_result)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(!datafile) {
|
|
||||||
if(error_result) *error_result = ERR_FILEIO_FILE_NOT_FOUND;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!gncxml_write(grp, datafile)) {
|
|
||||||
if(error_result) *error_result = ERR_FILEIO_MISC;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!make_backup) {
|
|
||||||
if(error_result) *error_result = ERR_BACKEND_NO_ERR;
|
|
||||||
return TRUE;
|
|
||||||
} else {
|
|
||||||
char * timestamp;
|
|
||||||
int filenamelen;
|
|
||||||
char * backup;
|
|
||||||
|
|
||||||
/* also, write a time-stamped backup file */
|
|
||||||
/* tag each filename with a timestamp */
|
|
||||||
timestamp = xaccDateUtilGetStampNow ();
|
|
||||||
|
|
||||||
filenamelen = strlen (datafile) + strlen (timestamp) + 6;
|
|
||||||
|
|
||||||
backup = (char *) malloc (filenamelen);
|
|
||||||
strcpy (backup, datafile);
|
|
||||||
strcat (backup, ".");
|
|
||||||
strcat (backup, timestamp);
|
|
||||||
strcat (backup, ".xac");
|
|
||||||
free (timestamp);
|
|
||||||
|
|
||||||
if(gncxml_write(grp, backup)) {
|
|
||||||
if(error_result) *error_result = ERR_BACKEND_NO_ERR;
|
|
||||||
free (backup);
|
|
||||||
return TRUE;
|
|
||||||
} else {
|
|
||||||
if(error_result) *error_result = ERR_FILEIO_MISC;
|
|
||||||
free (backup);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Should never get here */
|
|
||||||
if(error_result) *error_result = ERR_FILEIO_MISC;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
/********************************************************************\
|
|
||||||
* FileIO.h -- read and write binary format file for gnucash *
|
|
||||||
* Copyright (C) 1997 Robin D. Clark *
|
|
||||||
* Copyright (C) 1998, 1999 Linas Vepstas *
|
|
||||||
* Copyright (C) 1999, 2000 Rob Browning *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU General Public License as *
|
|
||||||
* published by the Free Software Foundation; either version 2 of *
|
|
||||||
* the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License*
|
|
||||||
* along with this program; if not, contact: *
|
|
||||||
* *
|
|
||||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
||||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
|
||||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
|
||||||
* *
|
|
||||||
* Author: Rob Clark *
|
|
||||||
* Internet: rclark@cs.hmc.edu *
|
|
||||||
* Address: 609 8th Street *
|
|
||||||
* Huntington Beach, CA 92648-4632 *
|
|
||||||
\********************************************************************/
|
|
||||||
|
|
||||||
#ifndef __FILE_IO_H__
|
|
||||||
#define __FILE_IO_H__
|
|
||||||
|
|
||||||
#include "Backend.h"
|
|
||||||
#include "Group.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
These function read/write the data in an AccountGroup to a file.
|
|
||||||
The read functions will automatically detect the format of the file
|
|
||||||
if possible. The write functions write the file in the "current"
|
|
||||||
format. These days, that means XML.
|
|
||||||
|
|
||||||
The read functions return NULL on error, and set the error parameter
|
|
||||||
(if it's not NULL) to indicate what went wrong.
|
|
||||||
|
|
||||||
The write functions return FALSE on error and set the error
|
|
||||||
parameter similarly.
|
|
||||||
|
|
||||||
In most cases, these functions should not be used directly. They
|
|
||||||
are not "safe" against file-locking errors. Use the Session object
|
|
||||||
instead.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
AccountGroup *xaccReadAccountGroupFile(const char *datafile,
|
|
||||||
GNCBackendError *error);
|
|
||||||
|
|
||||||
gboolean xaccWriteAccountGroupFile(const char *datafile,
|
|
||||||
AccountGroup *grp,
|
|
||||||
gboolean make_backup,
|
|
||||||
GNCBackendError *error);
|
|
||||||
/* If make_backup is true, write out a time-stamped copy of the file
|
|
||||||
into the same directory as the indicated file, with a filename of
|
|
||||||
"file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
|
|
||||||
current year/month/day/hour/minute/second. */
|
|
||||||
|
|
||||||
#endif /* __XACC_FILEIO_H__ */
|
|
@ -70,6 +70,7 @@ void xaccGroupMergeAccounts (AccountGroup *grp);
|
|||||||
gboolean xaccGroupNotSaved (AccountGroup *grp);
|
gboolean xaccGroupNotSaved (AccountGroup *grp);
|
||||||
void xaccGroupMarkSaved (AccountGroup *grp);
|
void xaccGroupMarkSaved (AccountGroup *grp);
|
||||||
void xaccGroupMarkNotSaved (AccountGroup *grp);
|
void xaccGroupMarkNotSaved (AccountGroup *grp);
|
||||||
|
|
||||||
void xaccGroupMarkDoFree (AccountGroup *grp);
|
void xaccGroupMarkDoFree (AccountGroup *grp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
#include "io-gncxml-p.h"
|
||||||
#include "sixtp.h"
|
#include "sixtp.h"
|
||||||
|
|
||||||
#include "sixtp-parsers.h"
|
#include "sixtp-parsers.h"
|
||||||
#include "sixtp-utils.h"
|
#include "sixtp-utils.h"
|
||||||
|
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "TransLog.h"
|
#include "TransLog.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
static short module = MOD_IO;
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -47,6 +56,38 @@ ledger_data_start_handler(GSList* sibling_data, gpointer parent_data,
|
|||||||
return(ag != NULL);
|
return(ag != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
ledger_data_after_child_handler(gpointer data_for_children,
|
||||||
|
GSList* data_from_children,
|
||||||
|
GSList* sibling_data,
|
||||||
|
gpointer parent_data,
|
||||||
|
gpointer global_data,
|
||||||
|
gpointer *result,
|
||||||
|
const gchar *tag,
|
||||||
|
const gchar *child_tag,
|
||||||
|
sixtp_child_result *child_result)
|
||||||
|
{
|
||||||
|
if(!child_result) return(TRUE);
|
||||||
|
|
||||||
|
/* if we see the pricedb, deal with it */
|
||||||
|
if(child_result->type != SIXTP_CHILD_RESULT_NODE) return(TRUE);
|
||||||
|
if(strcmp(child_result->tag, "pricedb") == 0) {
|
||||||
|
GNCPriceDB *pdb = (GNCPriceDB *) child_result->data;
|
||||||
|
GNCParseStatus *status = (GNCParseStatus *) global_data;
|
||||||
|
|
||||||
|
g_return_val_if_fail(pdb, FALSE);
|
||||||
|
g_return_val_if_fail(status, FALSE);
|
||||||
|
|
||||||
|
if(status->pricedb) {
|
||||||
|
PERR("hit pricedb twice in data file.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
status->pricedb = pdb;
|
||||||
|
child_result->should_cleanup = FALSE;
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ledger_data_end_handler(gpointer data_for_children,
|
ledger_data_end_handler(gpointer data_for_children,
|
||||||
GSList *data_from_children, GSList *sibling_data,
|
GSList *data_from_children, GSList *sibling_data,
|
||||||
@ -111,6 +152,7 @@ ledger_data_parser_new(void)
|
|||||||
sixtp_new(), FALSE,
|
sixtp_new(), FALSE,
|
||||||
SIXTP_START_HANDLER_ID, ledger_data_start_handler,
|
SIXTP_START_HANDLER_ID, ledger_data_start_handler,
|
||||||
SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
|
SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
|
||||||
|
SIXTP_AFTER_CHILD_HANDLER_ID, ledger_data_after_child_handler,
|
||||||
SIXTP_END_HANDLER_ID, ledger_data_end_handler,
|
SIXTP_END_HANDLER_ID, ledger_data_end_handler,
|
||||||
SIXTP_CLEANUP_RESULT_ID, ledger_data_result_cleanup,
|
SIXTP_CLEANUP_RESULT_ID, ledger_data_result_cleanup,
|
||||||
SIXTP_FAIL_HANDLER_ID, ledger_data_fail_handler,
|
SIXTP_FAIL_HANDLER_ID, ledger_data_fail_handler,
|
||||||
@ -123,6 +165,7 @@ ledger_data_parser_new(void)
|
|||||||
if(!sixtp_add_some_sub_parsers(
|
if(!sixtp_add_some_sub_parsers(
|
||||||
top_level, TRUE,
|
top_level, TRUE,
|
||||||
"commodity", commodity_restore_parser_new(),
|
"commodity", commodity_restore_parser_new(),
|
||||||
|
"pricedb", gnc_pricedb_parser_new(),
|
||||||
"account", gnc_account_parser_new(),
|
"account", gnc_account_parser_new(),
|
||||||
"transaction", gnc_transaction_parser_new(),
|
"transaction", gnc_transaction_parser_new(),
|
||||||
0))
|
0))
|
||||||
|
@ -11,7 +11,6 @@ libgncengine_la_SOURCES = \
|
|||||||
Account.c \
|
Account.c \
|
||||||
Backend.c \
|
Backend.c \
|
||||||
DateUtils.c \
|
DateUtils.c \
|
||||||
FileIO.c \
|
|
||||||
Group.c \
|
Group.c \
|
||||||
NetIO.c \
|
NetIO.c \
|
||||||
Query.c \
|
Query.c \
|
||||||
@ -35,6 +34,8 @@ libgncengine_la_SOURCES = \
|
|||||||
gnc-engine-util.c \
|
gnc-engine-util.c \
|
||||||
gnc-event.c \
|
gnc-event.c \
|
||||||
gnc-numeric.c \
|
gnc-numeric.c \
|
||||||
|
gnc-pricedb.c \
|
||||||
|
gnc-pricedb-xml-v1.c \
|
||||||
sixtp-dom-generators.c \
|
sixtp-dom-generators.c \
|
||||||
sixtp-dom-parsers.c \
|
sixtp-dom-parsers.c \
|
||||||
sixtp-kvp-parser.c \
|
sixtp-kvp-parser.c \
|
||||||
@ -56,8 +57,6 @@ noinst_HEADERS = \
|
|||||||
AccountP.h \
|
AccountP.h \
|
||||||
BackendP.h \
|
BackendP.h \
|
||||||
DateUtils.h \
|
DateUtils.h \
|
||||||
FileIO.h \
|
|
||||||
FileIOP.h \
|
|
||||||
GNCId.h \
|
GNCId.h \
|
||||||
GNCIdP.h \
|
GNCIdP.h \
|
||||||
Group.h \
|
Group.h \
|
||||||
@ -83,6 +82,7 @@ noinst_HEADERS = \
|
|||||||
gnc-event.h \
|
gnc-event.h \
|
||||||
gnc-event-p.h \
|
gnc-event-p.h \
|
||||||
gnc-numeric.h \
|
gnc-numeric.h \
|
||||||
|
gnc-pricedb.h \
|
||||||
gnc-xml-helper.h \
|
gnc-xml-helper.h \
|
||||||
gnc-xml.h \
|
gnc-xml.h \
|
||||||
sixtp-dom-generators.h \
|
sixtp-dom-generators.h \
|
||||||
|
@ -59,8 +59,10 @@ struct _xmlend {
|
|||||||
Backend *xmlendNew (void);
|
Backend *xmlendNew (void);
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
/* Perform vaious validty checks on the reply:
|
/* Perform various validty checks on the reply:
|
||||||
* -- was the content type text/gnc-xml ?
|
* -- was the content type text/gnc-xml ?
|
||||||
* -- was there a reply body, of positive length?
|
* -- was there a reply body, of positive length?
|
||||||
* -- did the body appear to contain gnc xml data?
|
* -- did the body appear to contain gnc xml data?
|
||||||
@ -202,7 +204,8 @@ xmlbeBookLoad (Backend *bend)
|
|||||||
if (0 >= len) return NULL;
|
if (0 >= len) return NULL;
|
||||||
|
|
||||||
bufp = ghttp_get_body(request);
|
bufp = ghttp_get_body(request);
|
||||||
grp = gncxml_read_from_buf ((char *)bufp, len);
|
|
||||||
|
grp = gnc_book_load_from_buf ((char *)bufp, len);
|
||||||
|
|
||||||
LEAVE(" ");
|
LEAVE(" ");
|
||||||
return grp;
|
return grp;
|
||||||
@ -272,9 +275,12 @@ xmlbeBookEnd (Backend *b)
|
|||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Backend *
|
Backend *
|
||||||
xmlendNew (void)
|
xmlendNew (void)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
XMLBackend *be;
|
XMLBackend *be;
|
||||||
|
|
||||||
be = (XMLBackend *) malloc (sizeof (XMLBackend));
|
be = (XMLBackend *) malloc (sizeof (XMLBackend));
|
||||||
@ -300,7 +306,8 @@ xmlendNew (void)
|
|||||||
be->query_url = NULL;
|
be->query_url = NULL;
|
||||||
|
|
||||||
return (Backend *) be;
|
return (Backend *) be;
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ============================== END OF FILE ======================== */
|
/* ============================== END OF FILE ======================== */
|
||||||
|
@ -375,7 +375,7 @@ static Account *
|
|||||||
GetOrMakeAccount (AccountGroup *root, Transaction *trans,
|
GetOrMakeAccount (AccountGroup *root, Transaction *trans,
|
||||||
const char *name_root)
|
const char *name_root)
|
||||||
{
|
{
|
||||||
const gnc_commodity * currency;
|
gnc_commodity * currency;
|
||||||
char * accname;
|
char * accname;
|
||||||
Account * acc;
|
Account * acc;
|
||||||
|
|
||||||
|
@ -1049,9 +1049,10 @@ xaccIsCommonCurrency(const gnc_commodity * currency_1,
|
|||||||
return (c1c2 == 1) || (c1s2 == 1) || (s1c2 == 1) || (s1s2 == 1);
|
return (c1c2 == 1) || (c1s2 == 1) || (s1c2 == 1) || (s1s2 == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const gnc_commodity *
|
static gnc_commodity *
|
||||||
FindCommonExclSCurrency (GList *splits, const gnc_commodity * ra,
|
FindCommonExclSCurrency (GList *splits,
|
||||||
const gnc_commodity * rb, Split *excl_split)
|
gnc_commodity * ra, gnc_commodity * rb,
|
||||||
|
Split *excl_split)
|
||||||
{
|
{
|
||||||
GList *node;
|
GList *node;
|
||||||
|
|
||||||
@ -1060,7 +1061,7 @@ FindCommonExclSCurrency (GList *splits, const gnc_commodity * ra,
|
|||||||
for (node = splits; node; node = node->next)
|
for (node = splits; node; node = node->next)
|
||||||
{
|
{
|
||||||
Split *s = node->data;
|
Split *s = node->data;
|
||||||
const gnc_commodity * sa, * sb;
|
gnc_commodity * sa, * sb;
|
||||||
|
|
||||||
if (s == excl_split)
|
if (s == excl_split)
|
||||||
continue;
|
continue;
|
||||||
@ -1113,17 +1114,16 @@ FindCommonExclSCurrency (GList *splits, const gnc_commodity * ra,
|
|||||||
* don't exclude one split from the splitlist when looking for a
|
* don't exclude one split from the splitlist when looking for a
|
||||||
* common currency.
|
* common currency.
|
||||||
*/
|
*/
|
||||||
static const gnc_commodity *
|
static gnc_commodity *
|
||||||
FindCommonCurrency (GList *splits,
|
FindCommonCurrency (GList *splits, gnc_commodity * ra, gnc_commodity * rb)
|
||||||
const gnc_commodity * ra, const gnc_commodity * rb)
|
|
||||||
{
|
{
|
||||||
return FindCommonExclSCurrency(splits, ra, rb, NULL);
|
return FindCommonExclSCurrency(splits, ra, rb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccTransFindCommonCurrency (Transaction *trans)
|
xaccTransFindCommonCurrency (Transaction *trans)
|
||||||
{
|
{
|
||||||
const gnc_commodity *ra, *rb, *retval;
|
gnc_commodity *ra, *rb, *retval;
|
||||||
Split *split;
|
Split *split;
|
||||||
|
|
||||||
if (!trans) return NULL;
|
if (!trans) return NULL;
|
||||||
@ -1161,16 +1161,16 @@ xaccTransFindCommonCurrency (Transaction *trans)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccTransIsCommonCurrency (Transaction *trans, const gnc_commodity * ra)
|
xaccTransIsCommonCurrency (Transaction *trans, gnc_commodity * ra)
|
||||||
{
|
{
|
||||||
if (!trans) return NULL;
|
if (!trans) return NULL;
|
||||||
return FindCommonCurrency (trans->splits, ra, NULL);
|
return FindCommonCurrency (trans->splits, ra, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccTransIsCommonExclSCurrency (Transaction *trans,
|
xaccTransIsCommonExclSCurrency (Transaction *trans,
|
||||||
const gnc_commodity * ra,
|
gnc_commodity * ra,
|
||||||
Split *excl_split)
|
Split *excl_split)
|
||||||
{
|
{
|
||||||
if (!trans) return NULL;
|
if (!trans) return NULL;
|
||||||
@ -1182,7 +1182,7 @@ xaccTransIsCommonExclSCurrency (Transaction *trans,
|
|||||||
/* The new routine for setting the common currency */
|
/* The new routine for setting the common currency */
|
||||||
|
|
||||||
void
|
void
|
||||||
xaccTransSetCurrency (Transaction *trans, const gnc_commodity *curr)
|
xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr)
|
||||||
{
|
{
|
||||||
if (!trans || !curr) return;
|
if (!trans || !curr) return;
|
||||||
|
|
||||||
|
@ -253,8 +253,7 @@ int xaccTransCountSplits (Transaction *trans);
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
#define xaccTransGetCurrency xaccTransFindCommonCurrency
|
#define xaccTransGetCurrency xaccTransFindCommonCurrency
|
||||||
void xaccTransSetCurrency (Transaction *trans,
|
void xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr);
|
||||||
const gnc_commodity *curr);
|
|
||||||
|
|
||||||
/* ---------
|
/* ---------
|
||||||
* and now for the 'old' routines
|
* and now for the 'old' routines
|
||||||
@ -281,7 +280,7 @@ gboolean xaccIsCommonCurrency(const gnc_commodity * currency_1,
|
|||||||
* If all of the splits share both a common security and a common currency,
|
* If all of the splits share both a common security and a common currency,
|
||||||
* then the string name for the currency is returned.
|
* then the string name for the currency is returned.
|
||||||
*/
|
*/
|
||||||
const gnc_commodity * xaccTransFindCommonCurrency (Transaction *trans);
|
gnc_commodity * xaccTransFindCommonCurrency (Transaction *trans);
|
||||||
|
|
||||||
/* The xaccTransIsCommonCurrency () method compares the input commodity
|
/* The xaccTransIsCommonCurrency () method compares the input commodity
|
||||||
* to the currency/security denominations of all splits in the
|
* to the currency/security denominations of all splits in the
|
||||||
@ -299,8 +298,8 @@ const gnc_commodity * xaccTransFindCommonCurrency (Transaction *trans);
|
|||||||
* common. This routine is useful in dealing with securities of
|
* common. This routine is useful in dealing with securities of
|
||||||
* differing types as they are moved across accounts.
|
* differing types as they are moved across accounts.
|
||||||
*/
|
*/
|
||||||
const gnc_commodity * xaccTransIsCommonCurrency(Transaction *trans,
|
gnc_commodity * xaccTransIsCommonCurrency(Transaction *trans,
|
||||||
const gnc_commodity * curr);
|
gnc_commodity *curr);
|
||||||
|
|
||||||
/* The xaccTransIsCommonExclSCurrency () method compares the input
|
/* The xaccTransIsCommonExclSCurrency () method compares the input
|
||||||
* string to the currency/security denominations of all splits in
|
* string to the currency/security denominations of all splits in
|
||||||
@ -312,9 +311,9 @@ const gnc_commodity * xaccTransIsCommonCurrency(Transaction *trans,
|
|||||||
* that split is of no relevance when determining whether the new
|
* that split is of no relevance when determining whether the new
|
||||||
* entry has a common currency with the other splits.
|
* entry has a common currency with the other splits.
|
||||||
*/
|
*/
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
xaccTransIsCommonExclSCurrency (Transaction *trans,
|
xaccTransIsCommonExclSCurrency (Transaction *trans,
|
||||||
const gnc_commodity * currency,
|
gnc_commodity * currency,
|
||||||
Split *excl_split);
|
Split *excl_split);
|
||||||
|
|
||||||
/* The xaccTransGetImbalance() method returns the total value of the
|
/* The xaccTransGetImbalance() method returns the total value of the
|
||||||
|
@ -51,13 +51,23 @@ static short module = MOD_ENGINE;
|
|||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
|
|
||||||
int
|
gboolean
|
||||||
timespec_cmp (const Timespec *ta, const Timespec *tb)
|
timespec_equal (const Timespec *ta, const Timespec *tb)
|
||||||
{
|
{
|
||||||
|
if(ta == tb) return TRUE;
|
||||||
|
if(ta->tv_sec != tb->tv_sec) return FALSE;
|
||||||
|
if(ta->tv_nsec != tb->tv_nsec) return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
timespec_cmp(const Timespec *ta, const Timespec *tb)
|
||||||
|
{
|
||||||
|
if(ta == tb) return 0;
|
||||||
if(ta->tv_sec < tb->tv_sec) return -1;
|
if(ta->tv_sec < tb->tv_sec) return -1;
|
||||||
if(ta->tv_sec > tb->tv_sec) return +1;
|
if(ta->tv_sec > tb->tv_sec) return 1;
|
||||||
if(ta->tv_nsec < tb->tv_nsec) return -1;
|
if(ta->tv_nsec < tb->tv_nsec) return -1;
|
||||||
if(ta->tv_nsec > tb->tv_nsec) return +1;
|
if(ta->tv_nsec > tb->tv_nsec) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +77,10 @@ typedef struct timespec64 Timespec;
|
|||||||
|
|
||||||
/** Prototypes ******************************************************/
|
/** Prototypes ******************************************************/
|
||||||
|
|
||||||
/* The timespec_cmp() routine returns 0 if ta equals tb,
|
/* strict equality */
|
||||||
* -1 if ta<tb, and +1 if ta>tb
|
gboolean timespec_equal(const Timespec *ta, const Timespec *tb);
|
||||||
*/
|
/* comparison: if (ta < tb) -1; else if (ta > tb) 1; else 0; */
|
||||||
int timespec_cmp (const Timespec *ta, const Timespec *tb);
|
int timespec_cmp(const Timespec *ta, const Timespec *tb);
|
||||||
|
|
||||||
void setDateFormat(DateFormat df);
|
void setDateFormat(DateFormat df);
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ gnc_account_end_handler(gpointer data_for_children,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlFreeNode(result);
|
xmlFreeNode((xmlNodePtr) result);
|
||||||
|
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
@ -280,5 +280,5 @@ gnc_account_end_handler(gpointer data_for_children,
|
|||||||
sixtp*
|
sixtp*
|
||||||
gnc_account_sixtp_parser_create(void)
|
gnc_account_sixtp_parser_create(void)
|
||||||
{
|
{
|
||||||
return sixtp_dom_parser_new(gnc_account_end_handler);
|
return sixtp_dom_parser_new(gnc_account_end_handler, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
* FileIOP.h -- private header for binary file i/o *
|
* gnc-book-p.h -- private functions for gnc books. *
|
||||||
* datafile for gnucash (X-Accountant) *
|
|
||||||
* Copyright (C) 1997 Robin D. Clark *
|
|
||||||
* Copyright (C) 1998, 1999 Linas Vepstas *
|
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or *
|
* This program is free software; you can redistribute it and/or *
|
||||||
* modify it under the terms of the GNU General Public License as *
|
* modify it under the terms of the GNU General Public License as *
|
||||||
@ -20,11 +17,25 @@
|
|||||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||||
|
* *
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
|
|
||||||
#ifndef __XACC_FILEIO_P_H__
|
/*
|
||||||
#define __XACC_FILEIO_P_H__
|
* HISTORY:
|
||||||
|
* Created 2001 by Rob Browning
|
||||||
|
* Copyright (c) 2001 Rob Browning
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GNC_BOOK_P_H__
|
||||||
|
#define __GNC_BOOK_P_H__
|
||||||
|
|
||||||
|
#include "gnc-book.h"
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
|
|
||||||
#endif /* __XACC_FILEIO_P_H__ */
|
void gnc_book_set_group(GNCBook *book, AccountGroup *grp);
|
||||||
|
void gnc_book_set_pricedb(GNCBook *book, GNCPriceDB *db);
|
||||||
|
|
||||||
|
void gnc_book_mark_saved(GNCBook *book);
|
||||||
|
|
||||||
|
#endif /* __GNC_BOOK_P_H__ */
|
@ -44,12 +44,19 @@
|
|||||||
|
|
||||||
#include "Backend.h"
|
#include "Backend.h"
|
||||||
#include "BackendP.h"
|
#include "BackendP.h"
|
||||||
#include "FileIO.h"
|
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "NetIO.h"
|
#include "NetIO.h"
|
||||||
#include "Scrub.h"
|
#include "Scrub.h"
|
||||||
#include "TransLog.h"
|
#include "TransLog.h"
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
#include "gnc-pricedb-p.h"
|
||||||
|
#include "DateUtils.h"
|
||||||
|
#include "io-gncxml.h"
|
||||||
|
#include "io-gncbin.h"
|
||||||
|
|
||||||
|
|
||||||
#include "gnc-book.h"
|
#include "gnc-book.h"
|
||||||
|
#include "gnc-book-p.h"
|
||||||
#include "gnc-engine.h"
|
#include "gnc-engine.h"
|
||||||
#include "gnc-engine-util.h"
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
@ -58,6 +65,7 @@ static short module = MOD_IO;
|
|||||||
struct _gnc_book
|
struct _gnc_book
|
||||||
{
|
{
|
||||||
AccountGroup *topgroup;
|
AccountGroup *topgroup;
|
||||||
|
GNCPriceDB *pricedb;
|
||||||
|
|
||||||
/* the requested book id, in the form or a URI, such as
|
/* the requested book id, in the form or a URI, such as
|
||||||
* file:/some/where, or sql:server.host.com:555
|
* file:/some/where, or sql:server.host.com:555
|
||||||
@ -88,7 +96,7 @@ struct _gnc_book
|
|||||||
Backend *backend;
|
Backend *backend;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnc_book_clear_error (GNCBook *book)
|
gnc_book_clear_error (GNCBook *book)
|
||||||
@ -102,7 +110,7 @@ gnc_book_push_error (GNCBook *book, GNCBackendError err)
|
|||||||
book->last_err = err;
|
book->last_err = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
GNCBackendError
|
GNCBackendError
|
||||||
gnc_book_get_error (GNCBook * book)
|
gnc_book_get_error (GNCBook * book)
|
||||||
@ -121,31 +129,28 @@ gnc_book_pop_error (GNCBook * book)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnc_book_init (GNCBook *book)
|
gnc_book_init (GNCBook *book)
|
||||||
{
|
{
|
||||||
if (!book) return;
|
if(!book) return;
|
||||||
|
|
||||||
book->topgroup = xaccMallocAccountGroup ();
|
book->topgroup = xaccMallocAccountGroup();
|
||||||
|
book->pricedb = gnc_pricedb_create();
|
||||||
gnc_book_clear_error (book);
|
gnc_book_clear_error (book);
|
||||||
book->lockfd = -1;
|
book->lockfd = -1;
|
||||||
};
|
}
|
||||||
|
|
||||||
GNCBook *
|
GNCBook *
|
||||||
gnc_book_new (void)
|
gnc_book_new (void)
|
||||||
{
|
{
|
||||||
GNCBook *book;
|
GNCBook *book = g_new0(GNCBook, 1);
|
||||||
|
gnc_book_init(book);
|
||||||
book = g_new0(GNCBook, 1);
|
|
||||||
|
|
||||||
gnc_book_init (book);
|
|
||||||
|
|
||||||
return book;
|
return book;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
gnc_commodity_table*
|
gnc_commodity_table*
|
||||||
gnc_book_get_commodity_table(GNCBook *book)
|
gnc_book_get_commodity_table(GNCBook *book)
|
||||||
@ -167,7 +172,23 @@ gnc_book_set_group (GNCBook *book, AccountGroup *grp)
|
|||||||
book->topgroup = grp;
|
book->topgroup = grp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
GNCPriceDB *
|
||||||
|
gnc_book_get_pricedb(GNCBook *book)
|
||||||
|
{
|
||||||
|
if(!book) return NULL;
|
||||||
|
return book->pricedb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_book_set_pricedb(GNCBook *book, GNCPriceDB *db)
|
||||||
|
{
|
||||||
|
if(!book) return;
|
||||||
|
book->pricedb = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
Backend *
|
Backend *
|
||||||
xaccGNCBookGetBackend (GNCBook *book)
|
xaccGNCBookGetBackend (GNCBook *book)
|
||||||
@ -176,7 +197,7 @@ xaccGNCBookGetBackend (GNCBook *book)
|
|||||||
return book->backend;
|
return book->backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
gnc_book_get_file_path (GNCBook *book)
|
gnc_book_get_file_path (GNCBook *book)
|
||||||
@ -185,7 +206,7 @@ gnc_book_get_file_path (GNCBook *book)
|
|||||||
return book->fullpath;
|
return book->fullpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
gnc_book_get_url (GNCBook *book)
|
gnc_book_get_url (GNCBook *book)
|
||||||
@ -194,8 +215,16 @@ gnc_book_get_url (GNCBook *book)
|
|||||||
return book->book_id;
|
return book->book_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_book_mark_saved(GNCBook *book)
|
||||||
|
{
|
||||||
|
xaccGroupMarkSaved(gnc_book_get_group(book));
|
||||||
|
gnc_pricedb_mark_clean(gnc_book_get_pricedb(book));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
static gboolean
|
static gboolean
|
||||||
gnc_book_get_file_lock (GNCBook *book)
|
gnc_book_get_file_lock (GNCBook *book)
|
||||||
{
|
{
|
||||||
@ -266,7 +295,104 @@ gnc_book_get_file_lock (GNCBook *book)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Load financial data from a file into the book, automtically
|
||||||
|
detecting the format of the file, if possible. Return FALSE on
|
||||||
|
error, and set the error parameter to indicate what went wrong if
|
||||||
|
it's not NULL. This function does not manage file locks in any
|
||||||
|
way. */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gnc_book_load_from_file(GNCBook *book)
|
||||||
|
{
|
||||||
|
const gchar *name = gnc_book_get_file_path(book);
|
||||||
|
if(!name) return FALSE;
|
||||||
|
|
||||||
|
if(gnc_is_xml_data_file(name)) {
|
||||||
|
if(gnc_book_load_from_xml_file(book)) {
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
gnc_book_push_error(book, ERR_BACKEND_MISC);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* presume it's an old-style binary file */
|
||||||
|
GNCBackendError error;
|
||||||
|
|
||||||
|
gnc_book_load_from_binfile(book);
|
||||||
|
error = gnc_book_get_binfile_io_error();
|
||||||
|
|
||||||
|
if(error == ERR_BACKEND_NO_ERR) {
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
gnc_book_push_error(book, error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Should never get here */
|
||||||
|
gnc_book_push_error(book, ERR_BACKEND_MISC);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Write the financial data in a book to a file, returning FALSE on
|
||||||
|
error and setting the error_result to indicate what went wrong if
|
||||||
|
it's not NULL. This function does not manage file locks in any
|
||||||
|
way.
|
||||||
|
|
||||||
|
If make_backup is true, write out a time-stamped copy of the file
|
||||||
|
into the same directory as the indicated file, with a filename of
|
||||||
|
"file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
|
||||||
|
current year/month/day/hour/minute/second. */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gnc_book_write_to_file(GNCBook *book,
|
||||||
|
gboolean make_backup)
|
||||||
|
{
|
||||||
|
const gchar *datafile = gnc_book_get_file_path(book);
|
||||||
|
|
||||||
|
if(!gnc_book_write_to_xml_file(book, datafile)) {
|
||||||
|
gnc_book_push_error(book, ERR_BACKEND_MISC);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!make_backup) {
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
char * timestamp;
|
||||||
|
int filenamelen;
|
||||||
|
char * backup;
|
||||||
|
|
||||||
|
/* also, write a time-stamped backup file */
|
||||||
|
/* tag each filename with a timestamp */
|
||||||
|
timestamp = xaccDateUtilGetStampNow ();
|
||||||
|
|
||||||
|
filenamelen = strlen (datafile) + strlen (timestamp) + 6;
|
||||||
|
|
||||||
|
backup = (char *) malloc (filenamelen);
|
||||||
|
strcpy (backup, datafile);
|
||||||
|
strcat (backup, ".");
|
||||||
|
strcat (backup, timestamp);
|
||||||
|
strcat (backup, ".xac");
|
||||||
|
free (timestamp);
|
||||||
|
|
||||||
|
if(gnc_book_write_to_xml_file(book, backup)) {
|
||||||
|
free (backup);
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
gnc_book_push_error(book, ERR_BACKEND_MISC);
|
||||||
|
free (backup);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Should never get here */
|
||||||
|
gnc_book_push_error(book, ERR_BACKEND_MISC);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gnc_book_begin_file (GNCBook *book, const char * filefrag,
|
gnc_book_begin_file (GNCBook *book, const char * filefrag,
|
||||||
@ -305,7 +431,7 @@ gnc_book_begin_file (GNCBook *book, const char * filefrag,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gnc_book_begin (GNCBook *book, const char * book_id,
|
gnc_book_begin (GNCBook *book, const char * book_id,
|
||||||
@ -450,12 +576,12 @@ gnc_book_begin (GNCBook *book, const char * book_id,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gnc_book_load (GNCBook *book)
|
gnc_book_load (GNCBook *book)
|
||||||
{
|
{
|
||||||
GNCBackendError retval;
|
GNCBackendError backend_err;
|
||||||
|
|
||||||
if (!book) return FALSE;
|
if (!book) return FALSE;
|
||||||
if (!book->book_id) return FALSE;
|
if (!book->book_id) return FALSE;
|
||||||
@ -479,25 +605,25 @@ gnc_book_load (GNCBook *book)
|
|||||||
xaccGroupMarkDoFree (book->topgroup);
|
xaccGroupMarkDoFree (book->topgroup);
|
||||||
xaccFreeAccountGroup (book->topgroup);
|
xaccFreeAccountGroup (book->topgroup);
|
||||||
book->topgroup = NULL;
|
book->topgroup = NULL;
|
||||||
|
gnc_pricedb_destroy(book->pricedb);
|
||||||
|
book->pricedb = NULL;
|
||||||
|
|
||||||
xaccLogSetBaseName(book->fullpath);
|
xaccLogSetBaseName(book->fullpath);
|
||||||
|
|
||||||
gnc_book_clear_error (book);
|
gnc_book_clear_error (book);
|
||||||
book->topgroup = xaccReadAccountGroupFile (book->fullpath,
|
gnc_book_load_from_file(book);
|
||||||
&retval);
|
|
||||||
if (ERR_BACKEND_NO_ERR != retval) gnc_book_push_error (book, retval);
|
|
||||||
xaccLogEnable();
|
xaccLogEnable();
|
||||||
|
|
||||||
if (!book->topgroup || (gnc_book_get_error(book) != ERR_BACKEND_NO_ERR))
|
if (!book->topgroup) return FALSE;
|
||||||
{
|
if (!book->pricedb) return FALSE;
|
||||||
return FALSE;
|
if (gnc_book_get_error(book) != ERR_BACKEND_NO_ERR) return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
xaccGroupScrubSplits (book->topgroup);
|
xaccGroupScrubSplits (book->topgroup);
|
||||||
|
|
||||||
LEAVE("book_id=%s", book->book_id);
|
LEAVE("book_id=%s", book->book_id);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((strncmp(book->book_id, "http://", 7) == 0) ||
|
else if ((strncmp(book->book_id, "http://", 7) == 0) ||
|
||||||
(strncmp(book->book_id, "https://", 8) == 0) ||
|
(strncmp(book->book_id, "https://", 8) == 0) ||
|
||||||
(strncmp(book->book_id, "postgres://", 11) == 0))
|
(strncmp(book->book_id, "postgres://", 11) == 0))
|
||||||
@ -545,7 +671,19 @@ gnc_book_load (GNCBook *book)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_book_not_saved(GNCBook *book)
|
||||||
|
{
|
||||||
|
if(!book) return FALSE;
|
||||||
|
|
||||||
|
return(xaccGroupNotSaved(book->topgroup)
|
||||||
|
||
|
||||||
|
gnc_pricedb_dirty(book->pricedb));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gnc_book_save_may_clobber_data (GNCBook *book)
|
gnc_book_save_may_clobber_data (GNCBook *book)
|
||||||
@ -562,12 +700,11 @@ gnc_book_save_may_clobber_data (GNCBook *book)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
void
|
void
|
||||||
gnc_book_save (GNCBook *book)
|
gnc_book_save (GNCBook *book)
|
||||||
{
|
{
|
||||||
GNCBackendError retval;
|
|
||||||
Backend *be;
|
Backend *be;
|
||||||
if (!book) return;
|
if (!book) return;
|
||||||
|
|
||||||
@ -579,27 +716,26 @@ gnc_book_save (GNCBook *book)
|
|||||||
* then give the user the option to save to disk.
|
* then give the user the option to save to disk.
|
||||||
*/
|
*/
|
||||||
be = book->backend;
|
be = book->backend;
|
||||||
if (be && be->sync && book->topgroup)
|
if (be && be->sync && book->topgroup) {
|
||||||
{
|
GNCBackendError err;
|
||||||
/* if invoked as SaveAs(), then backend not yet set */
|
|
||||||
xaccGroupSetBackend (book->topgroup, be);
|
/* if invoked as SaveAs(), then backend not yet set */
|
||||||
|
xaccGroupSetBackend (book->topgroup, be);
|
||||||
|
|
||||||
(be->sync)(be, book->topgroup);
|
(be->sync)(be, book->topgroup);
|
||||||
retval = xaccBackendGetError(be);
|
err = xaccBackendGetError(be);
|
||||||
|
|
||||||
if (ERR_BACKEND_NO_ERR != retval)
|
if (ERR_BACKEND_NO_ERR != err) {
|
||||||
{
|
gnc_book_push_error (book, err);
|
||||||
gnc_book_push_error (book, retval);
|
|
||||||
|
/* we close the backend here ... isn't this a bit harsh ??? */
|
||||||
/* we close the backend here ... isn't this a bit harsh ??? */
|
if (be->book_end) {
|
||||||
if (be->book_end)
|
(be->book_end)(be);
|
||||||
{
|
}
|
||||||
(be->book_end)(be);
|
}
|
||||||
}
|
return;
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the fullpath doesn't exist, either the user failed to initialize,
|
/* if the fullpath doesn't exist, either the user failed to initialize,
|
||||||
* or the lockfile was never obtained. Either way, we can't write. */
|
* or the lockfile was never obtained. Either way, we can't write. */
|
||||||
gnc_book_clear_error (book);
|
gnc_book_clear_error (book);
|
||||||
@ -610,16 +746,15 @@ gnc_book_save (GNCBook *book)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (book->topgroup)
|
if (book->topgroup) {
|
||||||
{
|
if(!gnc_book_write_to_file(book, TRUE)) {
|
||||||
xaccWriteAccountGroupFile (book->fullpath, book->topgroup,
|
gnc_book_push_error (book, ERR_BACKEND_MISC);
|
||||||
TRUE, &retval);
|
}
|
||||||
if (ERR_BACKEND_NO_ERR != retval) gnc_book_push_error (book, retval);
|
|
||||||
}
|
}
|
||||||
LEAVE(" ");
|
LEAVE(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
void
|
void
|
||||||
gnc_book_end (GNCBook *book)
|
gnc_book_end (GNCBook *book)
|
||||||
@ -677,6 +812,10 @@ gnc_book_destroy (GNCBook *book)
|
|||||||
|
|
||||||
xaccFreeAccountGroup (book->topgroup);
|
xaccFreeAccountGroup (book->topgroup);
|
||||||
book->topgroup = NULL;
|
book->topgroup = NULL;
|
||||||
|
|
||||||
|
gnc_pricedb_destroy (book->pricedb);
|
||||||
|
book->pricedb = NULL;
|
||||||
|
|
||||||
xaccLogEnable();
|
xaccLogEnable();
|
||||||
|
|
||||||
g_free (book);
|
g_free (book);
|
||||||
@ -684,7 +823,7 @@ gnc_book_destroy (GNCBook *book)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
/*
|
/*
|
||||||
* If $HOME/.gnucash/data directory doesn't exist, then create it.
|
* If $HOME/.gnucash/data directory doesn't exist, then create it.
|
||||||
*/
|
*/
|
||||||
@ -723,7 +862,7 @@ MakeHomeDir (void)
|
|||||||
g_free (data);
|
g_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
/* XXX hack alert -- we should be yanking this out of some config file */
|
/* XXX hack alert -- we should be yanking this out of some config file */
|
||||||
static char * searchpaths[] =
|
static char * searchpaths[] =
|
||||||
{
|
{
|
||||||
@ -858,7 +997,7 @@ xaccResolveFilePath (const char * filefrag)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================== */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
char *
|
char *
|
||||||
xaccResolveURL (const char * pathfrag)
|
xaccResolveURL (const char * pathfrag)
|
||||||
@ -886,5 +1025,3 @@ xaccResolveURL (const char * pathfrag)
|
|||||||
|
|
||||||
return (xaccResolveFilePath (pathfrag));
|
return (xaccResolveFilePath (pathfrag));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== END OF FILE ================== */
|
|
||||||
|
@ -54,10 +54,11 @@
|
|||||||
#define __GNC_BOOK_H__
|
#define __GNC_BOOK_H__
|
||||||
|
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "FileIO.h"
|
#include "Backend.h"
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
|
||||||
|
/** TYPES **********************************************************/
|
||||||
|
|
||||||
/** TYPEDEFS ********************************************************/
|
|
||||||
typedef struct _gnc_book GNCBook;
|
typedef struct _gnc_book GNCBook;
|
||||||
|
|
||||||
/** PROTOTYPES ******************************************************/
|
/** PROTOTYPES ******************************************************/
|
||||||
@ -116,14 +117,9 @@ gboolean gnc_book_load (GNCBook *book);
|
|||||||
GNCBackendError gnc_book_get_error (GNCBook *book);
|
GNCBackendError gnc_book_get_error (GNCBook *book);
|
||||||
GNCBackendError gnc_book_pop_error (GNCBook *book);
|
GNCBackendError gnc_book_pop_error (GNCBook *book);
|
||||||
|
|
||||||
/* The gnc_book_get_group() method will return the current top-level
|
|
||||||
* account group.
|
|
||||||
*
|
|
||||||
* The gnc_book_set_group() method will set the topgroup to a new value.
|
|
||||||
*/
|
|
||||||
AccountGroup * gnc_book_get_group (GNCBook *book);
|
|
||||||
void gnc_book_set_group (GNCBook *book, AccountGroup *topgroup);
|
|
||||||
|
|
||||||
|
AccountGroup *gnc_book_get_group (GNCBook *book);
|
||||||
|
GNCPriceDB *gnc_book_get_pricedb (GNCBook *book);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gnc_book_get_commodity_table returns the commodity table associated with
|
* gnc_book_get_commodity_table returns the commodity table associated with
|
||||||
@ -148,6 +144,12 @@ gnc_commodity_table* gnc_book_get_commodity_table(GNCBook *book);
|
|||||||
const char * gnc_book_get_file_path (GNCBook *book);
|
const char * gnc_book_get_file_path (GNCBook *book);
|
||||||
const char * gnc_book_get_url (GNCBook *book);
|
const char * gnc_book_get_url (GNCBook *book);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The gnc_book_not_saved() subroutine will return TRUE
|
||||||
|
* if any data in the book hasn't been saved to long-term storage.
|
||||||
|
*/
|
||||||
|
gboolean gnc_book_not_saved(GNCBook *book);
|
||||||
|
|
||||||
/* FIXME: This isn't as thorough as we might want it to be... */
|
/* FIXME: This isn't as thorough as we might want it to be... */
|
||||||
gboolean gnc_book_save_may_clobber_data (GNCBook *book);
|
gboolean gnc_book_save_may_clobber_data (GNCBook *book);
|
||||||
|
|
||||||
|
@ -141,5 +141,5 @@ gnc_commodity_end_handler(gpointer data_for_children,
|
|||||||
sixtp*
|
sixtp*
|
||||||
gnc_commodity_sixtp_parser_create(void)
|
gnc_commodity_sixtp_parser_create(void)
|
||||||
{
|
{
|
||||||
return sixtp_dom_parser_new(gnc_commodity_end_handler);
|
return sixtp_dom_parser_new(gnc_commodity_end_handler, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
@ -261,5 +261,36 @@ gnc_strisnum(const char *s)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************\
|
||||||
|
See header for docs.
|
||||||
|
\********************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
kv_pair_helper(gpointer key, gpointer val, gpointer user_data)
|
||||||
|
{
|
||||||
|
GSList **result = (GSList **) user_data;
|
||||||
|
GHashTableKVPair *kvp = g_new(GHashTableKVPair, 1);
|
||||||
|
|
||||||
|
kvp->key = key;
|
||||||
|
kvp->value = val;
|
||||||
|
*result = g_slist_prepend(*result, kvp);
|
||||||
|
}
|
||||||
|
|
||||||
|
GSList *
|
||||||
|
g_hash_table_key_value_pairs(GHashTable *table)
|
||||||
|
{
|
||||||
|
GSList *result_list = NULL;
|
||||||
|
g_hash_table_foreach(table, kv_pair_helper, &result_list);
|
||||||
|
return result_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_hash_table_kv_pair_free_gfunc(gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTableKVPair *kvp = (GHashTableKVPair *) data;
|
||||||
|
g_free(kvp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************* END OF FILE ******************************\
|
/************************* END OF FILE ******************************\
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
|
@ -171,4 +171,30 @@ char * ultostr (unsigned long val, int base);
|
|||||||
* whitespace. */
|
* whitespace. */
|
||||||
gboolean gnc_strisnum(const char *s);
|
gboolean gnc_strisnum(const char *s);
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************\
|
||||||
|
|
||||||
|
g_hash_table_key_value_pairs(hash): Returns a GSList* of all the
|
||||||
|
keys and values in a given hash table. Data elements of lists are
|
||||||
|
actual hash elements, so be careful, and deallocation of the
|
||||||
|
GHashTableKVPairs in the result list are the caller's
|
||||||
|
responsibility. A typical sequence might look like this:
|
||||||
|
|
||||||
|
GSList *kvps = g_hash_table_key_value_pairs(hash);
|
||||||
|
... use kvps->data->key and kvps->data->val, etc. here ...
|
||||||
|
g_slist_foreach(kvps, g_hash_table_kv_pair_free_gfunc, NULL);
|
||||||
|
g_slist_free(kvps);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gpointer key;
|
||||||
|
gpointer value;
|
||||||
|
} GHashTableKVPair;
|
||||||
|
|
||||||
|
GSList *g_hash_table_key_value_pairs(GHashTable *table);
|
||||||
|
void g_hash_table_kv_pair_free_gfunc(gpointer data, gpointer user_data);
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
34
src/engine/gnc-pricedb-p.h
Normal file
34
src/engine/gnc-pricedb-p.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/********************************************************************
|
||||||
|
* gnc-pricedb-p.h -- a simple price database for gnucash. *
|
||||||
|
* Copyright (C) 2001 Rob Browning *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||||
|
* *
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
#ifndef __GNC_PRICEDB_P_H__
|
||||||
|
#define __GNC_PRICEDB_P_H__
|
||||||
|
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
|
||||||
|
void gnc_pricedb_mark_clean(GNCPriceDB *db);
|
||||||
|
void gnc_pricedb_substitute_commodity(GNCPriceDB *db,
|
||||||
|
gnc_commodity *old_c,
|
||||||
|
gnc_commodity *new_c);
|
||||||
|
|
||||||
|
#endif
|
373
src/engine/gnc-pricedb-xml-v1.c
Normal file
373
src/engine/gnc-pricedb-xml-v1.c
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
|
#include "sixtp.h"
|
||||||
|
#include "sixtp-utils.h"
|
||||||
|
#include "sixtp-parsers.h"
|
||||||
|
#include "sixtp-dom-parsers.h"
|
||||||
|
#include "sixtp-dom-generators.h"
|
||||||
|
#include "sixtp-writers.h"
|
||||||
|
#include "sixtp-xml-write-utils.h"
|
||||||
|
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
static short module = MOD_ENGINE;
|
||||||
|
|
||||||
|
/* Read and Write the pricedb as XML -- something like this:
|
||||||
|
|
||||||
|
<pricedb>
|
||||||
|
price-1
|
||||||
|
price-2
|
||||||
|
...
|
||||||
|
</pricedb>
|
||||||
|
|
||||||
|
where each price should look roughly like this:
|
||||||
|
|
||||||
|
<price>
|
||||||
|
<price:commodity>
|
||||||
|
<cmdty:space>NASDAQ</cmdty:space>
|
||||||
|
<cmdty:id>RHAT</cmdty:id>
|
||||||
|
</price:commodity>
|
||||||
|
<price:currency>
|
||||||
|
<cmdty:space>ISO?</cmdty:space>
|
||||||
|
<cmdty:id>USD</cmdty:id>
|
||||||
|
</price:currency>
|
||||||
|
<price:time><ts:date>Mon ...</ts:date><ts:ns>12</ts:ns></price:time>
|
||||||
|
<price:source>Finance::Quote</price:source>
|
||||||
|
<price:type>bid</price:type>
|
||||||
|
<price:value>11011/100</price:value>
|
||||||
|
</price>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* READING */
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* <price>
|
||||||
|
|
||||||
|
restores a price. Does so via a walk of the XML tree in memory.
|
||||||
|
Returns a GNCPrice * in result.
|
||||||
|
|
||||||
|
Right now, a price is legitimate even if all of it's fields are not
|
||||||
|
set. We may need to change that later, but at the moment.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
price_parse_xml_sub_node(GNCPrice *p, xmlNodePtr sub_node)
|
||||||
|
{
|
||||||
|
if(!p || !sub_node) return FALSE;
|
||||||
|
|
||||||
|
if(safe_strcmp("price:commodity", sub_node->name) == 0) {
|
||||||
|
gnc_commodity *c = dom_tree_to_commodity_ref(sub_node);
|
||||||
|
if(!c) return FALSE;
|
||||||
|
gnc_price_set_commodity(p, c);
|
||||||
|
} else if(safe_strcmp("price:currency", sub_node->name) == 0) {
|
||||||
|
gnc_commodity *c = dom_tree_to_commodity_ref(sub_node);
|
||||||
|
if(!c) return FALSE;
|
||||||
|
gnc_price_set_currency(p, c);
|
||||||
|
} else if(safe_strcmp("price:time", sub_node->name) == 0) {
|
||||||
|
Timespec *t = dom_tree_to_timespec(sub_node);
|
||||||
|
if(!t) return FALSE;
|
||||||
|
gnc_price_set_time(p, t);
|
||||||
|
g_free(t);
|
||||||
|
} else if(safe_strcmp("price:source", sub_node->name) == 0) {
|
||||||
|
char *text = dom_tree_to_text(sub_node->xmlChildrenNode);
|
||||||
|
if(!text) return FALSE;
|
||||||
|
gnc_price_set_source(p, text);
|
||||||
|
g_free(text);
|
||||||
|
} else if(safe_strcmp("price:type", sub_node->name) == 0) {
|
||||||
|
char *text = dom_tree_to_text(sub_node->xmlChildrenNode);
|
||||||
|
if(!text) return FALSE;
|
||||||
|
gnc_price_set_type(p, text);
|
||||||
|
g_free(text);
|
||||||
|
} else if(safe_strcmp("price:value", sub_node->name) == 0) {
|
||||||
|
gnc_numeric *value = dom_tree_to_gnc_numeric(sub_node);
|
||||||
|
if(!value) return FALSE;
|
||||||
|
gnc_price_set_value(p, *value);
|
||||||
|
g_free(value);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
price_parse_xml_end_handler(gpointer data_for_children,
|
||||||
|
GSList* data_from_children,
|
||||||
|
GSList* sibling_data,
|
||||||
|
gpointer parent_data,
|
||||||
|
gpointer global_data,
|
||||||
|
gpointer *result,
|
||||||
|
const gchar *tag)
|
||||||
|
{
|
||||||
|
gboolean ok = TRUE;
|
||||||
|
xmlNodePtr price_xml = (xmlNodePtr) data_for_children;
|
||||||
|
xmlNodePtr child;
|
||||||
|
GNCPrice *p = NULL;
|
||||||
|
|
||||||
|
/* we haven't been handed the *top* level node yet... */
|
||||||
|
if(parent_data) return TRUE;
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
|
||||||
|
if(!price_xml) return FALSE;
|
||||||
|
if(price_xml->next) { ok = FALSE; goto cleanup_and_exit; }
|
||||||
|
if(price_xml->prev) { ok = FALSE; goto cleanup_and_exit; }
|
||||||
|
if(!price_xml->xmlChildrenNode) { ok = FALSE; goto cleanup_and_exit; }
|
||||||
|
|
||||||
|
p = gnc_price_create();
|
||||||
|
if(!p) { ok = FALSE; goto cleanup_and_exit; }
|
||||||
|
|
||||||
|
for(child = price_xml->xmlChildrenNode; child; child = child->next) {
|
||||||
|
switch(child->type) {
|
||||||
|
case XML_COMMENT_NODE:
|
||||||
|
break;
|
||||||
|
case XML_ELEMENT_NODE:
|
||||||
|
if(!price_parse_xml_sub_node(p, child)) {
|
||||||
|
ok = FALSE;
|
||||||
|
goto cleanup_and_exit;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PERR("Unknown node type (%d) while parsing gnc-price xml.", child->type);
|
||||||
|
child = NULL;
|
||||||
|
ok = FALSE;
|
||||||
|
goto cleanup_and_exit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_and_exit:
|
||||||
|
if(ok) {
|
||||||
|
*result = p;
|
||||||
|
} else {
|
||||||
|
*result = NULL;
|
||||||
|
gnc_price_unref(p);
|
||||||
|
}
|
||||||
|
xmlFreeNode(price_xml);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cleanup_gnc_price(sixtp_child_result *result)
|
||||||
|
{
|
||||||
|
if(result->data) gnc_price_unref((GNCPrice *) result->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sixtp *
|
||||||
|
gnc_price_parser_new (void)
|
||||||
|
{
|
||||||
|
return sixtp_dom_parser_new(price_parse_xml_end_handler,
|
||||||
|
cleanup_gnc_price,
|
||||||
|
cleanup_gnc_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* <pricedb> (lineage <ledger-data>)
|
||||||
|
|
||||||
|
restores a pricedb. We allocate the new db in the start block, the
|
||||||
|
children add to it, and it gets returned in result. Note that the
|
||||||
|
cleanup handler will destroy the pricedb, so the parent needs to
|
||||||
|
stop that if desired.
|
||||||
|
|
||||||
|
result: GNCPriceDB*
|
||||||
|
|
||||||
|
start: create new GNCPriceDB*, and leave in *data_for_children.
|
||||||
|
cleanup-result: destroy GNCPriceDB*
|
||||||
|
result-fail: destroy GNCPriceDB*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pricedb_start_handler(GSList* sibling_data,
|
||||||
|
gpointer parent_data,
|
||||||
|
gpointer global_data,
|
||||||
|
gpointer *data_for_children,
|
||||||
|
gpointer *result,
|
||||||
|
const gchar *tag,
|
||||||
|
gchar **attrs)
|
||||||
|
{
|
||||||
|
GNCPriceDB *db = gnc_pricedb_create();
|
||||||
|
g_return_val_if_fail(db, FALSE);
|
||||||
|
*result = db;
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pricedb_after_child_handler(gpointer data_for_children,
|
||||||
|
GSList* data_from_children,
|
||||||
|
GSList* sibling_data,
|
||||||
|
gpointer parent_data,
|
||||||
|
gpointer global_data,
|
||||||
|
gpointer *result,
|
||||||
|
const gchar *tag,
|
||||||
|
const gchar *child_tag,
|
||||||
|
sixtp_child_result *child_result)
|
||||||
|
{
|
||||||
|
GNCPriceDB *db = (GNCPriceDB *) *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail(db, FALSE);
|
||||||
|
|
||||||
|
/* right now children have to produce results :> */
|
||||||
|
if(!child_result) return(FALSE);
|
||||||
|
if(child_result->type != SIXTP_CHILD_RESULT_NODE) return(FALSE);
|
||||||
|
|
||||||
|
if(strcmp(child_result->tag, "price") == 0) {
|
||||||
|
GNCPrice *p = (GNCPrice *) child_result->data;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
gnc_pricedb_add_price(db, p);
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pricedb_cleanup_result_handler(sixtp_child_result *result)
|
||||||
|
{
|
||||||
|
if(result->data) {
|
||||||
|
GNCPriceDB *db = (GNCPriceDB *) result->data;
|
||||||
|
if(db) gnc_pricedb_destroy(db);
|
||||||
|
result->data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sixtp*
|
||||||
|
gnc_pricedb_parser_new(void)
|
||||||
|
{
|
||||||
|
sixtp *top_level;
|
||||||
|
sixtp *price_parser;
|
||||||
|
|
||||||
|
top_level =
|
||||||
|
sixtp_set_any(sixtp_new(), TRUE,
|
||||||
|
SIXTP_START_HANDLER_ID, pricedb_start_handler,
|
||||||
|
SIXTP_AFTER_CHILD_HANDLER_ID, pricedb_after_child_handler,
|
||||||
|
SIXTP_CHARACTERS_HANDLER_ID,
|
||||||
|
allow_and_ignore_only_whitespace,
|
||||||
|
SIXTP_RESULT_FAIL_ID, pricedb_cleanup_result_handler,
|
||||||
|
SIXTP_CLEANUP_RESULT_ID, pricedb_cleanup_result_handler,
|
||||||
|
SIXTP_NO_MORE_HANDLERS);
|
||||||
|
|
||||||
|
if(!top_level) return NULL;
|
||||||
|
|
||||||
|
price_parser = gnc_price_parser_new();
|
||||||
|
|
||||||
|
if(!price_parser) {
|
||||||
|
sixtp_destroy(top_level);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sixtp_add_sub_parser(top_level, "price", price_parser);
|
||||||
|
return top_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* WRITING */
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
add_child_or_kill_parent(xmlNodePtr parent, xmlNodePtr child)
|
||||||
|
{
|
||||||
|
if(!parent) return FALSE;
|
||||||
|
if(!child) {
|
||||||
|
xmlFreeNode(parent);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
xmlAddChild(parent, child);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlNodePtr
|
||||||
|
gnc_price_to_dom_tree(const char *tag, GNCPrice *price)
|
||||||
|
{
|
||||||
|
xmlNodePtr price_xml;
|
||||||
|
const gchar *typestr, *sourcestr;
|
||||||
|
xmlNodePtr tmpnode;
|
||||||
|
gnc_commodity *commodity;
|
||||||
|
gnc_commodity *currency;
|
||||||
|
Timespec *timesp;
|
||||||
|
gnc_numeric value;
|
||||||
|
|
||||||
|
if (!(tag && price)) return NULL;
|
||||||
|
|
||||||
|
price_xml = xmlNewNode(NULL, tag);
|
||||||
|
if(!price_xml) return NULL;
|
||||||
|
|
||||||
|
commodity = gnc_price_get_commodity(price);
|
||||||
|
currency = gnc_price_get_currency(price);
|
||||||
|
|
||||||
|
if(!(commodity && currency)) return NULL;
|
||||||
|
|
||||||
|
tmpnode = commodity_ref_to_dom_tree("price:commodity", commodity);
|
||||||
|
if(!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
|
||||||
|
|
||||||
|
tmpnode = commodity_ref_to_dom_tree("price:currency", currency);
|
||||||
|
if(!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
|
||||||
|
|
||||||
|
timesp = gnc_price_get_time(price);
|
||||||
|
tmpnode = timespec_to_dom_tree("price:time", timesp);
|
||||||
|
if(!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
|
||||||
|
|
||||||
|
sourcestr = gnc_price_get_source(price);
|
||||||
|
if(sourcestr && (strlen(sourcestr) != 0)) {
|
||||||
|
tmpnode = text_to_dom_tree("price:source", sourcestr);
|
||||||
|
if(!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typestr = gnc_price_get_type(price);
|
||||||
|
if(typestr && (strlen(typestr) != 0)) {
|
||||||
|
tmpnode = text_to_dom_tree("price:type", typestr);
|
||||||
|
if(!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = gnc_price_get_value(price);
|
||||||
|
tmpnode = gnc_numeric_to_dom_tree("price:value", &value);
|
||||||
|
if(!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
|
||||||
|
|
||||||
|
return price_xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_gnc_price_adapter(GNCPrice *p, gpointer data)
|
||||||
|
{
|
||||||
|
xmlNodePtr xml_node = (xmlNodePtr) data;
|
||||||
|
|
||||||
|
if(p) {
|
||||||
|
xmlNodePtr price_xml = gnc_price_to_dom_tree("price", p);
|
||||||
|
if(!price_xml) return FALSE;
|
||||||
|
xmlAddChild(xml_node, price_xml);
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_gnc_pricedb(xmlNodePtr p, const char *tag, GNCPriceDB *db)
|
||||||
|
{
|
||||||
|
xmlNodePtr db_xml = NULL;
|
||||||
|
|
||||||
|
if(!p || !tag) return FALSE;
|
||||||
|
if(!db) return TRUE;
|
||||||
|
|
||||||
|
db_xml= xmlNewTextChild(p, NULL, tag, NULL);
|
||||||
|
if(!db_xml) return FALSE;
|
||||||
|
|
||||||
|
xmlSetProp(db_xml, "version", "1");
|
||||||
|
|
||||||
|
if(!gnc_pricedb_foreach_price(db, xml_add_gnc_price_adapter, db_xml, TRUE))
|
||||||
|
{
|
||||||
|
xmlFreeNode(db_xml);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
733
src/engine/gnc-pricedb.c
Normal file
733
src/engine/gnc-pricedb.c
Normal file
@ -0,0 +1,733 @@
|
|||||||
|
/********************************************************************
|
||||||
|
* gnc-pricedb.c -- a simple price database for gnucash. *
|
||||||
|
* Copyright (C) 2001 Rob Browning *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||||
|
* *
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
#include "gnc-pricedb-p.h"
|
||||||
|
#include "gnc-engine.h"
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
static short module = MOD_ENGINE;
|
||||||
|
|
||||||
|
struct _GNCPriceDB {
|
||||||
|
GHashTable *commodity_hash;
|
||||||
|
gboolean dirty;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GNCPrice {
|
||||||
|
guint32 refcount;
|
||||||
|
GNCPriceDB *db;
|
||||||
|
gnc_commodity *commodity;
|
||||||
|
gnc_commodity *currency;
|
||||||
|
Timespec time;
|
||||||
|
char *source;
|
||||||
|
char *type;
|
||||||
|
gnc_numeric value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* GNCPrice functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* allocation */
|
||||||
|
GNCPrice *
|
||||||
|
gnc_price_create()
|
||||||
|
{
|
||||||
|
GNCPrice *p = g_new0(GNCPrice, 1);
|
||||||
|
p->refcount = 1;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_ref(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
p->refcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_unref(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(p->refcount == 0) {
|
||||||
|
PERR("gnc_price_unref: refcount == 0!");
|
||||||
|
assert(p->refcount != 0);
|
||||||
|
}
|
||||||
|
p->refcount--;
|
||||||
|
if(p->refcount == 0) {
|
||||||
|
if(p->type) g_cache_remove(gnc_engine_get_string_cache(), p->type);
|
||||||
|
memset(p, 0, sizeof(GNCPrice));
|
||||||
|
g_free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GNCPrice *
|
||||||
|
gnc_price_clone(GNCPrice* p)
|
||||||
|
{
|
||||||
|
/* the clone doesn't belong to a PriceDB */
|
||||||
|
GNCPrice *new_p;
|
||||||
|
|
||||||
|
if(!p) return NULL;
|
||||||
|
new_p = gnc_price_create();
|
||||||
|
if(!new_p) return NULL;
|
||||||
|
gnc_price_set_commodity(new_p, gnc_price_get_commodity(p));
|
||||||
|
gnc_price_set_time(new_p, gnc_price_get_time(p));
|
||||||
|
gnc_price_set_source(new_p, gnc_price_get_source(p));
|
||||||
|
gnc_price_set_type(new_p, gnc_price_get_type(p));
|
||||||
|
gnc_price_set_value(new_p, gnc_price_get_value(p));
|
||||||
|
gnc_price_set_currency(new_p, gnc_price_get_currency(p));
|
||||||
|
return(new_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setters */
|
||||||
|
void
|
||||||
|
gnc_price_set_commodity(GNCPrice *p, gnc_commodity *c)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(!gnc_commodity_equiv(p->commodity, c)) {
|
||||||
|
p->commodity = c;
|
||||||
|
if(p->db) p->db->dirty = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_set_currency(GNCPrice *p, gnc_commodity *c)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(!gnc_commodity_equiv(p->currency, c)) {
|
||||||
|
p->currency = c;
|
||||||
|
if(p->db) p->db->dirty = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_set_time(GNCPrice *p, Timespec *t)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(!timespec_equal(&(p->time), t)) {
|
||||||
|
p->time = *t;
|
||||||
|
if(p->db) p->db->dirty = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_set_source(GNCPrice *p, const char *s)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(safe_strcmp(p->source, s) != 0) {
|
||||||
|
GCache *cache = gnc_engine_get_string_cache();
|
||||||
|
char *tmp = g_cache_insert(cache, (gpointer) s);
|
||||||
|
if(p->source) g_cache_remove(cache, p->source);
|
||||||
|
p->source = tmp;
|
||||||
|
if(p->db) p->db->dirty = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_set_type(GNCPrice *p, const char* type)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(safe_strcmp(p->type, type) != 0) {
|
||||||
|
GCache *cache = gnc_engine_get_string_cache();
|
||||||
|
gchar *tmp = g_cache_insert(cache, (gpointer) type);
|
||||||
|
if(p->type) g_cache_remove(cache, p->type);
|
||||||
|
p->type = tmp;
|
||||||
|
if(p->db) p->db->dirty = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_set_value(GNCPrice *p, gnc_numeric value)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
if(!gnc_numeric_eq(p->value, value)) {
|
||||||
|
p->value = value;
|
||||||
|
if(p->db) p->db->dirty = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********/
|
||||||
|
/* getters */
|
||||||
|
gnc_commodity *
|
||||||
|
gnc_price_get_commodity(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return NULL;
|
||||||
|
return p->commodity;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timespec *
|
||||||
|
gnc_price_get_time(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return NULL;
|
||||||
|
return &(p->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
gnc_price_get_source(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return NULL;
|
||||||
|
return p->source;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
gnc_price_get_type(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return NULL;
|
||||||
|
return p->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnc_numeric
|
||||||
|
gnc_price_get_value(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) {
|
||||||
|
PERR("gnc_price_get_value: price NULL.\n");
|
||||||
|
return gnc_numeric_zero();
|
||||||
|
}
|
||||||
|
return p->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnc_commodity *
|
||||||
|
gnc_price_get_currency(GNCPrice *p)
|
||||||
|
{
|
||||||
|
if(!p) return NULL;
|
||||||
|
return p->currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setters */
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_prices_by_date(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
Timespec *time_a;
|
||||||
|
Timespec *time_b;
|
||||||
|
if(!a && !b) return 0;
|
||||||
|
/* nothing is always less than something */
|
||||||
|
if(!a) return -1;
|
||||||
|
|
||||||
|
time_a = gnc_price_get_time((GNCPrice *) a);
|
||||||
|
time_b = gnc_price_get_time((GNCPrice *) b);
|
||||||
|
return timespec_cmp(time_a, time_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_price_list_insert(GList **prices, GNCPrice *p)
|
||||||
|
{
|
||||||
|
GList *result_list;
|
||||||
|
|
||||||
|
if(!prices) return FALSE;
|
||||||
|
if(!p) return FALSE;
|
||||||
|
gnc_price_ref(p);
|
||||||
|
result_list = g_list_insert_sorted(*prices, p, compare_prices_by_date);
|
||||||
|
if(!result_list) return FALSE;
|
||||||
|
*prices = result_list;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_price_list_remove(GList **prices, GNCPrice *p)
|
||||||
|
{
|
||||||
|
GList *result_list;
|
||||||
|
GList *found_element;
|
||||||
|
|
||||||
|
if(!prices) return FALSE;
|
||||||
|
if(!p) return FALSE;
|
||||||
|
|
||||||
|
found_element = g_list_find(*prices, p);
|
||||||
|
if(!found_element) return TRUE;
|
||||||
|
|
||||||
|
result_list = g_list_remove_link(*prices, found_element);
|
||||||
|
gnc_price_unref((GNCPrice *) found_element->data);
|
||||||
|
g_list_free(found_element);
|
||||||
|
|
||||||
|
*prices = result_list;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
price_list_destroy_helper(gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
gnc_price_unref((GNCPrice *) data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_list_destroy(GList *prices)
|
||||||
|
{
|
||||||
|
g_list_foreach(prices, price_list_destroy_helper, NULL);
|
||||||
|
g_list_free(prices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* GNCPriceDB functions
|
||||||
|
|
||||||
|
A pricedb is a hash mapping price commodities (of type
|
||||||
|
gnc_commodity*) to hashes mapping price currencies (of type
|
||||||
|
gnc_commodity*) to price lists. The top-level key is the commodity
|
||||||
|
you want the prices for, and the second level key is the commodity
|
||||||
|
that the value is expressed in terms of.
|
||||||
|
|
||||||
|
See the header for other info.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
GNCPriceDB *
|
||||||
|
gnc_pricedb_create()
|
||||||
|
{
|
||||||
|
GNCPriceDB * result = g_new0(GNCPriceDB, 1);
|
||||||
|
result->commodity_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
|
g_return_val_if_fail (result->commodity_hash, NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_pricedb_currency_hash_data(gpointer key,
|
||||||
|
gpointer data,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GList *price_list = (GList *) data;
|
||||||
|
gnc_price_list_destroy(price_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_pricedb_commodity_hash_data(gpointer key,
|
||||||
|
gpointer data,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTable *currency_hash = (GHashTable *) data;
|
||||||
|
if (!currency_hash) return;
|
||||||
|
g_hash_table_foreach (currency_hash,
|
||||||
|
destroy_pricedb_currency_hash_data,
|
||||||
|
NULL);
|
||||||
|
g_hash_table_destroy(currency_hash);
|
||||||
|
currency_hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_pricedb_dirty(GNCPriceDB *p)
|
||||||
|
{
|
||||||
|
if(!p) return FALSE;
|
||||||
|
return p->dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_pricedb_mark_clean(GNCPriceDB *p)
|
||||||
|
{
|
||||||
|
if(!p) return;
|
||||||
|
p->dirty = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_pricedb_destroy(GNCPriceDB *db)
|
||||||
|
{
|
||||||
|
if(!db) return;
|
||||||
|
g_hash_table_foreach (db->commodity_hash,
|
||||||
|
destroy_pricedb_commodity_hash_data,
|
||||||
|
NULL);
|
||||||
|
g_hash_table_destroy (db->commodity_hash);
|
||||||
|
db->commodity_hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
|
||||||
|
{
|
||||||
|
/* this function will use p, adding a ref, so treat p as read-only
|
||||||
|
if this function succeeds. */
|
||||||
|
GList *price_list;
|
||||||
|
gnc_commodity *commodity;
|
||||||
|
gnc_commodity *currency;
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
|
||||||
|
if(!db || !p) return FALSE;
|
||||||
|
commodity = gnc_price_get_commodity(p);
|
||||||
|
if(!commodity) return FALSE;
|
||||||
|
currency = gnc_price_get_currency(p);
|
||||||
|
if(!currency) return FALSE;
|
||||||
|
if(!db->commodity_hash) return FALSE;
|
||||||
|
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
|
||||||
|
if(!currency_hash) {
|
||||||
|
currency_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
|
g_hash_table_insert(db->commodity_hash, commodity, currency_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
price_list = g_hash_table_lookup(currency_hash, currency);
|
||||||
|
if(!gnc_price_list_insert(&price_list, p)) return FALSE;
|
||||||
|
if(!price_list) return FALSE;
|
||||||
|
g_hash_table_insert(currency_hash, currency, price_list);
|
||||||
|
db->dirty = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p)
|
||||||
|
{
|
||||||
|
GList *price_list;
|
||||||
|
gnc_commodity *commodity;
|
||||||
|
gnc_commodity *currency;
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
|
||||||
|
if(!db || !p) return FALSE;
|
||||||
|
commodity = gnc_price_get_commodity(p);
|
||||||
|
if(!commodity) return FALSE;
|
||||||
|
currency = gnc_price_get_currency(p);
|
||||||
|
if(!currency) return FALSE;
|
||||||
|
if(!db->commodity_hash) return FALSE;
|
||||||
|
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
|
||||||
|
if(!currency_hash) return FALSE;
|
||||||
|
|
||||||
|
price_list = g_hash_table_lookup(currency_hash, currency);
|
||||||
|
if(!gnc_price_list_remove(&price_list, p)) return FALSE;
|
||||||
|
if(price_list) {
|
||||||
|
g_hash_table_insert(currency_hash, currency, price_list);
|
||||||
|
} else {
|
||||||
|
g_hash_table_remove(currency_hash, currency);
|
||||||
|
}
|
||||||
|
db->dirty = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GNCPrice *
|
||||||
|
gnc_pricedb_lookup_latest(GNCPriceDB *db,
|
||||||
|
gnc_commodity *commodity,
|
||||||
|
gnc_commodity *currency)
|
||||||
|
{
|
||||||
|
GList *price_list;
|
||||||
|
GNCPrice *result;
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
|
||||||
|
if(!db || !commodity || !currency) return NULL;
|
||||||
|
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
|
||||||
|
if(!currency_hash) return NULL;
|
||||||
|
|
||||||
|
price_list = g_hash_table_lookup(currency_hash, currency);
|
||||||
|
if(!price_list) return NULL;
|
||||||
|
|
||||||
|
result = price_list->data;
|
||||||
|
gnc_price_ref(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *
|
||||||
|
gnc_pricedb_lookup_at_time(GNCPriceDB *db,
|
||||||
|
gnc_commodity *c,
|
||||||
|
gnc_commodity *currency,
|
||||||
|
Timespec *t)
|
||||||
|
{
|
||||||
|
GList *price_list;
|
||||||
|
GList *result = NULL;
|
||||||
|
GList *item = NULL;
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
|
||||||
|
if(!db || !c || !currency || !t) return NULL;
|
||||||
|
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
|
||||||
|
if(!currency_hash) return NULL;
|
||||||
|
|
||||||
|
price_list = g_hash_table_lookup(currency_hash, currency);
|
||||||
|
if(!price_list) return NULL;
|
||||||
|
|
||||||
|
item = price_list;
|
||||||
|
while(item) {
|
||||||
|
GNCPrice *p = item->data;
|
||||||
|
Timespec *price_time = gnc_price_get_time(p);
|
||||||
|
if(timespec_equal(price_time, t)) {
|
||||||
|
result = g_list_prepend(result, p);
|
||||||
|
gnc_price_ref(p);
|
||||||
|
}
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/* gnc_pricedb_foreach_price infrastructure
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gboolean ok;
|
||||||
|
gboolean (*func)(GNCPrice *p, gpointer user_data);
|
||||||
|
gpointer user_data;
|
||||||
|
} GNCPriceDBForeachData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
pricedb_foreach_pricelist(gpointer key, gpointer val, gpointer user_data)
|
||||||
|
{
|
||||||
|
GList *price_list = (GList *) val;
|
||||||
|
GList *node = price_list;
|
||||||
|
GNCPriceDBForeachData *foreach_data = (GNCPriceDBForeachData *) user_data;
|
||||||
|
|
||||||
|
while(foreach_data->ok && node) {
|
||||||
|
GNCPrice *p = (GNCPrice *) node->data;
|
||||||
|
foreach_data->func(p, foreach_data->user_data);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pricedb_foreach_currencies_hash(gpointer key, gpointer val, gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTable *currencies_hash = (GHashTable *) val;
|
||||||
|
g_hash_table_foreach(currencies_hash, pricedb_foreach_pricelist, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
unstable_price_traversal(GNCPriceDB *db,
|
||||||
|
gboolean (*f)(GNCPrice *p, gpointer user_data),
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GNCPriceDBForeachData foreach_data;
|
||||||
|
|
||||||
|
if(!db || !f) return FALSE;
|
||||||
|
foreach_data.ok = TRUE;
|
||||||
|
foreach_data.func = f;
|
||||||
|
foreach_data.user_data = user_data;
|
||||||
|
|
||||||
|
g_hash_table_foreach(db->commodity_hash,
|
||||||
|
pricedb_foreach_currencies_hash,
|
||||||
|
&foreach_data);
|
||||||
|
|
||||||
|
return foreach_data.ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_kvpairs_by_commodity_key(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
GHashTableKVPair *kvpa = (GHashTableKVPair *) a;
|
||||||
|
GHashTableKVPair *kvpb = (GHashTableKVPair *) b;
|
||||||
|
gnc_commodity *ca;
|
||||||
|
gnc_commodity *cb;
|
||||||
|
int cmp_result;
|
||||||
|
|
||||||
|
if(a == b) return 0;
|
||||||
|
if(!a && !b) return 0;
|
||||||
|
if(!a) return -1;
|
||||||
|
if(!b) return 1;
|
||||||
|
|
||||||
|
ca = (gnc_commodity *) kvpa->key;
|
||||||
|
cb = (gnc_commodity *) kvpb->key;
|
||||||
|
|
||||||
|
cmp_result = safe_strcmp(gnc_commodity_get_namespace(ca),
|
||||||
|
gnc_commodity_get_namespace(cb));
|
||||||
|
|
||||||
|
if(cmp_result != 0) return cmp_result;
|
||||||
|
|
||||||
|
return safe_strcmp(gnc_commodity_get_mnemonic(ca),
|
||||||
|
gnc_commodity_get_mnemonic(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
stable_price_traversal(GNCPriceDB *db,
|
||||||
|
gboolean (*f)(GNCPrice *p, gpointer user_data),
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GSList *currency_hashes = NULL;
|
||||||
|
GSList *foo = NULL;
|
||||||
|
gboolean ok = TRUE;
|
||||||
|
GSList *i = NULL;
|
||||||
|
|
||||||
|
if(!db || !f) return FALSE;
|
||||||
|
|
||||||
|
currency_hashes = g_hash_table_key_value_pairs(db->commodity_hash);
|
||||||
|
currency_hashes = g_slist_sort(currency_hashes,
|
||||||
|
compare_kvpairs_by_commodity_key);
|
||||||
|
|
||||||
|
for(i = currency_hashes; i; i = i->next) {
|
||||||
|
GHashTableKVPair *kv_pair = (GHashTableKVPair *) i->data;
|
||||||
|
GHashTable *currency_hash = (GHashTable *) kv_pair->value;
|
||||||
|
GSList *price_lists = g_hash_table_key_value_pairs(currency_hash);
|
||||||
|
GSList *j;
|
||||||
|
|
||||||
|
price_lists = g_slist_sort(price_lists, compare_kvpairs_by_commodity_key);
|
||||||
|
for(j = price_lists; j; j = j->next) {
|
||||||
|
GHashTableKVPair *pricelist_kvp = (GHashTableKVPair *) j->data;
|
||||||
|
GList *price_list = (GList *) pricelist_kvp->value;
|
||||||
|
GList *node;
|
||||||
|
|
||||||
|
for(node = (GList *) price_list; node; node = node->next) {
|
||||||
|
GNCPrice *price = (GNCPrice *) node->data;
|
||||||
|
if(!f(price, user_data)) ok = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(price_lists) {
|
||||||
|
g_slist_foreach(price_lists, g_hash_table_kv_pair_free_gfunc, NULL);
|
||||||
|
g_slist_free(price_lists);
|
||||||
|
price_lists = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currency_hashes) {
|
||||||
|
g_slist_foreach(currency_hashes, g_hash_table_kv_pair_free_gfunc, NULL);
|
||||||
|
g_slist_free(currency_hashes);
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_pricedb_foreach_price(GNCPriceDB *db,
|
||||||
|
gboolean (*f)(GNCPrice *p, gpointer user_data),
|
||||||
|
gpointer user_data,
|
||||||
|
gboolean stable_order)
|
||||||
|
{
|
||||||
|
if(stable_order) return stable_price_traversal(db, f, user_data);
|
||||||
|
return unstable_price_traversal(db, f, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/* commodity substitution
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gnc_commodity *old_c;
|
||||||
|
gnc_commodity *new_c;
|
||||||
|
} GNCPriceFixupData;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gnc_price_fixup_legacy_commods(GNCPrice *p, gpointer data)
|
||||||
|
{
|
||||||
|
GNCPriceFixupData *fixup_data = (GNCPriceFixupData *) data;
|
||||||
|
gnc_commodity *price_c;
|
||||||
|
|
||||||
|
if (!p) return FALSE;
|
||||||
|
|
||||||
|
price_c = gnc_price_get_commodity(p);
|
||||||
|
if (gnc_commodity_equiv(price_c, fixup_data->old_c)) {
|
||||||
|
gnc_price_set_commodity(p, fixup_data->new_c);
|
||||||
|
}
|
||||||
|
price_c = gnc_price_get_currency(p);
|
||||||
|
if (gnc_commodity_equiv(price_c, fixup_data->old_c)) {
|
||||||
|
gnc_price_set_currency(p, fixup_data->new_c);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
remap_currency_hash_keys(gpointer key, gpointer val, gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTable *currencies_hash = (GHashTable *) val;
|
||||||
|
GNCPriceFixupData *fixup_data = (GNCPriceFixupData *) user_data;
|
||||||
|
GList *price_list;
|
||||||
|
|
||||||
|
price_list = g_hash_table_lookup(currencies_hash, fixup_data->old_c);
|
||||||
|
if(price_list) {
|
||||||
|
g_hash_table_remove(currencies_hash, fixup_data->old_c);
|
||||||
|
g_hash_table_insert(currencies_hash, fixup_data->new_c, price_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_pricedb_substitute_commodity(GNCPriceDB *db,
|
||||||
|
gnc_commodity *old_c,
|
||||||
|
gnc_commodity *new_c)
|
||||||
|
{
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
GNCPriceFixupData data;
|
||||||
|
|
||||||
|
if(!db || !old_c || !new_c) return;
|
||||||
|
|
||||||
|
data.old_c = old_c;
|
||||||
|
data.new_c = new_c;
|
||||||
|
|
||||||
|
/* first remap the relevant commodity -> currency hash, if any */
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, old_c);
|
||||||
|
if(currency_hash) {
|
||||||
|
g_hash_table_remove(db->commodity_hash, old_c);
|
||||||
|
g_hash_table_insert(db->commodity_hash, new_c, currency_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_foreach(db->commodity_hash, remap_currency_hash_keys, &data);
|
||||||
|
|
||||||
|
if(!gnc_pricedb_foreach_price(db,
|
||||||
|
gnc_price_fixup_legacy_commods,
|
||||||
|
&data,
|
||||||
|
FALSE)) {
|
||||||
|
PERR("Adjustments to legacy commodity pointers in pricedb failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
/* Semi-lame debugging code */
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_price_print(GNCPrice *p, FILE *f)
|
||||||
|
{
|
||||||
|
gnc_commodity *commodity;
|
||||||
|
gnc_commodity *currency;
|
||||||
|
if(!p) return;
|
||||||
|
if(!f) return;
|
||||||
|
|
||||||
|
commodity = gnc_price_get_commodity(p);
|
||||||
|
currency = gnc_price_get_currency(p);
|
||||||
|
|
||||||
|
if(!commodity) return;
|
||||||
|
if(!currency) return;
|
||||||
|
|
||||||
|
fprintf(f, " <pdb:price>\n");
|
||||||
|
fprintf(f, " <pdb:commodity pointer=%p>\n", commodity);
|
||||||
|
fprintf(f, " <cmdty:ref-space> %s</gnc:cmdty:ref-space>\n",
|
||||||
|
gnc_commodity_get_namespace(commodity));
|
||||||
|
fprintf(f, " <cmdty:ref-id>%s</cmdty:ref-id>\n",
|
||||||
|
gnc_commodity_get_mnemonic(commodity));
|
||||||
|
fprintf(f, " </pdb:commodity>\n");
|
||||||
|
fprintf(f, " <pdb:currency pointer=%p>\n", currency);
|
||||||
|
fprintf(f, " <cmdty:ref-space>%s</gnc:cmdty:ref-space>\n",
|
||||||
|
gnc_commodity_get_namespace(currency));
|
||||||
|
fprintf(f, " <cmdty:ref-id>%s</cmdty:ref-id>\n",
|
||||||
|
gnc_commodity_get_mnemonic(currency));
|
||||||
|
fprintf(f, " </pdb:currency>\n");
|
||||||
|
fprintf(f, " %s\n", gnc_price_get_source(p));
|
||||||
|
fprintf(f, " %s\n", gnc_price_get_type(p));
|
||||||
|
fprintf(f, " %g\n", gnc_numeric_to_double(gnc_price_get_value(p)));
|
||||||
|
fprintf(f, " </pdb:price>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
print_pricedb_adapter(GNCPrice *p, gpointer user_data)
|
||||||
|
{
|
||||||
|
FILE *f = (FILE *) user_data;
|
||||||
|
gnc_price_print(p, f);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_pricedb_print_contents(GNCPriceDB *db, FILE *f)
|
||||||
|
{
|
||||||
|
if(!db) { PERR("NULL PriceDB\n"); return; }
|
||||||
|
if(!f) { PERR("NULL FILE*\n"); return; }
|
||||||
|
|
||||||
|
fprintf(f, "<gnc:pricedb>\n");
|
||||||
|
gnc_pricedb_foreach_price(db, print_pricedb_adapter, f, FALSE);
|
||||||
|
fprintf(f, "</gnc:pricedb>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
169
src/engine/gnc-pricedb.h
Normal file
169
src/engine/gnc-pricedb.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/********************************************************************
|
||||||
|
* gnc-pricedb.h -- a simple price database for gnucash. *
|
||||||
|
* Copyright (C) 2001 Rob Browning *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||||
|
* *
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
#ifndef __GNC_PRICEDB_H__
|
||||||
|
#define __GNC_PRICEDB_H__
|
||||||
|
|
||||||
|
#include "date.h"
|
||||||
|
#include "gnc-numeric.h"
|
||||||
|
#include "gnc-commodity.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/**********************************************************************\
|
||||||
|
|
||||||
|
GNCPrice:
|
||||||
|
|
||||||
|
commodity: the item being priced.
|
||||||
|
|
||||||
|
value: the value of the item being priced.
|
||||||
|
|
||||||
|
currency: the denomination of the value of the item being priced.
|
||||||
|
|
||||||
|
time: the time the price was valid.
|
||||||
|
|
||||||
|
source: a string describing the source of the quote. These
|
||||||
|
strings will be something like this: "Finance::Quote",
|
||||||
|
"user:misc", "user:foo", etc. If the quote came from a user, as a
|
||||||
|
matter of policy, you *must* prefix the string you give with
|
||||||
|
"user:". For now, the only other reserved values are
|
||||||
|
"Finance::Quote" and "old-file-import".
|
||||||
|
|
||||||
|
type: the type of quote - types possible right now are bid, ask,
|
||||||
|
last, and unknown.
|
||||||
|
|
||||||
|
NOTE: for source and type, NULL and the empty string are
|
||||||
|
considered the same, so if one of these is "", then after a file
|
||||||
|
save/restore, it might be NULL. Behave accordingly.
|
||||||
|
|
||||||
|
GNCPrices are reference counted. When you gnc_price_create one or
|
||||||
|
clone it, the new price's count is set to 1. When you're finished
|
||||||
|
with a price, call gnc_price_unref. If you hand the pointer to
|
||||||
|
some other code that needs to keep it, make sure it calls
|
||||||
|
gnc_price_ref to indicate it's interest in that price, and calls
|
||||||
|
gnc_price_unref when it's finished with the price.
|
||||||
|
|
||||||
|
All of the getters return data that's internal to the GNCPrice,
|
||||||
|
not copies, so don't free these values.
|
||||||
|
|
||||||
|
All of the setters store copies of the data, with the exception of
|
||||||
|
the commodity field which just stores the pointer given. It is
|
||||||
|
assumed that commodities are a global resource and are pointer
|
||||||
|
unique.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _GNCPrice GNCPrice;
|
||||||
|
|
||||||
|
/* allocation */
|
||||||
|
GNCPrice *gnc_price_create(void); /* create and initialize a price */
|
||||||
|
GNCPrice *gnc_price_clone(GNCPrice* p);
|
||||||
|
void gnc_price_ref(GNCPrice *p);
|
||||||
|
void gnc_price_unref(GNCPrice *p);
|
||||||
|
|
||||||
|
/* setters */
|
||||||
|
void gnc_price_set_commodity(GNCPrice *p, gnc_commodity *c);
|
||||||
|
void gnc_price_set_currency(GNCPrice *p, gnc_commodity *c);
|
||||||
|
void gnc_price_set_time(GNCPrice *p, Timespec *t);
|
||||||
|
void gnc_price_set_source(GNCPrice *p, const char *source);
|
||||||
|
void gnc_price_set_type(GNCPrice *p, const char* type);
|
||||||
|
void gnc_price_set_value(GNCPrice *p, gnc_numeric value);
|
||||||
|
|
||||||
|
/* getters */
|
||||||
|
gnc_commodity * gnc_price_get_commodity(GNCPrice *p);
|
||||||
|
gnc_commodity * gnc_price_get_currency(GNCPrice *p);
|
||||||
|
Timespec * gnc_price_get_time(GNCPrice *p);
|
||||||
|
const char * gnc_price_get_source(GNCPrice *p);
|
||||||
|
const char * gnc_price_get_type(GNCPrice *p);
|
||||||
|
gnc_numeric gnc_price_get_value(GNCPrice *p);
|
||||||
|
|
||||||
|
/* price_list funcs
|
||||||
|
|
||||||
|
A price list is a time sorted GList of prices. The price list
|
||||||
|
maintains a ref for itself for all the prices in the list
|
||||||
|
(i.e. adding a price calls gnc_price_ref on it, removing a price
|
||||||
|
calls gnc_price_unref, etc. Destroying a list also removes this
|
||||||
|
list reference from the prices in the list. */
|
||||||
|
gboolean gnc_price_list_insert(GList **prices, GNCPrice *p);
|
||||||
|
gboolean gnc_price_list_remove(GList **prices, GNCPrice *p);
|
||||||
|
void gnc_price_list_destroy(GList *prices);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
GNCPriceDB
|
||||||
|
|
||||||
|
Whenever a you store a price in the pricedb, the pricedb adds its
|
||||||
|
own reference to the price, so you can safely unref that price when
|
||||||
|
you're finished with it.
|
||||||
|
|
||||||
|
Similarly, when the pricedb returns a price to you, either singly,
|
||||||
|
or in a price list, the price will have had a ref added for you, so
|
||||||
|
you only need to unref the price(s) when you're finished with them.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _GNCPriceDB GNCPriceDB;
|
||||||
|
|
||||||
|
GNCPriceDB * gnc_pricedb_create(void);
|
||||||
|
|
||||||
|
void gnc_pricedb_destroy(GNCPriceDB *db);
|
||||||
|
|
||||||
|
/* Add a price to the pricedb, you may drop your reference to the
|
||||||
|
price (i.e. call unref) after this succeeds, whenever you're
|
||||||
|
finished with the price. */
|
||||||
|
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p);
|
||||||
|
|
||||||
|
/* Remove a price from the pricedb. */
|
||||||
|
gboolean gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p);
|
||||||
|
|
||||||
|
GNCPrice * gnc_pricedb_lookup_latest(GNCPriceDB *db,
|
||||||
|
gnc_commodity *comodity,
|
||||||
|
gnc_commodity *currency);
|
||||||
|
|
||||||
|
/* Return all prices that match the given commodity, currency, and
|
||||||
|
timespec. Prices will be returned as a price_list (see above) */
|
||||||
|
GList * gnc_pricedb_lookup_at_time(GNCPriceDB *db,
|
||||||
|
gnc_commodity *commodity,
|
||||||
|
gnc_commodity *currency,
|
||||||
|
Timespec *t);
|
||||||
|
|
||||||
|
/* Call f once for each price in db, until and unless f returns FALSE.
|
||||||
|
If stable_order is not FALSE, make sure the ordering of the
|
||||||
|
traversal is stable (i.e. the same order every time given the same
|
||||||
|
db contents). */
|
||||||
|
gboolean gnc_pricedb_foreach_price(GNCPriceDB *db,
|
||||||
|
gboolean (*f)(GNCPrice *p,
|
||||||
|
gpointer user_data),
|
||||||
|
gpointer user_data,
|
||||||
|
gboolean stable_order);
|
||||||
|
|
||||||
|
/* Return FALSE if the database has not been modified */
|
||||||
|
gboolean gnc_pricedb_dirty(GNCPriceDB *p);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* semi-lame debugging code */
|
||||||
|
void gnc_price_print(GNCPrice *db, FILE *f);
|
||||||
|
void gnc_pricedb_print_contents(GNCPriceDB *db, FILE *f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -108,7 +108,9 @@
|
|||||||
#include "gnc-engine.h"
|
#include "gnc-engine.h"
|
||||||
#include "gnc-engine-util.h"
|
#include "gnc-engine-util.h"
|
||||||
#include "GNCIdP.h"
|
#include "GNCIdP.h"
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
|
||||||
|
#include "gnc-book-p.h"
|
||||||
|
|
||||||
#define PERMS 0666
|
#define PERMS 0666
|
||||||
#define WFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
|
#define WFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
|
||||||
@ -152,12 +154,96 @@ static AccountGroup *maingrp; /* temporary holder for file
|
|||||||
in our handling of keys and values here. We use int32s and
|
in our handling of keys and values here. We use int32s and
|
||||||
pointers interchangably ATM, and that may be problematic on some
|
pointers interchangably ATM, and that may be problematic on some
|
||||||
architectures...
|
architectures...
|
||||||
|
|
||||||
|
Only used *during* file read process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* used while reading */
|
|
||||||
static GHashTable *ids_to_finished_accounts;
|
static GHashTable *ids_to_finished_accounts;
|
||||||
static GHashTable *ids_to_unfinished_accounts;
|
static GHashTable *ids_to_unfinished_accounts;
|
||||||
|
|
||||||
|
/** PriceDB bits ******************************************************/
|
||||||
|
/* Commodity prices (stock quotes, etc.) used to be stored as zero
|
||||||
|
quantity (damount) splits inside the relevant accounts. Now we
|
||||||
|
used the pricedb. potential_quotes is where we put the info from
|
||||||
|
all these "quote splits" while reading, until we have a chance to
|
||||||
|
cram them into the pricedb. We can't do it any sooner because
|
||||||
|
until we finish reading the file, the Account*'s havent' been
|
||||||
|
filled out and so their commodities and types may not have been
|
||||||
|
initilized yet.
|
||||||
|
|
||||||
|
This shouldn't be a static global but see comments above RE ids_to*
|
||||||
|
hashes. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Split *split;
|
||||||
|
gnc_numeric price;
|
||||||
|
} GNCPotentialQuote;
|
||||||
|
|
||||||
|
static GSList *potential_quotes;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mark_potential_quote(Split *s, double price, double quantity)
|
||||||
|
{
|
||||||
|
static int count = 0;
|
||||||
|
|
||||||
|
if((price != 0) && DEQ(quantity, 0)){
|
||||||
|
GNCPotentialQuote *q = g_new0(GNCPotentialQuote, 1);
|
||||||
|
q->split = s;
|
||||||
|
q->price = double_to_gnc_numeric(price,
|
||||||
|
GNC_DENOM_AUTO,
|
||||||
|
GNC_DENOM_SIGFIGS(9) | GNC_RND_ROUND);
|
||||||
|
potential_quotes = g_slist_prepend(potential_quotes, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
cvt_potential_prices_to_pricedb_and_cleanup(GNCPriceDB **prices)
|
||||||
|
{
|
||||||
|
GSList *item = potential_quotes;
|
||||||
|
|
||||||
|
*prices = gnc_pricedb_create();
|
||||||
|
if (!*prices) return FALSE;
|
||||||
|
|
||||||
|
while(item)
|
||||||
|
{
|
||||||
|
GNCPotentialQuote *q = (GNCPotentialQuote *) item->data;
|
||||||
|
Account *split_acct = xaccSplitGetAccount(q->split);
|
||||||
|
GNCAccountType acct_type = xaccAccountGetType(split_acct);
|
||||||
|
|
||||||
|
/* at this point, we already know it's a split with a zero amount */
|
||||||
|
if((acct_type == STOCK) ||
|
||||||
|
(acct_type == MUTUAL) ||
|
||||||
|
(acct_type == CURRENCY)) {
|
||||||
|
/* this is a quote -- file it in the db and kill the split */
|
||||||
|
Transaction *txn = xaccSplitGetParent(q->split);
|
||||||
|
GNCPrice *price = gnc_price_create();
|
||||||
|
Timespec time = xaccTransRetDateEnteredTS(txn);
|
||||||
|
|
||||||
|
gnc_price_set_commodity(price, xaccAccountGetSecurity(split_acct));
|
||||||
|
gnc_price_set_currency(price, xaccAccountGetCurrency(split_acct));
|
||||||
|
gnc_price_set_time(price, &time);
|
||||||
|
gnc_price_set_source(price, "old-file-import");
|
||||||
|
gnc_price_set_type(price, "unknown");
|
||||||
|
gnc_price_set_value(price, q->price);
|
||||||
|
if(!gnc_pricedb_add_price(*prices, price)) {
|
||||||
|
PERR("problem adding price to pricedb.\n");
|
||||||
|
}
|
||||||
|
gnc_price_unref(price);
|
||||||
|
|
||||||
|
xaccTransBeginEdit(txn);
|
||||||
|
xaccSplitDestroy(q->split);
|
||||||
|
xaccTransCommitEdit(txn);
|
||||||
|
}
|
||||||
|
g_free(item->data);
|
||||||
|
item->data = NULL;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
g_slist_free(potential_quotes);
|
||||||
|
potential_quotes = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/** PROTOTYPES ******************************************************/
|
/** PROTOTYPES ******************************************************/
|
||||||
static Account *locateAccount (int acc_id);
|
static Account *locateAccount (int acc_id);
|
||||||
|
|
||||||
@ -197,8 +283,8 @@ static int readTSDate( int fd, Timespec *, int token );
|
|||||||
|
|
||||||
/*******************************************************/
|
/*******************************************************/
|
||||||
|
|
||||||
GNCBackendError
|
GNCBackendError
|
||||||
xaccGetGncBinFileIOError (void)
|
gnc_book_get_binfile_io_error(void)
|
||||||
{
|
{
|
||||||
/* reset the error code */
|
/* reset the error code */
|
||||||
int rc = error_code;
|
int rc = error_code;
|
||||||
@ -307,15 +393,15 @@ gnc_commodity_import_legacy(const char * currency_name) {
|
|||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
|
|
||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
* xaccReadAccountGroup *
|
|
||||||
* reads in the data from file descriptor *
|
* reads in the data from file descriptor *
|
||||||
* *
|
* *
|
||||||
* Args: fd -- the file descriptor to read the data from *
|
* Args: book -- the book in which to store the data *
|
||||||
|
* fd -- the file descriptor to read the data from *
|
||||||
* Return: the struct with the program data in it *
|
* Return: the struct with the program data in it *
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
static AccountGroup *
|
static gboolean
|
||||||
xaccReadAccountGroup(int fd)
|
gnc_load_financials_from_fd(GNCBook *book, int fd)
|
||||||
{
|
{
|
||||||
int err=0;
|
int err=0;
|
||||||
int token=0;
|
int token=0;
|
||||||
int num_unclaimed;
|
int num_unclaimed;
|
||||||
@ -328,7 +414,7 @@ xaccReadAccountGroup(int fd)
|
|||||||
if( 0 > fd )
|
if( 0 > fd )
|
||||||
{
|
{
|
||||||
error_code = ERR_FILEIO_FILE_NOT_FOUND;
|
error_code = ERR_FILEIO_FILE_NOT_FOUND;
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read in the file format token */
|
/* Read in the file format token */
|
||||||
@ -336,7 +422,7 @@ xaccReadAccountGroup(int fd)
|
|||||||
if( sizeof(int) != err )
|
if( sizeof(int) != err )
|
||||||
{
|
{
|
||||||
error_code = ERR_FILEIO_FILE_EMPTY;
|
error_code = ERR_FILEIO_FILE_EMPTY;
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
XACC_FLIP_INT (token);
|
XACC_FLIP_INT (token);
|
||||||
|
|
||||||
@ -350,36 +436,33 @@ xaccReadAccountGroup(int fd)
|
|||||||
* with, warn the user */
|
* with, warn the user */
|
||||||
if( VERSION < token ) {
|
if( VERSION < token ) {
|
||||||
error_code = ERR_FILEIO_FILE_TOO_NEW;
|
error_code = ERR_FILEIO_FILE_TOO_NEW;
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: is this OK (i.e. direct hashes for ints?) */
|
/* FIXME: is this OK (i.e. direct hashes for ints?) */
|
||||||
ids_to_finished_accounts = g_hash_table_new(g_direct_hash, g_direct_equal);
|
ids_to_finished_accounts = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
if(!ids_to_finished_accounts) {
|
if(!ids_to_finished_accounts) {
|
||||||
error_code = ERR_FILEIO_ALLOC;
|
error_code = ERR_BACKEND_ALLOC;
|
||||||
return(NULL);
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ids_to_unfinished_accounts = g_hash_table_new(g_direct_hash, g_direct_equal);
|
ids_to_unfinished_accounts = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
if(!ids_to_unfinished_accounts) {
|
if(!ids_to_unfinished_accounts) {
|
||||||
error_code = ERR_FILEIO_ALLOC;
|
error_code = ERR_BACKEND_ALLOC;
|
||||||
|
|
||||||
g_hash_table_destroy(ids_to_finished_accounts);
|
g_hash_table_destroy(ids_to_finished_accounts);
|
||||||
ids_to_finished_accounts = NULL;
|
ids_to_finished_accounts = NULL;
|
||||||
|
|
||||||
return(NULL);
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
potential_quotes = NULL;
|
||||||
|
|
||||||
/* disable logging during load; otherwise its just a mess */
|
/* disable logging during load; otherwise its just a mess */
|
||||||
xaccLogDisable();
|
xaccLogDisable();
|
||||||
holder = xaccMallocAccountGroup();
|
holder = xaccMallocAccountGroup();
|
||||||
grp = readGroup (fd, NULL, token);
|
grp = readGroup (fd, NULL, token);
|
||||||
|
|
||||||
/* mark the newly read group as saved, since the act of putting
|
|
||||||
* it together will have caused it to be marked up as not-saved.
|
|
||||||
*/
|
|
||||||
xaccGroupMarkSaved (grp);
|
|
||||||
|
|
||||||
/* auto-number the accounts, if they are not already numbered */
|
/* auto-number the accounts, if they are not already numbered */
|
||||||
xaccGroupDepthAutoCode (grp);
|
xaccGroupDepthAutoCode (grp);
|
||||||
|
|
||||||
@ -409,11 +492,35 @@ xaccReadAccountGroup(int fd)
|
|||||||
g_hash_table_destroy(ids_to_unfinished_accounts);
|
g_hash_table_destroy(ids_to_unfinished_accounts);
|
||||||
ids_to_unfinished_accounts = NULL;
|
ids_to_unfinished_accounts = NULL;
|
||||||
|
|
||||||
|
{
|
||||||
|
GNCPriceDB *tmpdb;
|
||||||
|
if(cvt_potential_prices_to_pricedb_and_cleanup(&tmpdb)) {
|
||||||
|
GNCPriceDB *db = gnc_book_get_pricedb(book);
|
||||||
|
if(db) gnc_pricedb_destroy(db);
|
||||||
|
gnc_book_set_pricedb(book, tmpdb);
|
||||||
|
} else {
|
||||||
|
PWARN("pricedb import failed.");
|
||||||
|
error_code = ERR_BACKEND_MISC;
|
||||||
|
gnc_pricedb_destroy(tmpdb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* set up various state that is not normally stored in the byte stream */
|
/* set up various state that is not normally stored in the byte stream */
|
||||||
xaccRecomputeGroupBalance (grp);
|
xaccRecomputeGroupBalance (grp);
|
||||||
|
|
||||||
xaccLogEnable();
|
xaccLogEnable();
|
||||||
return grp;
|
|
||||||
|
{
|
||||||
|
AccountGroup *g = gnc_book_get_group(book);
|
||||||
|
if (g) xaccFreeAccountGroup(g);
|
||||||
|
gnc_book_set_group(book, grp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mark the newly read book as saved, since the act of putting it
|
||||||
|
* together will have caused it to be marked up as not-saved. */
|
||||||
|
gnc_book_mark_saved(book);
|
||||||
|
|
||||||
|
return (error_code == ERR_BACKEND_NO_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
@ -423,25 +530,30 @@ xaccReadAccountGroup(int fd)
|
|||||||
* Args: datafile - the file to load the data from *
|
* Args: datafile - the file to load the data from *
|
||||||
* Return: the struct with the program data in it *
|
* Return: the struct with the program data in it *
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
AccountGroup *
|
void
|
||||||
xaccReadGncBinAccountGroupFile( const char *datafile )
|
gnc_book_load_from_binfile(GNCBook *book)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
AccountGroup *grp = 0x0;
|
|
||||||
|
const gchar *datafile = gnc_book_get_file_path(book);
|
||||||
|
if(!datafile) {
|
||||||
|
error_code = ERR_BACKEND_MISC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
maingrp = 0x0;
|
maingrp = 0x0;
|
||||||
error_code = ERR_BACKEND_NO_ERR;
|
error_code = ERR_BACKEND_NO_ERR;
|
||||||
|
|
||||||
fd = open( datafile, RFLAGS, 0 );
|
fd = open( datafile, RFLAGS, 0 );
|
||||||
if( 0 > fd )
|
if( 0 > fd ) {
|
||||||
{
|
|
||||||
error_code = ERR_FILEIO_FILE_NOT_FOUND;
|
error_code = ERR_FILEIO_FILE_NOT_FOUND;
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
grp = xaccReadAccountGroup (fd);
|
|
||||||
|
if(!gnc_load_financials_from_fd(book, fd)) return;
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return grp;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
@ -644,17 +756,15 @@ readAccount( int fd, AccountGroup *grp, int token )
|
|||||||
|
|
||||||
DEBUG ("expecting %d transactions \n", numTrans);
|
DEBUG ("expecting %d transactions \n", numTrans);
|
||||||
/* read the transactions */
|
/* read the transactions */
|
||||||
for( i=0; i<numTrans; i++ )
|
for( i=0; i<numTrans; i++ ) {
|
||||||
{
|
|
||||||
Transaction *trans;
|
Transaction *trans;
|
||||||
trans = readTransaction( fd, acc, token );
|
trans = readTransaction( fd, acc, token );
|
||||||
if( trans == NULL )
|
if(trans == NULL ) {
|
||||||
{
|
|
||||||
PERR ("Short Transaction Read: \n"
|
PERR ("Short Transaction Read: \n"
|
||||||
"\texpected %d got %d transactions \n",numTrans,i);
|
"\texpected %d got %d transactions \n", numTrans, i);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Not needed now. Since we always look in ids_to_finished_accounts
|
/* Not needed now. Since we always look in ids_to_finished_accounts
|
||||||
* first, it doesn't matter if we don't ever delete anything from
|
* first, it doesn't matter if we don't ever delete anything from
|
||||||
@ -802,7 +912,7 @@ xaccTransSetAction (Transaction *trans, const char *action)
|
|||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
|
|
||||||
static Transaction *
|
static Transaction *
|
||||||
readTransaction( int fd, Account *acc, int token )
|
readTransaction( int fd, Account *acc, int revision)
|
||||||
{
|
{
|
||||||
int err=0;
|
int err=0;
|
||||||
int acc_id;
|
int acc_id;
|
||||||
@ -821,13 +931,7 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
trans = xaccMallocTransaction();
|
trans = xaccMallocTransaction();
|
||||||
xaccTransBeginEdit (trans);
|
xaccTransBeginEdit (trans);
|
||||||
|
|
||||||
/* add in one split -- xaccMallocTransaction no longer auto-creates them. */
|
tmp = readString( fd, revision );
|
||||||
{
|
|
||||||
Split *s = xaccMallocSplit ();
|
|
||||||
xaccTransAppendSplit (trans, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = readString( fd, token );
|
|
||||||
if (NULL == tmp)
|
if (NULL == tmp)
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at num");
|
PERR ("Premature end of Transaction at num");
|
||||||
@ -838,9 +942,9 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
xaccTransSetNum (trans, tmp);
|
xaccTransSetNum (trans, tmp);
|
||||||
free (tmp);
|
free (tmp);
|
||||||
|
|
||||||
if (7 >= token) {
|
if (revision <= 7) {
|
||||||
time_t secs;
|
time_t secs;
|
||||||
secs = readDMYDate( fd, token );
|
secs = readDMYDate( fd, revision );
|
||||||
if( 0 == secs )
|
if( 0 == secs )
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at date");
|
PERR ("Premature end of Transaction at date");
|
||||||
@ -855,7 +959,7 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* read posted date first ... */
|
/* read posted date first ... */
|
||||||
rc = readTSDate( fd, &ts, token );
|
rc = readTSDate( fd, &ts, revision );
|
||||||
if( -1 == rc )
|
if( -1 == rc )
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at date");
|
PERR ("Premature end of Transaction at date");
|
||||||
@ -866,7 +970,7 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
xaccTransSetDateTS (trans, &ts);
|
xaccTransSetDateTS (trans, &ts);
|
||||||
|
|
||||||
/* then the entered date ... */
|
/* then the entered date ... */
|
||||||
rc = readTSDate( fd, &ts, token );
|
rc = readTSDate( fd, &ts, revision );
|
||||||
if( -1 == rc )
|
if( -1 == rc )
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at date");
|
PERR ("Premature end of Transaction at date");
|
||||||
@ -877,7 +981,7 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
xaccTransSetDateEnteredTS (trans, &ts);
|
xaccTransSetDateEnteredTS (trans, &ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = readString( fd, token );
|
tmp = readString( fd, revision );
|
||||||
if( NULL == tmp )
|
if( NULL == tmp )
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at description");
|
PERR ("Premature end of Transaction at description");
|
||||||
@ -892,8 +996,8 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
deprecated, and we don't think anyone ever used them anyway, but
|
deprecated, and we don't think anyone ever used them anyway, but
|
||||||
to be safe, if we find one, we store it in the old-docref slot, a
|
to be safe, if we find one, we store it in the old-docref slot, a
|
||||||
la old-price-source. */
|
la old-price-source. */
|
||||||
if (8 <= token) {
|
if (revision >= 8) {
|
||||||
tmp = readString( fd, token );
|
tmp = readString( fd, revision );
|
||||||
if( NULL == tmp ) {
|
if( NULL == tmp ) {
|
||||||
PERR ("Premature end of Transaction at docref");
|
PERR ("Premature end of Transaction at docref");
|
||||||
xaccTransDestroy(trans);
|
xaccTransDestroy(trans);
|
||||||
@ -916,17 +1020,10 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
* moved to splits. Thus, vast majority of stuff below
|
* moved to splits. Thus, vast majority of stuff below
|
||||||
* is skipped
|
* is skipped
|
||||||
*/
|
*/
|
||||||
if (4 >= token)
|
if (revision <= 4) {
|
||||||
{
|
Split* s;
|
||||||
Split * s;
|
|
||||||
|
|
||||||
/* The code below really wants to assume that there are a pair
|
tmp = readString( fd, revision );
|
||||||
* of splits in every transaction, so make it so.
|
|
||||||
*/
|
|
||||||
s = xaccMallocSplit ();
|
|
||||||
xaccTransAppendSplit (trans, s);
|
|
||||||
|
|
||||||
tmp = readString( fd, token );
|
|
||||||
if( NULL == tmp )
|
if( NULL == tmp )
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at memo");
|
PERR ("Premature end of Transaction at memo");
|
||||||
@ -941,9 +1038,9 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
free (tmp);
|
free (tmp);
|
||||||
|
|
||||||
/* action first introduced in version 3 of the file format */
|
/* action first introduced in version 3 of the file format */
|
||||||
if (3 <= token)
|
if (revision >= 3)
|
||||||
{
|
{
|
||||||
tmp = readString( fd, token );
|
tmp = readString( fd, revision );
|
||||||
if( NULL == tmp )
|
if( NULL == tmp )
|
||||||
{
|
{
|
||||||
PERR ("Premature end of Transaction at action");
|
PERR ("Premature end of Transaction at action");
|
||||||
@ -973,12 +1070,21 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
xaccTransCommitEdit (trans);
|
xaccTransCommitEdit (trans);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The code below really wants to assume that there are a pair
|
||||||
|
* of splits in every transaction, so make it so.
|
||||||
|
*/
|
||||||
|
s = xaccMallocSplit ();
|
||||||
|
xaccTransAppendSplit (trans, s);
|
||||||
|
s = xaccMallocSplit ();
|
||||||
|
xaccTransAppendSplit (trans, s);
|
||||||
|
|
||||||
s = xaccTransGetSplit (trans, 0);
|
s = xaccTransGetSplit (trans, 0);
|
||||||
xaccSplitSetReconcile (s, recn);
|
xaccSplitSetReconcile (s, recn);
|
||||||
s = xaccTransGetSplit (trans, 1);
|
s = xaccTransGetSplit (trans, 1);
|
||||||
xaccSplitSetReconcile (s, recn);
|
xaccSplitSetReconcile (s, recn);
|
||||||
|
|
||||||
if( 1 >= token ) {
|
if(revision <= 1) {
|
||||||
/* Note: this is for version 0 of file format only.
|
/* Note: this is for version 0 of file format only.
|
||||||
* What used to be reconciled, is now cleared... transactions
|
* What used to be reconciled, is now cleared... transactions
|
||||||
* aren't reconciled until you get your bank statement, and
|
* aren't reconciled until you get your bank statement, and
|
||||||
@ -996,8 +1102,9 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
* with the amount recorded as pennies.
|
* with the amount recorded as pennies.
|
||||||
* Version 2 and above store the share amounts and
|
* Version 2 and above store the share amounts and
|
||||||
* prices as doubles. */
|
* prices as doubles. */
|
||||||
if (1 == token) {
|
if (1 == revision) {
|
||||||
int amount;
|
int amount;
|
||||||
|
|
||||||
err = read( fd, &amount, sizeof(int) );
|
err = read( fd, &amount, sizeof(int) );
|
||||||
if( sizeof(int) != err )
|
if( sizeof(int) != err )
|
||||||
{
|
{
|
||||||
@ -1010,7 +1117,12 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
num_shares = 0.01 * ((double) amount); /* file stores pennies */
|
num_shares = 0.01 * ((double) amount); /* file stores pennies */
|
||||||
s = xaccTransGetSplit (trans, 0);
|
s = xaccTransGetSplit (trans, 0);
|
||||||
DxaccSplitSetShareAmount (s, num_shares);
|
DxaccSplitSetShareAmount (s, num_shares);
|
||||||
|
|
||||||
|
/* Version 1 files did not do double-entry */
|
||||||
|
s = xaccTransGetSplit (trans, 0);
|
||||||
|
xaccAccountInsertSplit( acc, s );
|
||||||
} else {
|
} else {
|
||||||
|
Account *peer_acc;
|
||||||
double damount;
|
double damount;
|
||||||
|
|
||||||
/* first, read number of shares ... */
|
/* first, read number of shares ... */
|
||||||
@ -1037,15 +1149,12 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
XACC_FLIP_DOUBLE (damount);
|
XACC_FLIP_DOUBLE (damount);
|
||||||
share_price = damount;
|
share_price = damount;
|
||||||
s = xaccTransGetSplit (trans, 0);
|
s = xaccTransGetSplit (trans, 0);
|
||||||
|
|
||||||
DxaccSplitSetSharePriceAndAmount (s, share_price, num_shares);
|
DxaccSplitSetSharePriceAndAmount (s, share_price, num_shares);
|
||||||
}
|
|
||||||
|
/* Read the account numbers for double-entry */
|
||||||
DEBUG ("num_shares %f \n", num_shares);
|
/* These are first used in Version 2 of the file format */
|
||||||
|
|
||||||
/* Read the account numbers for double-entry */
|
|
||||||
/* These are first used in Version 2 of the file format */
|
|
||||||
if (1 < token) {
|
|
||||||
Account *peer_acc;
|
|
||||||
/* first, read the credit account number */
|
/* first, read the credit account number */
|
||||||
err = read( fd, &acc_id, sizeof(int) );
|
err = read( fd, &acc_id, sizeof(int) );
|
||||||
if( err != sizeof(int) )
|
if( err != sizeof(int) )
|
||||||
@ -1064,6 +1173,8 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
s = xaccTransGetSplit (trans, 0);
|
s = xaccTransGetSplit (trans, 0);
|
||||||
if (peer_acc) xaccAccountInsertSplit( peer_acc, s);
|
if (peer_acc) xaccAccountInsertSplit( peer_acc, s);
|
||||||
|
|
||||||
|
mark_potential_quote(s, share_price, num_shares);
|
||||||
|
|
||||||
/* next read the debit account number */
|
/* next read the debit account number */
|
||||||
err = read( fd, &acc_id, sizeof(int) );
|
err = read( fd, &acc_id, sizeof(int) );
|
||||||
if( err != sizeof(int) )
|
if( err != sizeof(int) )
|
||||||
@ -1077,74 +1188,50 @@ readTransaction( int fd, Account *acc, int token )
|
|||||||
DEBUG ("debit %d\n", acc_id);
|
DEBUG ("debit %d\n", acc_id);
|
||||||
peer_acc = locateAccount (acc_id);
|
peer_acc = locateAccount (acc_id);
|
||||||
if (peer_acc) {
|
if (peer_acc) {
|
||||||
Split *split;
|
Split *s0 = xaccTransGetSplit (trans, 0);
|
||||||
s = xaccTransGetSplit (trans, 0);
|
Split *s1 = xaccTransGetSplit (trans, 1);
|
||||||
split = xaccTransGetSplit (trans, 1);
|
|
||||||
|
|
||||||
/* duplicate many of the attributes in the credit split */
|
/* duplicate many of the attributes in the credit split */
|
||||||
DxaccSplitSetSharePriceAndAmount (split, share_price, -num_shares);
|
DxaccSplitSetSharePriceAndAmount (s1, share_price, -num_shares);
|
||||||
xaccSplitSetReconcile (split, xaccSplitGetReconcile (s));
|
xaccSplitSetReconcile (s1, xaccSplitGetReconcile (s0));
|
||||||
xaccSplitSetMemo (split, xaccSplitGetMemo (s));
|
xaccSplitSetMemo (s1, xaccSplitGetMemo (s0));
|
||||||
xaccSplitSetAction (split, xaccSplitGetAction (s));
|
xaccSplitSetAction (s1, xaccSplitGetAction (s0));
|
||||||
xaccAccountInsertSplit (peer_acc, split);
|
xaccAccountInsertSplit (peer_acc, s1);
|
||||||
|
mark_potential_quote(s1, share_price, -num_shares);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* Version 1 files did not do double-entry */
|
|
||||||
s = xaccTransGetSplit (trans, 0);
|
|
||||||
xaccAccountInsertSplit( acc, s );
|
|
||||||
}
|
}
|
||||||
} else { /* else, read version 5 and above files */
|
} else { /* else, read version 5 and above files */
|
||||||
Split *split;
|
|
||||||
int offset = 0;
|
|
||||||
const char *notes = NULL;
|
const char *notes = NULL;
|
||||||
|
|
||||||
if (5 == token)
|
if (revision == 5) {
|
||||||
{
|
|
||||||
Split *s = trans->splits->data;
|
|
||||||
|
|
||||||
/* Version 5 files included a split that immediately
|
/* Version 5 files included a split that immediately
|
||||||
* followed the transaction, before the destination splits.
|
* followed the transaction, before the destination splits.
|
||||||
* Later versions don't have this. */
|
* Later versions don't have this. */
|
||||||
offset = 1;
|
Split *split = readSplit (fd, revision);
|
||||||
split = readSplit (fd, token);
|
xaccTransAppendSplit(trans, split);
|
||||||
xaccRemoveEntity(&s->guid);
|
|
||||||
xaccFreeSplit (s);
|
|
||||||
trans->splits->data = split;
|
|
||||||
split->parent = trans;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read number of splits */
|
/* read number of splits */
|
||||||
err = read( fd, &(numSplits), sizeof(int) );
|
err = read( fd, &(numSplits), sizeof(int) );
|
||||||
if( err != sizeof(int) )
|
if( err != sizeof(int) ) {
|
||||||
{
|
|
||||||
PERR ("Premature end of Transaction at num-splits");
|
PERR ("Premature end of Transaction at num-splits");
|
||||||
xaccTransDestroy(trans);
|
xaccTransDestroy(trans);
|
||||||
xaccTransCommitEdit (trans);
|
xaccTransCommitEdit (trans);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
XACC_FLIP_INT (numSplits);
|
XACC_FLIP_INT (numSplits);
|
||||||
for (i=0; i<numSplits; i++) {
|
for (i = 0; i < numSplits; i++) {
|
||||||
split = readSplit (fd, token);
|
Split *split = readSplit(fd, revision);
|
||||||
if (0 == i+offset) {
|
xaccTransAppendSplit(trans, split);
|
||||||
Split *s = trans->splits->data;
|
|
||||||
/* the first split has been malloced. just replace it */
|
if(!notes) {
|
||||||
xaccRemoveEntity (&s->guid);
|
notes = xaccSplitGetMemo (split);
|
||||||
xaccFreeSplit (s);
|
if(notes) xaccTransSetNotes (trans, notes);
|
||||||
trans->splits->data = split;
|
}
|
||||||
split->parent = trans;
|
}
|
||||||
} else {
|
|
||||||
xaccTransAppendSplit(trans, split);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!notes) {
|
|
||||||
notes = xaccSplitGetMemo (split);
|
|
||||||
if (notes)
|
|
||||||
xaccTransSetNotes (trans, notes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xaccTransCommitEdit (trans);
|
xaccTransCommitEdit (trans);
|
||||||
|
|
||||||
return trans;
|
return trans;
|
||||||
@ -1275,6 +1362,7 @@ readSplit ( int fd, int token )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
XACC_FLIP_DOUBLE (share_price);
|
XACC_FLIP_DOUBLE (share_price);
|
||||||
|
|
||||||
DxaccSplitSetSharePriceAndAmount (split, share_price, num_shares);
|
DxaccSplitSetSharePriceAndAmount (split, share_price, num_shares);
|
||||||
|
|
||||||
DEBUG ("num_shares %f \n", num_shares);
|
DEBUG ("num_shares %f \n", num_shares);
|
||||||
@ -1293,6 +1381,7 @@ readSplit ( int fd, int token )
|
|||||||
peer_acc = locateAccount (acc_id);
|
peer_acc = locateAccount (acc_id);
|
||||||
xaccAccountInsertSplit (peer_acc, split);
|
xaccAccountInsertSplit (peer_acc, split);
|
||||||
|
|
||||||
|
mark_potential_quote(split, share_price, num_shares);
|
||||||
return split;
|
return split;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1486,7 +1575,7 @@ xaccWriteGncBinAccountGroup(FILE *f, AccountGroup *grp )
|
|||||||
|
|
||||||
accounts_to_ids = g_hash_table_new(g_direct_hash, g_direct_equal);
|
accounts_to_ids = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
if(!accounts_to_ids) {
|
if(!accounts_to_ids) {
|
||||||
error_code = ERR_FILEIO_ALLOC;
|
error_code = ERR_BACKEND_ALLOC;
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,47 +31,26 @@
|
|||||||
#define __IO_GNCBIN_H__
|
#define __IO_GNCBIN_H__
|
||||||
|
|
||||||
#include "Backend.h"
|
#include "Backend.h"
|
||||||
#include "Group.h"
|
#include "gnc-book.h"
|
||||||
#include "FileIO.h"
|
|
||||||
|
|
||||||
/** PROTOTYPES ******************************************************/
|
/** PROTOTYPES ******************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The xaccReadAccountGroupFD() and xaccWriteAccountGroupFD()
|
* NOTE: These routines should not be used directly for file IO. They
|
||||||
* routines read and write the GnuCash "xacc" byte stream (file)
|
* are not inherently safe against file-locking errors. For direct
|
||||||
* format. This is a binary format that exactly represents all of the
|
* file IO, the gnc-book's higher level functions should be used.
|
||||||
* data that can appear in the AccountGroup structure as a sequence of
|
|
||||||
* bytes. The Read and Write routines are exact inverses of each other:
|
|
||||||
* that is, there is no loss of data involved in converting an
|
|
||||||
* AccountGroup into a byte stream and back again. These routines
|
|
||||||
* can be thought of as implementing a kind of "object persistance"
|
|
||||||
* for the AccountGroup object. Note that these routines can also
|
|
||||||
* be used to provide inter-process communication using either pipes or
|
|
||||||
* sockets. That is, by writing into a socket or pipe with the
|
|
||||||
* xaccWriteAccountGroupFD() routine, and reading from it at the other
|
|
||||||
* end with the xaccReadAccountGroupFD() routine, an exact duplicate of
|
|
||||||
* the AccountGroup can be created in a different process.
|
|
||||||
*
|
*
|
||||||
* NOTE: These routines should not be used directly for file IO.
|
* gnc_book_load_from_binfile() will load the financial data
|
||||||
* They are not inherently safe against file-locking errors.
|
* represented by the book's file_path into the indicated book.
|
||||||
* For direct file IO, the Session object should be used.
|
|
||||||
*
|
*
|
||||||
* The xaccReadOldBinAccountGroupFile() method will read the "xacc"
|
* gnc_book_get_binfile_io_error() will return an error code for any
|
||||||
* format byte stream from the indicated file, and build and return
|
* error detected that occured during reading or writing. It will
|
||||||
* the corresponding AccountGroup structure.
|
* reset the error code after being called. The current
|
||||||
*
|
* implementation can be thought of as a "stack of depth one", and
|
||||||
* If a read error occurred during reading, the returned value
|
* this routine as a "pop". Future implementations may have a
|
||||||
* may or may not be null. Use the xaccGetOldBinFileIOError() routine
|
* deeper stack.
|
||||||
* to check for read errors.
|
|
||||||
*
|
|
||||||
* The xaccGetOldBinFileIOError() method will return an error code for
|
|
||||||
* any error detected that occured during reading or writing. It
|
|
||||||
* will reset the error code after being called. The current
|
|
||||||
* implementation can be thought of as a "stack of depth one", and
|
|
||||||
* this routine as a "pop". Future implementations may have a
|
|
||||||
* deeper stack.
|
|
||||||
* */
|
* */
|
||||||
AccountGroup *xaccReadGncBinAccountGroupFile (const char *filename);
|
void gnc_book_load_from_binfile(GNCBook *book);
|
||||||
GNCBackendError xaccGetGncBinFileIOError (void);
|
GNCBackendError gnc_book_get_binfile_io_error(void);
|
||||||
|
|
||||||
#endif /* __IO_GNCBIN_H__ */
|
#endif /* __IO_GNCBIN_H__ */
|
||||||
|
57
src/engine/io-gncxml-p.h
Normal file
57
src/engine/io-gncxml-p.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/********************************************************************\
|
||||||
|
* io-gncxml-p.h - private header for xml read code *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 1999-2001 Rob Browning *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License as *
|
||||||
|
* published by the Free Software Foundation; either version 2 of *
|
||||||
|
* the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License*
|
||||||
|
* along with this program; if not, contact: *
|
||||||
|
* *
|
||||||
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||||
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||||
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||||
|
* *
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef __IO_GNCXML_P_H__
|
||||||
|
#define __IO_GNCXML_P_H__
|
||||||
|
|
||||||
|
#include "sixtp.h"
|
||||||
|
#include "io-gncxml.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GNC_PARSE_ERR_NONE,
|
||||||
|
GNC_PARSE_ERR_BAD_VERSION,
|
||||||
|
} GNCParseErr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* have we gotten the file version yet? */
|
||||||
|
gboolean seen_version;
|
||||||
|
gint64 version;
|
||||||
|
|
||||||
|
/* top level <gnc-data> parser - we need this so we can set it up
|
||||||
|
after we see the file version. */
|
||||||
|
sixtp *gnc_parser;
|
||||||
|
|
||||||
|
/* The account group */
|
||||||
|
AccountGroup *account_group;
|
||||||
|
|
||||||
|
/* The pricedb */
|
||||||
|
GNCPriceDB *pricedb;
|
||||||
|
|
||||||
|
/* The query */
|
||||||
|
Query *query;
|
||||||
|
|
||||||
|
GNCParseErr error;
|
||||||
|
} GNCParseStatus;
|
||||||
|
|
||||||
|
#endif
|
@ -16,9 +16,12 @@
|
|||||||
#include "gnc-xml-helper.h"
|
#include "gnc-xml-helper.h"
|
||||||
#include "Account.h"
|
#include "Account.h"
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
#include "gnc-engine-util.h"
|
#include "gnc-engine-util.h"
|
||||||
|
#include "gnc-book-p.h"
|
||||||
|
|
||||||
#include "io-gncxml.h"
|
#include "io-gncxml.h"
|
||||||
|
#include "io-gncxml-p.h"
|
||||||
|
|
||||||
#include "sixtp.h"
|
#include "sixtp.h"
|
||||||
#include "sixtp-stack.h"
|
#include "sixtp-stack.h"
|
||||||
@ -48,33 +51,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* static short module = MOD_IO; */
|
static short module = MOD_IO;
|
||||||
|
|
||||||
/* ========================================================== */
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GNC_PARSE_ERR_NONE,
|
|
||||||
GNC_PARSE_ERR_BAD_VERSION,
|
|
||||||
} GNCParseErr;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* have we gotten the file version yet? */
|
|
||||||
gboolean seen_version;
|
|
||||||
gint64 version;
|
|
||||||
|
|
||||||
/* top level <gnc-data> parser - we need this so we can set it up
|
|
||||||
after we see the file version. */
|
|
||||||
sixtp *gnc_parser;
|
|
||||||
|
|
||||||
/* The account group */
|
|
||||||
AccountGroup *account_group;
|
|
||||||
|
|
||||||
/* The query */
|
|
||||||
Query *query;
|
|
||||||
|
|
||||||
GNCParseErr error;
|
|
||||||
} GNCParseStatus;
|
|
||||||
|
|
||||||
|
|
||||||
/* ================================================================= */
|
/* ================================================================= */
|
||||||
/* <version> (lineage <gnc>)
|
/* <version> (lineage <gnc>)
|
||||||
@ -283,6 +260,7 @@ gncxml_setup_for_read (GNCParseStatus *global_parse_status)
|
|||||||
global_parse_status->seen_version = FALSE;
|
global_parse_status->seen_version = FALSE;
|
||||||
global_parse_status->gnc_parser = gnc_pr;
|
global_parse_status->gnc_parser = gnc_pr;
|
||||||
global_parse_status->account_group = NULL;
|
global_parse_status->account_group = NULL;
|
||||||
|
global_parse_status->pricedb = NULL;
|
||||||
global_parse_status->query = NULL;
|
global_parse_status->query = NULL;
|
||||||
global_parse_status->error = GNC_PARSE_ERR_NONE;
|
global_parse_status->error = GNC_PARSE_ERR_NONE;
|
||||||
|
|
||||||
@ -292,16 +270,18 @@ gncxml_setup_for_read (GNCParseStatus *global_parse_status)
|
|||||||
/* ================================================================== */
|
/* ================================================================== */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gncxml_read(const gchar *filename,
|
gnc_book_load_from_xml_file(GNCBook *book)
|
||||||
AccountGroup **result_group)
|
|
||||||
{
|
{
|
||||||
gboolean parse_ok;
|
gboolean parse_ok;
|
||||||
gpointer parse_result = NULL;
|
gpointer parse_result = NULL;
|
||||||
sixtp *top_level_pr;
|
sixtp *top_level_pr;
|
||||||
GNCParseStatus global_parse_status;
|
GNCParseStatus global_parse_status;
|
||||||
|
const gchar *filename;
|
||||||
|
|
||||||
|
g_return_val_if_fail(book, FALSE);
|
||||||
|
|
||||||
|
filename = gnc_book_get_file_path(book);
|
||||||
g_return_val_if_fail(filename, FALSE);
|
g_return_val_if_fail(filename, FALSE);
|
||||||
g_return_val_if_fail(result_group, FALSE);
|
|
||||||
|
|
||||||
top_level_pr = gncxml_setup_for_read (&global_parse_status);
|
top_level_pr = gncxml_setup_for_read (&global_parse_status);
|
||||||
g_return_val_if_fail(top_level_pr, FALSE);
|
g_return_val_if_fail(top_level_pr, FALSE);
|
||||||
@ -314,8 +294,29 @@ gncxml_read(const gchar *filename,
|
|||||||
|
|
||||||
sixtp_destroy(top_level_pr);
|
sixtp_destroy(top_level_pr);
|
||||||
|
|
||||||
if(parse_ok && global_parse_status.account_group) {
|
if(parse_ok) {
|
||||||
*result_group = global_parse_status.account_group;
|
if(!global_parse_status.account_group)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
{
|
||||||
|
AccountGroup *g = gnc_book_get_group(book);
|
||||||
|
|
||||||
|
if(g) xaccFreeAccountGroup(g);
|
||||||
|
gnc_book_set_group(book, global_parse_status.account_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(global_parse_status.pricedb)
|
||||||
|
{
|
||||||
|
GNCPriceDB *db = gnc_book_get_pricedb(book);
|
||||||
|
|
||||||
|
if(db) gnc_pricedb_destroy(db);
|
||||||
|
|
||||||
|
gnc_book_set_pricedb(book, global_parse_status.pricedb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gnc_book_set_pricedb(book, gnc_pricedb_create());
|
||||||
|
}
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
} else {
|
} else {
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@ -324,6 +325,40 @@ gncxml_read(const gchar *filename,
|
|||||||
|
|
||||||
/* ================================================================== */
|
/* ================================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_is_xml_data_file(const gchar *filename)
|
||||||
|
{
|
||||||
|
FILE *f = NULL;
|
||||||
|
char first_chunk[256];
|
||||||
|
const char* cursor = NULL;
|
||||||
|
ssize_t num_read;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(filename, result);
|
||||||
|
|
||||||
|
f = fopen(filename, "r");
|
||||||
|
g_return_val_if_fail(f, result);
|
||||||
|
|
||||||
|
num_read = fread(first_chunk, sizeof(char), sizeof(first_chunk) - 1, f);
|
||||||
|
if(num_read == 0) goto cleanup_and_exit;
|
||||||
|
first_chunk[num_read] = '\0';
|
||||||
|
|
||||||
|
cursor = first_chunk;
|
||||||
|
while(*cursor && isspace(*cursor)) cursor++;
|
||||||
|
|
||||||
|
if(cursor && strncmp(cursor, "<?xml", 5) == 0) {
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_and_exit:
|
||||||
|
if(f) fclose(f);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
static GNCParseStatus*
|
static GNCParseStatus*
|
||||||
read_from_buf(char *bufp, int bufsz)
|
read_from_buf(char *bufp, int bufsz)
|
||||||
{
|
{
|
||||||
@ -389,36 +424,6 @@ gncxml_read_query (char * bufp, int bufsz)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================== */
|
#endif
|
||||||
|
|
||||||
gboolean
|
|
||||||
is_gncxml_file(const gchar *filename)
|
|
||||||
{
|
|
||||||
FILE *f = NULL;
|
|
||||||
char first_chunk[256];
|
|
||||||
const char* cursor = NULL;
|
|
||||||
ssize_t num_read;
|
|
||||||
gboolean result = FALSE;
|
|
||||||
|
|
||||||
g_return_val_if_fail(filename, result);
|
|
||||||
|
|
||||||
f = fopen(filename, "r");
|
|
||||||
g_return_val_if_fail(f, result);
|
|
||||||
|
|
||||||
num_read = fread(first_chunk, sizeof(char), sizeof(first_chunk) - 1, f);
|
|
||||||
if(num_read == 0) goto cleanup_and_exit;
|
|
||||||
first_chunk[num_read] = '\0';
|
|
||||||
|
|
||||||
cursor = first_chunk;
|
|
||||||
while(*cursor && isspace(*cursor)) cursor++;
|
|
||||||
|
|
||||||
if(cursor && strncmp(cursor, "<?xml", 5) == 0) {
|
|
||||||
result = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_and_exit:
|
|
||||||
if(f) fclose(f);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ======================= END OF FILE ============================== */
|
/* ======================= END OF FILE ============================== */
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* e.g. even some simple #define macros might help here ...
|
* e.g. even some simple #define macros might help here ...
|
||||||
*
|
*
|
||||||
* HISTORY:
|
* HISTORY:
|
||||||
* Initial code by Rob L. Browning 4Q 2000
|
* Initial code by Rob Browning 4Q 2000
|
||||||
* Tuneups by James LewisMoss Dec 2000-Feb 2001
|
* Tuneups by James LewisMoss Dec 2000-Feb 2001
|
||||||
* Generic I/O hack by Linas Vepstas January 2001
|
* Generic I/O hack by Linas Vepstas January 2001
|
||||||
*
|
*
|
||||||
@ -81,6 +81,8 @@ static const gchar *gncxml_emacs_trailer =
|
|||||||
"<!-- mode: xml -->\n"
|
"<!-- mode: xml -->\n"
|
||||||
"<!-- End: -->\n";
|
"<!-- End: -->\n";
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gncxml_append_emacs_trailer(const gchar *filename)
|
gncxml_append_emacs_trailer(const gchar *filename)
|
||||||
{
|
{
|
||||||
@ -98,6 +100,7 @@ gncxml_append_emacs_trailer(const gchar *filename)
|
|||||||
return fclose(toappend);
|
return fclose(toappend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* =============================================================== */
|
/* =============================================================== */
|
||||||
/* create a new xml document and poke all the query terms into it. */
|
/* create a new xml document and poke all the query terms into it. */
|
||||||
|
|
||||||
@ -134,16 +137,20 @@ gncxml_new_query_doc (Query *q)
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* =============================================================== */
|
/* =============================================================== */
|
||||||
/* create a new xml document and poke all account & txn data into it. */
|
/* create a new xml document and poke all account & txn data into it. */
|
||||||
|
|
||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
gncxml_newdoc (AccountGroup *group, int do_txns)
|
gncxml_newdoc (GNCBook *book, int do_txns)
|
||||||
{
|
{
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
xmlNodePtr ledger_data;
|
xmlNodePtr ledger_data;
|
||||||
xmlNodePtr tmpnode;
|
xmlNodePtr tmpnode;
|
||||||
|
AccountGroup *group = gnc_book_get_group(book);
|
||||||
|
GNCPriceDB *pricedb = gnc_book_get_pricedb(book);
|
||||||
|
|
||||||
doc = xmlNewDoc("1.0");
|
doc = xmlNewDoc("1.0");
|
||||||
doc->xmlRootNode = xmlNewDocNode(doc, NULL, "gnc", NULL);
|
doc->xmlRootNode = xmlNewDocNode(doc, NULL, "gnc", NULL);
|
||||||
|
|
||||||
@ -162,7 +169,13 @@ gncxml_newdoc (AccountGroup *group, int do_txns)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!xml_add_commodity_restorers(ledger_data)) {
|
if(!xml_add_commodity_restorers(ledger_data)) {
|
||||||
PERR ("couldn't commodity restore");
|
PERR ("couldn't create commodity restorers");
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
return 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!xml_add_gnc_pricedb(ledger_data, "pricedb", pricedb)) {
|
||||||
|
PERR ("couldn't create pricedb");
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
@ -184,6 +197,8 @@ gncxml_newdoc (AccountGroup *group, int do_txns)
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
/* =============================================================== */
|
/* =============================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -229,18 +244,20 @@ gncxml_write_query_to_buf (Query *q, char **bufp, int *sz)
|
|||||||
PINFO ("wrote %d bytes", *sz);
|
PINFO ("wrote %d bytes", *sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* =============================================================== */
|
/* =============================================================== */
|
||||||
/* write the account group to a filename */
|
/* write the account group to a filename */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gncxml_write(AccountGroup *group, const gchar *filename)
|
gnc_book_write_to_xml_file(GNCBook *book, const gchar *filename)
|
||||||
{
|
{
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!group || !filename) return FALSE;
|
if(!filename) return FALSE;
|
||||||
|
|
||||||
doc = gncxml_newdoc (group, 1);
|
doc = gncxml_newdoc (book, 1);
|
||||||
if (!doc) return FALSE;
|
if (!doc) return FALSE;
|
||||||
|
|
||||||
xmlIndentTreeOutput = TRUE;
|
xmlIndentTreeOutput = TRUE;
|
||||||
|
@ -12,30 +12,25 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "Group.h"
|
#include "gnc-book.h"
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
|
|
||||||
/* read in an account group from a file */
|
/* FIXME: eventually, we probably need to add an error stack
|
||||||
gboolean gncxml_read(const gchar *filename, AccountGroup **result_group);
|
accessable via gnc_book_get_xml_io_error() a la binfile. */
|
||||||
|
|
||||||
|
/* read in an account group from a file */
|
||||||
|
gboolean gnc_book_load_from_xml_file(GNCBook *book);
|
||||||
|
|
||||||
|
/* write all account info to a file */
|
||||||
|
gboolean gnc_book_write_to_xml_file(GNCBook *book, const char *filename);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
/* read an account group from a buffer in memory
|
/* read an account group from a buffer in memory
|
||||||
* the pointer bufp must point at the ascii xml, and bufsz
|
* the pointer bufp must point at the ascii xml, and bufsz
|
||||||
* must be the size of the buffer.
|
* must be the size of the buffer.
|
||||||
*/
|
*/
|
||||||
AccountGroup *
|
AccountGroup *gncxml_read_from_buf (char *bufp, int bufsz);
|
||||||
gncxml_read_from_buf (char *bufp, int bufsz);
|
|
||||||
|
|
||||||
Query *
|
|
||||||
gncxml_read_query (char *bufp, int bufsz);
|
|
||||||
|
|
||||||
/* write all account info to a file */
|
|
||||||
gboolean gncxml_write(AccountGroup *group, const gchar *name);
|
|
||||||
|
|
||||||
/* The is_gncxml_file() routine checks to see if the first few
|
|
||||||
* chars of the file look like gnc-xml data.
|
|
||||||
*/
|
|
||||||
gboolean is_gncxml_file(const gchar *name);
|
|
||||||
|
|
||||||
/* write all account info into memory. This routine returns a
|
/* write all account info into memory. This routine returns a
|
||||||
* pointer to freshly malloced memory in bufp. You muse free
|
* pointer to freshly malloced memory in bufp. You muse free
|
||||||
@ -43,14 +38,22 @@ gboolean is_gncxml_file(const gchar *name);
|
|||||||
* returned in sz
|
* returned in sz
|
||||||
*/
|
*/
|
||||||
void gncxml_write_to_buf (AccountGroup *group, char **bufp, int *sz);
|
void gncxml_write_to_buf (AccountGroup *group, char **bufp, int *sz);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* write only the account and currency info to the buf, do *not*
|
* write only the account and currency info to the buf, do *not*
|
||||||
* write any of the splits or transactions
|
* write any of the splits or transactions
|
||||||
*/
|
*/
|
||||||
void gncxml_write_group_to_buf (AccountGroup *group, char **bufp, int *sz);
|
void gncxml_write_group_to_buf (AccountGroup *group, char **bufp, int *sz);
|
||||||
|
|
||||||
/* write the query terms to memory */
|
#endif
|
||||||
void gncxml_write_query_to_buf (Query *q, char **bufp, int *sz);
|
|
||||||
|
|
||||||
|
/* write/read query terms to/from memory */
|
||||||
|
void gncxml_write_query_to_buf (Query *q, char **bufp, int *sz);
|
||||||
|
Query *gncxml_read_query (char *bufp, int bufsz);
|
||||||
|
|
||||||
|
/* The is_gncxml_file() routine checks to see if the first few
|
||||||
|
* chars of the file look like gnc-xml data.
|
||||||
|
*/
|
||||||
|
gboolean gnc_is_xml_data_file(const gchar *name);
|
||||||
|
|
||||||
#endif /* __IO_GNCXML_H__ */
|
#endif /* __IO_GNCXML_H__ */
|
||||||
|
@ -10,6 +10,19 @@
|
|||||||
#include "GNCId.h"
|
#include "GNCId.h"
|
||||||
#include "kvp_frame.h"
|
#include "kvp_frame.h"
|
||||||
|
|
||||||
|
xmlNodePtr
|
||||||
|
text_to_dom_tree(const char *tag, const char *str)
|
||||||
|
{
|
||||||
|
xmlNodePtr result;
|
||||||
|
|
||||||
|
g_return_val_if_fail(tag, NULL);
|
||||||
|
g_return_val_if_fail(str, NULL);
|
||||||
|
result = xmlNewNode(NULL, tag);
|
||||||
|
g_return_val_if_fail(result, NULL);
|
||||||
|
xmlNodeAddContent(result, str);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
xmlNodePtr
|
xmlNodePtr
|
||||||
guid_to_dom_tree(const char *tag, const GUID* gid)
|
guid_to_dom_tree(const char *tag, const GUID* gid)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "gnc-numeric.h"
|
#include "gnc-numeric.h"
|
||||||
#include "kvp_frame.h"
|
#include "kvp_frame.h"
|
||||||
|
|
||||||
|
xmlNodePtr text_to_dom_tree(const char *tag, const char *str);
|
||||||
xmlNodePtr guid_to_dom_tree(const char *tag, const GUID* gid);
|
xmlNodePtr guid_to_dom_tree(const char *tag, const GUID* gid);
|
||||||
xmlNodePtr commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c);
|
xmlNodePtr commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c);
|
||||||
xmlNodePtr timespec_to_dom_tree(const char *tag, const Timespec *spec);
|
xmlNodePtr timespec_to_dom_tree(const char *tag, const Timespec *spec);
|
||||||
|
@ -368,14 +368,17 @@ dom_tree_to_kvp_frame(xmlNodePtr node)
|
|||||||
gchar *
|
gchar *
|
||||||
dom_tree_to_text(xmlNodePtr tree)
|
dom_tree_to_text(xmlNodePtr tree)
|
||||||
{
|
{
|
||||||
/* Expect *only* text and comment sibling nodes. Ignore comment
|
/* Expect *only* text and comment sibling nodes in the given tree --
|
||||||
nodes and collapse text nodes into one string. Return NULL if
|
which actually may only be a "list". i.e. if you're trying to
|
||||||
expectations are unsatisfied.
|
extract bar from <foo>bar</foo>, pass in <foo>->xmlChildrenNode
|
||||||
|
to this function. This expectation is different from the rest of
|
||||||
|
the dom_tree_to_* converters...
|
||||||
|
|
||||||
|
Ignores comment nodes and collapse text nodes into one string.
|
||||||
|
Returns NULL if expectations are unsatisfied.
|
||||||
|
|
||||||
If there are a lot of text sub-nodes, this algorithm may be
|
If there are a lot of text sub-nodes, this algorithm may be
|
||||||
inefficient because it'll reallocate a lot.
|
inefficient as it will reallocate a lot. */
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
gboolean ok = TRUE;
|
gboolean ok = TRUE;
|
||||||
xmlNodePtr current;
|
xmlNodePtr current;
|
||||||
@ -392,7 +395,9 @@ dom_tree_to_text(xmlNodePtr tree)
|
|||||||
case XML_COMMENT_NODE:
|
case XML_COMMENT_NODE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PERR("dom_tree_to_text: hit illegal node type while extracting text.");
|
PERR("dom_tree_to_text: hit illegal node while extracting text.");
|
||||||
|
PERR(" (name %s) (type %d) (content %s)",
|
||||||
|
current->name, current->type, current->content);
|
||||||
current = NULL;
|
current = NULL;
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -26,10 +26,15 @@ sixtp* query_server_parser_new (void);
|
|||||||
sixtp* kvp_frame_parser_new(void);
|
sixtp* kvp_frame_parser_new(void);
|
||||||
|
|
||||||
/* from sixtp-to-dom-parser.c */
|
/* from sixtp-to-dom-parser.c */
|
||||||
sixtp* sixtp_dom_parser_new(sixtp_end_handler ender);
|
|
||||||
|
|
||||||
|
/* Create a parser that will turn the entire sub-tree into a DOM tree
|
||||||
|
an pass it in as (don't put anything into parent_data)
|
||||||
|
you must deal with the xml tree in *result.
|
||||||
|
*/
|
||||||
|
sixtp* sixtp_dom_parser_new(sixtp_end_handler ender,
|
||||||
|
sixtp_result_handler cleanup_result_by_default_func,
|
||||||
|
sixtp_result_handler cleanup_result_on_fail_func);
|
||||||
|
|
||||||
|
sixtp* gnc_pricedb_parser_new(void);
|
||||||
|
|
||||||
#endif /* _SIXTP_PARSERS_H_ */
|
#endif /* _SIXTP_PARSERS_H_ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,12 +21,18 @@ static gboolean dom_start_handler(
|
|||||||
if(parent_data == NULL)
|
if(parent_data == NULL)
|
||||||
{
|
{
|
||||||
thing = xmlNewNode(global_namespace, tag);
|
thing = xmlNewNode(global_namespace, tag);
|
||||||
|
/* only publish the result if we're the parent */
|
||||||
|
*result = thing;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
thing = xmlNewChild((xmlNodePtr)parent_data, global_namespace,
|
thing = xmlNewChild((xmlNodePtr) parent_data,
|
||||||
tag, NULL);
|
global_namespace,
|
||||||
|
tag,
|
||||||
|
NULL);
|
||||||
|
*result = NULL;
|
||||||
}
|
}
|
||||||
|
*data_for_children = thing;
|
||||||
|
|
||||||
if(attrs != NULL)
|
if(attrs != NULL)
|
||||||
{
|
{
|
||||||
@ -36,10 +42,32 @@ static gboolean dom_start_handler(
|
|||||||
atptr += 2;
|
atptr += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
*result = thing;
|
static void
|
||||||
*data_for_children = thing;
|
dom_fail_handler(gpointer data_for_children,
|
||||||
|
GSList* data_from_children,
|
||||||
|
GSList* sibling_data,
|
||||||
|
gpointer parent_data,
|
||||||
|
gpointer global_data,
|
||||||
|
gpointer *result,
|
||||||
|
const gchar *tag)
|
||||||
|
{
|
||||||
|
if(*result) xmlFreeNode(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean is_whitespace(const char *text, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if(!isspace(text[i]))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +83,10 @@ static gboolean dom_chars_handler(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sixtp* sixtp_dom_parser_new(sixtp_end_handler ender)
|
sixtp *
|
||||||
|
sixtp_dom_parser_new(sixtp_end_handler ender,
|
||||||
|
sixtp_result_handler cleanup_result_by_default_func,
|
||||||
|
sixtp_result_handler cleanup_result_on_fail_func)
|
||||||
{
|
{
|
||||||
sixtp *top_level;
|
sixtp *top_level;
|
||||||
|
|
||||||
@ -66,11 +97,22 @@ sixtp* sixtp_dom_parser_new(sixtp_end_handler ender)
|
|||||||
SIXTP_START_HANDLER_ID, dom_start_handler,
|
SIXTP_START_HANDLER_ID, dom_start_handler,
|
||||||
SIXTP_CHARACTERS_HANDLER_ID, dom_chars_handler,
|
SIXTP_CHARACTERS_HANDLER_ID, dom_chars_handler,
|
||||||
SIXTP_END_HANDLER_ID, ender,
|
SIXTP_END_HANDLER_ID, ender,
|
||||||
|
SIXTP_FAIL_HANDLER_ID, dom_fail_handler,
|
||||||
SIXTP_NO_MORE_HANDLERS)))
|
SIXTP_NO_MORE_HANDLERS)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cleanup_result_by_default_func)
|
||||||
|
{
|
||||||
|
sixtp_set_cleanup_result(top_level, cleanup_result_by_default_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cleanup_result_by_default_func)
|
||||||
|
{
|
||||||
|
sixtp_set_result_fail(top_level, cleanup_result_on_fail_func);
|
||||||
|
}
|
||||||
|
|
||||||
if(!sixtp_add_sub_parser(top_level, SIXTP_MAGIC_CATCHER, top_level))
|
if(!sixtp_add_sub_parser(top_level, SIXTP_MAGIC_CATCHER, top_level))
|
||||||
{
|
{
|
||||||
sixtp_destroy(top_level);
|
sixtp_destroy(top_level);
|
||||||
@ -79,4 +121,3 @@ sixtp* sixtp_dom_parser_new(sixtp_end_handler ender)
|
|||||||
|
|
||||||
return top_level;
|
return top_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,10 @@ concatenate_child_result_chars(GSList *data_from_children) {
|
|||||||
I don't understand the claim; I'm just going to use
|
I don't understand the claim; I'm just going to use
|
||||||
atof or strtod to accomplish this.
|
atof or strtod to accomplish this.
|
||||||
|
|
||||||
|
RLB writes: FIXME: OK, but at the very least this may cause a
|
||||||
|
locale dependency. Whoever fixes that, please delete this whole
|
||||||
|
comment block.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
|
|
||||||
#ifndef _SIXTP_WRITERS_H_
|
#ifndef _SIXTP_WRITERS_H_
|
||||||
#define _SIXTP_WRITERS_H_
|
#define _SIXTP_WRITERS_H_
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "gnc-xml-helper.h"
|
#include "gnc-xml-helper.h"
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
|
#include "gnc-pricedb.h"
|
||||||
|
|
||||||
gboolean xml_add_account_restorers(xmlNodePtr p, AccountGroup *g);
|
gboolean xml_add_account_restorers(xmlNodePtr p, AccountGroup *g);
|
||||||
|
|
||||||
@ -20,6 +19,8 @@ gboolean xml_add_query_restorers(xmlNodePtr p, Query *q);
|
|||||||
|
|
||||||
gboolean xml_add_txn_and_split_restorers(xmlNodePtr p, AccountGroup *g);
|
gboolean xml_add_txn_and_split_restorers(xmlNodePtr p, AccountGroup *g);
|
||||||
|
|
||||||
|
gboolean xml_add_gnc_price(xmlNodePtr p, const char *tag, GNCPrice *db);
|
||||||
|
|
||||||
|
gboolean xml_add_gnc_pricedb(xmlNodePtr p, const char *tag, GNCPriceDB *db);
|
||||||
|
|
||||||
#endif /* _SIXTP_WRITERS_H_ */
|
#endif /* _SIXTP_WRITERS_H_ */
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -328,7 +330,7 @@ sixtp_sax_start_handler(void *user_data,
|
|||||||
gchar *next_parser_tag = NULL;
|
gchar *next_parser_tag = NULL;
|
||||||
gboolean lookup_success = FALSE;
|
gboolean lookup_success = FALSE;
|
||||||
sixtp_stack_frame *new_frame = NULL;
|
sixtp_stack_frame *new_frame = NULL;
|
||||||
|
|
||||||
g_return_if_fail(pdata->parsing_ok);
|
g_return_if_fail(pdata->parsing_ok);
|
||||||
|
|
||||||
current_frame = (sixtp_stack_frame *) pdata->stack->data;
|
current_frame = (sixtp_stack_frame *) pdata->stack->data;
|
||||||
|
@ -216,7 +216,7 @@ gnc_ui_get_account_field_value_string (Account *account,
|
|||||||
break;
|
break;
|
||||||
case ACCOUNT_BALANCE_EURO :
|
case ACCOUNT_BALANCE_EURO :
|
||||||
{
|
{
|
||||||
const gnc_commodity * account_currency =
|
gnc_commodity * account_currency =
|
||||||
xaccAccountGetCurrency(account);
|
xaccAccountGetCurrency(account);
|
||||||
gnc_numeric balance = gnc_ui_account_get_balance(account, FALSE);
|
gnc_numeric balance = gnc_ui_account_get_balance(account, FALSE);
|
||||||
gnc_numeric euro_balance = gnc_convert_to_euro(account_currency,
|
gnc_numeric euro_balance = gnc_convert_to_euro(account_currency,
|
||||||
@ -237,7 +237,7 @@ gnc_ui_get_account_field_value_string (Account *account,
|
|||||||
break;
|
break;
|
||||||
case ACCOUNT_TOTAL_EURO :
|
case ACCOUNT_TOTAL_EURO :
|
||||||
{
|
{
|
||||||
const gnc_commodity * account_currency =
|
gnc_commodity * account_currency =
|
||||||
xaccAccountGetCurrency(account);
|
xaccAccountGetCurrency(account);
|
||||||
gnc_numeric balance = gnc_ui_account_get_balance(account, TRUE);
|
gnc_numeric balance = gnc_ui_account_get_balance(account, TRUE);
|
||||||
gnc_numeric euro_balance = gnc_convert_to_euro(account_currency,
|
gnc_numeric euro_balance = gnc_convert_to_euro(account_currency,
|
||||||
@ -411,7 +411,7 @@ gnc_localeconv (void)
|
|||||||
return &lc;
|
return &lc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_locale_default_currency (void)
|
gnc_locale_default_currency (void)
|
||||||
{
|
{
|
||||||
static gnc_commodity * currency;
|
static gnc_commodity * currency;
|
||||||
@ -526,7 +526,7 @@ is_decimal_fraction (int fraction, guint8 *max_decimal_places_p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GNCPrintAmountInfo
|
GNCPrintAmountInfo
|
||||||
gnc_commodity_print_info (const gnc_commodity *commodity,
|
gnc_commodity_print_info (gnc_commodity *commodity,
|
||||||
gboolean use_symbol)
|
gboolean use_symbol)
|
||||||
{
|
{
|
||||||
GNCPrintAmountInfo info;
|
GNCPrintAmountInfo info;
|
||||||
|
@ -100,7 +100,7 @@ PriceSourceCode gnc_get_source_code (const char * codename);
|
|||||||
struct lconv * gnc_localeconv (void);
|
struct lconv * gnc_localeconv (void);
|
||||||
|
|
||||||
/* Returns the default currency of the current locale. */
|
/* Returns the default currency of the current locale. */
|
||||||
const gnc_commodity * gnc_locale_default_currency (void);
|
gnc_commodity * gnc_locale_default_currency (void);
|
||||||
|
|
||||||
/* Returns the number of decimal place to print in the current locale */
|
/* Returns the number of decimal place to print in the current locale */
|
||||||
int gnc_locale_decimal_places (void);
|
int gnc_locale_decimal_places (void);
|
||||||
@ -123,7 +123,7 @@ int gnc_locale_decimal_places (void);
|
|||||||
|
|
||||||
typedef struct _GNCPrintAmountInfo
|
typedef struct _GNCPrintAmountInfo
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity; /* may be NULL */
|
gnc_commodity *commodity; /* may be NULL */
|
||||||
|
|
||||||
guint8 max_decimal_places;
|
guint8 max_decimal_places;
|
||||||
guint8 min_decimal_places;
|
guint8 min_decimal_places;
|
||||||
@ -137,7 +137,7 @@ typedef struct _GNCPrintAmountInfo
|
|||||||
|
|
||||||
GNCPrintAmountInfo gnc_default_print_info (gboolean use_symbol);
|
GNCPrintAmountInfo gnc_default_print_info (gboolean use_symbol);
|
||||||
|
|
||||||
GNCPrintAmountInfo gnc_commodity_print_info (const gnc_commodity *commodity,
|
GNCPrintAmountInfo gnc_commodity_print_info (gnc_commodity *commodity,
|
||||||
gboolean use_symbol);
|
gboolean use_symbol);
|
||||||
|
|
||||||
GNCPrintAmountInfo gnc_account_quantity_print_info (Account *account,
|
GNCPrintAmountInfo gnc_account_quantity_print_info (Account *account,
|
||||||
|
@ -125,7 +125,7 @@ static void
|
|||||||
gnc_account_to_ui(AccountWindow *aw)
|
gnc_account_to_ui(AccountWindow *aw)
|
||||||
{
|
{
|
||||||
Account *account = aw_get_account (aw);
|
Account *account = aw_get_account (aw);
|
||||||
const gnc_commodity * commodity;
|
gnc_commodity * commodity;
|
||||||
const char *string;
|
const char *string;
|
||||||
gboolean tax_related;
|
gboolean tax_related;
|
||||||
gint pos = 0;
|
gint pos = 0;
|
||||||
@ -179,7 +179,7 @@ static void
|
|||||||
gnc_ui_to_account(AccountWindow *aw)
|
gnc_ui_to_account(AccountWindow *aw)
|
||||||
{
|
{
|
||||||
Account *account = aw_get_account (aw);
|
Account *account = aw_get_account (aw);
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
Account *parent_account;
|
Account *parent_account;
|
||||||
const char *old_string;
|
const char *old_string;
|
||||||
const char *string;
|
const char *string;
|
||||||
@ -280,7 +280,7 @@ gnc_finish_ok (AccountWindow *aw,
|
|||||||
/* do it all again, if needed */
|
/* do it all again, if needed */
|
||||||
if (aw->dialog_type == NEW_ACCOUNT && aw->subaccount_names)
|
if (aw->dialog_type == NEW_ACCOUNT && aw->subaccount_names)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
Account *parent;
|
Account *parent;
|
||||||
Account *account;
|
Account *account;
|
||||||
GList *node;
|
GList *node;
|
||||||
@ -440,11 +440,11 @@ static void
|
|||||||
gnc_account_change_currency_security(Account *account,
|
gnc_account_change_currency_security(Account *account,
|
||||||
GHashTable *change_currency,
|
GHashTable *change_currency,
|
||||||
GHashTable *change_security,
|
GHashTable *change_security,
|
||||||
const gnc_commodity * currency,
|
gnc_commodity * currency,
|
||||||
const gnc_commodity * security)
|
gnc_commodity * security)
|
||||||
{
|
{
|
||||||
const gnc_commodity * old_currency;
|
gnc_commodity * old_currency;
|
||||||
const gnc_commodity * old_security;
|
gnc_commodity * old_security;
|
||||||
gboolean new_currency;
|
gboolean new_currency;
|
||||||
gboolean new_security;
|
gboolean new_security;
|
||||||
GSList *stack;
|
GSList *stack;
|
||||||
@ -782,8 +782,8 @@ gnc_edit_account_ok(AccountWindow *aw)
|
|||||||
GNCAccountType current_type;
|
GNCAccountType current_type;
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
const gnc_commodity * currency;
|
gnc_commodity * currency;
|
||||||
const gnc_commodity * security;
|
gnc_commodity * security;
|
||||||
|
|
||||||
/* check for valid name */
|
/* check for valid name */
|
||||||
name = gtk_entry_get_text(GTK_ENTRY(aw->name_entry));
|
name = gtk_entry_get_text(GTK_ENTRY(aw->name_entry));
|
||||||
@ -1483,7 +1483,7 @@ static AccountWindow *
|
|||||||
gnc_ui_new_account_window_internal (Account *base_account,
|
gnc_ui_new_account_window_internal (Account *base_account,
|
||||||
GList *subaccount_names)
|
GList *subaccount_names)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
AccountWindow *aw;
|
AccountWindow *aw;
|
||||||
Account *account;
|
Account *account;
|
||||||
|
|
||||||
|
@ -78,10 +78,10 @@ select_modal_callback(const gnc_commodity * arg, void * data) {
|
|||||||
* gnc_ui_select_commodity_modal()
|
* gnc_ui_select_commodity_modal()
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_ui_select_commodity_modal(const gnc_commodity * orig_sel,
|
gnc_ui_select_commodity_modal(gnc_commodity * orig_sel,
|
||||||
GtkWidget * parent) {
|
GtkWidget * parent) {
|
||||||
const gnc_commodity * retval = NULL;
|
gnc_commodity * retval = NULL;
|
||||||
|
|
||||||
SelectCommodityWindow * win =
|
SelectCommodityWindow * win =
|
||||||
gnc_ui_select_commodity_create(orig_sel, &select_modal_callback, &retval);
|
gnc_ui_select_commodity_create(orig_sel, &select_modal_callback, &retval);
|
||||||
@ -406,7 +406,7 @@ new_modal_callback(const gnc_commodity * arg, void * data) {
|
|||||||
* gnc_ui_new_commodity_modal()
|
* gnc_ui_new_commodity_modal()
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_ui_new_commodity_modal(const char * selected_namespace,
|
gnc_ui_new_commodity_modal(const char * selected_namespace,
|
||||||
GtkWidget * parent) {
|
GtkWidget * parent) {
|
||||||
gnc_commodity * retval = NULL;
|
gnc_commodity * retval = NULL;
|
||||||
|
@ -38,11 +38,11 @@ void gnc_ui_select_commodity_destroy(SelectCommodityWindow * w);
|
|||||||
|
|
||||||
void gnc_ui_new_commodity_destroy(NewCommodityWindow * w);
|
void gnc_ui_new_commodity_destroy(NewCommodityWindow * w);
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_ui_select_commodity_modal(const gnc_commodity * orig_sel,
|
gnc_ui_select_commodity_modal(gnc_commodity * orig_sel,
|
||||||
GtkWidget * parent);
|
GtkWidget * parent);
|
||||||
|
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_ui_new_commodity_modal(const char * default_namespace,
|
gnc_ui_new_commodity_modal(const char * default_namespace,
|
||||||
GtkWidget * parent);
|
GtkWidget * parent);
|
||||||
|
|
||||||
|
@ -496,7 +496,7 @@ close_handler (gpointer user_data)
|
|||||||
FinCalcDialog *
|
FinCalcDialog *
|
||||||
gnc_ui_fincalc_dialog_create(void)
|
gnc_ui_fincalc_dialog_create(void)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
GNCPrintAmountInfo print_info;
|
GNCPrintAmountInfo print_info;
|
||||||
FinCalcDialog *fcd;
|
FinCalcDialog *fcd;
|
||||||
GtkObject *fcdo;
|
GtkObject *fcdo;
|
||||||
|
@ -195,7 +195,7 @@ gnc_option_set_ui_value(GNCOption *option, gboolean use_default)
|
|||||||
}
|
}
|
||||||
else if (safe_strcmp(type, "currency") == 0)
|
else if (safe_strcmp(type, "currency") == 0)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
|
|
||||||
commodity = gnc_scm_to_commodity (value);
|
commodity = gnc_scm_to_commodity (value);
|
||||||
if (commodity)
|
if (commodity)
|
||||||
@ -206,7 +206,7 @@ gnc_option_set_ui_value(GNCOption *option, gboolean use_default)
|
|||||||
}
|
}
|
||||||
else if (safe_strcmp(type, "commodity") == 0)
|
else if (safe_strcmp(type, "commodity") == 0)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
|
|
||||||
commodity = gnc_scm_to_commodity (value);
|
commodity = gnc_scm_to_commodity (value);
|
||||||
if (commodity)
|
if (commodity)
|
||||||
@ -480,7 +480,7 @@ gnc_option_get_ui_value(GNCOption *option)
|
|||||||
}
|
}
|
||||||
else if (safe_strcmp(type, "currency") == 0)
|
else if (safe_strcmp(type, "currency") == 0)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
|
|
||||||
commodity =
|
commodity =
|
||||||
gnc_currency_edit_get_currency(GNC_CURRENCY_EDIT(option->widget));
|
gnc_currency_edit_get_currency(GNC_CURRENCY_EDIT(option->widget));
|
||||||
@ -489,7 +489,7 @@ gnc_option_get_ui_value(GNCOption *option)
|
|||||||
}
|
}
|
||||||
else if (safe_strcmp(type, "commodity") == 0)
|
else if (safe_strcmp(type, "commodity") == 0)
|
||||||
{
|
{
|
||||||
const gnc_commodity *commodity;
|
gnc_commodity *commodity;
|
||||||
|
|
||||||
commodity =
|
commodity =
|
||||||
gnc_commodity_edit_get_commodity(GNC_COMMODITY_EDIT(option->widget));
|
gnc_commodity_edit_get_commodity(GNC_COMMODITY_EDIT(option->widget));
|
||||||
|
@ -38,7 +38,12 @@
|
|||||||
#include "gnc-commodity.h"
|
#include "gnc-commodity.h"
|
||||||
#include "gnc-engine.h"
|
#include "gnc-engine.h"
|
||||||
#include "gnc-ui.h"
|
#include "gnc-ui.h"
|
||||||
|
#include "gnc-pricedb-p.h"
|
||||||
|
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
|
/* This static indicates the debugging module that this .o belongs to. */
|
||||||
|
static short module = MOD_GUI;
|
||||||
|
|
||||||
struct _commoditydruid {
|
struct _commoditydruid {
|
||||||
GtkWidget * window;
|
GtkWidget * window;
|
||||||
@ -395,7 +400,6 @@ gnc_ui_commodity_druid_comm_check_cb(GnomeDruidPage * page, gpointer druid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
finish_helper(gpointer key, gpointer value, gpointer data) {
|
finish_helper(gpointer key, gpointer value, gpointer data) {
|
||||||
CommodityDruid * cd = data;
|
CommodityDruid * cd = data;
|
||||||
@ -404,11 +408,22 @@ finish_helper(gpointer key, gpointer value, gpointer data) {
|
|||||||
key);
|
key);
|
||||||
GList * accts;
|
GList * accts;
|
||||||
GList * node;
|
GList * node;
|
||||||
|
GNCBook * book = gncGetCurrentBook();
|
||||||
|
|
||||||
|
if(!book) {
|
||||||
|
PERR("finish_helper - no current book.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* key is the old mnemonic, value is a pointer to the gnc_commodity
|
/* key is the old mnemonic, value is a pointer to the gnc_commodity
|
||||||
* structure. */
|
* structure. */
|
||||||
gnc_commodity_table_insert(gnc_engine_commodities(), comm);
|
gnc_commodity_table_insert(gnc_engine_commodities(), comm);
|
||||||
|
|
||||||
|
/* s/old commodity/new commodity/g in the pricedb */
|
||||||
|
gnc_pricedb_substitute_commodity(gnc_book_get_pricedb(book),
|
||||||
|
old_comm,
|
||||||
|
comm);
|
||||||
|
|
||||||
/* now replace all the accounts using old_comm with new_comm */
|
/* now replace all the accounts using old_comm with new_comm */
|
||||||
accts = xaccGroupGetSubAccounts(gncGetCurrentGroup());
|
accts = xaccGroupGetSubAccounts(gncGetCurrentGroup());
|
||||||
|
|
||||||
|
@ -1184,7 +1184,7 @@ gnc_ui_qif_import_convert(QIFImportWindow * wind) {
|
|||||||
char * mnemonic = NULL;
|
char * mnemonic = NULL;
|
||||||
char * namespace = NULL;
|
char * namespace = NULL;
|
||||||
char * fullname = NULL;
|
char * fullname = NULL;
|
||||||
gchar * row_text[4] = { NULL, NULL, NULL, NULL };
|
const gchar * row_text[4] = { NULL, NULL, NULL, NULL };
|
||||||
int rownum;
|
int rownum;
|
||||||
|
|
||||||
/* get the default currency */
|
/* get the default currency */
|
||||||
@ -1281,7 +1281,7 @@ gnc_ui_qif_import_convert(QIFImportWindow * wind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rownum = gtk_clist_append(GTK_CLIST(wind->new_transaction_list),
|
rownum = gtk_clist_append(GTK_CLIST(wind->new_transaction_list),
|
||||||
row_text);
|
(gchar **) row_text);
|
||||||
|
|
||||||
retval = gh_cdr(retval);
|
retval = gh_cdr(retval);
|
||||||
}
|
}
|
||||||
@ -1662,7 +1662,7 @@ refresh_old_transactions(QIFImportWindow * wind, int selection) {
|
|||||||
SCM selected;
|
SCM selected;
|
||||||
Transaction * gnc_xtn;
|
Transaction * gnc_xtn;
|
||||||
Split * gnc_split;
|
Split * gnc_split;
|
||||||
gchar * row_text[4] = { NULL, NULL, NULL, NULL };
|
const gchar * row_text[4] = { NULL, NULL, NULL, NULL };
|
||||||
int rownum;
|
int rownum;
|
||||||
|
|
||||||
gtk_clist_column_titles_passive (GTK_CLIST(wind->old_transaction_list));
|
gtk_clist_column_titles_passive (GTK_CLIST(wind->old_transaction_list));
|
||||||
@ -1703,7 +1703,7 @@ refresh_old_transactions(QIFImportWindow * wind, int selection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rownum = gtk_clist_append(GTK_CLIST(wind->old_transaction_list),
|
rownum = gtk_clist_append(GTK_CLIST(wind->old_transaction_list),
|
||||||
row_text);
|
(gchar **) row_text);
|
||||||
|
|
||||||
gnc_clist_set_check (GTK_CLIST(wind->old_transaction_list),
|
gnc_clist_set_check (GTK_CLIST(wind->old_transaction_list),
|
||||||
rownum, 3, selected != SCM_BOOL_F);
|
rownum, 3, selected != SCM_BOOL_F);
|
||||||
|
@ -141,7 +141,7 @@ static void
|
|||||||
select_currency_cb(GtkButton * button, gpointer user_data)
|
select_currency_cb(GtkButton * button, gpointer user_data)
|
||||||
{
|
{
|
||||||
GNCCommodityEdit *gce = user_data;
|
GNCCommodityEdit *gce = user_data;
|
||||||
const gnc_commodity *new_commodity;
|
gnc_commodity *new_commodity;
|
||||||
GtkWidget *toplevel;
|
GtkWidget *toplevel;
|
||||||
|
|
||||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
|
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
|
||||||
@ -202,7 +202,7 @@ gnc_commodity_edit_new (void)
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gnc_commodity_edit_set_commodity (GNCCommodityEdit *gce,
|
gnc_commodity_edit_set_commodity (GNCCommodityEdit *gce,
|
||||||
const gnc_commodity *commodity)
|
gnc_commodity *commodity)
|
||||||
{
|
{
|
||||||
const char *text;
|
const char *text;
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ gnc_commodity_edit_set_commodity (GNCCommodityEdit *gce,
|
|||||||
*
|
*
|
||||||
* Returns the commodity currently selected by the widget.
|
* Returns the commodity currently selected by the widget.
|
||||||
*/
|
*/
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_commodity_edit_get_commodity (GNCCommodityEdit *gce)
|
gnc_commodity_edit_get_commodity (GNCCommodityEdit *gce)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(gce != NULL, NULL);
|
g_return_val_if_fail(gce != NULL, NULL);
|
||||||
|
@ -48,7 +48,7 @@ typedef struct {
|
|||||||
GtkWidget *entry; /* display of commodity name */
|
GtkWidget *entry; /* display of commodity name */
|
||||||
GtkWidget *button; /* button for popping up commodity window */
|
GtkWidget *button; /* button for popping up commodity window */
|
||||||
|
|
||||||
const gnc_commodity *selected_commodity;
|
gnc_commodity *selected_commodity;
|
||||||
} GNCCommodityEdit;
|
} GNCCommodityEdit;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -60,9 +60,9 @@ guint gnc_commodity_edit_get_type (void);
|
|||||||
GtkWidget *gnc_commodity_edit_new (void);
|
GtkWidget *gnc_commodity_edit_new (void);
|
||||||
|
|
||||||
void gnc_commodity_edit_set_commodity (GNCCommodityEdit *gce,
|
void gnc_commodity_edit_set_commodity (GNCCommodityEdit *gce,
|
||||||
const gnc_commodity *commodity);
|
gnc_commodity *commodity);
|
||||||
|
|
||||||
const gnc_commodity * gnc_commodity_edit_get_commodity (GNCCommodityEdit *gce);
|
gnc_commodity * gnc_commodity_edit_get_commodity (GNCCommodityEdit *gce);
|
||||||
|
|
||||||
END_GNOME_DECLS
|
END_GNOME_DECLS
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ gnc_currency_edit_set_currency (GNCCurrencyEdit *gce,
|
|||||||
*
|
*
|
||||||
* Returns the selected currency.
|
* Returns the selected currency.
|
||||||
*/
|
*/
|
||||||
const gnc_commodity *
|
gnc_commodity *
|
||||||
gnc_currency_edit_get_currency (GNCCurrencyEdit *gce)
|
gnc_currency_edit_get_currency (GNCCurrencyEdit *gce)
|
||||||
{
|
{
|
||||||
const char *mnemonic;
|
const char *mnemonic;
|
||||||
|
@ -57,7 +57,7 @@ GtkWidget *gnc_currency_edit_new (void);
|
|||||||
void gnc_currency_edit_set_currency (GNCCurrencyEdit *gce,
|
void gnc_currency_edit_set_currency (GNCCurrencyEdit *gce,
|
||||||
const gnc_commodity *currency);
|
const gnc_commodity *currency);
|
||||||
|
|
||||||
const gnc_commodity * gnc_currency_edit_get_currency (GNCCurrencyEdit *gce);
|
gnc_commodity * gnc_currency_edit_get_currency (GNCCurrencyEdit *gce);
|
||||||
|
|
||||||
END_GNOME_DECLS
|
END_GNOME_DECLS
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#include "AccWindow.h"
|
#include "AccWindow.h"
|
||||||
#include "FileBox.h"
|
#include "FileBox.h"
|
||||||
#include "FileDialog.h"
|
#include "FileDialog.h"
|
||||||
#include "FileIO.h"
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "SplitLedger.h"
|
#include "SplitLedger.h"
|
||||||
#include "TransLog.h"
|
#include "TransLog.h"
|
||||||
|
@ -105,7 +105,7 @@ static GNCMainInfo * gnc_get_main_info(void);
|
|||||||
* kept around for the duration of the calculation. There may, in fact
|
* kept around for the duration of the calculation. There may, in fact
|
||||||
* be better ways to do this, but none occurred. */
|
* be better ways to do this, but none occurred. */
|
||||||
struct _GNCCurrencyAcc {
|
struct _GNCCurrencyAcc {
|
||||||
const gnc_commodity * currency;
|
gnc_commodity * currency;
|
||||||
gnc_numeric assets;
|
gnc_numeric assets;
|
||||||
gnc_numeric profits;
|
gnc_numeric profits;
|
||||||
};
|
};
|
||||||
@ -117,7 +117,7 @@ typedef struct _GNCCurrencyAcc GNCCurrencyAcc;
|
|||||||
* currency, plus (eventually) one for the default currency
|
* currency, plus (eventually) one for the default currency
|
||||||
* accumulation (like the EURO). */
|
* accumulation (like the EURO). */
|
||||||
struct _GNCCurrencyItem {
|
struct _GNCCurrencyItem {
|
||||||
const gnc_commodity * currency;
|
gnc_commodity * currency;
|
||||||
GtkWidget *listitem;
|
GtkWidget *listitem;
|
||||||
GtkWidget *assets_label;
|
GtkWidget *assets_label;
|
||||||
GtkWidget *profits_label;
|
GtkWidget *profits_label;
|
||||||
@ -132,7 +132,7 @@ typedef struct _GNCCurrencyItem GNCCurrencyItem;
|
|||||||
* only handles a single currency.
|
* only handles a single currency.
|
||||||
*/
|
*/
|
||||||
static GNCCurrencyItem *
|
static GNCCurrencyItem *
|
||||||
gnc_ui_build_currency_item(const gnc_commodity * currency)
|
gnc_ui_build_currency_item(gnc_commodity * currency)
|
||||||
{
|
{
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
GtkWidget *topbox;
|
GtkWidget *topbox;
|
||||||
@ -200,7 +200,7 @@ gnc_ui_build_currency_item(const gnc_commodity * currency)
|
|||||||
* This will search the given list, and if no accumulator is found,
|
* This will search the given list, and if no accumulator is found,
|
||||||
* will allocate a fresh one. */
|
* will allocate a fresh one. */
|
||||||
static GNCCurrencyAcc *
|
static GNCCurrencyAcc *
|
||||||
gnc_ui_get_currency_accumulator(GList **list, const gnc_commodity * currency)
|
gnc_ui_get_currency_accumulator(GList **list, gnc_commodity * currency)
|
||||||
{
|
{
|
||||||
GList *current;
|
GList *current;
|
||||||
GNCCurrencyAcc *found;
|
GNCCurrencyAcc *found;
|
||||||
@ -231,7 +231,7 @@ gnc_ui_get_currency_accumulator(GList **list, const gnc_commodity * currency)
|
|||||||
* the item into the list. */
|
* the item into the list. */
|
||||||
|
|
||||||
static GNCCurrencyItem *
|
static GNCCurrencyItem *
|
||||||
gnc_ui_get_currency_item(GList **list, const gnc_commodity * currency,
|
gnc_ui_get_currency_item(GList **list, gnc_commodity * currency,
|
||||||
GtkWidget *holder)
|
GtkWidget *holder)
|
||||||
{
|
{
|
||||||
GList *current;
|
GList *current;
|
||||||
@ -261,9 +261,9 @@ gnc_ui_accounts_recurse (AccountGroup *group, GList **currency_list,
|
|||||||
gnc_numeric amount;
|
gnc_numeric amount;
|
||||||
AccountGroup *children;
|
AccountGroup *children;
|
||||||
GNCAccountType account_type;
|
GNCAccountType account_type;
|
||||||
const gnc_commodity * account_currency;
|
gnc_commodity * account_currency;
|
||||||
const gnc_commodity * default_currency;
|
gnc_commodity * default_currency;
|
||||||
const gnc_commodity * euro_commodity;
|
gnc_commodity * euro_commodity;
|
||||||
GNCCurrencyAcc *currency_accum;
|
GNCCurrencyAcc *currency_accum;
|
||||||
GNCCurrencyAcc *euro_accum = NULL;
|
GNCCurrencyAcc *euro_accum = NULL;
|
||||||
GList *list;
|
GList *list;
|
||||||
@ -368,7 +368,7 @@ gnc_ui_refresh_statusbar (void)
|
|||||||
AccountGroup *group;
|
AccountGroup *group;
|
||||||
char asset_string[256];
|
char asset_string[256];
|
||||||
char profit_string[256];
|
char profit_string[256];
|
||||||
const gnc_commodity * default_currency;
|
gnc_commodity * default_currency;
|
||||||
GNCCurrencyAcc *currency_accum;
|
GNCCurrencyAcc *currency_accum;
|
||||||
GNCCurrencyItem *currency_item;
|
GNCCurrencyItem *currency_item;
|
||||||
GList *currency_list;
|
GList *currency_list;
|
||||||
@ -1368,7 +1368,7 @@ gnc_main_create_summary_bar (GnomeApp *app, GNCMainInfo *main_info)
|
|||||||
{
|
{
|
||||||
GtkWidget *summarybar;
|
GtkWidget *summarybar;
|
||||||
GtkWidget *combo_box;
|
GtkWidget *combo_box;
|
||||||
const gnc_commodity * default_currency;
|
gnc_commodity * default_currency;
|
||||||
GNCCurrencyItem *def_item;
|
GNCCurrencyItem *def_item;
|
||||||
|
|
||||||
summarybar = gtk_hbox_new (FALSE, 5);
|
summarybar = gtk_hbox_new (FALSE, 5);
|
||||||
|
@ -2113,7 +2113,7 @@ static void
|
|||||||
gnc_register_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
|
gnc_register_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
|
||||||
{
|
{
|
||||||
RegWindow *regData = data;
|
RegWindow *regData = data;
|
||||||
const gnc_commodity * currency;
|
gnc_commodity * currency;
|
||||||
GNCPrintAmountInfo print_info;
|
GNCPrintAmountInfo print_info;
|
||||||
gnc_numeric amount;
|
gnc_numeric amount;
|
||||||
Account *leader;
|
Account *leader;
|
||||||
|
@ -2,3 +2,4 @@ Makefile
|
|||||||
Makefile.in
|
Makefile.in
|
||||||
gnc-prices
|
gnc-prices
|
||||||
gnc-prices-2
|
gnc-prices-2
|
||||||
|
price-quote-helper
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
bin_SCRIPTS = gnc-prices
|
bin_SCRIPTS = gnc-prices
|
||||||
|
pkgdata_SCRIPTS=price-quote-helper
|
||||||
|
|
||||||
perllibdir = ${GNC_LIBDIR}/perl
|
perllibdir = ${GNC_LIBDIR}/perl
|
||||||
|
|
||||||
@ -8,8 +9,8 @@ perlsharedir = ${GNC_SHAREDIR}/perl
|
|||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
.cvsignore \
|
.cvsignore \
|
||||||
Quote_example.pl \
|
Quote_example.pl \
|
||||||
gnc-prices-2.in \
|
|
||||||
gnc-prices.in \
|
gnc-prices.in \
|
||||||
|
price-qupte-helper.in \
|
||||||
value_portfolio
|
value_portfolio
|
||||||
|
|
||||||
## We borrow guile's convention and use @-...-@ as the substitution
|
## We borrow guile's convention and use @-...-@ as the substitution
|
||||||
@ -26,3 +27,13 @@ gnc-prices: gnc-prices.in
|
|||||||
mv $@.tmp $@
|
mv $@.tmp $@
|
||||||
|
|
||||||
CLEANFILES += gnc-prices
|
CLEANFILES += gnc-prices
|
||||||
|
|
||||||
|
price-quote-helper: price-quote-helper.in
|
||||||
|
rm -f $@.tmp
|
||||||
|
sed < $@.in > $@.tmp \
|
||||||
|
-e 's:@-PERL-@:${PERL}:g' \
|
||||||
|
-e 's:@-PERLINCL-@:${PERLINCL}:g'
|
||||||
|
chmod +x $@.tmp
|
||||||
|
mv $@.tmp $@
|
||||||
|
|
||||||
|
CLEANFILES += price-quote-helper
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
#!/usr/bin/perl -w
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use English;
|
|
||||||
use Finance::Quote;
|
|
||||||
|
|
||||||
## Simple program to get quotes and feed them back to gnucash.
|
|
||||||
|
|
||||||
## Modified by Paul Fenwick <pjf@cpan.org>, June 2000, to take
|
|
||||||
## advantage of new Finance::Quote features.
|
|
||||||
|
|
||||||
## Input (on standard input - one entry per line and one line per entry)
|
|
||||||
##
|
|
||||||
## (fetch "NYSE" "IBM")
|
|
||||||
## (fetch "nyse" "ibm" "axp")
|
|
||||||
## (fetch "nasdaq" "jdsu")
|
|
||||||
## (fetch "nasdaq" "CSCO" "jdsu")
|
|
||||||
|
|
||||||
## Output (on standard output, one output form per input line)
|
|
||||||
|
|
||||||
## Schemified version of finance-quote's output, so basically an alist
|
|
||||||
## of alists, as in the example below. Only fields that this script
|
|
||||||
## knows about (and knows how to convert to scheme) are returned, so
|
|
||||||
## the conversion function will have to be updated whenever
|
|
||||||
## Finance::Quote changes.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## On error, result may be just #f, or errors may be stored with each
|
|
||||||
## quote as indicated in Finance::Quote.
|
|
||||||
|
|
||||||
## Exit status
|
|
||||||
##
|
|
||||||
## 0 - success
|
|
||||||
## non-zero - failure
|
|
||||||
|
|
||||||
# TODO:
|
|
||||||
|
|
||||||
# Is this safe? Can we just double all backslashes and backslash
|
|
||||||
# escape all double quotes and get the right answer?
|
|
||||||
|
|
||||||
# Right now this is more inefficient than it needs to be. We ask for
|
|
||||||
# each stock individually, but we should batch reqests to the same
|
|
||||||
# source. Perhaps later...
|
|
||||||
|
|
||||||
my $exit_status = 0;
|
|
||||||
|
|
||||||
# Create a stockquote object.
|
|
||||||
my $quoter = Finance::Quote->new();
|
|
||||||
|
|
||||||
sub schemify_str {
|
|
||||||
my($str) = @_;
|
|
||||||
|
|
||||||
# Right now this is a hack. We just make sure the outgoing string
|
|
||||||
# has no double quotes in it by mangling them all to single quotes.
|
|
||||||
# This is wrong, but it's better than letting dangerous strings
|
|
||||||
# through. We can always improve this later.
|
|
||||||
|
|
||||||
# Have to do this because the perl-mode parser freaks out otherwise.
|
|
||||||
my $dq = '"';
|
|
||||||
my $sq = "'";
|
|
||||||
|
|
||||||
$str =~ s/$dq/$sq/gmo;
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
my @lookup_items = ();
|
|
||||||
|
|
||||||
while(<>) {
|
|
||||||
|
|
||||||
# This big ugly nasty thing just matches something like this
|
|
||||||
|
|
||||||
# ("FOO" "BAR")
|
|
||||||
|
|
||||||
# where, rougly speaking, whitespace is allowed almost everywhere,
|
|
||||||
# this text constitutes the entire line, and the double-quotes and
|
|
||||||
# parens shown are the only occurences of those characters allowed
|
|
||||||
# in the line.
|
|
||||||
|
|
||||||
# Have to do this because the perl-mode parser freaks out otherwise.
|
|
||||||
my $dq = '"';
|
|
||||||
|
|
||||||
my $security_name;
|
|
||||||
my $quote_source_name;
|
|
||||||
|
|
||||||
if($_ =~ m/^\s* \(\s* $dq ([^$dq]+) $dq \s* $dq([^$dq]+)$dq \s*\) \s*$/ox) {
|
|
||||||
$security_name = $1;
|
|
||||||
$quote_source_name = $2;
|
|
||||||
} else {
|
|
||||||
my $scm_str = schemify_str($_);
|
|
||||||
print "(error bad-input-line \"Ignoring bad input line: $scm_str\")\n";
|
|
||||||
$exit_status |= 1;
|
|
||||||
# Yes this is ugly, but it really is what we mean here.
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
my %quote_data = $quoter->fetch($quote_source_name,$security_name);
|
|
||||||
|
|
||||||
unless($quote_data{$quote_source_name,'success'}) {
|
|
||||||
# We don't have to schemify the source or name - the regexp filtered it.
|
|
||||||
print "(error quote-lookup-failed ";
|
|
||||||
print "\"Lookup of $security_name at $quote_source_name failed.\")\n";
|
|
||||||
$exit_status |= 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $security_price = $quote_data{$security_name, 'price'};
|
|
||||||
my $quote_date = $quote_data{$security_name, 'date'};
|
|
||||||
|
|
||||||
if(!$security_price) {
|
|
||||||
# We don't have to schemify the source or name - the regexp filtered it.
|
|
||||||
print "(error price-not-found " .
|
|
||||||
"\"Couldn't find price for $security_name " .
|
|
||||||
"in response from $quote_source_name.\")\n";
|
|
||||||
$exit_status |= 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
## We'll just let gnucash deal with the date...
|
|
||||||
$quote_date = schemify_str($quote_date);
|
|
||||||
|
|
||||||
## Whew. Finally.
|
|
||||||
print "(quote";
|
|
||||||
print " (name . \"$security_name\")";
|
|
||||||
print " (date . \"$quote_date\")";
|
|
||||||
print " (price . \"$security_price\")\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
exit $exit_status;
|
|
||||||
|
|
||||||
__END__
|
|
282
src/quotes/price-quote-helper.in
Normal file
282
src/quotes/price-quote-helper.in
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
#!@-PERL-@ -w
|
||||||
|
######################################################################
|
||||||
|
### price-quote-helper - present a scheme interface to Finance::Quote
|
||||||
|
### Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
|
||||||
|
###
|
||||||
|
### This program is free software; you can redistribute it and/or
|
||||||
|
### modify it under the terms of the GNU General Public License as
|
||||||
|
### published by the Free Software Foundation; either version 2 of
|
||||||
|
### the License, or (at your option) any later version.
|
||||||
|
###
|
||||||
|
### This program is distributed in the hope that it will be useful,
|
||||||
|
### but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
### GNU General Public License for more details.
|
||||||
|
###
|
||||||
|
### You should have received a copy of the GNU General Public License
|
||||||
|
### along with this program# if not, contact:
|
||||||
|
###
|
||||||
|
### Free Software Foundation Voice: +1-617-542-5942
|
||||||
|
### 59 Temple Place - Suite 330 Fax: +1-617-542-2652
|
||||||
|
### Boston, MA 02111-1307, USA gnu@gnu.org
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
use lib '@-PERLINCL-@';
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use English;
|
||||||
|
use FileHandle;
|
||||||
|
use Date::Manip;
|
||||||
|
use Finance::Quote;
|
||||||
|
|
||||||
|
# Input: (on standard input - one entry per line and one line per
|
||||||
|
# entry, and double quotes must only be delimiters, not string
|
||||||
|
# content -- remember, we don't have a real scheme parser on the perl
|
||||||
|
# side :>).
|
||||||
|
#
|
||||||
|
# (fetch "NYSE" "IBM")
|
||||||
|
# (fetch "NYSE" "IBM" "AXP")
|
||||||
|
# (fetch "NASDAQ" "JDSU")
|
||||||
|
# (fetch "NASDAQ" "CSCO" "JDSU")
|
||||||
|
#
|
||||||
|
|
||||||
|
# Output (on standard output, one output form per input line):
|
||||||
|
|
||||||
|
# Schemified version of finance-quote's output, basically an alist of
|
||||||
|
# alists, as in the example below. Right now, the only a few fields
|
||||||
|
# that this script knows about (and knows how to convert to scheme)
|
||||||
|
# are returned, so the conversion function will have to be updated
|
||||||
|
# whenever Finance::Quote changes. Right now, you'll get symbol,
|
||||||
|
# utc, and last, as here:
|
||||||
|
#
|
||||||
|
# $ echo '(fetch "NASDAQ" "CSCO")' | ./price-quote-helper
|
||||||
|
# (("CSCO" (symbol . "CSCO") (utc . 982709400) (last . 26.5625))
|
||||||
|
# ("JDSU" (symbol . "JDSU") (utc . 982709400) (last . 33.0625)))
|
||||||
|
|
||||||
|
# On error, result may be just #f, or errors may be stored with each
|
||||||
|
# quote as indicated in Finance::Quote. Also, whenever the
|
||||||
|
# conversion fails, the field will have the value 'failed-conversion,
|
||||||
|
# and accordingly this symbol will never be a legitimate conversion.
|
||||||
|
|
||||||
|
# Exit status
|
||||||
|
#
|
||||||
|
# 0 - success
|
||||||
|
# non-zero - failure
|
||||||
|
|
||||||
|
sub schemify_string {
|
||||||
|
my($str) = @_;
|
||||||
|
|
||||||
|
if(!$str) { return "failed-conversion"; }
|
||||||
|
|
||||||
|
# FIXME: Is this safe? Can we just double all backslashes and backslash
|
||||||
|
# escape all double quotes and get the right answer?
|
||||||
|
|
||||||
|
# double all backslashes.
|
||||||
|
my $bs = "\\";
|
||||||
|
$str =~ s/$bs$bs/$bs$bs/gmo;
|
||||||
|
|
||||||
|
# escape all double quotes.
|
||||||
|
# Have to do this because the perl-mode parser freaks out otherwise.
|
||||||
|
my $dq = '"';
|
||||||
|
$str =~ s/$dq/$bs$dq/gmo;
|
||||||
|
return '"' . $str . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub schemify_boolean {
|
||||||
|
my($bool) = @_;
|
||||||
|
|
||||||
|
if($bool) {
|
||||||
|
return "#t";
|
||||||
|
} else {
|
||||||
|
return "#f";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub schemify_num {
|
||||||
|
my($numstr) = @_;
|
||||||
|
# This is for normal numbers, not the funny ones like "2.346B".
|
||||||
|
# For now we don't need to do anything.
|
||||||
|
|
||||||
|
if(!$numstr) { return "failed-conversion"; }
|
||||||
|
|
||||||
|
if($numstr =~ /^\s*(\d+(\.\d+)?)$/o) {
|
||||||
|
return $1;
|
||||||
|
} else {
|
||||||
|
return "failed-conversion";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub schemify_date {
|
||||||
|
# return the date in epoch seconds.
|
||||||
|
my ($datestr) = @_;
|
||||||
|
|
||||||
|
my $date = ParseDate($datestr);
|
||||||
|
my $result = UnixDate($date, "%s");
|
||||||
|
if($result !~ /^(\+|-)?\d+$/) {
|
||||||
|
$result = "failed-conversion";
|
||||||
|
}
|
||||||
|
return("$result");
|
||||||
|
}
|
||||||
|
|
||||||
|
# sub schemify_range {
|
||||||
|
# #convert range in form ``num1 - num2'' to ``(num1 num2)''.
|
||||||
|
# }
|
||||||
|
|
||||||
|
sub get_quote_utc {
|
||||||
|
# return the date in utc epoch seconds.
|
||||||
|
my ($item, $timezone, $quotehash) = @_;
|
||||||
|
|
||||||
|
if(!$timezone) { return "failed-conversion"; }
|
||||||
|
|
||||||
|
my $datestr = $$quotehash{$item, 'date'};
|
||||||
|
my $timestr = $$quotehash{$item, 'time'};
|
||||||
|
|
||||||
|
if(!$datestr) {
|
||||||
|
return "failed-conversion";
|
||||||
|
}
|
||||||
|
my $parsestr = $datestr;
|
||||||
|
if($timestr) {
|
||||||
|
$parsestr .= " $timestr";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $date = Date_ConvTZ(ParseDate($parsestr), $timezone, 'UTC');
|
||||||
|
|
||||||
|
my $result = UnixDate($date, "%s");
|
||||||
|
if($result !~ /^(\+|-)?\d+$/) {
|
||||||
|
$result = "failed-conversion";
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub schemify_quote {
|
||||||
|
my($itemname, $quotehash, $indentlevel, $timezone) = @_;
|
||||||
|
my $scmname = schemify_string($itemname);
|
||||||
|
my $quotedata = "";
|
||||||
|
my $field;
|
||||||
|
my $data;
|
||||||
|
|
||||||
|
$field = 'symbol';
|
||||||
|
$data = schemify_string($$quotehash{$itemname, $field});
|
||||||
|
$quotedata .= "($field . $data)";
|
||||||
|
|
||||||
|
$field = 'utc';
|
||||||
|
$data = get_quote_utc($itemname, $timezone, $quotehash);
|
||||||
|
$quotedata .= " ($field . $data)";
|
||||||
|
|
||||||
|
$field = 'last';
|
||||||
|
$data = schemify_num($$quotehash{$itemname, $field});
|
||||||
|
$quotedata .= " ($field . $data)";
|
||||||
|
|
||||||
|
return "($scmname $quotedata)";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub schemify_quotes {
|
||||||
|
my($items, $quotehash, $timezone) = @_;
|
||||||
|
my $resultstr = "";
|
||||||
|
my $i;
|
||||||
|
my $separator = "";
|
||||||
|
|
||||||
|
# we have to pass in @$items because Finance::Quote just uses the
|
||||||
|
# mangled "$name$field string as the key, so there's no way (I know
|
||||||
|
# of) to find out which stocks are in a given quotehash, just given
|
||||||
|
# the quotehash.
|
||||||
|
|
||||||
|
foreach $i (@$items) {
|
||||||
|
$resultstr .= $separator . schemify_quote($i, $quotehash, 2, $timezone);
|
||||||
|
if(!$separator) { $separator = "\n "; }
|
||||||
|
}
|
||||||
|
return "($resultstr)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_exchange_timezone {
|
||||||
|
my($exchange) = @_;
|
||||||
|
my $tz;
|
||||||
|
$exchange = lc($exchange);
|
||||||
|
|
||||||
|
if($exchange eq "nasdaq") {
|
||||||
|
$tz = 'EST';
|
||||||
|
} elsif ($exchange eq "nyse") {
|
||||||
|
$tz = 'EST';
|
||||||
|
} else {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parse_input_line {
|
||||||
|
|
||||||
|
# FIXME: we need to rewrite parsing to handle commands modularly.
|
||||||
|
# Right now all we do is hard-code "fetch".
|
||||||
|
|
||||||
|
my($input) = @_;
|
||||||
|
# Have to do this because the perl-mode parser freaks out otherwise.
|
||||||
|
my $dq = '"';
|
||||||
|
my $exchange;
|
||||||
|
my @items;
|
||||||
|
|
||||||
|
# Make sure we have an opening ( preceeded only by whitespace.
|
||||||
|
# and kill it off if we do...
|
||||||
|
if($input !~ s/^\s*\(\s*fetch\s+//o) { return 0; }
|
||||||
|
|
||||||
|
# Make sure we have an ending ) followed only by whitespace
|
||||||
|
# and kill it off if we do...
|
||||||
|
if($input !~ s/\s*\)\s*$//o) { return 0; }
|
||||||
|
|
||||||
|
# Now grab the exchange.
|
||||||
|
if($input !~ /^$dq([^$dq]+)$dq\s*/o) { return 0; }
|
||||||
|
|
||||||
|
$exchange = $1;
|
||||||
|
$input = $POSTMATCH;
|
||||||
|
|
||||||
|
# Now grab all the items.
|
||||||
|
while($input) {
|
||||||
|
if($input !~ /^$dq([^$dq]+)$dq\s*/o) { return 0; }
|
||||||
|
|
||||||
|
my $item = $1;
|
||||||
|
push @items, $item;
|
||||||
|
$input = $POSTMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @result = ($exchange, \@items);
|
||||||
|
return \@result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Runtime.
|
||||||
|
|
||||||
|
# Create a stockquote object.
|
||||||
|
my $quoter = Finance::Quote->new();
|
||||||
|
my $prgnam = "scmio-finance-quote";
|
||||||
|
|
||||||
|
# Make sure USD is the default.
|
||||||
|
$quoter->set_currency("USD");
|
||||||
|
|
||||||
|
while(<>) {
|
||||||
|
|
||||||
|
my $result = parse_input_line($_);
|
||||||
|
|
||||||
|
if(!$result) {
|
||||||
|
print STDERR "$prgnam: bad input line ($_)\n";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my($exchange, $items) = @$result;
|
||||||
|
|
||||||
|
my $quote_data = $quoter->fetch($exchange, @$items);
|
||||||
|
|
||||||
|
if(!$quote_data) {
|
||||||
|
print "#f\n";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $zone = get_exchange_timezone($exchange);
|
||||||
|
print schemify_quotes(\@$items, $quote_data, $zone);
|
||||||
|
STDOUT->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
## Local Variables:
|
||||||
|
## mode: perl
|
||||||
|
## End:
|
@ -38,6 +38,8 @@ gnc_regular_scm_files = \
|
|||||||
options-utilities.scm \
|
options-utilities.scm \
|
||||||
path.scm \
|
path.scm \
|
||||||
prefs.scm \
|
prefs.scm \
|
||||||
|
price-quotes.scm \
|
||||||
|
process.scm \
|
||||||
report.scm \
|
report.scm \
|
||||||
report-html.scm \
|
report-html.scm \
|
||||||
report-utilities.scm \
|
report-utilities.scm \
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
(define gnc:*command-line-remaining* #f)
|
(define gnc:*command-line-remaining* #f)
|
||||||
|
|
||||||
|
(gnc:depend "price-quotes.scm")
|
||||||
|
|
||||||
;;(use-modules (ice-9 getopt-long))
|
;;(use-modules (ice-9 getopt-long))
|
||||||
|
|
||||||
;;(define (gnc:is-boolean-arg? arg)
|
;;(define (gnc:is-boolean-arg? arg)
|
||||||
@ -169,6 +171,26 @@
|
|||||||
(cons (lambda () (load val))
|
(cons (lambda () (load val))
|
||||||
gnc:*batch-mode-things-to-do*)))))
|
gnc:*batch-mode-things-to-do*)))))
|
||||||
|
|
||||||
|
; (cons "add-price-quotes"
|
||||||
|
; (cons 'string
|
||||||
|
; (lambda (val)
|
||||||
|
; (set! gnc:*batch-mode-things-to-do*
|
||||||
|
; (cons
|
||||||
|
; (lambda ()
|
||||||
|
; (display (get-1-quote "NASDAQ" val)))
|
||||||
|
; gnc:*batch-mode-things-to-do*)))))
|
||||||
|
|
||||||
|
; (cons "add-price-quotes"
|
||||||
|
; (cons 'string
|
||||||
|
; (lambda (val)
|
||||||
|
; (set! gnc:*batch-mode-things-to-do*
|
||||||
|
; (cons
|
||||||
|
; (lambda ()
|
||||||
|
; (with-
|
||||||
|
; (gnc:book-add-quotes
|
||||||
|
;
|
||||||
|
; gnc:*batch-mode-things-to-do*)))))
|
||||||
|
|
||||||
(cons "load-user-config"
|
(cons "load-user-config"
|
||||||
(cons 'boolean gnc:load-user-config-if-needed))
|
(cons 'boolean gnc:load-user-config-if-needed))
|
||||||
|
|
||||||
|
@ -16,9 +16,8 @@
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(define (import-old-currencies from-filename)
|
(define (import-old-currencies from-filename)
|
||||||
(if (gnc:commodity-table-has-namespace
|
(if (gnc:commodity-table-has-namespace (gnc:engine-commodities)
|
||||||
(gnc:engine-commodities)
|
"GNC_LEGACY_CURRENCIES")
|
||||||
"GNC_LEGACY_CURRENCIES")
|
|
||||||
(gnc:import-legacy-commodities from-filename)))
|
(gnc:import-legacy-commodities from-filename)))
|
||||||
|
|
||||||
(gnc:hook-add-dangler gnc:*file-opened-hook* import-old-currencies)
|
(gnc:hook-add-dangler gnc:*file-opened-hook* import-old-currencies)
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
|
|
||||||
(gnc:support "engine-utilities.scm")
|
(gnc:support "engine-utilities.scm")
|
||||||
|
|
||||||
(define (gnc:filename->account-group filename)
|
(define (gnc:filename->book filename)
|
||||||
"Returns an account group on success and #f on failure"
|
"Returns a book on success and #f on failure"
|
||||||
(let* ((session (gnc:malloc-session)))
|
(let* ((session (gnc:malloc-session)))
|
||||||
(if (not session)
|
(if (not session)
|
||||||
#f
|
#f
|
||||||
@ -84,13 +84,15 @@
|
|||||||
(loop (cdr splits)))))
|
(loop (cdr splits)))))
|
||||||
(reverse retval)))
|
(reverse retval)))
|
||||||
|
|
||||||
|
;;(define (gnc:group-map-accounts thunk group)
|
||||||
|
;; (let ((retval '()))
|
||||||
|
;; (let loop ((accounts (or (gnc:group-get-subaccounts group) '())))
|
||||||
|
;; (if (not (null? accounts))
|
||||||
|
;; (begin
|
||||||
|
;; (set! retval (cons (thunk (car accounts)) retval))
|
||||||
|
;; (loop (cdr accounts)))))
|
||||||
|
;; (reverse retval)))
|
||||||
|
|
||||||
(define (gnc:group-map-accounts thunk group)
|
(define (gnc:group-map-accounts thunk group)
|
||||||
(let ((retval '()))
|
(let ((accounts (or (gnc:group-get-subaccounts group) '())))
|
||||||
(let loop ((accounts (or (gnc:group-get-subaccounts group) '())))
|
(map thunk accounts)))
|
||||||
(if (not (null? accounts))
|
|
||||||
(begin
|
|
||||||
(set! retval (cons (thunk (car accounts)) retval))
|
|
||||||
(loop (cdr accounts)))))
|
|
||||||
(reverse retval)))
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
(gnc:depend "report/report-list.scm")
|
(gnc:depend "report/report-list.scm")
|
||||||
(gnc:depend "qif-import/qif-import.scm")
|
(gnc:depend "qif-import/qif-import.scm")
|
||||||
(gnc:depend "printing/print-check.scm")
|
(gnc:depend "printing/print-check.scm")
|
||||||
|
(gnc:depend "src/price-quotes.scm")
|
||||||
|
|
||||||
;; Load the system configs
|
;; Load the system configs
|
||||||
(if (not (gnc:load-system-config-if-needed))
|
(if (not (gnc:load-system-config-if-needed))
|
||||||
|
65
src/scm/price-quotes.scm
Normal file
65
src/scm/price-quotes.scm
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;; price-quotes.scm - manage sub-processes.
|
||||||
|
;;; Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
|
||||||
|
;;;
|
||||||
|
;;; This program is free software; you can redistribute it and/or
|
||||||
|
;;; modify it under the terms of the GNU General Public License as
|
||||||
|
;;; published by the Free Software Foundation; either version 2 of
|
||||||
|
;;; the License, or (at your option) any later version.
|
||||||
|
;;;
|
||||||
|
;;; This program is distributed in the hope that it will be useful,
|
||||||
|
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;;; GNU General Public License for more details.
|
||||||
|
;;;
|
||||||
|
;;; You should have received a copy of the GNU General Public License
|
||||||
|
;;; along with this program; if not, contact:
|
||||||
|
;;;
|
||||||
|
;;; Free Software Foundation Voice: +1-617-542-5942
|
||||||
|
;;; 59 Temple Place - Suite 330 Fax: +1-617-542-2652
|
||||||
|
;;; Boston, MA 02111-1307, USA gnu@gnu.org
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(gnc:support "price-quotes.scm")
|
||||||
|
(gnc:depend "process.scm")
|
||||||
|
|
||||||
|
(define gnc:*price-quote-helper*
|
||||||
|
"/home/rlb/opt/gnucash-working/share/gnucash/price-quote-helper")
|
||||||
|
|
||||||
|
(define (get-1-quote exchange . items)
|
||||||
|
(let ((cmd (apply list 'fetch exchange items))
|
||||||
|
(quoter (run-sub-process #f
|
||||||
|
gnc:*price-quote-helper*
|
||||||
|
gnc:*price-quote-helper*)))
|
||||||
|
(and quoter
|
||||||
|
(write cmd (caddr quoter))
|
||||||
|
(newline (caddr quoter))
|
||||||
|
(force-output (caddr quoter))
|
||||||
|
(let ((result (read (cadr quoter))))
|
||||||
|
(close-input-port (cadr quoter))
|
||||||
|
(close-output-port (caddr quoter))
|
||||||
|
result))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (gnc:book-add-quotes book)
|
||||||
|
|
||||||
|
(define (find-quotables group)
|
||||||
|
(define (quotable-account? a)
|
||||||
|
(case (gnc:account-get-type a)
|
||||||
|
;; we no longer care what the price source was - Finance::Quote
|
||||||
|
;; doesn't let you specify a particular source.
|
||||||
|
((stock mutual-fund currency) (gnc:account-get-price-src a))
|
||||||
|
(else #f)))
|
||||||
|
(filter quotable-account? (gnc:group-get-subaccounts group)))
|
||||||
|
|
||||||
|
(display (list book)) (newline)
|
||||||
|
(display (list (gnc:book-get-group book))) (newline)
|
||||||
|
|
||||||
|
(let* ((group (gnc:book-get-group book))
|
||||||
|
(quotables (and group (find-quotables group)))
|
||||||
|
(commodities (and quotables
|
||||||
|
(map gnc:account-get-commodity quotables))))
|
||||||
|
(for-each (lambda (c)
|
||||||
|
(display (list "Get quote for" (gnc:commodity-get-mnemonic c)))
|
||||||
|
(newline))
|
||||||
|
commodities)))
|
179
src/scm/process.scm
Normal file
179
src/scm/process.scm
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;; process.scm - manage sub-processes.
|
||||||
|
;;; Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
|
||||||
|
;;;
|
||||||
|
;;; This program is free software; you can redistribute it and/or
|
||||||
|
;;; modify it under the terms of the GNU General Public License as
|
||||||
|
;;; published by the Free Software Foundation; either version 2 of
|
||||||
|
;;; the License, or (at your option) any later version.
|
||||||
|
;;;
|
||||||
|
;;; This program is distributed in the hope that it will be useful,
|
||||||
|
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;;; GNU General Public License for more details.
|
||||||
|
;;;
|
||||||
|
;;; You should have received a copy of the GNU General Public License
|
||||||
|
;;; along with this program; if not, contact:
|
||||||
|
;;;
|
||||||
|
;;; Free Software Foundation Voice: +1-617-542-5942
|
||||||
|
;;; 59 Temple Place - Suite 330 Fax: +1-617-542-2652
|
||||||
|
;;; Boston, MA 02111-1307, USA gnu@gnu.org
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(gnc:support "process.scm")
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Run the program specified by path with the given args as a
|
||||||
|
;;; sub-proces. If envt is not #f, then use it as the sub-process
|
||||||
|
;;; environment (as per execle in the guile info pages). Note that
|
||||||
|
;;; you must specify the path explicitly.
|
||||||
|
;;;
|
||||||
|
;;; Returns #f on failure, or
|
||||||
|
;;; (pid child-output-pipe child-input-pipe child-standard-error-pipe)
|
||||||
|
;;; on success. Right now the standard-error pipe is always #f.
|
||||||
|
;;;
|
||||||
|
;;; For example:
|
||||||
|
;;;
|
||||||
|
;;; (run-sub-process "/bin/date" "--rfc-822")
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (run-sub-process envt path . args)
|
||||||
|
(let ((parent-to-child-pipe (false-if-exception (pipe)))
|
||||||
|
(child-to-parent-pipe (false-if-exception (pipe))))
|
||||||
|
(if (not (and parent-to-child-pipe
|
||||||
|
child-to-parent-pipe))
|
||||||
|
#f
|
||||||
|
(let* ((parent-read-pipe (car child-to-parent-pipe))
|
||||||
|
(parent-write-pipe (cdr parent-to-child-pipe))
|
||||||
|
(child-read-pipe (car parent-to-child-pipe))
|
||||||
|
(child-write-pipe (cdr child-to-parent-pipe))
|
||||||
|
(pid (false-if-exception (primitive-fork))))
|
||||||
|
|
||||||
|
(if (not (zero? pid))
|
||||||
|
;; we're the parent
|
||||||
|
(begin
|
||||||
|
(close-input-port child-read-pipe)
|
||||||
|
(close-output-port child-write-pipe)
|
||||||
|
(list pid parent-read-pipe parent-write-pipe #f))
|
||||||
|
;; else we're the child
|
||||||
|
(begin
|
||||||
|
;; set standard-input and standard-output at the fd
|
||||||
|
;; level -- which is really all that matters since
|
||||||
|
;; we're about to exec...
|
||||||
|
(close-input-port parent-read-pipe)
|
||||||
|
(close-output-port parent-write-pipe)
|
||||||
|
(dup->fdes child-read-pipe 0)
|
||||||
|
(dup->fdes child-write-pipe 1)
|
||||||
|
;; now launch the child process.
|
||||||
|
(or (false-if-exception
|
||||||
|
(if envt
|
||||||
|
(apply execle path envt args)
|
||||||
|
(apply execl path args)))
|
||||||
|
(exit 1))))))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; Random test code.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
; (define (get-1-quote exchange . items)
|
||||||
|
; (let ((cmd (apply list 'fetch exchange items))
|
||||||
|
; (quoter (run-sub-process #f
|
||||||
|
; "./scmio-finance-quote"
|
||||||
|
; "./scmio-finance-quote")))
|
||||||
|
; (and quoter
|
||||||
|
; (write cmd (caddr quoter))
|
||||||
|
; (newline (caddr quoter))
|
||||||
|
; (force-output (caddr quoter))
|
||||||
|
; (let ((result (read (cadr quoter))))
|
||||||
|
; (close-input-port (cadr quoter))
|
||||||
|
; (close-output-port (caddr quoter))
|
||||||
|
; result))))
|
||||||
|
|
||||||
|
; (define (parrot)
|
||||||
|
; (let loop ((input (false-if-exception (read))))
|
||||||
|
; (cond
|
||||||
|
; ((eof-object? input) (quit 0))
|
||||||
|
; ((not input) (quit 0))
|
||||||
|
; (else (write input)
|
||||||
|
; (force-output)
|
||||||
|
; (loop (read))))))
|
||||||
|
|
||||||
|
; (define (launch-parrot envt path args)
|
||||||
|
; ;; Returns (pid child-input-port child-output-port child-error-port)
|
||||||
|
; ;; Right now the error port is broken...
|
||||||
|
|
||||||
|
; (let* ((pid #f)
|
||||||
|
; (sockets (false-if-exception (socketpair AF_UNIX SOCK_STREAM 0))))
|
||||||
|
|
||||||
|
; (if sockets
|
||||||
|
; (set! pid (false-if-exception (primitive-fork))))
|
||||||
|
|
||||||
|
; (cond
|
||||||
|
; ((not pid) #f)
|
||||||
|
|
||||||
|
; ((= pid 0)
|
||||||
|
; ;; We're the child.
|
||||||
|
|
||||||
|
; ;; set standard-input and standard-output, swapping input and
|
||||||
|
; ;; output sockets from parent...
|
||||||
|
; (display 'foo) (newline) (flush-all-ports)
|
||||||
|
; ;;(redirect-port (car sockets) (current-input-port))
|
||||||
|
; (set-current-input-port (cdr sockets))
|
||||||
|
; (display 'bar) (newline) (flush-all-ports)
|
||||||
|
; ;;(redirect-port (cdr sockets) (current-output-port))
|
||||||
|
; (set-current-output-port (cdr sockets))
|
||||||
|
|
||||||
|
; (parrot))
|
||||||
|
|
||||||
|
; ; (or (false-if-exception
|
||||||
|
; ; (if envt
|
||||||
|
; ; (apply execle path envt args)
|
||||||
|
; ; (apply execl path args)))
|
||||||
|
; ; (exit 1)))
|
||||||
|
|
||||||
|
; (else
|
||||||
|
; ;; we're the parent
|
||||||
|
; ;; child-input-port child-output-port child-error-port
|
||||||
|
; (list pid (car sockets) #f)))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; This code was part of an attempt to just return one
|
||||||
|
;;; read-write-port for the child, but I had some trouble getting it
|
||||||
|
;;; to work. I think either (1) this was misguided from the start
|
||||||
|
;;; since you can't hook up the plumbing this way, or (2) I was
|
||||||
|
;;; forgetting some flushing or something somewhere that kept it from
|
||||||
|
;;; working. At one point, I knew which of these two options was
|
||||||
|
;;; true, but I can't recall what I concluded now, so I'll leave the
|
||||||
|
;;; code here in case we want to resurrect it...
|
||||||
|
|
||||||
|
; (define (run-sub-process envt path . args)
|
||||||
|
; (let ((pid #f)
|
||||||
|
; (sockets (false-if-exception (socketpair AF_UNIX SOCK_STREAM 0))))
|
||||||
|
|
||||||
|
; (if sockets
|
||||||
|
; (set! pid (false-if-exception (primitive-fork))))
|
||||||
|
|
||||||
|
; (cond
|
||||||
|
; ((or (not sockets) (not pid)) #f)
|
||||||
|
|
||||||
|
; ((= pid 0)
|
||||||
|
; ;; We're the child: set standard-input and standard-output to be
|
||||||
|
; ;; the socket that's connected to the parent.
|
||||||
|
; (set-current-input-port (cdr sockets))
|
||||||
|
; (set-current-output-port (cdr sockets))
|
||||||
|
; (dup->fdes (cdr sockets) 0)
|
||||||
|
; (dup->fdes (cdr sockets) 1)
|
||||||
|
|
||||||
|
; ;; now launch the child process.
|
||||||
|
; (or (false-if-exception
|
||||||
|
; (if envt
|
||||||
|
; (apply execle path envt args)
|
||||||
|
; (apply execl path args)))
|
||||||
|
; (exit 1)))
|
||||||
|
|
||||||
|
; (else
|
||||||
|
; ;; we're the parent
|
||||||
|
; (list pid (car sockets) #f)))))
|
Loading…
Reference in New Issue
Block a user