[Gnucash-changes] Sync the g2 branch with the gnome2-merge-8 tag.
David Hampton
hampton at cvs.gnucash.org
Mon May 3 02:17:36 EDT 2004
Log Message:
-----------
Sync the g2 branch with the gnome2-merge-8 tag. (2004-05-02)
Tags:
----
gnucash-gnome2-dev
Modified Files:
--------------
gnucash:
ChangeLog
GNOME2_STATUS
HACKING
configure.in
gnucash/accounts/hu_HU:
Makefile.am
gnucash/macros:
autogen.sh
gnucash/src/backend/file:
gnc-freqspec-xml-v2.c
gnucash/src/backend/postgres:
PostgresBackend.c
checkpoint.c
events.c
kvp-sql.c
price.c
putil.h
txn.c
txnmass.c
gnucash/src/doc:
TODO-schedxactions
guid.txt
gnucash/src/engine:
FreqSpec.c
FreqSpec.h
Transaction.c
gnc-date.c
gnc-date.h
gnc-engine-util.c
gnc-engine-util.h
guid.c
guid.h
kvp_frame.h
qof.h
qofbook.h
qofclass.c
qofclass.h
qofid.h
qofobject.c
qofquery.c
qofquery.h
qofquerycore-p.h
qofquerycore.c
qofquerycore.h
qofsession.c
gnucash/src/engine/test:
.cvsignore
test-date.c
gnucash/src/gnome:
dialog-scheduledxaction.c
dialog-sx-from-trans.c
druid-loan.c
gnucash/src/gnome/glade:
sched-xact.glade
gnucash/src/gnome-search:
dialog-search.c
gnc-general-search.c
gnucash/src/gnome-utils:
gnc-dense-cal.c
gnc-query-list.c
search-param.c
gnucash/src/import-export/hbci:
dialog-hbcitrans.c
dialog-hbcitrans.h
gnc-hbci-transfer.c
gnucash/src/import-export/hbci/glade:
hbci.glade
gnucash/src/import-export/log-replay:
gnc-log-replay.c
gnucash/src/register/ledger-core:
gnc-ledger-display.c
gnucash/src/register/register-core:
formulacell.c
gnucash/src/report/report-system:
html-utilities.scm
report-system.scm
gnucash/src/report/standard-reports:
balance-sheet.scm
pnl.scm
gnucash/src/report/utility-reports:
iframe-url.scm
gnucash/src/scm:
Makefile.am
main.scm
Added Files:
-----------
gnucash/src/engine:
qofgobj.c
qofgobj.h
qofquery-deserial.c
qofquery-deserial.h
qofquery-serialize.c
qofquery-serialize.h
qofsql.c
qofsql.h
Revision Data
-------------
Index: hbci.glade
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/hbci/glade/hbci.glade,v
retrieving revision 1.27.2.9
retrieving revision 1.27.2.10
diff -Lsrc/import-export/hbci/glade/hbci.glade -Lsrc/import-export/hbci/glade/hbci.glade -u -r1.27.2.9 -r1.27.2.10
--- src/import-export/hbci/glade/hbci.glade
+++ src/import-export/hbci/glade/hbci.glade
@@ -1211,48 +1211,48 @@
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
- <widget class="GtkLabel" id="label834">
- <property name="label" translatable="yes">HBCI account name</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
+ <widget class="GtkLabel" id="label834">
+ <property name="label" translatable="yes">HBCI account name</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
</child>
<child>
- <widget class="GtkLabel" id="label835">
- <property name="label" translatable="yes">GnuCash account name</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
+ <widget class="GtkLabel" id="label835">
+ <property name="label" translatable="yes">GnuCash account name</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
</child>
<child>
- <widget class="GtkLabel" id="label836">
- <property name="label" translatable="yes">New?</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
+ <widget class="GtkLabel" id="label836">
+ <property name="label" translatable="yes">New?</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
</child>
</widget>
</child>
@@ -1980,7 +1980,7 @@
<child>
<widget class="GtkTable" id="table6">
<property name="visible">True</property>
- <property name="n_rows">20</property>
+ <property name="n_rows">21</property>
<property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">0</property>
@@ -2123,19 +2123,6 @@
</child>
<child>
- <widget class="GtkHSeparator" id="hseparator5">
- <property name="visible">True</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">3</property>
- <property name="top_attach">6</property>
- <property name="bottom_attach">7</property>
- <property name="x_options">fill</property>
- </packing>
- </child>
-
- <child>
<widget class="GtkLabel" id="recp_bankname_heading">
<property name="visible">True</property>
<property name="label" translatable="yes">at Bank</property>
@@ -2541,12 +2528,95 @@
<property name="spacing">4</property>
<child>
- <widget class="GtkButton" id="add_templ_button">
+ <widget class="GtkVBox" id="vbox158">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Add current</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="add_templ_button">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Add current</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="add_template_cb"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="moveup_templ_button">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-up</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="moveup_templ_cb"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="movedown_templ_button">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-down</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="movedown_templ_cb"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="sort_templ_button">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Sort</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="sort_templ_cb"/>
+ </widget>
+ <packing>
+ <property name="padding">10</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="del_templ_button">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Delete</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="del_template_cb"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -2557,19 +2627,24 @@
</child>
<child>
- <widget class="GtkOptionMenu" id="template_optionmenu">
+ <widget class="GtkScrolledWindow" id="template_scrolledwindow">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="history">0</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
- <widget class="GtkMenu" id="menu1">
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
<child>
- <widget class="GtkMenuItem" id="no_template_1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">-- No Template --</property>
- <property name="use_underline">True</property>
+ <widget class="GtkList" id="template_list">
+ <property name="selection_mode">GTK_SELECTION_SINGLE</property>
+ <signal name="select_child" handler="on_template_list_select_child"/>
+ <signal name="selection_changed" handler="on_template_list_selection_changed"/>
+ <signal name="unselect_child" handler="on_template_list_unselect_child"/>
</widget>
</child>
</widget>
@@ -2577,8 +2652,8 @@
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
@@ -2608,8 +2683,36 @@
<packing>
<property name="left_attach">0</property>
<property name="right_attach">3</property>
+ <property name="top_attach">20</property>
+ <property name="bottom_attach">21</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHSeparator" id="hseparator8">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">3</property>
<property name="top_attach">19</property>
<property name="bottom_attach">20</property>
+ <property name="y_padding">1</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHSeparator" id="hseparator5">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="y_padding">1</property>
<property name="x_options">fill</property>
</packing>
</child>
Index: configure.in
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/configure.in,v
retrieving revision 1.359.2.30
retrieving revision 1.359.2.31
diff -Lconfigure.in -Lconfigure.in -u -r1.359.2.30 -r1.359.2.31
--- configure.in
+++ configure.in
@@ -1060,7 +1060,8 @@
LIBOBJS_SEDSCRIPT="s,\.[[^.]]* ,$U&,g;s,\.[[^.]]*\$\$,$U&,"
AC_SUBST(LIBOBJS_SEDSCRIPT)
-AC_OUTPUT( m4/Makefile po/Makefile.in
+AC_OUTPUT( po/Makefile.in
+ m4/Makefile
dnl # Makefiles
Makefile
accounts/Makefile
Index: ChangeLog
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/ChangeLog,v
retrieving revision 1.1487.2.122
retrieving revision 1.1487.2.123
diff -LChangeLog -LChangeLog -u -r1.1487.2.122 -r1.1487.2.123
--- ChangeLog
+++ ChangeLog
@@ -1,12 +1,15 @@
2004-05-02 David Hampton <hampton at employees.org>
+ * various files: Merge in changes to HEAD from 2004-03-03
+ (gnome2-merge-7) through today (gnome2-merge-8).
+
* src/business/business-core/Makefile.am:
* src/business/business-gnome/Makefile.am:
* src/import-export/binary-import/Makefile.am: Work around
problems with libltdl3.
* src/import-export/hbci/druid-hbci-initial.c: Eliminate a couiple
- of compiler warning messages.
+ of compiler warning messages.
2004-05-02 Joshua Sled <jsled at asynchronous.org>
@@ -2561,6 +2564,164 @@
-=-=-=- cvs HEAD ChangeLog is below this line -=-=-=-
+2004-05-02 David Hampton <hampton at employees.org>
+
+ * src/business/business-core/Makefile.am:
+ * src/business/business-gnome/Makefile.am:
+ * src/import-export/binary-import/Makefile.am: Work around
+ problems with libltdl3.
+
+2004-04-26 Derek Atkins <derek at ihtfp.com>
+
+ * src/scm/Makefile.am: look in ${srcdir} for build-config.scm.in
+ Fixes #141129
+
+2004-04-20 Derek Atkins <derek at ihtfp.com>
+
+ * src/report/report-system/html-utilities.scm:
+ Fix a broken recursion problem. Don't call show-acct? from
+ use-acct? so we don't recurse ad flictum. This recursive
+ call isn't necessary, just have use-acct? recurse unto itself.
+
+2004-04-19 Derek Atkins <derek at ihtfp.com>
+
+ * src/report/standard-reports/balance-sheet.scm:
+ * src/report/standard-reports/pnl.scm:
+ Fabien COELHO's zero-balance patch to remove accounts of
+ zero balance from the report.
+
+2004-04-18 Derek Atkins <derek at ihtfp.com>
+
+ * src/engine/Transaction.c: fix a comment to better explain why
+ we have no-op functions for some parameters.
+ * src/engine/qof*: Revert Linas' patch from last night which
+ is broken is way too many ways to count. First, the code didn't
+ compile. Second it was calling functions that took one argument
+ with two due to broken casting. Third, it had repurcusions in
+ other sections of the code that Linas needs to take into account.
+
+2004-05-16 Derek Atkins <derek at ihtfp.com>
+
+ * src/macros/autogen.sh: Add MORE warnings around gettext because
+ some users STILL don't "get it".
+
+2004-05-15 Derek Atkins <derek at ihtfp.com>
+
+ * src/import-export/hbci/dialog-hbcitrans.c: Don't use C++/C99
+ declarations. Declare variables at the top of the function.
+ Fixes #140070
+
+2004-04-12 Chris Lyttle <chris at wilddev.net>
+
+ * src/scm/main.scm: Update for 1.8.9 release
+
+2004-04-05 Derek Atkins <derek at ihtfp.com>
+
+ * macros/autogen.sh: make sure we always have intl and po Makefiles
+ in the configure script. Sometimes it was ripped out without being
+ replaced. Reported by twunder.
+
+ * src/engine/test/.cvsignore: ignore test-link in CVS.
+
+2004-04-01 Derek Atkins <derek at ihtfp.com>
+
+ * src/gnome/dialog-scheduledxaction.c: Move variable declaration
+ to the top of the block.
+
+2004-03-31 Derek Atkins <derek at ihtfp.com>
+
+ * configure.in: move m4/Makefile to its own line
+ * macros/autogen.sh: add code to remove "intl/Makefile po/Makefile"
+ from AC_OUTPUT in configure.in prior to calling gettextize
+ to make sure that you can build from CVS with recent versions
+ of gettextize. Tested with both RH9 and RH7.3 to make sure
+ it works with both old and new. Fixes #120206.
+
+ * accounts/hu_HU/Makefile.am: don't include files in the DIST that
+ we don't have in CVS.
+
+2004-03-30 Derek Atkins <derek at ihtfp.com>
+
+ * src/report/report-system/report-system.scm:
+ * src/report/utility-reports/iframe-url.scm:
+ don't need to require format; main.scm handles it, and
+ the default "format" (simple-format) is sufficient to
+ handle everything we need. This allows gnucash to work
+ with slib3.
+
+2004-03-14 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome/druid-loan.c (ld_get_loan_range): Fix precedence bug
+ screwing up loan review page.
+
+2004-03-14 Joshua Sled <jsled at asynchronous.org>
+
+ * src/register/register-core/formulacell.c
+ (gnc_formula_cell_modify_verify): Add ':' to the token list of
+ allowable characters in the formula cell. Fixes Bug#106260.
+
+2004-03-14 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome/druid-loan.c (gnc_ui_sx_loan_druid_create): Use the
+ account-list filtering capability of the GncAccountSel to only
+ show/allow-creation-of valid account-types in the
+ loan-druid. Fixes Bug#124595.
+
+2004-03-13 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome/dialog-scheduledxaction.c (gnc_sxed_check_consistent):
+ Bug#133709 fix: when we have a problem parsing a credit/debit
+ cell, indicate to the user what occurred.
+
+2004-03-08 Christian Stimming <stimming at tuhh.de>
+
+ * src/import-export/hbci/dialog-hbcitrans.c, dialog-hbcitrans.h,
+ glade/hbci.glade, gnc-hbci-transfer.c: Transfer template management
+ GUI added by Bernd Wagner <F.J.Bernd.Wagner at t-online.de>
+
+2004-03-07 Joshua Sled <jsled at asynchronous.org>
+
+ * HACKING: Added instructions about running under valgrind.
+
+ * lib/gnucash_valgrind.supp: Added a large set of valgrind
+ suppressions for both guile and gnucash.
+
+ * src/register/ledger-core/gnc-ledger-display.c
+ (gnc_ledger_display_template_gl): Change the reg_type to
+ SEARCH_LEDGER so all the 'action' types appear. Bug#108833.
+
+ * src/gnome/glade/sched-xact.glade: Remove unused 'ledger_status'
+ widget. Bug#102269.
+
+ * src/gnome-utils/gnc-dense-cal.c (gnc_dense_cal_draw_to_buffer):
+ At least be consistent about the background coloring of the month
+ labels, even if we're still not using GTK themeage correctly.
+
+ * src/gnome-utils/gnc-dense-cal.c (gnc_dense_cal_destroy): Destroy
+ the transient window when the widget is destroyed. Bug#103910.
+
+ * src/gnome/dialog-scheduledxaction.c
+ (gnc_ui_scheduled_xaction_editor_dialog_create): Make the advance
+ and remind spin-buttons editable [Bug#94963].
+
+ * src/gnome/glade/sched-xact.glade: Change the upper bound on the
+ advance and remind spins to 365 [days], with a page-size of 30
+ [days].
+
+ * src/gnome/dialog-sx-from-trans.c (gnc_sx_create_from_trans):
+ Disallow the Scheduling of being-editing transactions in the
+ Register, preventing a class of unbalacned SX template
+ transactions from being entered and propogated through the
+ system. See Bug#130330.
+
+ * src/engine/FreqSpec.c (xaccFreqSpecGetFreqStr): Fix nasty
+ memory-corruption issue; insufficent bounds checking on array
+ index. Bug#125600.
+
+ * src/gnome/dialog-sxsincelast.c (create_each_transaction_helper):
+ Better handling of various error cases in
+ transaction-creation. Bug#102311; Bug#130330.
+
2004-03-03 Derek Atkins <derek at ihtfp.com>
* src/register/ledger-core/split-register-load.c: make the code a
@@ -2568,6 +2729,20 @@
variable name inside a block of code and "over-riding" an
existing variable. Unlikely to actually fix anything, but
you never know what a compiler might do.
+
+2004-03-01 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome/dialog-scheduledxaction.c (gnc_sxed_check_consistent):
+ Fix for part of Bug#121740 -- only allow auto-create SXes which
+ have splits to be created.
+
+2004-02-07 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome/dialog-scheduledxaction.c (editor_ok_button_clicked):
+ * src/gnome-utils/gnc-frequency.c (gnc_frequency_save_state):
+ * src/backend/file/gnc-freqspec-xml-v2.c (fs_none_handler):
+ * src/engine/FreqSpec.c (xaccFreqSpecGetFreqStr):
+ Adding "NONE" as an allowable FreqSpec [Bug#103968].
2004-02-14 Christian Stimming <stimming at tuhh.de>
Index: HACKING
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/HACKING,v
retrieving revision 1.5.4.1
retrieving revision 1.5.4.2
diff -LHACKING -LHACKING -u -r1.5.4.1 -r1.5.4.2
--- HACKING
+++ HACKING
@@ -129,4 +129,14 @@
guile bugs, some g_has_table bugs, and then the program exited prematurely
for no appearenet reason. :-(
-If you know how to fix this, please update tehse instructions.
+For the moment, use the supressions in lib/gnucash_valgrind.supp.
+
+This file needs to be cleaned up in two ways:
+
+1/ There are a bunch of duplicate supressions in the file.
+ * The supressions in place were auto-generated by valgrind itself
+ [--gen-suppressions=yes], and it makes no effort to output the
+ suppression only once.
+
+2/ There are a bunch of suppressions which need to not be supressions, but
+ instead just not be generated by valgrind.
Index: GNOME2_STATUS
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/Attic/GNOME2_STATUS,v
retrieving revision 1.1.2.17
retrieving revision 1.1.2.18
diff -LGNOME2_STATUS -LGNOME2_STATUS -u -r1.1.2.17 -r1.1.2.18
--- GNOME2_STATUS
+++ GNOME2_STATUS
@@ -13,7 +13,7 @@
names of active developers, that'd be great.
========================================
- Last sync with HEAD on 2004-01-16
+ Last sync with HEAD on 2004-05-02
========================================
========================================
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/accounts/hu_HU/Makefile.am,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -Laccounts/hu_HU/Makefile.am -Laccounts/hu_HU/Makefile.am -u -r1.1 -r1.1.4.1
--- accounts/hu_HU/Makefile.am
+++ accounts/hu_HU/Makefile.am
@@ -20,21 +20,5 @@
acctchrt_spouseretire.gnucash-xea
EXTRA_DIST = \
- acctlist_brokerage.gnucash-xea \
- acctchrt_business.gnucash-xea \
- acctlist_carloan.gnucash-xea \
- acctlist_cdmoneymkt.gnucash-xea \
- acctchrt_checkbook.gnucash-xea \
- acctlist_childcare.gnucash-xea \
- acctlist_common.gnucash-xea \
- acctlist_eduloan.gnucash-xea \
- acctlist_fixedassets.gnucash-xea \
- acctlist_homeloan.gnucash-xea \
- acctlist_homeown.gnucash-xea \
- acctlist_otherloan.gnucash-xea \
- acctlist_renter.gnucash-xea \
- acctlist_retiremt.gnucash-xea \
- acctlist_spouseinc.gnucash-xea \
- acctlist_spouseretire.gnucash-xea \
${account_DATA} \
.cvsignore
Index: autogen.sh
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/macros/autogen.sh,v
retrieving revision 1.15.4.6
retrieving revision 1.15.4.7
diff -Lmacros/autogen.sh -Lmacros/autogen.sh -u -r1.15.4.6 -r1.15.4.7
--- macros/autogen.sh
+++ macros/autogen.sh
@@ -111,17 +111,14 @@
DIE=1
}
-#GETTEXTIZE_VERSION=`${GETTEXTIZE} --version`
-#gettextize_major_version=`echo ${GETTEXTIZE_VERSION} | \
-# sed 's/^.*GNU gettext.* \([0-9]*\)\.\([0-9]*\).\([0-9]*\).*$/\1/'`
-#gettextize_minor_version=`echo ${GETTEXTIZE_VERSION} | \
-# sed 's/^.*GNU gettext.* \([0-9]*\)\.\([0-9]*\).\([0-9]*\).*$/\2/'`
-#if [ $gettextize_major_version -gt 0 -o \
-# $gettextize_minor_version -gt 10 ]; then
-# INTL="--intl";
-#else
-# INTL="";
-#fi
+gettext_version=`gettextize --version 2>&1 | sed -n 's/^.*GNU gettext.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+case $gettext_version in
+0.10.*)
+ ;;
+
+*)
+ INTL="--intl --no-changelog";;
+esac
#(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && {
# (${LIBTOOL} --version) < /dev/null > /dev/null 2>&1 || {
@@ -224,33 +221,50 @@
fi
fi
done
+
+ echo
+ echo "*** WARNING ***"
+ echo "*** We're about to run \"gettext\" which may spew a few paragraphs"
+ echo "*** of crap at you and ask you to acknowledge it. If it does this,"
+ echo "*** just hit return to acknowledge gettext. You DO NOT need to do"
+ echo "*** anything that it asks of you except hitting return."
+ echo
if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then
- if grep "sed.*POTFILES" configure.in >/dev/null; then
- : do nothing -- we still have an old unmodified configure.in
- else
- echo "Creating $dr/aclocal.m4 ..."
- test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
- echo "Running gettextize... Ignore non-fatal messages."
- echo "no" | gettextize --force --copy
- echo "Making $dr/aclocal.m4 writable ..."
- test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+ if grep "sed.*POTFILES" configure.in >/dev/null; then
+ : do nothing -- we still have an old unmodified configure.in
+ else
+ echo "Creating $dr/aclocal.m4 ..."
+ test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+ echo "(1) Running ${GETTEXTIZE}... Ignore non-fatal messages."
+ echo "no" | ${GETTEXTIZE} --force --copy $INTL
+ echo "Making $dr/aclocal.m4 writable ..."
+ test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
fi
+ grep "intl/Makefile" configure.in > /dev/null ||
+ ( sed -e 's#^AC_OUTPUT(#AC_OUTPUT( intl/Makefile po/Makefile.in#' \
+ configure.in >configure.in.new && mv configure.in.new configure.in )
fi
if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then
echo "Creating $dr/aclocal.m4 ..."
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
- echo "Running gettextize... Ignore non-fatal messages."
- echo "no" | gettextize --force --copy
+ echo "(2) Running ${GETTEXTIZE}... Ignore non-fatal messages."
+ echo "no" | gettextize --force --copy $INTL
echo "Making $dr/aclocal.m4 writable ..."
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+ grep "intl/Makefile" configure.in > /dev/null ||
+ ( sed -e 's#^AC_OUTPUT(#AC_OUTPUT( intl/Makefile po/Makefile.in#' \
+ configure.in >configure.in.new && mv configure.in.new configure.in )
fi
if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then
echo "Creating $dr/aclocal.m4 ..."
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
- echo "Running gettextize... Ignore non-fatal messages."
+ echo "(3) Running gettextize... Ignore non-fatal messages."
echo "no" | glib-gettextize --force --copy
echo "Making $dr/aclocal.m4 writable ..."
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+ grep "po/Makefile.in" configure.in > /dev/null ||
+ ( sed -e 's#^AC_OUTPUT(#AC_OUTPUT( po/Makefile.in#' \
+ configure.in >configure.in.new && mv configure.in.new configure.in )
fi
if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then
echo "Running intltoolize ..."
Index: gnc-freqspec-xml-v2.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/gnc-freqspec-xml-v2.c,v
retrieving revision 1.6.4.2
retrieving revision 1.6.4.3
diff -Lsrc/backend/file/gnc-freqspec-xml-v2.c -Lsrc/backend/file/gnc-freqspec-xml-v2.c -u -r1.6.4.2 -r1.6.4.3
--- src/backend/file/gnc-freqspec-xml-v2.c
+++ src/backend/file/gnc-freqspec-xml-v2.c
@@ -86,6 +86,7 @@
};
struct freqTypeTuple freqTypeStrs[] = {
+ { "none", INVALID },
{ "once", ONCE },
{ "daily", DAILY },
{ "weekly", WEEKLY },
@@ -163,6 +164,11 @@
xmlAddChild( ret, xmlSub );
switch( fs->type ) {
+
+ case INVALID: {
+ xmlSub = xmlNewNode( NULL, "fs:none" );
+ } break;
+
case ONCE: {
xmlSub = xmlNewNode( NULL, "fs:once" );
xmlAddChild( xmlSub,
@@ -260,7 +266,6 @@
xmlAddChild( ret, xmlComposites );
} break;
- case INVALID:
default:
g_return_val_if_fail( FALSE, NULL );
}
@@ -414,6 +419,21 @@
static
gboolean
+fs_none_handler( xmlNodePtr node, gpointer data )
+{
+ fsParseData *fspd = data;
+ gboolean successful;
+ successful = dom_tree_generic_parse( node,
+ fs_union_dom_handlers,
+ fspd );
+ if ( !successful )
+ return FALSE;
+ fspd->fs->type = INVALID;
+ return TRUE;
+}
+
+static
+gboolean
fs_once_handler( xmlNodePtr node, gpointer data )
{
fsParseData *fspd = data;
@@ -531,6 +551,7 @@
{ "gnc:freqspec", gnc_fs_handler, 0, 0 },
{ "fs:ui_type", fs_uift_handler, 1, 0 },
{ "fs:id", fs_guid_handler, 1, 0 },
+ { "fs:none", fs_none_handler, 0, 0 },
{ "fs:once", fs_once_handler, 0, 0 },
{ "fs:daily", fs_daily_handler, 0, 0 },
{ "fs:weekly", fs_weekly_handler, 0, 0 },
Index: price.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/price.c,v
retrieving revision 1.17.4.4
retrieving revision 1.17.4.5
diff -Lsrc/backend/postgres/price.c -Lsrc/backend/postgres/price.c -u -r1.17.4.4 -r1.17.4.5
--- src/backend/postgres/price.c
+++ src/backend/postgres/price.c
@@ -310,7 +310,7 @@
modity = gnc_string_to_commodity (DB_GET_VAL("currency",j), book);
gnc_price_set_currency (pr, modity);
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("time",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("time",j));
gnc_price_set_time (pr, ts);
gnc_price_set_source (pr, DB_GET_VAL("source",j));
Index: txn.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/txn.c,v
retrieving revision 1.23.4.3
retrieving revision 1.23.4.4
diff -Lsrc/backend/postgres/txn.c -Lsrc/backend/postgres/txn.c -u -r1.23.4.3 -r1.23.4.4
--- src/backend/postgres/txn.c
+++ src/backend/postgres/txn.c
@@ -480,7 +480,7 @@
/* next, restore all split data */
xaccSplitSetMemo(s, DB_GET_VAL("memo",j));
xaccSplitSetAction(s, DB_GET_VAL("action",j));
- ts = gnc_iso8601_to_timespec_local
+ ts = gnc_iso8601_to_timespec_gmt
(DB_GET_VAL("date_reconciled",j));
xaccSplitSetDateReconciledTS (s, &ts);
@@ -774,9 +774,9 @@
if (do_set_guid) xaccTransSetGUID (trans, trans_guid);
xaccTransSetNum (trans, DB_GET_VAL("num",j));
xaccTransSetDescription (trans, DB_GET_VAL("description",j));
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_posted",j));
xaccTransSetDatePostedTS (trans, &ts);
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_entered",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_entered",j));
xaccTransSetDateEnteredTS (trans, &ts);
xaccTransSetVersion (trans, atoi(DB_GET_VAL("version",j)));
xaccTransSetCurrency (trans, currency);
Index: checkpoint.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/checkpoint.c,v
retrieving revision 1.9.4.2
retrieving revision 1.9.4.3
diff -Lsrc/backend/postgres/checkpoint.c -Lsrc/backend/postgres/checkpoint.c -u -r1.9.4.2 -r1.9.4.3
--- src/backend/postgres/checkpoint.c
+++ src/backend/postgres/checkpoint.c
@@ -115,7 +115,7 @@
/* malloc a new checkpoint, set it to the dawn of unix time ... */
bp = g_chunk_new0 (Checkpoint, chunk);
checkpoints = g_list_prepend (checkpoints, bp);
- this_ts = gnc_iso8601_to_timespec_local (CK_EARLIEST_DATE);
+ this_ts = gnc_iso8601_to_timespec_gmt (CK_EARLIEST_DATE);
bp->date_start = this_ts;
bp->account_guid = acct_guid;
bp->commodity = commodity_name;
@@ -153,11 +153,11 @@
goto done;
}
- if (0 == i) this_ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",0));
+ if (0 == i) this_ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_posted",0));
if (2 == jrows) {
- next_ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",1));
+ next_ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_posted",1));
} else if (1 == i) {
- next_ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",0));
+ next_ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_posted",0));
}
PQclear (result);
i++;
@@ -192,7 +192,7 @@
done:
/* set the timestamp on the final checkpoint into the distant future */
- this_ts = gnc_iso8601_to_timespec_local (CK_LAST_DATE);
+ this_ts = gnc_iso8601_to_timespec_gmt (CK_LAST_DATE);
bp->date_end = this_ts;
/* now store the checkpoints */
@@ -320,7 +320,7 @@
get_checkpoint_date_cb (PGBackend *be, PGresult *result, int j, gpointer data)
{
Checkpoint *chk = (Checkpoint *) data;
- chk->date_start = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_start", j));
+ chk->date_start = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_start", j));
return data;
}
@@ -371,7 +371,7 @@
SEND_QUERY (be,be->buff, );
/* provide default value, in case there are no checkpoints */
- chk->date_start = gnc_iso8601_to_timespec_local (CK_EARLIEST_DATE);
+ chk->date_start = gnc_iso8601_to_timespec_gmt (CK_EARLIEST_DATE);
pgendGetResults (be, get_checkpoint_date_cb, chk);
LEAVE("be=%p", be);
Index: txnmass.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/txnmass.c,v
retrieving revision 1.14.4.3
retrieving revision 1.14.4.4
diff -Lsrc/backend/postgres/txnmass.c -Lsrc/backend/postgres/txnmass.c -u -r1.14.4.3 -r1.14.4.4
--- src/backend/postgres/txnmass.c
+++ src/backend/postgres/txnmass.c
@@ -98,9 +98,9 @@
xaccTransSetNum (trans, DB_GET_VAL("num",j));
xaccTransSetDescription (trans, DB_GET_VAL("description",j));
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_posted",j));
xaccTransSetDatePostedTS (trans, &ts);
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_entered",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_entered",j));
xaccTransSetDateEnteredTS (trans, &ts);
xaccTransSetVersion (trans, atoi(DB_GET_VAL("version",j)));
trans->idata = atoi (DB_GET_VAL("iguid",j));
@@ -151,7 +151,7 @@
/* next, restore all split data */
xaccSplitSetMemo(s, DB_GET_VAL("memo",j));
xaccSplitSetAction(s, DB_GET_VAL("action",j));
- ts = gnc_iso8601_to_timespec_local
+ ts = gnc_iso8601_to_timespec_gmt
(DB_GET_VAL("date_reconciled",j));
xaccSplitSetDateReconciledTS (s, &ts);
Index: PostgresBackend.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/PostgresBackend.c,v
retrieving revision 1.43.4.4
retrieving revision 1.43.4.5
diff -Lsrc/backend/postgres/PostgresBackend.c -Lsrc/backend/postgres/PostgresBackend.c -u -r1.43.4.4 -r1.43.4.5
--- src/backend/postgres/PostgresBackend.c
+++ src/backend/postgres/PostgresBackend.c
@@ -476,9 +476,9 @@
xaccTransSetNum (trans, DB_GET_VAL("num",j));
xaccTransSetDescription (trans, DB_GET_VAL("description",j));
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_posted",j));
xaccTransSetDatePostedTS (trans, &ts);
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_entered",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_entered",j));
xaccTransSetDateEnteredTS (trans, &ts);
xaccTransSetVersion (trans, atoi(DB_GET_VAL("version",j)));
trans->idata = atoi(DB_GET_VAL("iguid",j));
@@ -919,7 +919,7 @@
if ((MODE_SINGLE_FILE != be->session_mode) &&
(MODE_SINGLE_UPDATE != be->session_mode))
{
- Timespec ts = gnc_iso8601_to_timespec_local (CK_BEFORE_LAST_DATE);
+ Timespec ts = gnc_iso8601_to_timespec_gmt (CK_BEFORE_LAST_DATE);
pgendGroupGetAllBalances (be, grp, ts);
}
else
@@ -1493,7 +1493,7 @@
static void
pgend_book_load_poll (QofBackend *bend, QofBook *book)
{
- Timespec ts = gnc_iso8601_to_timespec_local (CK_BEFORE_LAST_DATE);
+ Timespec ts = gnc_iso8601_to_timespec_gmt (CK_BEFORE_LAST_DATE);
AccountGroup *grp;
PGBackend *be = (PGBackend *)bend;
Index: kvp-sql.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/kvp-sql.c,v
retrieving revision 1.13.2.1
retrieving revision 1.13.2.2
diff -Lsrc/backend/postgres/kvp-sql.c -Lsrc/backend/postgres/kvp-sql.c -u -r1.13.2.1 -r1.13.2.2
--- src/backend/postgres/kvp-sql.c
+++ src/backend/postgres/kvp-sql.c
@@ -471,7 +471,7 @@
{
Timespec ts;
KVP_HANDLER_SETUP;
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL ("data", j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL ("data", j));
kv = kvp_value_new_timespec (ts);
KVP_HANDLER_TAKEDOWN;
}
Index: putil.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/putil.h,v
retrieving revision 1.10.4.3
retrieving revision 1.10.4.4
diff -Lsrc/backend/postgres/putil.h -Lsrc/backend/postgres/putil.h -u -r1.10.4.3 -r1.10.4.4
--- src/backend/postgres/putil.h
+++ src/backend/postgres/putil.h
@@ -284,7 +284,7 @@
*/
#define COMP_DATE(sqlname,fun,ndiffs) { \
Timespec eng_time = fun; \
- Timespec sql_time = gnc_iso8601_to_timespec_local( \
+ Timespec sql_time = gnc_iso8601_to_timespec_gmt( \
DB_GET_VAL(sqlname,0)); \
if (eng_time.tv_sec != sql_time.tv_sec) { \
char buff[80]; \
@@ -302,7 +302,7 @@
*/
#define COMP_NOW(sqlname,fun,ndiffs) { \
Timespec eng_time = xaccTransRetDateEnteredTS(ptr); \
- Timespec sql_time = gnc_iso8601_to_timespec_local( \
+ Timespec sql_time = gnc_iso8601_to_timespec_gmt( \
DB_GET_VAL(sqlname,0)); \
if (eng_time.tv_sec > sql_time.tv_sec) { \
char buff[80]; \
Index: events.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/events.c,v
retrieving revision 1.13.4.2
retrieving revision 1.13.4.3
diff -Lsrc/backend/postgres/events.c -Lsrc/backend/postgres/events.c -u -r1.13.4.2 -r1.13.4.3
--- src/backend/postgres/events.c
+++ src/backend/postgres/events.c
@@ -187,7 +187,7 @@
}
string_to_guid (guid_str, &guid);
- ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_changed",j));
+ ts = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_changed",j));
/* Compress multiple events for the same object. In other
* words, keep only the last event for this object.
@@ -437,7 +437,7 @@
Timespec latest;
/* get event timestamp */
- latest = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_changed",j));
+ latest = gnc_iso8601_to_timespec_gmt (DB_GET_VAL("date_changed",j));
latest.tv_sec ++; /* ignore old, pre-logon events */
be->last_account = latest;
Index: TODO-schedxactions
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/doc/TODO-schedxactions,v
retrieving revision 1.19
retrieving revision 1.19.4.1
diff -Lsrc/doc/TODO-schedxactions -Lsrc/doc/TODO-schedxactions -u -r1.19 -r1.19.4.1
--- src/doc/TODO-schedxactions
+++ src/doc/TODO-schedxactions
@@ -3,6 +3,15 @@
Main Scheduled Transaction todo list
------------------------------------
+. Bug#102311...
+
+ . As per comment 2004-01-05T16:31, there is an issue when other pieces of
+ the system change accounts that SXes depend on. We have two options:
+ 1: handle change at account-deletion time ["remove this acocunt will
+ affect this scheduled transaction ... what to do?"]
+ 2: break out of SX since-last-run processing ["this account was removed;
+ {edit,delete} SX?"].
+
##################################################
### To-Do
###
Index: guid.txt
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/doc/guid.txt,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -Lsrc/doc/guid.txt -Lsrc/doc/guid.txt -u -r1.1 -r1.1.2.1
--- src/doc/guid.txt
+++ src/doc/guid.txt
@@ -49,4 +49,14 @@
same accounts, etc), but doesn't have the old transactions.
+The Issue:
+----------
+The current book-closing code makes a copy of the account tree,
+and sorts all transactions, by date, into the new or the old
+account tree. With the goal of not confusing the new and the
+old account trees, the book closing code issues the old accounts
+a new set of guids. The Pro's & Con's of this scheme:
+
+Pro: The 'old', closed accounts can be uniquely accessed according
+to thier GUID's, without causing confusion with similar/same.
Index: gnc-log-replay.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/log-replay/gnc-log-replay.c,v
retrieving revision 1.4.2.4
retrieving revision 1.4.2.5
diff -Lsrc/import-export/log-replay/gnc-log-replay.c -Lsrc/import-export/log-replay/gnc-log-replay.c -u -r1.4.2.4 -r1.4.2.5
--- src/import-export/log-replay/gnc-log-replay.c
+++ src/import-export/log-replay/gnc-log-replay.c
@@ -174,17 +174,17 @@
}
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
{
- record.log_date = gnc_iso8601_to_timespec_local(tok_ptr);
+ record.log_date = gnc_iso8601_to_timespec_gmt(tok_ptr);
record.log_date_present=TRUE;
}
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
{
- record.date_entered = gnc_iso8601_to_timespec_local(tok_ptr);
+ record.date_entered = gnc_iso8601_to_timespec_gmt(tok_ptr);
record.date_entered_present=TRUE;
}
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
{
- record.date_posted = gnc_iso8601_to_timespec_local(tok_ptr);
+ record.date_posted = gnc_iso8601_to_timespec_gmt(tok_ptr);
record.date_posted_present=TRUE;
}
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
@@ -239,7 +239,7 @@
}
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
{
- record.date_reconciled = gnc_iso8601_to_timespec_local(tok_ptr);
+ record.date_reconciled = gnc_iso8601_to_timespec_gmt(tok_ptr);
record.date_reconciled_present=TRUE;
}
Index: qofquery.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery.h,v
retrieving revision 1.5.2.3
retrieving revision 1.5.2.4
diff -Lsrc/engine/qofquery.h -Lsrc/engine/qofquery.h -u -r1.5.2.3 -r1.5.2.4
--- src/engine/qofquery.h
+++ src/engine/qofquery.h
@@ -55,11 +55,16 @@
/** "Known" Object Parameters -- all objects must support these */
#define QOF_QUERY_PARAM_BOOK "book"
#define QOF_QUERY_PARAM_GUID "guid"
-#define QOF_QUERY_PARAM_ACTIVE "active" /* it's ok if an object does
- * not support this */
+
+/** "Known" Object Parameters -- some objects might support these */
+#define QOF_QUERY_PARAM_ACTIVE "active"
/* --------------------------------------------------------- */
-/** Startup and Shutdown */
+/** Subsystem initialization and shutdown. Call init() once
+ * to initalize the query subsytem; call shutdown() to free
+ * up any resources associated with the query subsystem.
+ * Typically called during application startup, shutdown.
+ */
void qof_query_init (void);
void qof_query_shutdown (void);
@@ -106,17 +111,28 @@
* param_list = make_list (SPLIT_ACCOUNT, ACCOUNT_NAME, NULL);
* qof_query_add_term (query, param_list, QOF_COMPARE_EQUAL,
* acct_name_pred_data, QOF_QUERY_AND);
+ *
+ * Please note that QofQuery does not, at this time, support joins.
+ * That is, one cannot specify a predicate that is a parameter list.
+ * Put another way, one cannot search for objects where
+ * obja->thingy == objb->stuff
*/
void qof_query_add_term (QofQuery *query, GSList *param_list,
QofQueryPredData *pred_data, QofQueryOp op);
+/** DOCUMENT ME !! */
void qof_query_add_guid_match (QofQuery *q, GSList *param_list,
const GUID *guid, QofQueryOp op);
+/** DOCUMENT ME !! */
void qof_query_add_guid_list_match (QofQuery *q, GSList *param_list,
GList *guid_list, QofGuidMatch options,
QofQueryOp op);
+/** Handy-dandy convenience routines, avoids having to create
+ * a separate predicate for boolean matches. We might want to
+ * create handy-dandy sugar routines for the other predicate types
+ * as well. */
void qof_query_add_boolean_match (QofQuery *q,
GSList *param_list,
gboolean value,
@@ -151,10 +167,18 @@
/** Return the number of terms in thq query. */
int qof_query_num_terms (QofQuery *q);
+/** DOCUMENT ME !! */
gboolean qof_query_has_term_type (QofQuery *q, GSList *term_param);
GSList * qof_query_get_term_type (QofQuery *q, GSList *term_param);
+/** Make a copy of the indicated query */
QofQuery * qof_query_copy (QofQuery *q);
+
+/** Make a copy of the indicated query, inverting the sense
+ * of the search. In other words, if the original query search
+ * for all objects with a certain condition, the inverted query
+ * will search for all object with NOT that condition.
+ */
QofQuery * qof_query_invert(QofQuery *q);
/** Merges two queries together. Both queries must be compatible
@@ -165,8 +189,8 @@
*/
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op);
-/** Like qof_query_merge, but this will merge q2 into q1. q2 remains
- * unchanged.
+/** Like qof_query_merge, but this will merge a copy of q2 into q1.
+ * q2 remains unchanged.
*/
void qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op);
@@ -233,15 +257,15 @@
*/
gboolean qof_query_equal (QofQuery *q1, QofQuery *q2);
-/* Print the Query in human-readable format.
+/** Print the Query in human-readable format.
* Useful for debugging and development.
*/
void qof_query_print (QofQuery *query);
-/* Return the type of data we're querying for */
+/** Return the type of data we're querying for */
QofIdType qof_query_get_search_for (QofQuery *q);
-/* Return the list of books we're using */
+/** Return the list of books we're using */
GList * qof_query_get_books (QofQuery *q);
#endif /* QOF_QUERYNEW_H */
--- /dev/null
+++ src/engine/qofsql.h
@@ -0,0 +1,143 @@
+/********************************************************************\
+ * qofsql.h -- QOF client-side SQL parser *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+/** @addtogroup Engine
+ @{ */
+/**
+ @file qofsql.h
+ @breif QOF client-side SQL parser.
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
+*/
+
+#ifndef QOF_SQL_QUERY_H
+#define QOF_SQL_QUERY_H
+
+#include <glib.h>
+#include <qof/kvp_frame.h>
+#include <qof/qofbook.h>
+#include <qof/qofquery.h>
+
+typedef struct _QofSqlQuery QofSqlQuery;
+
+/** Create a new SQL-syntax query machine.
+ */
+QofSqlQuery * qof_sql_query_new (void);
+void qof_sql_query_destroy (QofSqlQuery *);
+
+/** Set the book to be searched (you can search multiple books)
+ * If no books are set, no results will be returned (since there
+ * is nothing to search over).
+ */
+void qof_sql_query_set_book (QofSqlQuery *q, QofBook *book);
+
+/** Perform the query, return the results.
+ * The book must be set in order to be able to perform a query.
+ *
+ * The returned list is a list of ... See below ...
+ * The returned list will have been sorted using the indicated sort
+ * order, (by default ascending order) and trimed to the
+ * max_results length.
+ * Do NOT free the resulting list. This list is managed internally
+ * by QofSqlQuery.
+ *
+ * The types of SQL queries that are allowed at this point are very
+ * limited. In general, only the following types of queries are
+ * supported:
+ * SELECT * FROM SomeObj WHERE (param_a < 10.0) AND (param_b = "asdf")
+ * SORT BY param_c DESC;
+ * The returned list is a list of all of the instances of 'SomeObj' that
+ * mathc the query. The 'SORT' term is optional. The 'WHERE' term is
+ * optional; but if you don't include 'WHERE', you will get a list of
+ * all of the object instances. The Boolean operations 'AND' and 'OR'
+ * together with parenthesis can be used to construct arbitrarily
+ * nested predicates.
+ *
+ * If the param is a KVP frame, then we use a special markup to
+ * indicate frame values. The markup should look like
+ * /some/kvp/path:value. Thus, for example,
+ * SELECT * FROM SomeObj WHERE (param_a < '/some/kvp:10.0')
+ * will search for the object where param_a is a KVP frame, and this
+ * KVP frame contains a path '/some/kvp' and the value stored at that
+ * path is floating-point and that float value is less than 10.0.
+ *
+ * The following are types of queries are NOT supported:
+ * SELECT a,b,c FROM ...
+ * I am thinking of implementing the above as a list of KVP's
+ * whose keys would be a,b,c and values would be the results of the
+ * search.
+ *
+ * Also unsupported are joins:
+ * SELECT * FROM ObjA,ObjB WHERE (ObjA.thingy = ObjB.Stuff);
+ * The problem with the above is that the search requires a nested
+ * search loop, aka a 'join', which is not currently supported in the
+ * underlying QofQuery code.
+ *
+ * Also unsupported: UPDATE and INSERT.
+ */
+
+GList * qof_sql_query_run (QofSqlQuery *query, const char * str);
+
+/** Same as above, but just parse/pre-process the query; do
+ * not actually run it over the dataset. The QofBook does not
+ * need to be set before calling this function.
+ */
+void qof_sql_query_parse (QofSqlQuery *query, const char * str);
+
+/** Return the QofQuery form of the previously parsed query. */
+QofQuery * qof_sql_query_get_query (QofSqlQuery *);
+
+/** Run the previously parsed query. The QofBook must be set
+ * before this function can be called. Note, teh QofBook can
+ * be changed between each successive call to this routine.
+ * This routine can be called after either qof_sql_query_parse()
+ * or qof_sql_query_run() because both will set up the parse.
+ */
+GList * qof_sql_query_rerun (QofSqlQuery *query);
+
+/**
+ * Set the kvp frame to be used for formulating 'indirect' predicates.
+ *
+ * Although joins are not supported (see above), there is one special
+ * hack that one can use to pass data indirectly into the predicates.
+ * This is by using a KVP key name to reference the value to be used
+ * for a predicate. Thus, for example,
+ * SELECT * FROM SomeObj WHERE (param_a = KVP:/some/key/path);
+ * will look up the value stored at '/some/key/path', and use that
+ * value to form the actual predicate. So, for example, if
+ * the value stored at '/some/key/path' was 2, then the actual
+ * query run will be
+ * SELECT * FROM SomeObj WHERE (param_a = 2);
+ * The lookup occurs at the time that the query is formulated.
+ *
+ * The query does *not* take over ownership of the kvp frame,
+ * nor does it copy it. Thus, the kvp frame must exist when the
+ * query is formulated, and it is the responsibility of the
+ * caller to free it when no longer needed.
+ *
+ * Note that because this feature is a kind of a hack put in place
+ * due to the lack of support for joins, it will probably go away
+ * (be deprecated) if/when joins are implemented.
+ */
+void qof_sql_query_set_kvp (QofSqlQuery *, KvpFrame *);
+
+#endif /* QOF_SQL_QUERY_H */
+/** @} */
Index: qofquery.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery.c,v
retrieving revision 1.10.2.3
retrieving revision 1.10.2.4
diff -Lsrc/engine/qofquery.c -Lsrc/engine/qofquery.c -u -r1.10.2.3 -r1.10.2.4
--- src/engine/qofquery.c
+++ src/engine/qofquery.c
@@ -1,5 +1,5 @@
/********************************************************************\
- * QofQuery.c -- API for finding Gnucash objects *
+ * qof_query.c -- Implement predicate API for searching for objects *
* Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU> *
* *
* This program is free software; you can redistribute it and/or *
@@ -72,9 +72,9 @@
* convert types.
*/
gboolean use_default;
- GSList * param_fcns;
+ GSList * param_fcns; /* Chain of paramters to walk */
QofSortFunc obj_cmp; /* In case you are comparing objects */
- QofCompareFunc comp_fcn; /* When you are comparing core types */
+ QofCompareFunc comp_fcn; /* When you are comparing core types */
};
/* The QUERY structure */
@@ -280,9 +280,9 @@
static int cmp_func (QofQuerySort *sort, QofSortFunc default_sort,
gconstpointer a, gconstpointer b)
{
+ QofParam *param = NULL;
GSList *node;
gpointer conva, convb;
- QofAccessFunc get_fcn = NULL; /* to appease the compiler */
g_return_val_if_fail (sort, 0);
@@ -304,7 +304,7 @@
convb = (gpointer)b;
for (node = sort->param_fcns; node; node = node->next)
{
- get_fcn = node->data;
+ param = node->data;
/* The last term is really the "parameter getter",
* unless we're comparing objects ;) */
@@ -312,13 +312,14 @@
break;
/* Do the converstions */
- conva = get_fcn (conva);
- convb = get_fcn (convb);
+ conva = (param->param_getfcn) (conva, param);
+ convb = (param->param_getfcn) (convb, param);
}
+
/* And now return the (appropriate) compare */
if (sort->comp_fcn)
{
- int rc = sort->comp_fcn (conva, convb, sort->options, get_fcn);
+ int rc = sort->comp_fcn (conva, convb, sort->options, param);
return rc;
}
@@ -381,21 +382,21 @@
if (qt->param_fcns && qt->pred_fcn)
{
GSList *node;
- QofAccessFunc get_fcn;
+ QofParam *param = NULL;
gpointer conv_obj = object;
/* iterate through the conversions */
- for (node = qt->param_fcns; node; node = node->next) {
- get_fcn = node->data;
+ for (node = qt->param_fcns; node; node = node->next)
+ {
+ param = node->data;
/* The last term is the actual parameter getter */
- if (!node->next)
- break;
+ if (!node->next) break;
- conv_obj = get_fcn (conv_obj);
+ conv_obj = param->param_getfcn (conv_obj, param);
}
- if (((qt->pred_fcn)(conv_obj, get_fcn, qt->pdata)) == qt->invert)
+ if (((qt->pred_fcn)(conv_obj, param, qt->pdata)) == qt->invert)
{
and_terms_ok = 0;
break;
@@ -428,8 +429,9 @@
*
* returns NULL if the first parameter is bad (and final is unchanged).
*/
-static GSList * compile_params (GSList *param_list, QofIdType start_obj,
- QofParam const **final)
+static GSList *
+compile_params (GSList *param_list, QofIdType start_obj,
+ QofParam const **final)
{
const QofParam *objDef = NULL;
GSList *fcns = NULL;
@@ -447,8 +449,8 @@
/* If it doesn't exist, then we've reached the end */
if (!objDef) break;
- /* Save off this function */
- fcns = g_slist_prepend (fcns, objDef->param_getfcn);
+ /* Save off this parameter */
+ fcns = g_slist_prepend (fcns, (gpointer) objDef);
/* Save this off, just in case */
*final = objDef;
@@ -742,7 +744,7 @@
}
}
- /* and then iterate over all the objects */
+ /* And then iterate over all the objects */
qof_object_foreach (q->search_for, book, (QofEntityForeachCB) check_item_cb, &qcb);
}
@@ -976,7 +978,7 @@
retval->max_results = q->max_results;
break;
- /* this is demorgan expansion for a single AND expression. */
+ /* This is the DeMorgan expansion for a single AND expression. */
/* !(abc) = !a + !b + !c */
case 1:
retval = qof_query_create();
@@ -993,7 +995,7 @@
new_oterm = g_list_append(NULL, qt);
/* g_list_append() can take forever, so let's do this for speed
- * in "large" queries
+ * in "large" queries.
*/
retval->terms = g_list_reverse(retval->terms);
retval->terms = g_list_prepend(retval->terms, new_oterm);
@@ -1001,7 +1003,7 @@
}
break;
- /* if there are multiple OR-terms, we just recurse by
+ /* If there are multiple OR-terms, we just recurse by
* breaking it down to !(a + b + c) =
* !a * !(b + c) = !a * !b * !c. */
default:
@@ -1018,7 +1020,7 @@
retval = qof_query_merge(iright, ileft, QOF_QUERY_AND);
retval->books = g_list_copy (q->books);
retval->max_results = q->max_results;
- retval->search_for = q->search_for;
+ retval->search_for = q->search_for;
retval->changed = 1;
qof_query_destroy(iright);
@@ -1036,7 +1038,8 @@
* combine 2 Query objects by the logical operation in "op".
********************************************************************/
-QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
+QofQuery *
+qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
{
QofQuery * retval = NULL;
@@ -1045,13 +1048,29 @@
GList * i, * j;
QofIdType search_for;
- if(!q1 || !q2 ) return NULL;
+ if(!q1) return q2;
+ if(!q2) return q1;
+
if (q1->search_for && q2->search_for)
g_return_val_if_fail (safe_strcmp (q1->search_for, q2->search_for) == 0,
NULL);
search_for = (q1->search_for ? q1->search_for : q2->search_for);
+ /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty.
+ * The goal of this tweak is to all the user to start with
+ * an empty q1 and then append to it recursively
+ * (and q1 (and q2 (and q3 (and q4 ....))))
+ * without bombing out because the append started with an
+ * empty list.
+ * We do essentially the same check in qof_query_add_term()
+ * so that the first term added to an empty query doesn't screw up.
+ */
+ if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1)))
+ {
+ op = QOF_QUERY_OR;
+ }
+
switch(op)
{
case QOF_QUERY_OR:
@@ -1229,6 +1248,12 @@
qof_book_get_guid(book), QOF_QUERY_AND);
}
+GList * qof_query_get_books (QofQuery *q)
+{
+ if (!q) return NULL;
+ return q->books;
+}
+
void qof_query_add_boolean_match (QofQuery *q, GSList *param_list, gboolean value,
QofQueryOp op)
{
@@ -1389,6 +1414,7 @@
}
/***************************************************************************/
+/***************************************************************************/
/* Query Print functions. qof_query_print is public; everthing else supports
* that.
* Just call qof_query_print(QofQuery *q), and it will print out the query
@@ -1480,7 +1506,7 @@
searchFor = qof_query_get_search_for (query);
gs = g_string_new ("Query Object Type: ");
- g_string_append (gs, searchFor);
+ g_string_append (gs, (NULL == searchFor)? "(null)" : searchFor);
output = g_list_append (output, gs);
return output;
@@ -1525,7 +1551,7 @@
static GList *
qof_query_printSorts (QofQuerySort *s[], const gint numSorts, GList * output)
{
- GSList *gsl = NULL;
+ GSList *gsl, *n = NULL;
gint curSort;
GString *gs = g_string_new (" Sort Parameters:\n");
@@ -1538,14 +1564,19 @@
}
increasing = qof_query_sort_get_increasing (s[curSort]);
- for (gsl = qof_query_sort_get_param_path (s[curSort]); gsl; gsl = gsl->next)
+ gsl = qof_query_sort_get_param_path (s[curSort]);
+ if (gsl) g_string_sprintfa (gs, " Param: ");
+ for (n=gsl; n; n = n->next)
+ {
+ QofIdType param_name = n->data;
+ if (gsl != n)g_string_sprintfa (gs, "\n ");
+ g_string_sprintfa (gs, "%s", param_name);
+ }
+ if (gsl)
{
- GString *sortParm = g_string_new (gsl->data);
- g_string_sprintfa (gs, " Param: %s %s\n", sortParm->str,
- increasing ? "DESC" : "ASC");
- g_string_free (sortParm, TRUE);
+ g_string_sprintfa (gs, " %s\n", increasing ? "DESC" : "ASC");
+ g_string_sprintfa (gs, " Options: 0x%x\n", s[curSort]->options);
}
- /* TODO: finish this for loop */
}
output = g_list_append (output, gs);
@@ -1575,6 +1606,8 @@
path = qof_query_term_get_param_path (qt);
invert = qof_query_term_is_inverted (qt);
+ if (invert) output = g_list_append (output,
+ g_string_new(" INVERT SENSE "));
output = g_list_append (output, qof_query_printParamPath (path));
output = g_list_append (output, qof_query_printPredData (pd));
output = g_list_append (output, g_string_new("\n"));
@@ -1612,8 +1645,14 @@
gs = g_string_new (" Pred Data:\n ");
g_string_append (gs, (gchar *) pd->type_name);
- g_string_sprintfa (gs, "\n how: %s",
- qof_query_printStringForHow (pd->how));
+
+ /* Char Predicate and GUID predicate dosn't use the 'how' field. */
+ if (safe_strcmp (pd->type_name, QOF_TYPE_CHAR) &&
+ safe_strcmp (pd->type_name, QOF_TYPE_GUID))
+ {
+ g_string_sprintfa (gs, "\n how: %s",
+ qof_query_printStringForHow (pd->how));
+ }
qof_query_printValueForParam (pd, gs);
@@ -1688,11 +1727,15 @@
{
GSList *node;
query_kvp_t pdata = (query_kvp_t) pd;
+ g_string_sprintfa (gs, "\n kvp path: ");
for (node = pdata->path; node; node = node->next)
{
- g_string_sprintfa (gs, "\n kvp path: %s", (gchar *) node->data);
- return;
+ g_string_sprintfa (gs, "/%s", (gchar *) node->data);
}
+ g_string_sprintfa (gs, "\n");
+ g_string_sprintfa (gs, " kvp value: %s\n",
+ kvp_value_to_string (pdata->value));
+ return;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
{
@@ -1709,7 +1752,7 @@
if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
{
query_double_t pdata = (query_double_t) pd;
- g_string_sprintfa (gs, " double: %20.16g", pdata->val);
+ g_string_sprintfa (gs, " double: %.18g", pdata->val);
return;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
@@ -1831,8 +1874,4 @@
return "UNKNOWN MATCH TYPE";
} /* qof_query_printGuidMatch */
-GList * qof_query_get_books (QofQuery *q)
-{
- if (!q) return NULL;
- return q->books;
-}
+/* ======================== END OF FILE =================== */
Index: qofid.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofid.h,v
retrieving revision 1.2.6.2
retrieving revision 1.2.6.3
diff -Lsrc/engine/qofid.h -Lsrc/engine/qofid.h -u -r1.2.6.2 -r1.2.6.3
--- src/engine/qofid.h
+++ src/engine/qofid.h
@@ -134,7 +134,12 @@
void qof_collection_foreach (QofCollection *,
QofEntityForeachCB, gpointer user_data);
-/** store and retreive arbitrary object-defined data */
+/** Store and retreive arbitrary object-defined data
+ *
+ * XXX We need to add a callback for when the collection is being
+ * destroyed, so that the user has a chance to clean up anything
+ * that was put in the 'data' member here.
+ */
gpointer qof_collection_get_data (QofCollection *col);
void qof_collection_set_data (QofCollection *col, gpointer user_data);
Index: qofquerycore.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquerycore.h,v
retrieving revision 1.5.2.2
retrieving revision 1.5.2.3
diff -Lsrc/engine/qofquerycore.h -Lsrc/engine/qofquerycore.h -u -r1.5.2.2 -r1.5.2.3
--- src/engine/qofquerycore.h
+++ src/engine/qofquerycore.h
@@ -1,5 +1,5 @@
/********************************************************************\
- * qofquerycore.h -- API for providing core Query data types *
+ * qofquerycore.h -- API for providing core Query data types *
* Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU> *
* *
* This program is free software; you can redistribute it and/or *
@@ -59,10 +59,18 @@
QOF_STRING_MATCH_CASEINSENSITIVE
} QofStringMatch;
-/* Comparisons for QOF_TYPE_DATE */
+/** Comparisons for QOF_TYPE_DATE
+ * The QOF_DATE_MATCH_DAY comparison rounds the two time
+ * values to mid-day and then compares these rounded values.
+ * The QOF_DATE_MATCH_TIME comparison matches teh time values,
+ * down to the second.
+ */
+/* XXX remove these deprecated old names .. */
+#define QOF_DATE_MATCH_ROUNDED QOF_DATE_MATCH_DAY
+#define QOF_DATE_MATCH_NORMAL QOF_DATE_MATCH_TIME
typedef enum {
QOF_DATE_MATCH_NORMAL = 1,
- QOF_DATE_MATCH_ROUNDED
+ QOF_DATE_MATCH_DAY
} QofDateMatch;
/* Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED */
@@ -106,23 +114,40 @@
/** Core Data Type Predicates */
-QofQueryPredData *qof_query_string_predicate (QofQueryCompare how, char *str,
- QofStringMatch options,
- gboolean is_regex);
+QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
+ const char *str,
+ QofStringMatch options,
+ gboolean is_regex);
+
QofQueryPredData *qof_query_date_predicate (QofQueryCompare how,
- QofDateMatch options, Timespec date);
+ QofDateMatch options,
+ Timespec date);
+
QofQueryPredData *qof_query_numeric_predicate (QofQueryCompare how,
- QofNumericMatch options,
- gnc_numeric value);
+ QofNumericMatch options,
+ gnc_numeric value);
+
QofQueryPredData *qof_query_guid_predicate (QofGuidMatch options, GList *guids);
QofQueryPredData *qof_query_int32_predicate (QofQueryCompare how, gint32 val);
QofQueryPredData *qof_query_int64_predicate (QofQueryCompare how, gint64 val);
QofQueryPredData *qof_query_double_predicate (QofQueryCompare how, double val);
QofQueryPredData *qof_query_boolean_predicate (QofQueryCompare how, gboolean val);
QofQueryPredData *qof_query_char_predicate (QofCharMatch options,
- const char *chars);
+ const char *chars);
+
+/** The qof_query_kvp_predicate() matches the object that has
+ * the value 'value' located at the path 'path'. In a certain
+ * sense, the 'path' is handled as if it were a paramter.
+ */
QofQueryPredData *qof_query_kvp_predicate (QofQueryCompare how,
- GSList *path, const KvpValue *value);
+ GSList *path,
+ const KvpValue *value);
+
+/** Same predicate as above, except that 'path' is assumed to be
+ * a string containing slash-separated pathname. */
+QofQueryPredData *qof_query_kvp_predicate_path (QofQueryCompare how,
+ const char *path,
+ const KvpValue *value);
/** Copy a predicate. */
QofQueryPredData *qof_query_core_predicate_copy (QofQueryPredData *pdata);
@@ -136,7 +161,6 @@
/** Return a printable string for a core data object. Caller needs
* to g_free() the returned string.
*/
-char * qof_query_core_to_string (char const *type, gpointer object,
- QofAccessFunc fcn);
+char * qof_query_core_to_string (QofType, gpointer object, QofParam *getter);
#endif /* QOF_QUERYCORE_H */
Index: qofquerycore.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquerycore.c,v
retrieving revision 1.8.2.3
retrieving revision 1.8.2.4
diff -Lsrc/engine/qofquerycore.c -Lsrc/engine/qofquerycore.c -u -r1.8.2.3 -r1.8.2.4
--- src/engine/qofquerycore.c
+++ src/engine/qofquerycore.c
@@ -39,69 +39,51 @@
/* A function to copy a query's predicate data */
typedef QofQueryPredData *(*QueryPredicateCopyFunc) (QofQueryPredData *pdata);
-/* A function to take the object, apply the get_fcn, and return
- * a printable string. Note that this QofAccessFunc function should
- * be returning a type equal to this core object type.
+/* A function to take the object, apply the getter->param_getfcn,
+ * and return a printable string. Note that this QofParam->getfnc
+ * function should be returning a type equal to this core object type.
*
* Note that this string MUST be freed by the caller.
*/
-typedef char * (*QueryToString) (gpointer object, QofAccessFunc get_fcn);
+typedef char * (*QueryToString) (gpointer object, QofParam *getter);
/* A function to test for equality of predicate data */
typedef gboolean (*QueryPredicateEqual) (QofQueryPredData *p1,
QofQueryPredData *p2);
-/* This function registers a new Core Object with the QofQuery
- * subsystem. It maps the "core_name" object to the given
- * query_predicate, predicate_copy, and predicate_data_free functions.
- */
-static void qof_query_register_core_object (char const *type_name,
- QofQueryPredicateFunc pred,
- QofCompareFunc comp,
- QueryPredicateCopyFunc copy,
- QueryPredDataFree pd_free,
- QueryToString to_string,
- QueryPredicateEqual pred_equal);
-/* An example:
- *
- * qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
- * string_compare_fcn, string_free_pdata,
- * string_print_fcn, pred_equal_fcn);
- */
-
-static QueryPredicateCopyFunc gncQueryCoreGetCopy (char const *type);
-static QueryPredDataFree gncQueryCoreGetPredFree (char const *type);
+static QueryPredicateCopyFunc qof_query_copy_predicate (QofType type);
+static QueryPredDataFree qof_query_predicate_free (QofType type);
/* Core Type Predicate helpers */
-typedef const char * (*query_string_getter) (gpointer);
+typedef const char * (*query_string_getter) (gpointer, QofParam *);
static const char * query_string_type = QOF_TYPE_STRING;
-typedef Timespec (*query_date_getter) (gpointer);
+typedef Timespec (*query_date_getter) (gpointer, QofParam *);
static const char * query_date_type = QOF_TYPE_DATE;
-typedef gnc_numeric (*query_numeric_getter) (gpointer);
+typedef gnc_numeric (*query_numeric_getter) (gpointer, QofParam *);
static const char * query_numeric_type = QOF_TYPE_NUMERIC;
-typedef GList * (*query_glist_getter) (gpointer);
-typedef const GUID * (*query_guid_getter) (gpointer);
+typedef GList * (*query_glist_getter) (gpointer, QofParam *);
+typedef const GUID * (*query_guid_getter) (gpointer, QofParam *);
static const char * query_guid_type = QOF_TYPE_GUID;
-typedef gint32 (*query_int32_getter) (gpointer);
+typedef gint32 (*query_int32_getter) (gpointer, QofParam *);
static const char * query_int32_type = QOF_TYPE_INT32;
-typedef gint64 (*query_int64_getter) (gpointer);
+typedef gint64 (*query_int64_getter) (gpointer, QofParam *);
static const char * query_int64_type = QOF_TYPE_INT64;
-typedef double (*query_double_getter) (gpointer);
+typedef double (*query_double_getter) (gpointer, QofParam *);
static const char * query_double_type = QOF_TYPE_DOUBLE;
-typedef gboolean (*query_boolean_getter) (gpointer);
+typedef gboolean (*query_boolean_getter) (gpointer, QofParam *);
static const char * query_boolean_type = QOF_TYPE_BOOLEAN;
-typedef char (*query_char_getter) (gpointer);
+typedef char (*query_char_getter) (gpointer, QofParam *);
static const char * query_char_type = QOF_TYPE_CHAR;
-typedef KvpFrame * (*query_kvp_getter) (gpointer);
+typedef KvpFrame * (*query_kvp_getter) (gpointer, QofParam *);
static const char * query_kvp_type = QOF_TYPE_KVP;
/* Tables for predicate storage and lookup */
@@ -128,7 +110,8 @@
NULL); \
}
#define VERIFY_PREDICATE(str) { \
- g_return_val_if_fail (get_fcn != NULL, PREDICATE_ERROR); \
+ g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \
+ g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \
g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \
g_return_val_if_fail (pd->type_name == str || \
!safe_strcmp (str, pd->type_name), \
@@ -140,8 +123,10 @@
/* QOF_TYPE_STRING */
-static int string_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+string_match_predicate (gpointer object,
+ QofParam *getter,
+ QofQueryPredData *pd)
{
query_string_t pdata = (query_string_t) pd;
const char *s;
@@ -149,7 +134,7 @@
VERIFY_PREDICATE (query_string_type);
- s = ((query_string_getter)get_fcn) (object);
+ s = ((query_string_getter)getter->param_getfcn) (object, getter);
if (!s) s = "";
@@ -178,14 +163,15 @@
}
}
-static int string_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+string_compare_func (gpointer a, gpointer b, gint options,
+ QofParam *getter)
{
const char *s1, *s2;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
+ g_return_val_if_fail (a && b && getter &&getter->param_getfcn, COMPARE_ERROR);
- s1 = ((query_string_getter)get_fcn) (a);
- s2 = ((query_string_getter)get_fcn) (b);
+ s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
+ s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
return safe_strcasecmp (s1, s2);
@@ -193,7 +179,8 @@
return safe_strcmp (s1, s2);
}
-static void string_free_pdata (QofQueryPredData *pd)
+static void
+string_free_pdata (QofQueryPredData *pd)
{
query_string_t pdata = (query_string_t) pd;
@@ -207,18 +194,20 @@
g_free (pdata);
}
-static QofQueryPredData *string_copy_predicate (QofQueryPredData *pd)
+static QofQueryPredData *
+string_copy_predicate (QofQueryPredData *pd)
{
query_string_t pdata = (query_string_t) pd;
VERIFY_PDATA_R (query_string_type);
- return qof_query_string_predicate (pd->how, pdata->matchstring, pdata->options,
- pdata->is_regex);
+ return qof_query_string_predicate (pd->how, pdata->matchstring,
+ pdata->options,
+ pdata->is_regex);
}
-static gboolean string_predicate_equal (QofQueryPredData *p1,
-QofQueryPredData *p2)
+static gboolean
+string_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
{
query_string_t pd1 = (query_string_t) p1;
query_string_t pd2 = (query_string_t) p2;
@@ -228,9 +217,10 @@
return (safe_strcmp (pd1->matchstring, pd2->matchstring) == 0);
}
-QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
- char *str, QofStringMatch options,
- gboolean is_regex)
+QofQueryPredData *
+qof_query_string_predicate (QofQueryCompare how,
+ const char *str, QofStringMatch options,
+ gboolean is_regex)
{
query_string_t pdata;
@@ -256,17 +246,20 @@
return ((QofQueryPredData*)pdata);
}
-static char * string_to_string (gpointer object, QofAccessFunc get)
+static char *
+string_to_string (gpointer object, QofParam *getter)
{
- const char *res = ((query_string_getter)get)(object);
+ const char *res;
+ res = ((query_string_getter)getter->param_getfcn)(object, getter);
if (res)
return g_strdup (res);
return NULL;
}
-/* QOF_TYPE_DATE */
+/* QOF_TYPE_DATE =================================================== */
-static int date_compare (Timespec ta, Timespec tb, QofDateMatch options)
+static int
+date_compare (Timespec ta, Timespec tb, QofDateMatch options)
{
if (options == QOF_DATE_MATCH_ROUNDED) {
ta = timespecCanonicalDayTime (ta);
@@ -286,7 +279,8 @@
return 0;
}
-static int date_match_predicate (gpointer object, QofAccessFunc get_fcn,
+static int
+date_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
query_date_t pdata = (query_date_t)pd;
@@ -295,7 +289,7 @@
VERIFY_PREDICATE (query_date_type);
- objtime = ((query_date_getter)get_fcn) (object);
+ objtime = ((query_date_getter)getter->param_getfcn) (object, getter);
compare = date_compare (objtime, pdata->date, pdata->options);
switch (pd->how) {
@@ -317,20 +311,21 @@
}
}
-static int date_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
Timespec ta, tb;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
- ta = ((query_date_getter)get_fcn) (a);
- tb = ((query_date_getter)get_fcn) (b);
+ ta = ((query_date_getter)getter->param_getfcn) (a, getter);
+ tb = ((query_date_getter)getter->param_getfcn) (b, getter);
return date_compare (ta, tb, options);
}
-static void date_free_pdata (QofQueryPredData *pd)
+static void
+date_free_pdata (QofQueryPredData *pd)
{
query_date_t pdata = (query_date_t)pd;
@@ -349,7 +344,8 @@
return qof_query_date_predicate (pd->how, pdata->options, pdata->date);
}
-static gboolean date_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
+static gboolean
+date_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
{
query_date_t pd1 = (query_date_t) p1;
query_date_t pd2 = (query_date_t) p2;
@@ -360,7 +356,7 @@
QofQueryPredData *
qof_query_date_predicate (QofQueryCompare how,
- QofDateMatch options, Timespec date)
+ QofDateMatch options, Timespec date)
{
query_date_t pdata;
@@ -383,9 +379,10 @@
return TRUE;
}
-static char * date_to_string (gpointer object, QofAccessFunc get)
+static char *
+date_to_string (gpointer object, QofParam *getter)
{
- Timespec ts = ((query_date_getter)get)(object);
+ Timespec ts = ((query_date_getter)getter->param_getfcn)(object, getter);
if (ts.tv_sec || ts.tv_nsec)
return g_strdup (gnc_print_date (ts));
@@ -393,10 +390,11 @@
return NULL;
}
-/* QOF_TYPE_NUMERIC */
+/* QOF_TYPE_NUMERIC ================================================= */
-static int numeric_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData* pd)
+static int
+numeric_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData* pd)
{
query_numeric_t pdata = (query_numeric_t)pd;
gnc_numeric obj_val;
@@ -404,7 +402,7 @@
VERIFY_PREDICATE (query_numeric_type);
- obj_val = ((query_numeric_getter)get_fcn) (object);
+ obj_val = ((query_numeric_getter)getter->param_getfcn) (object, getter);
switch (pdata->options) {
case QOF_NUMERIC_MATCH_CREDIT:
@@ -447,20 +445,21 @@
}
}
-static int numeric_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
gnc_numeric va, vb;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
- va = ((query_numeric_getter)get_fcn) (a);
- vb = ((query_numeric_getter)get_fcn) (b);
+ va = ((query_numeric_getter)getter->param_getfcn) (a, getter);
+ vb = ((query_numeric_getter)getter->param_getfcn) (b, getter);
return gnc_numeric_compare (va, vb);
}
-static void numeric_free_pdata (QofQueryPredData* pd)
+static void
+numeric_free_pdata (QofQueryPredData* pd)
{
query_numeric_t pdata = (query_numeric_t)pd;
VERIFY_PDATA (query_numeric_type);
@@ -487,8 +486,8 @@
QofQueryPredData *
qof_query_numeric_predicate (QofQueryCompare how,
- QofNumericMatch options,
- gnc_numeric value)
+ QofNumericMatch options,
+ gnc_numeric value)
{
query_numeric_t pdata;
pdata = g_new0 (query_numeric_def, 1);
@@ -499,24 +498,29 @@
return ((QofQueryPredData*)pdata);
}
-static char * numeric_to_string (gpointer object, QofAccessFunc get)
+static char *
+numeric_to_string (gpointer object, QofParam *getter)
{
- gnc_numeric num = ((query_numeric_getter)get)(object);
+ gnc_numeric num;
+ num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
return g_strdup (gnc_numeric_to_string (num));
}
-static char * debcred_to_string (gpointer object, QofAccessFunc get)
+static char *
+debcred_to_string (gpointer object, QofParam *getter)
{
- gnc_numeric num = ((query_numeric_getter)get)(object);
+ gnc_numeric num;
+ num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
return g_strdup (gnc_numeric_to_string (num));
}
-/* QOF_TYPE_GUID */
+/* QOF_TYPE_GUID =================================================== */
-static int guid_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+guid_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData *pd)
{
query_guid_t pdata = (query_guid_t)pd;
GList *node, *o_list;
@@ -527,17 +531,18 @@
switch (pdata->options) {
case QOF_GUID_MATCH_ALL:
- /* object is a GList of objects; get_fcn must be called on each one.
+ /* object is a GList of objects; param_getfcn must be called on each one.
* See if every guid in the predicate is accounted-for in the
* object list
*/
- for (node = pdata->guids; node; node = node->next) {
-
+ for (node = pdata->guids; node; node = node->next)
+ {
/* See if this GUID matches the object's guid */
- for (o_list = object; o_list; o_list = o_list->next) {
- guid = ((query_guid_getter)get_fcn) (o_list->data);
- if (guid_equal (node->data, guid))
+ for (o_list = object; o_list; o_list = o_list->next)
+ {
+ guid = ((query_guid_getter)getter->param_getfcn) (o_list->data, getter);
+ if (guid_equal (node->data, guid))
break;
}
@@ -560,17 +565,19 @@
case QOF_GUID_MATCH_LIST_ANY:
/* object is a single object, getter returns a GList* of GUID*
*
- * see if any GUID* in the returned list matches any guid in the
- * predicate match list
+ * See if any GUID* in the returned list matches any guid in the
+ * predicate match list.
*/
- o_list = ((query_glist_getter)get_fcn) (object);
+ o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
- for (node = o_list; node; node = node->next) {
+ for (node = o_list; node; node = node->next)
+ {
GList *node2;
/* Search the predicate data for a match */
- for (node2 = pdata->guids; node2; node2 = node2->next) {
+ for (node2 = pdata->guids; node2; node2 = node2->next)
+ {
if (guid_equal (node->data, node2->data))
break;
}
@@ -594,8 +601,9 @@
* See if the guid is in the list
*/
- guid = ((query_guid_getter)get_fcn) (object);
- for (node = pdata->guids; node; node = node->next) {
+ guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
+ for (node = pdata->guids; node; node = node->next)
+ {
if (guid_equal (node->data, guid))
break;
}
@@ -619,13 +627,16 @@
}
}
-static void guid_free_pdata (QofQueryPredData *pd)
+static void
+guid_free_pdata (QofQueryPredData *pd)
{
query_guid_t pdata = (query_guid_t)pd;
GList *node;
VERIFY_PDATA (query_guid_type);
for (node = pdata->guids; node; node = node->next)
+ {
guid_free (node->data);
+ }
g_list_free (pdata->guids);
g_free (pdata);
}
@@ -648,23 +659,29 @@
if (pd1->options != pd2->options) return FALSE;
if (g_list_length (l1) != g_list_length (l2)) return FALSE;
for ( ; l1 ; l1 = l1->next, l2 = l2->next)
+ {
if (!guid_equal (l1->data, l2->data))
return FALSE;
+ }
return TRUE;
}
QofQueryPredData *
-qof_query_guid_predicate (QofGuidMatch options, GList *guids)
+qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
{
query_guid_t pdata;
GList *node;
+ if (NULL == guid_list) return NULL;
+
pdata = g_new0 (query_guid_def, 1);
pdata->pd.how = QOF_COMPARE_EQUAL;
pdata->pd.type_name = query_guid_type;
pdata->options = options;
- pdata->guids = g_list_copy (guids);
- for (node = pdata->guids; node; node = node->next) {
+
+ pdata->guids = g_list_copy (guid_list);
+ for (node = pdata->guids; node; node = node->next)
+ {
GUID *guid = guid_malloc ();
*guid = *((GUID *)node->data);
node->data = guid;
@@ -675,15 +692,16 @@
/* ================================================================ */
/* QOF_TYPE_INT32 */
-static int int32_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+int32_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData *pd)
{
gint32 val;
query_int32_t pdata = (query_int32_t)pd;
VERIFY_PREDICATE (query_int32_type);
- val = ((query_int32_getter)get_fcn) (object);
+ val = ((query_int32_getter)getter->param_getfcn) (object, getter);
switch (pd->how) {
case QOF_COMPARE_LT:
@@ -704,21 +722,23 @@
}
}
-static int int32_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+int32_compare_func (gpointer a, gpointer b, gint options,
+ QofParam *getter)
{
gint32 v1, v2;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
- v1 = ((query_int32_getter)get_fcn)(a);
- v2 = ((query_int32_getter)get_fcn)(b);
+ v1 = ((query_int32_getter)getter->param_getfcn)(a, getter);
+ v2 = ((query_int32_getter)getter->param_getfcn)(b, getter);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
-static void int32_free_pdata (QofQueryPredData *pd)
+static void
+int32_free_pdata (QofQueryPredData *pd)
{
query_int32_t pdata = (query_int32_t)pd;
VERIFY_PDATA (query_int32_type);
@@ -752,9 +772,10 @@
return ((QofQueryPredData*)pdata);
}
-static char * int32_to_string (gpointer object, QofAccessFunc get)
+static char *
+int32_to_string (gpointer object, QofParam *getter)
{
- gint32 num = ((query_int32_getter)get)(object);
+ gint32 num = ((query_int32_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%d", num);
}
@@ -762,15 +783,16 @@
/* ================================================================ */
/* QOF_TYPE_INT64 */
-static int int64_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+int64_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData *pd)
{
gint64 val;
query_int64_t pdata = (query_int64_t)pd;
VERIFY_PREDICATE (query_int64_type);
- val = ((query_int64_getter)get_fcn) (object);
+ val = ((query_int64_getter)getter->param_getfcn) (object, getter);
switch (pd->how) {
case QOF_COMPARE_LT:
@@ -791,21 +813,23 @@
}
}
-static int int64_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+int64_compare_func (gpointer a, gpointer b, gint options,
+ QofParam *getter)
{
gint64 v1, v2;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
- v1 = ((query_int64_getter)get_fcn)(a);
- v2 = ((query_int64_getter)get_fcn)(b);
+ v1 = ((query_int64_getter)getter->param_getfcn)(a, getter);
+ v2 = ((query_int64_getter)getter->param_getfcn)(b, getter);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
-static void int64_free_pdata (QofQueryPredData *pd)
+static void
+int64_free_pdata (QofQueryPredData *pd)
{
query_int64_t pdata = (query_int64_t)pd;
VERIFY_PDATA (query_int64_type);
@@ -839,9 +863,10 @@
return ((QofQueryPredData*)pdata);
}
-static char * int64_to_string (gpointer object, QofAccessFunc get)
+static char *
+int64_to_string (gpointer object, QofParam *getter)
{
- gint64 num = ((query_int64_getter)get)(object);
+ gint64 num = ((query_int64_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf (GNC_SCANF_LLD, num);
}
@@ -849,15 +874,16 @@
/* ================================================================ */
/* QOF_TYPE_DOUBLE */
-static int double_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+double_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData *pd)
{
double val;
query_double_t pdata = (query_double_t)pd;
VERIFY_PREDICATE (query_double_type);
- val = ((query_double_getter)get_fcn) (object);
+ val = ((query_double_getter)getter->param_getfcn) (object, getter);
switch (pd->how) {
case QOF_COMPARE_LT:
@@ -878,21 +904,23 @@
}
}
-static int double_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+double_compare_func (gpointer a, gpointer b, gint options,
+ QofParam *getter)
{
double v1, v2;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
- v1 = ((query_double_getter)get_fcn) (a);
- v2 = ((query_double_getter)get_fcn) (b);
+ v1 = ((query_double_getter)getter->param_getfcn) (a, getter);
+ v2 = ((query_double_getter)getter->param_getfcn) (b, getter);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
-static void double_free_pdata (QofQueryPredData *pd)
+static void
+double_free_pdata (QofQueryPredData *pd)
{
query_double_t pdata = (query_double_t)pd;
VERIFY_PDATA (query_double_type);
@@ -926,24 +954,26 @@
return ((QofQueryPredData*)pdata);
}
-static char * double_to_string (gpointer object, QofAccessFunc get)
+static char *
+double_to_string (gpointer object, QofParam *getter)
{
- double num = ((query_double_getter)get)(object);
+ double num = ((query_double_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%f", num);
}
-/* QOF_TYPE_BOOLEAN */
+/* QOF_TYPE_BOOLEAN =================================================== */
-static int boolean_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+boolean_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData *pd)
{
gboolean val;
query_boolean_t pdata = (query_boolean_t)pd;
VERIFY_PREDICATE (query_boolean_type);
- val = ((query_boolean_getter)get_fcn) (object);
+ val = ((query_boolean_getter)getter->param_getfcn) (object, getter);
switch (pd->how) {
case QOF_COMPARE_EQUAL:
@@ -956,19 +986,21 @@
}
}
-static int boolean_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+boolean_compare_func (gpointer a, gpointer b, gint options,
+ QofParam *getter)
{
gboolean va, vb;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
- va = ((query_boolean_getter)get_fcn) (a);
- vb = ((query_boolean_getter)get_fcn) (b);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
+ va = ((query_boolean_getter)getter->param_getfcn) (a, getter);
+ vb = ((query_boolean_getter)getter->param_getfcn) (b, getter);
if (!va && vb) return -1;
if (va && !vb) return 1;
return 0;
}
-static void boolean_free_pdata (QofQueryPredData *pd)
+static void
+boolean_free_pdata (QofQueryPredData *pd)
{
query_boolean_t pdata = (query_boolean_t)pd;
VERIFY_PDATA (query_boolean_type);
@@ -1005,16 +1037,18 @@
return ((QofQueryPredData*)pdata);
}
-static char * boolean_to_string (gpointer object, QofAccessFunc get)
+static char *
+boolean_to_string (gpointer object, QofParam *getter)
{
- gboolean num = ((query_boolean_getter)get)(object);
+ gboolean num = ((query_boolean_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%s", (num ? "X" : ""));
}
-/* QOF_TYPE_CHAR */
+/* QOF_TYPE_CHAR =================================================== */
-static int char_match_predicate (gpointer object, QofAccessFunc get_fcn,
+static int
+char_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
char c;
@@ -1022,7 +1056,7 @@
VERIFY_PREDICATE (query_char_type);
- c = ((query_char_getter)get_fcn) (object);
+ c = ((query_char_getter)getter->param_getfcn) (object, getter);
switch (pdata->options) {
case QOF_CHAR_MATCH_ANY:
@@ -1037,17 +1071,18 @@
}
}
-static int char_compare_func (gpointer a, gpointer b, gint options,
- QofAccessFunc get_fcn)
+static int
+char_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
char va, vb;
- g_return_val_if_fail (a && b && get_fcn, COMPARE_ERROR);
- va = ((query_char_getter)get_fcn)(a);
- vb = ((query_char_getter)get_fcn)(b);
+ g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
+ va = ((query_char_getter)getter->param_getfcn)(a, getter);
+ vb = ((query_char_getter)getter->param_getfcn)(b, getter);
return (va-vb);
}
-static void char_free_pdata (QofQueryPredData *pd)
+static void
+char_free_pdata (QofQueryPredData *pd)
{
query_char_t pdata = (query_char_t)pd;
VERIFY_PDATA (query_char_type);
@@ -1086,17 +1121,19 @@
return ((QofQueryPredData*)pdata);
}
-static char * char_to_string (gpointer object, QofAccessFunc get)
+static char *
+char_to_string (gpointer object, QofParam *getter)
{
- char num = ((query_char_getter)get)(object);
+ char num = ((query_char_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%c", num);
}
-/* QOF_TYPE_KVP */
+/* QOF_TYPE_KVP ================================================ */
-static int kvp_match_predicate (gpointer object, QofAccessFunc get_fcn,
- QofQueryPredData *pd)
+static int
+kvp_match_predicate (gpointer object, QofParam *getter,
+ QofQueryPredData *pd)
{
int compare;
KvpFrame *kvp;
@@ -1105,7 +1142,7 @@
VERIFY_PREDICATE (query_kvp_type);
- kvp = ((query_kvp_getter)get_fcn) (object);
+ kvp = ((query_kvp_getter)getter->param_getfcn) (object, getter);
if (!kvp)
return 0;
@@ -1138,14 +1175,16 @@
}
}
-static void kvp_free_pdata (QofQueryPredData *pd)
+static void
+kvp_free_pdata (QofQueryPredData *pd)
{
query_kvp_t pdata = (query_kvp_t)pd;
GSList *node;
VERIFY_PDATA (query_kvp_type);
kvp_value_delete (pdata->value);
- for (node = pdata->path; node; node = node->next) {
+ for (node = pdata->path; node; node = node->next)
+ {
g_free (node->data);
node->data = NULL;
}
@@ -1172,8 +1211,10 @@
n2 = pd2->path;
for ( ; n1 && n2; n1 = n1->next, n2 = n2->next)
+ {
if (safe_strcmp (n1->data, n2->data) != 0)
return FALSE;
+ }
if (n1 || n2)
return FALSE;
@@ -1183,7 +1224,7 @@
QofQueryPredData *
qof_query_kvp_predicate (QofQueryCompare how,
- GSList *path, const KvpValue *value)
+ GSList *path, const KvpValue *value)
{
query_kvp_t pdata;
GSList *node;
@@ -1201,20 +1242,90 @@
return ((QofQueryPredData*)pdata);
}
-/* initialization */
+QofQueryPredData *
+qof_query_kvp_predicate_path (QofQueryCompare how,
+ const char *path, const KvpValue *value)
+{
+ QofQueryPredData *pd;
+ GSList *spath = NULL;
+ char *str, *p;
+
+ if (!path) return NULL;
+
+ str = g_strdup (path);
+ p = str;
+ if (0 == *p) return NULL;
+ if ('/' == *p) p++;
+
+ while (p)
+ {
+ spath = g_slist_append (spath, p);
+ p = strchr (p, '/');
+ if (p) { *p = 0; p++; }
+ }
+
+ pd = qof_query_kvp_predicate (how, spath, value);
+ g_free (str);
+ return pd;
+}
+
+/* initialization ================================================== */
+/** This function registers a new Core Object with the QofQuery
+ * subsystem. It maps the "core_name" object to the given
+ * query_predicate, predicate_copy, and predicate_data_free functions.
+ *
+ * An example:
+ * qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
+ * string_compare_fcn, string_free_pdata,
+ * string_print_fcn, pred_equal_fcn);
+ */
+
+
+static void
+qof_query_register_core_object (QofType core_name,
+ QofQueryPredicateFunc pred,
+ QofCompareFunc comp,
+ QueryPredicateCopyFunc copy,
+ QueryPredDataFree pd_free,
+ QueryToString toString,
+ QueryPredicateEqual pred_equal)
+{
+ g_return_if_fail (core_name);
+ g_return_if_fail (*core_name != '\0');
+
+ if (pred)
+ g_hash_table_insert (predTable, (char *)core_name, pred);
+
+ if (comp)
+ g_hash_table_insert (cmpTable, (char *)core_name, comp);
+
+ if (copy)
+ g_hash_table_insert (copyTable, (char *)core_name, copy);
+
+ if (pd_free)
+ g_hash_table_insert (freeTable, (char *)core_name, pd_free);
+
+ if (toString)
+ g_hash_table_insert (toStringTable, (char *)core_name, toString);
+
+ if (pred_equal)
+ g_hash_table_insert (predEqualTable, (char *)core_name, pred_equal);
+}
static void init_tables (void)
{
unsigned int i;
- struct {
- char const *name;
- QofQueryPredicateFunc pred;
- QofCompareFunc comp;
+ struct
+ {
+ QofType name;
+ QofQueryPredicateFunc pred;
+ QofCompareFunc comp;
QueryPredicateCopyFunc copy;
- QueryPredDataFree pd_free;
- QueryToString toString;
- QueryPredicateEqual pred_equal;
- } knownTypes[] = {
+ QueryPredDataFree pd_free;
+ QueryToString toString;
+ QueryPredicateEqual pred_equal;
+ } knownTypes[] =
+ {
{ QOF_TYPE_STRING, string_match_predicate, string_compare_func,
string_copy_predicate, string_free_pdata, string_to_string,
string_predicate_equal },
@@ -1250,7 +1361,8 @@
};
/* Register the known data types */
- for (i = 0; i < (sizeof(knownTypes)/sizeof(*knownTypes)); i++) {
+ for (i = 0; i < (sizeof(knownTypes)/sizeof(*knownTypes)); i++)
+ {
qof_query_register_core_object (knownTypes[i].name,
knownTypes[i].pred,
knownTypes[i].comp,
@@ -1261,7 +1373,8 @@
}
}
-static QueryPredicateCopyFunc gncQueryCoreGetCopy (char const *type)
+static QueryPredicateCopyFunc
+qof_query_copy_predicate (QofType type)
{
QueryPredicateCopyFunc rc;
g_return_val_if_fail (type, NULL);
@@ -1269,43 +1382,13 @@
return rc;
}
-static QueryPredDataFree gncQueryCoreGetPredFree (char const *type)
+static QueryPredDataFree
+qof_query_predicate_free (QofType type)
{
g_return_val_if_fail (type, NULL);
return g_hash_table_lookup (freeTable, type);
}
-static void
-qof_query_register_core_object (char const *core_name,
- QofQueryPredicateFunc pred,
- QofCompareFunc comp,
- QueryPredicateCopyFunc copy,
- QueryPredDataFree pd_free,
- QueryToString toString,
- QueryPredicateEqual pred_equal)
-{
- g_return_if_fail (core_name);
- g_return_if_fail (*core_name != '\0');
-
- if (pred)
- g_hash_table_insert (predTable, (char *)core_name, pred);
-
- if (comp)
- g_hash_table_insert (cmpTable, (char *)core_name, comp);
-
- if (copy)
- g_hash_table_insert (copyTable, (char *)core_name, copy);
-
- if (pd_free)
- g_hash_table_insert (freeTable, (char *)core_name, pd_free);
-
- if (toString)
- g_hash_table_insert (toStringTable, (char *)core_name, toString);
-
- if (pred_equal)
- g_hash_table_insert (predEqualTable, (char *)core_name, pred_equal);
-}
-
/********************************************************************/
/* PUBLISHED API FUNCTIONS */
@@ -1340,14 +1423,14 @@
}
QofQueryPredicateFunc
-qof_query_core_get_predicate (char const *type)
+qof_query_core_get_predicate (QofType type)
{
g_return_val_if_fail (type, NULL);
return g_hash_table_lookup (predTable, type);
}
QofCompareFunc
-qof_query_core_get_compare (char const *type)
+qof_query_core_get_compare (QofType type)
{
g_return_val_if_fail (type, NULL);
return g_hash_table_lookup (cmpTable, type);
@@ -1361,7 +1444,7 @@
g_return_if_fail (pdata);
g_return_if_fail (pdata->type_name);
- free_fcn = gncQueryCoreGetPredFree (pdata->type_name);
+ free_fcn = qof_query_predicate_free (pdata->type_name);
free_fcn (pdata);
}
@@ -1373,24 +1456,24 @@
g_return_val_if_fail (pdata, NULL);
g_return_val_if_fail (pdata->type_name, NULL);
- copy = gncQueryCoreGetCopy (pdata->type_name);
+ copy = qof_query_copy_predicate (pdata->type_name);
return (copy (pdata));
}
char *
-qof_query_core_to_string (char const *type, gpointer object,
- QofAccessFunc get)
+qof_query_core_to_string (QofType type, gpointer object,
+ QofParam *getter)
{
QueryToString toString;
g_return_val_if_fail (type, NULL);
g_return_val_if_fail (object, NULL);
- g_return_val_if_fail (get, NULL);
+ g_return_val_if_fail (getter, NULL);
toString = g_hash_table_lookup (toStringTable, type);
g_return_val_if_fail (toString, NULL);
- return toString (object, get);
+ return toString (object, getter);
}
gboolean
--- /dev/null
+++ src/engine/qofsql.c
@@ -0,0 +1,660 @@
+/********************************************************************\
+ * qofsql.c -- QOF client-side SQL parser *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+/**
+ @file qofsql.c
+ @breif QOF client-side SQL parser.
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
+
+*/
+
+#include <stdlib.h> /* for working atoll */
+
+#include <glib.h>
+#include <libsql/sql_parser.h>
+#include <qof/kvp_frame.h>
+#include <qof/gnc-date.h>
+#include <qof/gnc-numeric.h>
+#include <qof/gnc-trace.h>
+#include <qof/guid.h>
+#include <qof/qofbook.h>
+#include <qof/qofquery.h>
+#include <qof/qofquerycore.h>
+#include <qof/qofsql.h>
+#include <qof/gnc-engine-util.h>
+
+static short module = MOD_QUERY;
+
+/* =================================================================== */
+
+struct _QofSqlQuery
+{
+ sql_statement *parse_result;
+ QofQuery *qof_query;
+ QofBook *book;
+ char * single_global_tablename;
+ KvpFrame *kvp_join;
+};
+
+/* ========================================================== */
+
+QofSqlQuery *
+qof_sql_query_new(void)
+{
+ QofSqlQuery * sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
+
+ sqn->qof_query = NULL;
+ sqn->parse_result = NULL;
+ sqn->book = NULL;
+ sqn->single_global_tablename = NULL;
+ sqn->kvp_join = NULL;
+
+ return sqn;
+}
+
+/* ========================================================== */
+
+void
+qof_sql_query_destroy (QofSqlQuery *q)
+{
+ if (!q) return;
+ qof_query_destroy (q->qof_query);
+ sql_destroy (q->parse_result);
+ g_free (q);
+}
+
+/* ========================================================== */
+
+QofQuery *
+qof_sql_query_get_query (QofSqlQuery *q)
+{
+ if (!q) return NULL;
+ return q->qof_query;
+}
+
+/* ========================================================== */
+
+void
+qof_sql_query_set_book (QofSqlQuery *q, QofBook *book)
+{
+ if (!q) return;
+ q->book = book;
+}
+
+/* ========================================================== */
+
+void
+qof_sql_query_set_kvp (QofSqlQuery *q, KvpFrame *kvp)
+{
+ if (!q) return;
+ q->kvp_join = kvp;
+}
+
+/* ========================================================== */
+
+static inline void
+get_table_and_param (char * str, char **tab, char **param)
+{
+ char * end = strchr (str, '.');
+ if (!end)
+ {
+ *tab = 0;
+ *param = str;
+ return;
+ }
+ *end = 0;
+ *tab = str;
+ *param = end+1;
+}
+
+static inline char *
+dequote_string (char *str)
+{
+ /* strip out quotation marks ... */
+ if (('\'' == str[0]) ||
+ ('\"' == str[0]))
+ {
+ str ++;
+ size_t len = strlen(str);
+ str[len-1] = 0;
+ }
+ return str;
+}
+
+static QofQuery *
+handle_single_condition (QofSqlQuery *query, sql_condition * cond)
+{
+ char tmpbuff[128];
+ GSList *param_list;
+ QofQueryPredData *pred_data = NULL;
+
+ if (NULL == cond)
+ {
+ PWARN("missing condition");
+ return NULL;
+ }
+
+ /* -------------------------------- */
+ /* field to match, assumed, for now to be on the left */
+ /* XXX fix this so it can be either left or right */
+ if (NULL == cond->d.pair.left)
+ {
+ PWARN("missing left paramter");
+ return NULL;
+ }
+ sql_field_item * sparam = cond->d.pair.left->item;
+ if (SQL_name != sparam->type)
+ {
+ PWARN("we support only paramter names at this time (parsed %d)",
+ sparam->type);
+ return NULL;
+ }
+ char * qparam_name = sparam->d.name->data;
+ if (NULL == qparam_name)
+ {
+ PWARN ("missing paramter name");
+ return NULL;
+ }
+
+ /* -------------------------------- */
+ /* value to match, assumed, for now, to be on the right. */
+ /* XXX fix this so it can be either left or right */
+ if (NULL == cond->d.pair.right)
+ {
+ PWARN ("missing right paramter");
+ return NULL;
+ }
+ sql_field_item * svalue = cond->d.pair.right->item;
+ if (SQL_name != svalue->type)
+ {
+ PWARN("we support only simple values (parsed as %d)", svalue->type);
+ return NULL;
+ }
+ char * qvalue_name = svalue->d.name->data;
+ if (NULL == qvalue_name)
+ {
+ PWARN("missing value");
+ return NULL;
+ }
+ qvalue_name = dequote_string (qvalue_name);
+ qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name);
+
+ /* Look to see if its the special KVP value holder.
+ * If it is, look up the value. */
+ if (0 == strncasecmp (qvalue_name, "kvp://", 6))
+ {
+ if (NULL == query->kvp_join)
+ {
+ PWARN ("missing kvp frame");
+ return NULL;
+ }
+ KvpValue *kv = kvp_frame_get_value (query->kvp_join, qvalue_name+5);
+ /* If there's no value, its not an error;
+ * we just don't do this predicate */
+ if (!kv) return NULL;
+ KvpValueType kvt = kvp_value_get_type (kv);
+
+ tmpbuff[0] = 0x0;
+ qvalue_name = tmpbuff;
+ switch (kvt)
+ {
+ case KVP_TYPE_GINT64:
+ {
+ gint64 ival = kvp_value_get_gint64(kv);
+ sprintf (tmpbuff, "%lld\n", ival);
+ break;
+ }
+ case KVP_TYPE_DOUBLE:
+ {
+ double ival = kvp_value_get_double(kv);
+ sprintf (tmpbuff, "%26.18g\n", ival);
+ break;
+ }
+ case KVP_TYPE_STRING:
+ /* If there's no value, its not an error;
+ * we just don't do this predicate */
+ qvalue_name = kvp_value_get_string (kv);
+ if (!qvalue_name) return NULL;
+ break;
+ case KVP_TYPE_GUID:
+ case KVP_TYPE_TIMESPEC:
+ case KVP_TYPE_BINARY:
+ case KVP_TYPE_GLIST:
+ case KVP_TYPE_NUMERIC:
+ case KVP_TYPE_FRAME:
+ PWARN ("unhandled kvp type=%d", kvt);
+ return NULL;
+ }
+ }
+
+ /* -------------------------------- */
+ /* Now start building the QOF paramter */
+ param_list = qof_query_build_param_list (qparam_name, NULL);
+
+ /* Get the where-term comparison operator */
+ QofQueryCompare qop;
+ switch (cond->op)
+ {
+ case SQL_eq: qop = QOF_COMPARE_EQUAL; break;
+ case SQL_gt: qop = QOF_COMPARE_GT; break;
+ case SQL_lt: qop = QOF_COMPARE_LT; break;
+ case SQL_geq: qop = QOF_COMPARE_GTE; break;
+ case SQL_leq: qop = QOF_COMPARE_LTE; break;
+ case SQL_diff: qop = QOF_COMPARE_NEQ; break;
+ default:
+ /* XXX for string-type queries, we should be able to
+ * support 'IN' for substring search. Also regex. */
+ PWARN ("Unsupported compare op (parsed as %s)", cond->op);
+ return NULL;
+ }
+
+ /* OK, need to know the type of the thing being matched
+ * in order to build the correct predicate. Get the type
+ * from the object parameters. */
+ char *table_name;
+ char *param_name;
+ get_table_and_param (qparam_name, &table_name, ¶m_name);
+ if (NULL == table_name)
+ {
+ table_name = query->single_global_tablename;
+ }
+
+ if (NULL == table_name)
+ {
+ PWARN ("Need to specify an object class to query");
+ return NULL;
+ }
+
+ if (FALSE == qof_class_is_registered (table_name))
+ {
+ PWARN ("The query object \'%s\' is not known", table_name);
+ return NULL;
+ }
+
+ QofType param_type = qof_class_get_parameter_type (table_name, param_name);
+ if (!param_type)
+ {
+ PWARN ("The parameter \'%s\' on object \'%s\' is not known",
+ param_name, table_name);
+ return NULL;
+ }
+
+ if (!strcmp (param_type, QOF_TYPE_STRING))
+ {
+ pred_data =
+ qof_query_string_predicate (qop, /* comparison to make */
+ qvalue_name, /* string to match */
+ QOF_STRING_MATCH_CASEINSENSITIVE, /* case matching */
+ FALSE); /* use_regexp */
+ }
+ else if (!strcmp (param_type, QOF_TYPE_CHAR))
+ {
+ QofCharMatch cm = QOF_CHAR_MATCH_ANY;
+ if (QOF_COMPARE_NEQ == qop) cm = QOF_CHAR_MATCH_NONE;
+ pred_data = qof_query_char_predicate (cm, qvalue_name);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_INT32))
+ {
+ gint32 ival = atoi (qvalue_name);
+ pred_data = qof_query_int32_predicate (qop, ival);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_INT64))
+ {
+ gint64 ival = atoll (qvalue_name);
+ pred_data = qof_query_int64_predicate (qop, ival);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_DOUBLE))
+ {
+ double ival = atof (qvalue_name);
+ pred_data = qof_query_double_predicate (qop, ival);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
+ {
+ gboolean ival = qof_util_bool_to_int (qvalue_name);
+ pred_data = qof_query_boolean_predicate (qop, ival);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_DATE))
+ {
+ // XXX FIXME: this doesn't handle time strings, only date strings
+ // XXX should also see if we need to do a day-compare or time-compare.
+ /* work around highly bogus locale setting */
+ qof_date_format_set(QOF_DATE_FORMAT_US);
+
+ time_t exact;
+ int rc = qof_scan_date_secs (qvalue_name, &exact);
+ if (0 == rc)
+ {
+ PWARN ("unable to parse date: %s", qvalue_name);
+ return NULL;
+ }
+ Timespec ts;
+ ts.tv_sec = exact;
+ ts.tv_nsec = 0;
+ pred_data = qof_query_date_predicate (qop, QOF_DATE_MATCH_DAY, ts);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_NUMERIC))
+ {
+ gnc_numeric ival;
+ string_to_gnc_numeric (qvalue_name, &ival);
+ pred_data = qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_DEBCRED))
+ {
+ // XXX this probably needs some work ...
+ gnc_numeric ival;
+ string_to_gnc_numeric (qvalue_name, &ival);
+ pred_data = qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_GUID))
+ {
+ GUID guid;
+ gboolean rc = string_to_guid (qvalue_name, &guid);
+ if (0 == rc)
+ {
+ PWARN ("unable to parse guid: %s", qvalue_name);
+ return NULL;
+ }
+
+ // XXX less, than greater than don't make sense,
+ // should check for those bad conditions
+
+ QofGuidMatch gm = QOF_GUID_MATCH_ANY;
+ if (QOF_COMPARE_NEQ == qop) gm = QOF_GUID_MATCH_NONE;
+ GList *guid_list = g_list_append (NULL, &guid);
+ pred_data = qof_query_guid_predicate (gm, guid_list);
+
+ g_list_free (guid_list);
+ }
+ else if (!strcmp (param_type, QOF_TYPE_KVP))
+ {
+ /* We are expecting an encoded value that looks like
+ * /some/path/string:value
+ */
+ char *sep = strchr (qvalue_name, ':');
+ if (!sep) return NULL;
+ *sep = 0;
+ char * path = qvalue_name;
+ char * str = sep +1;
+ char * p;
+ /* If str has only digits, we know its a plain number.
+ * If its numbers and a decimal point, assume a float
+ * If its numbers and a slash, assume numeric
+ * If its 32 bytes of hex, assume GUID
+ * If it looks like an iso date ...
+ * else assume its a string.
+ */
+ KvpValue *kval = NULL;
+ int len = strlen (str);
+ if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
+ {
+ GUID guid;
+ string_to_guid (str, &guid);
+ kval = kvp_value_new_guid (&guid);
+ }
+ else
+ if (len == strspn (str, "0123456789"))
+ {
+ kval = kvp_value_new_gint64 (atoll(str));
+ }
+ else
+ if ((p=strchr (str, '.')) &&
+ ((len-1) == (strspn (str, "0123456789") +
+ strspn (p+1, "0123456789"))))
+ {
+ kval = kvp_value_new_double (atof(str));
+ }
+
+ else
+ if ((p=strchr (str, '/')) &&
+ ((len-1) == (strspn (str, "0123456789") +
+ strspn (p+1, "0123456789"))))
+ {
+ gnc_numeric num;
+ string_to_gnc_numeric (str, &num);
+ kval = kvp_value_new_gnc_numeric (num);
+ }
+ else
+ if ((p=strchr (str, '-')) &&
+ (p=strchr (p+1, '-')) &&
+ (p=strchr (p+1, ' ')) &&
+ (p=strchr (p+1, ':')) &&
+ (p=strchr (p+1, ':')))
+ {
+ kval = kvp_value_new_timespec (gnc_iso8601_to_timespec_gmt(str));
+ }
+
+ /* The default handler is a string */
+ if (NULL == kval)
+ {
+ kval = kvp_value_new_string (str);
+ }
+ pred_data = qof_query_kvp_predicate_path (qop, path, kval);
+ }
+ else
+ {
+ PWARN ("The predicate type \"%s\" is unsupported for now", param_type);
+ return NULL;
+ }
+
+ QofQuery *qq = qof_query_create();
+ qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM);
+ return qq;
+}
+
+/* ========================================================== */
+
+static QofQuery *
+handle_where (QofSqlQuery *query, sql_where *swear)
+{
+ switch (swear->type)
+ {
+ case SQL_pair:
+ {
+ QofQuery *qleft = handle_where (query, swear->d.pair.left);
+ QofQuery *qright = handle_where (query, swear->d.pair.right);
+ if (NULL == qleft) return qright;
+ if (NULL == qright) return qleft;
+ QofQueryOp qop;
+ switch (swear->d.pair.op)
+ {
+ case SQL_and: qop = QOF_QUERY_AND; break;
+ case SQL_or: qop = QOF_QUERY_OR; break;
+ /* XXX should add support for nand, nor, xor */
+ default:
+ qof_query_destroy (qleft);
+ qof_query_destroy (qright);
+ return NULL;
+ }
+ QofQuery * qq = qof_query_merge (qleft, qright, qop);
+ qof_query_destroy (qleft);
+ qof_query_destroy (qright);
+ return qq;
+ }
+ case SQL_negated:
+ {
+ QofQuery *qq = handle_where (query, swear->d.negated);
+ QofQuery *qneg = qof_query_invert (qq);
+ qof_query_destroy (qq);
+ return qneg;
+ }
+
+ case SQL_single:
+ {
+ sql_condition * cond = swear->d.single;
+ return handle_single_condition (query, cond);
+ }
+ }
+ return NULL;
+}
+
+/* ========================================================== */
+
+static void
+handle_sort_order (QofSqlQuery *query, GList *sorder_list)
+{
+ if (!sorder_list) return;
+
+ GSList *qsp[3];
+ gboolean direction[3];
+ int i;
+
+ for (i=0; i<3; i++)
+ {
+ qsp[i] = NULL;
+ direction[i] = 0;
+
+ if (sorder_list)
+ {
+ sql_order_field *sorder = sorder_list->data;
+
+ /* Set the sort direction */
+ if (SQL_asc == sorder->order_type) direction[i] = TRUE;
+
+ /* Find the paramter name */
+ char * qparam_name = NULL;
+ GList *n = sorder->name;
+ if (n)
+ {
+ qparam_name = n->data;
+ if (qparam_name)
+ {
+ qsp[i] = qof_query_build_param_list (qparam_name, NULL);
+ }
+ n = n->next; /* next paramter */
+ }
+ else
+ {
+ /* if no next paramter, then next order-by */
+ sorder_list = sorder_list->next;
+ }
+ }
+ }
+
+ qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]);
+ qof_query_set_sort_increasing (query->qof_query, direction[0],
+ direction[1], direction[2]);
+}
+
+/* ========================================================== */
+
+void
+qof_sql_query_parse (QofSqlQuery *query, const char *str)
+{
+ if (!query) return;
+
+ /* Delete old query, if any */
+ /* XXX FIXME we should also delete the parse_result as well */
+ if (query->qof_query)
+ {
+ qof_query_destroy (query->qof_query);
+ query->qof_query = NULL;
+ }
+
+ /* Parse the SQL string */
+ query->parse_result = sql_parse (str);
+
+ if (!query->parse_result)
+ {
+ PWARN ("parse error");
+ return;
+ }
+
+ if (SQL_select != query->parse_result->type)
+ {
+ PWARN("currently, only SELECT statements are supported, "
+ "got type=%d", query->parse_result);
+ return;
+ }
+
+ /* If the user wrote "SELECT * FROM tablename WHERE ..."
+ * then we have a single global tablename. But if the
+ * user wrote "SELECT * FROM tableA, tableB WHERE ..."
+ * then we don't have a single unique table-name.
+ */
+ GList *tables = sql_statement_get_tables (query->parse_result);
+ if (1 == g_list_length (tables))
+ {
+ query->single_global_tablename = tables->data;
+ }
+
+ sql_select_statement *sss = query->parse_result->statement;
+ sql_where * swear = sss->where;
+ if (swear)
+ {
+ /* Walk over the where terms, turn them into QOF predicates */
+ query->qof_query = handle_where (query, swear);
+ if (NULL == query->qof_query) return;
+ }
+ else
+ {
+ query->qof_query = qof_query_create();
+ }
+
+ /* Provide support for different sort orders */
+ handle_sort_order (query, sss->order);
+
+ /* We also want to set the type of thing to search for.
+ * If the user said SELECT * FROM ... then we should return
+ * a list of QofEntity. Otherwise, we return ... ?
+ * XXX all this needs fixing.
+ */
+ qof_query_search_for (query->qof_query, query->single_global_tablename);
+}
+
+/* ========================================================== */
+
+GList *
+qof_sql_query_run (QofSqlQuery *query, const char *str)
+{
+ GList *node;
+
+ if (!query) return NULL;
+
+ qof_sql_query_parse (query, str);
+ if (NULL == query->qof_query) return NULL;
+
+ qof_query_set_book (query->qof_query, query->book);
+
+ // qof_query_print (query->qof_query);
+ GList *results = qof_query_run (query->qof_query);
+
+ return results;
+}
+
+GList *
+qof_sql_query_rerun (QofSqlQuery *query)
+{
+ GList *node;
+
+ if (!query) return NULL;
+
+ if (NULL == query->qof_query) return NULL;
+
+ qof_query_set_book (query->qof_query, query->book);
+
+ // qof_query_print (query->qof_query);
+ GList *results = qof_query_run (query->qof_query);
+
+ return results;
+}
+
+/* ========================== END OF FILE =================== */
Index: qofquerycore-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquerycore-p.h,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -Lsrc/engine/qofquerycore-p.h -Lsrc/engine/qofquerycore-p.h -u -r1.4 -r1.4.2.1
--- src/engine/qofquerycore-p.h
+++ src/engine/qofquerycore-p.h
@@ -37,22 +37,22 @@
void qof_query_core_shutdown (void);
/*
- * An arbitrary Query Predicate. Given the gnucash object and the
+ * An arbitrary Query Predicate. Given the object and the
* particular parameter get-function (obtained from the registry by
* the Query internals), compare the object's parameter to the
- * predicate data
+ * predicate data.
*/
typedef int (*QofQueryPredicateFunc) (gpointer object,
- QofAccessFunc get_fcn,
+ QofParam *getter,
QofQueryPredData *pdata);
/* A callback for how to compare two (same-type) objects based on a
- * common get_fcn (parameter member), using the provided comparrison
+ * common getter (parameter member), using the provided comparison
* options (which are the type-specific options).
*/
typedef int (*QofCompareFunc) (gpointer a, gpointer b,
gint compare_options,
- QofAccessFunc get_fcn);
+ QofParam *getter);
/* Lookup functions */
QofQueryPredicateFunc qof_query_core_get_predicate (char const *type);
Index: qof.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qof.h,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -Lsrc/engine/qof.h -Lsrc/engine/qof.h -u -r1.2.4.1 -r1.2.4.2
--- src/engine/qof.h
+++ src/engine/qof.h
@@ -37,5 +37,6 @@
#include "qof/qofquery.h"
#include "qof/qofquerycore.h"
#include "qof/qofsession.h"
+#include "qof/qofsql.h"
#endif /* QOF_H_ */
Index: guid.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/guid.c,v
retrieving revision 1.25.4.4
retrieving revision 1.25.4.5
diff -Lsrc/engine/guid.c -Lsrc/engine/guid.c -u -r1.25.4.4 -r1.25.4.5
--- src/engine/guid.c
+++ src/engine/guid.c
@@ -82,6 +82,7 @@
GUID *
guid_malloc (void)
{
+ if (!guid_memchunk) guid_memchunk_init();
return g_chunk_new (GUID, guid_memchunk);
}
--- /dev/null
+++ src/engine/qofquery-deserial.c
@@ -0,0 +1,719 @@
+/********************************************************************\
+ * qofquery-deserial.c -- Convert Qof-Query XML to QofQuery *
+ * Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+// #include "config.h"
+
+#include <stdlib.h>
+#include <glib.h>
+#include <libxml/parser.h>
+
+#include "qofquery-deserial.h"
+#include "qofquery-serialize.h"
+#include "qofquery-p.h"
+#include "qofquerycore-p.h"
+#include "gnc-engine-util.h"
+
+#define CACHE_INSERT(str) \
+ g_cache_insert(gnc_engine_get_string_cache(), (gpointer)(str))
+#define CACHE_REMOVE(str) \
+ g_cache_remove(gnc_engine_get_string_cache(), (gpointer)(str))
+
+/* =========================================================== */
+
+#define GET_TEXT(node) ({ \
+ char * sstr = NULL; \
+ xmlNodePtr text; \
+ text = node->xmlChildrenNode; \
+ if (text && 0 == strcmp ("text", text->name)) { \
+ sstr = text->content; \
+ } \
+ sstr; \
+})
+
+#define GET_STR(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ FN (SELF, str); \
+ } \
+ else
+
+#define GET_DBL(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ double rate = atof (str); \
+ FN (SELF, rate); \
+ } \
+ else
+
+#define GET_INT32(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gint32 ival = atoi (str); \
+ FN (SELF, ival); \
+ } \
+ else
+
+#define GET_INT64(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gint64 ival = atoll (str); \
+ FN (SELF, ival); \
+ } \
+ else
+
+#define GET_DATE(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ Timespec tval = gnc_iso8601_to_timespec_gmt (str); \
+ FN (SELF, tval); \
+ } \
+ else
+
+#define GET_BOOL(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gboolean bval = qof_util_bool_to_int (str); \
+ FN (SELF, bval); \
+ } \
+ else
+
+#define GET_NUMERIC(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gnc_numeric nval; \
+ string_to_gnc_numeric (str, &nval); \
+ FN (SELF, nval); \
+ } \
+ else
+
+#define GET_GUID(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ GUID guid; \
+ string_to_guid (str, &guid); \
+ FN (SELF, &guid); \
+ } \
+ else
+
+#define GET_HOW(VAL,TOK,A,B,C,D,E,F) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_COMPARE_##A; \
+ if (!strcmp (#A, str)) ival = QOF_COMPARE_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_COMPARE_##B; \
+ else if (!strcmp (#C, str)) ival = QOF_COMPARE_##C; \
+ else if (!strcmp (#D, str)) ival = QOF_COMPARE_##D; \
+ else if (!strcmp (#E, str)) ival = QOF_COMPARE_##E; \
+ else if (!strcmp (#F, str)) ival = QOF_COMPARE_##F; \
+ VAL = ival; \
+ } \
+ else
+
+#define GET_MATCH2(VAL,TOK,PFX,A,B) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_##PFX##_##A; \
+ if (!strcmp (#A, str)) ival = QOF_##PFX##_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_##PFX##_##B; \
+ VAL = ival; \
+ } \
+ else
+
+#define GET_MATCH3(VAL,TOK,PFX,A,B,C) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_##PFX##_##A; \
+ if (!strcmp (#A, str)) ival = QOF_##PFX##_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_##PFX##_##B; \
+ else if (!strcmp (#C, str)) ival = QOF_##PFX##_##C; \
+ VAL = ival; \
+ } \
+ else
+
+#define GET_MATCH5(VAL,TOK,PFX,A,B,C,D,E) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_##PFX##_##A; \
+ if (!strcmp (#A, str)) ival = QOF_##PFX##_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_##PFX##_##B; \
+ else if (!strcmp (#C, str)) ival = QOF_##PFX##_##C; \
+ else if (!strcmp (#D, str)) ival = QOF_##PFX##_##D; \
+ else if (!strcmp (#E, str)) ival = QOF_##PFX##_##E; \
+ VAL = ival; \
+ } \
+ else
+
+/* =============================================================== */
+/* Autogen the code for the simple, repetitive predicates */
+
+#define SIMPLE_PRED_HANDLER(SUBRNAME,CTYPE,GETTER,XMLTYPE,PRED) \
+static QofQueryPredData * \
+SUBRNAME (xmlNodePtr root) \
+{ \
+ xmlNodePtr xp = root->xmlChildrenNode; \
+ xmlNodePtr node; \
+ \
+ QofQueryCompare how = QOF_COMPARE_EQUAL; \
+ CTYPE val = 0; \
+ \
+ for (node=xp; node; node = node->next) \
+ { \
+ if (node->type != XML_ELEMENT_NODE) continue; \
+ \
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ); \
+ GETTER (0, val=, XMLTYPE); \
+ {} \
+ } \
+ \
+ QofQueryPredData *pred; \
+ pred = PRED (how, val); \
+ return pred; \
+}
+
+SIMPLE_PRED_HANDLER (qof_query_pred_double_from_xml,
+ double,
+ GET_DBL,
+ "qofquery:double",
+ qof_query_double_predicate);
+
+SIMPLE_PRED_HANDLER (qof_query_pred_int64_from_xml,
+ gint64,
+ GET_INT64,
+ "qofquery:int64",
+ qof_query_int64_predicate);
+
+SIMPLE_PRED_HANDLER (qof_query_pred_int32_from_xml,
+ gint32,
+ GET_INT32,
+ "qofquery:int32",
+ qof_query_int32_predicate);
+
+SIMPLE_PRED_HANDLER (qof_query_pred_boolean_from_xml,
+ gboolean,
+ GET_BOOL,
+ "qofquery:boolean",
+ qof_query_boolean_predicate);
+
+/* =============================================================== */
+
+static void wrap_new_gint64(KvpValue **v, gint64 value) {
+ *v = kvp_value_new_gint64 (value); }
+static void wrap_new_double(KvpValue **v, double value) {
+ *v = kvp_value_new_double (value); }
+static void wrap_new_numeric(KvpValue **v, gnc_numeric value) {
+ *v = kvp_value_new_gnc_numeric (value); }
+static void wrap_new_string(KvpValue **v, const char * value) {
+ *v = kvp_value_new_string (value); }
+static void wrap_new_guid(KvpValue **v, const GUID * value) {
+ *v = kvp_value_new_guid (value); }
+static void wrap_new_timespec(KvpValue **v, Timespec value) {
+ *v = kvp_value_new_timespec (value); }
+
+
+static QofQueryPredData *
+qof_query_pred_kvp_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ GSList *path = NULL;
+ KvpValue *value = NULL;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ if (0 == strcmp ("qofquery:kvp-path", node->name))
+ {
+ const char *str = GET_TEXT (node);
+ path = g_slist_append (path, (gpointer) str);
+ }
+ else
+ GET_INT64(&value, wrap_new_gint64, "qofquery:int64");
+ GET_DBL(&value, wrap_new_double, "qofquery:double");
+ GET_NUMERIC(&value, wrap_new_numeric, "qofquery:numeric");
+ GET_STR(&value, wrap_new_string, "qofquery:string");
+ GET_GUID(&value, wrap_new_guid, "qofquery:guid");
+ GET_DATE(&value, wrap_new_timespec, "qofquery:date");
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_kvp_predicate (how, path, value);
+ g_slist_free (path);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_guid_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+ GList *guid_list = NULL;
+
+ QofGuidMatch sm = QOF_GUID_MATCH_ANY;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ /* char pred doesn't have GET_HOW */
+ GET_MATCH5 (sm, "qofquery:guid-match",
+ GUID_MATCH, ANY, NONE, NULL, ALL, LIST_ANY);
+
+ if (0 == strcmp ("qofquery:guid", node->name))
+ {
+ const char *str = GET_TEXT (node);
+ GUID *guid = guid_malloc ();
+ gboolean decode = string_to_guid (str, guid);
+ if (decode)
+ {
+ guid_list = g_list_append (guid_list, guid);
+ }
+ else
+ {
+ guid_free (guid);
+ // XXX error! let someone know!
+ }
+ }
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_guid_predicate (sm, guid_list);
+
+ /* The predicate made a copy of everything, so free our stuff */
+ GList *n;
+ for (n=guid_list; n; n=n->next)
+ {
+ guid_free (n->data);
+ }
+ g_list_free (guid_list);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_char_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofCharMatch sm = QOF_CHAR_MATCH_ANY;
+ const char * char_list = NULL;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ /* char pred doesn't have GET_HOW */
+ GET_MATCH2 (sm, "qofquery:char-match",
+ CHAR_MATCH, ANY, NONE);
+ GET_STR (0, char_list=, "qofquery:char-list");
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_char_predicate (sm, char_list);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_numeric_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ QofNumericMatch sm = QOF_NUMERIC_MATCH_ANY;
+ gnc_numeric num;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ GET_MATCH3 (sm, "qofquery:numeric-match",
+ NUMERIC_MATCH, DEBIT, CREDIT, ANY);
+ GET_NUMERIC (0, num=, "qofquery:numeric");
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_numeric_predicate (how, sm, num);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_date_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ QofDateMatch sm = QOF_DATE_MATCH_ROUNDED;
+ Timespec date = {0,0};
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ GET_MATCH2 (sm, "qofquery:date-match",
+ DATE_MATCH, NORMAL, ROUNDED);
+ GET_DATE (0, date=, "qofquery:date");
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_date_predicate (how, sm, date);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_string_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ QofStringMatch sm = QOF_STRING_MATCH_CASEINSENSITIVE;
+ gboolean is_regex = FALSE;
+ const char *pstr = NULL;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ GET_BOOL (0, is_regex=, "qofquery:is-regex");
+ GET_STR (0, pstr=, "qofquery:string");
+ GET_MATCH2 (sm, "qofquery:string-match",
+ STRING_MATCH, NORMAL, CASEINSENSITIVE);
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_string_predicate (how, pstr, sm , is_regex);
+ return pred;
+}
+
+/* =============================================================== */
+
+static GSList *
+qof_query_param_path_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr pterms = root->xmlChildrenNode;
+ GSList *plist = NULL;
+ xmlNodePtr node;
+ for (node=pterms; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ if (0 == strcmp (node->name, "qofquery:param"))
+ {
+ const char *str = GET_TEXT (node);
+ plist = g_slist_append (plist, CACHE_INSERT(str));
+ }
+ }
+ return plist;
+}
+
+/* =============================================================== */
+
+static void
+qof_query_term_from_xml (QofQuery *q, xmlNodePtr root)
+{
+ xmlNodePtr node;
+ xmlNodePtr term = root->xmlChildrenNode;
+ QofQueryPredData *pred = NULL;
+ GSList *path = NULL;
+
+ for (node=term; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+ if (0 == strcmp (node->name, "qofquery:invert"))
+ {
+ QofQuery *qt = qof_query_create();
+ qof_query_term_from_xml (qt, node);
+ QofQuery *qinv = qof_query_invert (qt);
+ qof_query_merge_in_place (q, qinv, QOF_QUERY_AND);
+ qof_query_destroy (qinv);
+ qof_query_destroy (qt);
+ return;
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:param-path"))
+ {
+ path = qof_query_param_path_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-string"))
+ {
+ pred = qof_query_pred_string_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-date"))
+ {
+ pred = qof_query_pred_date_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-numeric"))
+ {
+ pred = qof_query_pred_numeric_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-int32"))
+ {
+ pred = qof_query_pred_int32_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-int64"))
+ {
+ pred = qof_query_pred_int64_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-double"))
+ {
+ pred = qof_query_pred_double_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-boolean"))
+ {
+ pred = qof_query_pred_boolean_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-char"))
+ {
+ pred = qof_query_pred_char_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-guid"))
+ {
+ pred = qof_query_pred_guid_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-kvp"))
+ {
+ pred = qof_query_pred_kvp_from_xml (node);
+ }
+ else
+ {
+ // warning unhandled predicate type
+ }
+ }
+
+ /* At this level, the terms should always be anded */
+ qof_query_add_term (q, path, pred, QOF_QUERY_AND);
+}
+
+/* =============================================================== */
+
+static void
+qof_query_and_terms_from_xml (QofQuery *q, xmlNodePtr root)
+{
+ xmlNodePtr andterms = root->xmlChildrenNode;
+ xmlNodePtr node;
+ for (node=andterms; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ if (0 == strcmp (node->name, "qofquery:term"))
+ {
+ qof_query_term_from_xml (q, node);
+ }
+ }
+}
+
+/* =============================================================== */
+
+static void
+qof_query_or_terms_from_xml (QofQuery *q, xmlNodePtr root)
+{
+ xmlNodePtr andterms = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ for (node=andterms; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ if (0 == strcmp (node->name, "qofquery:and-terms"))
+ {
+ QofQuery *qand = qof_query_create ();
+ qof_query_and_terms_from_xml (qand, node);
+ qof_query_merge_in_place (q, qand, QOF_QUERY_OR);
+ qof_query_destroy (qand);
+ }
+ }
+}
+
+/* =============================================================== */
+
+QofQuery *
+qof_query_from_xml (xmlNodePtr root)
+{
+ QofQuery *q;
+
+ if (!root) return NULL;
+
+ xmlChar * version = xmlGetProp(root, "version");
+ if (!root->name || strcmp ("qof:qofquery", root->name))
+ {
+ // XXX something is wrong. warn ...
+ return NULL;
+ }
+
+ q = qof_query_create ();
+
+ xmlNodePtr qpart = root->xmlChildrenNode;
+ xmlNodePtr node;
+ for (node=qpart; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_STR (q, qof_query_search_for, "qofquery:search-for");
+ GET_INT32 (q, qof_query_set_max_results, "qofquery:max-results");
+ if (0 == strcmp (node->name, "qofquery:or-terms"))
+ {
+ qof_query_or_terms_from_xml (q, node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:sort-list"))
+ {
+// XXX unfinished I'm bored
+ }
+ else
+ {
+ // XXX unknown node type tell someone about it
+ }
+ }
+
+ return q;
+}
+
+/* =============================================================== */
+
+#ifdef UNIT_TEST
+
+#include <stdio.h>
+#include <qof/qofsql.h>
+
+int main (int argc, char * argv[])
+{
+ QofQuery *q, *qnew;
+ QofSqlQuery *sq;
+
+ guid_init();
+ qof_query_init();
+ qof_object_initialize ();
+
+ static QofParam params[] = {
+ { "adate", QOF_TYPE_DATE, NULL, NULL},
+ { "aint", QOF_TYPE_INT32, NULL, NULL},
+ { "aint64", QOF_TYPE_INT64, NULL, NULL},
+ { "aflt", QOF_TYPE_DOUBLE, NULL, NULL},
+ { "abool", QOF_TYPE_BOOLEAN, NULL, NULL},
+ { "astr", QOF_TYPE_STRING, NULL, NULL},
+ { "adate", QOF_TYPE_DATE, NULL, NULL},
+ { "anum", QOF_TYPE_NUMERIC, NULL, NULL},
+ { "achar", QOF_TYPE_CHAR, NULL, NULL},
+ { "aguid", QOF_TYPE_GUID, NULL, NULL},
+ { "akvp", QOF_TYPE_KVP, NULL, NULL},
+ { NULL },
+ };
+
+ qof_class_register ("GncABC", NULL, params);
+ sq = qof_sql_query_new();
+
+ qof_sql_query_parse (sq,
+ "SELECT * from GncABC WHERE aint = 123 "
+ "and not aint64 = 6123123456789 "
+ "or abool = TRUE "
+ "and not aflt >= \'3.14159265358979\' "
+ "and not astr=\'asdf\' "
+ "and adate<\'01-01-01\' "
+ "or anum<\'12301/100\' "
+ "or achar != asdf "
+ "and aguid != abcdef01234567890fedcba987654321 "
+ "and akvp != \'/some/path:abcdef01234567890fedcba987654321\' "
+ "and not akvp != \'/some/path/glop:1234\' "
+ "and akvp = \'/arf/arf/arf:10.234\' "
+ "and akvp != \'/some/other/path:qwerty1234uiop\' "
+ "and not akvp = \'/some/final/path:123401/100\' "
+ );
+ // qof_sql_query_parse (sq, "SELECT * from GncABC;");
+ q = qof_sql_query_get_query (sq);
+
+ qof_query_print (q);
+
+ xmlNodePtr topnode = qof_query_to_xml (q);
+
+ qnew = qof_query_from_xml (topnode);
+ printf (" ------------------------------------------------------- \n");
+ qof_query_print (qnew);
+
+ /* If the before and after trees are the same, the test pases. */
+ gboolean eq = qof_query_equal (q, qnew);
+ printf ("Are the two equal? answer=%d\n", eq);
+
+#define DOPRINT 1
+#ifdef DOPRINT
+ xmlDocPtr doc = doc = xmlNewDoc("1.0");
+ xmlDocSetRootElement(doc,topnode);
+
+ xmlChar *xbuf;
+ int bufsz;
+ xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
+
+ printf ("%s\n", xbuf);
+ xmlFree (xbuf);
+ xmlFreeDoc(doc);
+#endif
+
+ return 0;
+}
+
+#endif /* UNIT_TEST */
+
+/* ======================== END OF FILE =================== */
Index: gnc-engine-util.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine-util.h,v
retrieving revision 1.32.4.3
retrieving revision 1.32.4.4
diff -Lsrc/engine/gnc-engine-util.h -Lsrc/engine/gnc-engine-util.h -u -r1.32.4.3 -r1.32.4.4
--- src/engine/gnc-engine-util.h
+++ src/engine/gnc-engine-util.h
@@ -25,7 +25,7 @@
@brief GnuCash engine utility functions
@author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
@author Copyright (C) 2000 Bill Gribble <grib at billgribble.com>
- @author Copyright (C) 1997-2002 Linas Vepstas <linas at linas.org>
+ @author Copyright (C) 1997-2002,2004 Linas Vepstas <linas at linas.org>
*/
#ifndef QOF_UTIL_H
@@ -67,42 +67,50 @@
/** Prototypes *************************************************/
-/* The safe_strcmp compares strings a and b the same way that strcmp()
+/** The safe_strcmp compares strings a and b the same way that strcmp()
* does, except that either may be null. This routine assumes that
* a non-null string is always greater than a null string.
*/
int safe_strcmp (const char * da, const char * db);
int safe_strcasecmp (const char * da, const char * db);
-/* The null_strcmp compares strings a and b the same way that strcmp()
+/** The null_strcmp compares strings a and b the same way that strcmp()
* does, except that either may be null. This routine assumes that
* a null string is equal to the empty string.
*/
int null_strcmp (const char * da, const char * db);
-/* Search for str2 in first nchar chars of str1, ignore case. Return
+/** Search for str2 in first nchar chars of str1, ignore case. Return
* pointer to first match, or null. These are just like that strnstr
* and the strstr functions, except that they ignore the case. */
extern char *strncasestr(const char *str1, const char *str2, size_t len);
extern char *strcasestr(const char *str1, const char *str2);
-/* The ultostr() subroutine is the inverse of strtoul(). It accepts a
+/** The ultostr() subroutine is the inverse of strtoul(). It accepts a
* number and prints it in the indicated base. The returned string
* should be g_freed when done. */
char * ultostr (unsigned long val, int base);
-/* Returns true if string s is a number, possibly surrounded by
+/** Returns true if string s is a number, possibly surrounded by
* whitespace. */
gboolean gnc_strisnum(const char *s);
-/* Define a gnucash stpcpy */
+/** Local copy of stpcpy, used wtih libc's that don't have one. */
char * gnc_stpcpy (char *dest, const char *src);
#ifndef HAVE_STPCPY
#define stpcpy gnc_stpcpy
#endif
+/** Return NULL if the field is whitespace (blank, tab, formfeed etc.)
+ * Else return pointer to first non-whitespace character.
+ */
+const char * qof_util_whitespace_filter (const char * val);
+/** Return integer 1 if the string starts with 't' or 'T' or
+ * contains the word 'true' or 'TRUE'; if string is a number,
+ * return that number. (Leading whitespace is ignored). */
+int qof_util_bool_to_int (const char * val);
/** Many strings used throughout the engine are likely to be duplicated.
* So we provide a reference counted cache system for the strings, which
Index: qofbook.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbook.h,v
retrieving revision 1.5.2.1
retrieving revision 1.5.2.2
diff -Lsrc/engine/qofbook.h -Lsrc/engine/qofbook.h -u -r1.5.2.1 -r1.5.2.2
--- src/engine/qofbook.h
+++ src/engine/qofbook.h
@@ -71,7 +71,12 @@
associated with it. */
void qof_book_destroy (QofBook *book);
-/** \return The table of entities of the given type. */
+/** \return The table of entities of the given type.
+ * If the collection doesn't yet exist for the indicated type,
+ * it is created. Thus, this routine is gaurenteed to return
+ * a non-NULL value. (Unless the system malloc failed (out of
+ * memory) in which case what happens??).
+ */
QofCollection * qof_book_get_collection (QofBook *, QofIdType);
/** Invoke the indicated callback on each collection in the book. */
@@ -81,10 +86,13 @@
/** \return The kvp data for the book */
KvpFrame * qof_book_get_slots (QofBook *book);
-/** The qof_book_set_data() allows
- * arbitrary pointers to structs to be stored in QofBook.
- * This is the "prefered" method for extending QofBook to hold
- * new data types.
+/** The qof_book_set_data() allows arbitrary pointers to structs
+ * to be stored in QofBook. This is the "prefered" method for
+ * extending QofBook to hold new data types.
+ *
+ * XXX FIXME: we need to add a destroy callback, so that when the
+ * book gets destroyed, the user gets notified and thus has a chance
+ * to clean up.
*/
void qof_book_set_data (QofBook *book, const char *key, gpointer data);
Index: gnc-engine-util.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine-util.c,v
retrieving revision 1.29.4.2
retrieving revision 1.29.4.3
diff -Lsrc/engine/gnc-engine-util.c -Lsrc/engine/gnc-engine-util.c -u -r1.29.4.2 -r1.29.4.3
--- src/engine/gnc-engine-util.c
+++ src/engine/gnc-engine-util.c
@@ -1,7 +1,7 @@
/********************************************************************\
* gnc-engine-util.c -- GnuCash engine utility functions *
* Copyright (C) 1997 Robin D. Clark *
- * Copyright (C) 1997-2001 Linas Vepstas <linas at linas.org> *
+ * Copyright (C) 1997-2001,2004 Linas Vepstas <linas at linas.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -28,6 +28,7 @@
#include <ctype.h>
#include <glib.h>
+#include <stdlib.h>
#include <string.h>
#include "gnc-engine-util.h"
@@ -177,6 +178,41 @@
{
strcpy (dest, src);
return (dest + strlen (src));
+}
+
+/* =================================================================== */
+/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)
+ * Else return pointer to first non-whitespace character. */
+
+const char *
+qof_util_whitespace_filter (const char * val)
+{
+ size_t len;
+ if (!val) return NULL;
+
+ len = strspn (val, "\a\b\t\n\v\f\r ");
+ if (0 == val[len]) return NULL;
+ return val+len;
+}
+
+/* =================================================================== */
+/* Return integer 1 if the string starts with 't' or 'T' or contains the
+ * word 'true' or 'TRUE'; if string is a number, return that number. */
+
+int
+qof_util_bool_to_int (const char * val)
+{
+ const char * p = qof_util_whitespace_filter (val);
+ if (!p) return 0;
+ if ('t' == p[0]) return 1;
+ if ('T' == p[0]) return 1;
+ if ('y' == p[0]) return 1;
+ if ('Y' == p[0]) return 1;
+ if (strstr (p, "true")) return 1;
+ if (strstr (p, "TRUE")) return 1;
+ if (strstr (p, "yes")) return 1;
+ if (strstr (p, "YES")) return 1;
+ return atoi (val);
}
/********************************************************************\
Index: qofclass.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.c,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -Lsrc/engine/qofclass.c -Lsrc/engine/qofclass.c -u -r1.1 -r1.1.6.1
--- src/engine/qofclass.c
+++ src/engine/qofclass.c
@@ -46,27 +46,36 @@
/********************************************************************/
/* PUBLISHED API FUNCTIONS */
-void qof_class_register (QofIdTypeConst obj_name,
- QofSortFunc default_sort_function,
- const QofParam *params)
+void
+qof_class_register (QofIdTypeConst obj_name,
+ QofSortFunc default_sort_function,
+ const QofParam *params)
{
+ GHashTable *ht;
int i;
if (!obj_name) return;
if (default_sort_function)
+ {
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
+ }
- if (params) {
- GHashTable *ht = g_hash_table_lookup (paramTable, obj_name);
+ ht = g_hash_table_lookup (paramTable, obj_name);
- /* If it doesn't already exist, create a new table for this object */
- if (!ht) {
- ht = g_hash_table_new (g_str_hash, g_str_equal);
- g_hash_table_insert (paramTable, (char *)obj_name, ht);
- }
+ /* If it doesn't already exist, create a new table for this object */
+ if (!ht)
+ {
+ ht = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (paramTable, (char *)obj_name, ht);
+ }
- /* Now insert all the parameters */
+ /* At least right now, we allow dummy, paramterless objects,
+ * for testing purposes. Although I suppose that should be
+ * an error.. */
+ /* Now insert all the parameters */
+ if (params)
+ {
for (i = 0; params[i].param_name; i++)
g_hash_table_insert (ht,
(char *)params[i].param_name,
@@ -74,7 +83,8 @@
}
}
-void qof_class_init(void)
+void
+qof_class_init(void)
{
if (initialized) return;
initialized = TRUE;
@@ -83,7 +93,8 @@
sortTable = g_hash_table_new (g_str_hash, g_str_equal);
}
-void qof_class_shutdown (void)
+void
+qof_class_shutdown (void)
{
if (!initialized) return;
initialized = FALSE;
@@ -93,6 +104,15 @@
g_hash_table_destroy (sortTable);
}
+gboolean
+qof_class_is_registered (QofIdTypeConst obj_name)
+{
+ if (!obj_name) return FALSE;
+
+ if (g_hash_table_lookup (paramTable, obj_name)) return TRUE;
+
+ return FALSE;
+}
const QofParam *
qof_class_get_parameter (QofIdTypeConst obj_name,
@@ -105,8 +125,10 @@
ht = g_hash_table_lookup (paramTable, obj_name);
if (!ht)
- PERR ("no object type %s", obj_name);
- g_return_val_if_fail (ht, NULL);
+ {
+ PERR ("no object of type %s", obj_name);
+ return NULL;
+ }
return (g_hash_table_lookup (ht, parameter));
}
Index: kvp_frame.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp_frame.h,v
retrieving revision 1.22.4.5
retrieving revision 1.22.4.6
diff -Lsrc/engine/kvp_frame.h -Lsrc/engine/kvp_frame.h -u -r1.22.4.5 -r1.22.4.6
--- src/engine/kvp_frame.h
+++ src/engine/kvp_frame.h
@@ -74,9 +74,16 @@
/** Enum to enumerate possible types in the union KvpValue
* XXX FIXME TODO: People have asked for boolean values,
* e.g. in xaccAccountSetAutoInterestXfer
+ *
+ * XXX In the long run, this should be synchronized with the
+ * core QOF types, which in turn should be synced to the g_types
+ * in GLib. Unfortuantely, this requies writing a pile of code
+ * to handle all of the different cases.
+ * An alternative might be to make kvp values inherit from the
+ * core g_types (i.e. add new core g_types) ??
*/
typedef enum {
- KVP_TYPE_GINT64,
+ KVP_TYPE_GINT64=1,
KVP_TYPE_DOUBLE,
KVP_TYPE_NUMERIC,
KVP_TYPE_STRING,
--- /dev/null
+++ src/engine/qofgobj.c
@@ -0,0 +1,309 @@
+/********************************************************************\
+ * qofgobj.c -- QOF to GLib GObject mapping *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+#include <qof/gnc-trace.h>
+#include <qof/qof.h>
+#include <qof/qofgobj.h>
+
+static short module = MOD_QUERY;
+
+static gboolean initialized = FALSE;
+static GSList *paramList = NULL;
+static GSList *classList = NULL;
+
+/* =================================================================== */
+
+#if 0
+static gboolean
+clear_table (gpointer key, gpointer value, gpointer user_data)
+{
+ g_slist_free (value);
+ return TRUE;
+}
+#endif
+
+void
+qof_gobject_init(void)
+{
+ if (initialized) return;
+ initialized = TRUE;
+
+ // gobjectClassTable = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* Init the other subsystems that we need */
+ qof_object_initialize();
+ qof_query_init ();
+}
+
+void
+qof_gobject_shutdown (void)
+{
+ if (!initialized) return;
+ initialized = FALSE;
+
+ GSList *n;
+ for (n=paramList; n; n=n->next) g_free(n->data);
+ g_slist_free (paramList);
+
+ for (n=classList; n; n=n->next) g_free(n->data);
+ g_slist_free (classList);
+
+#if 0
+ // XXX also need to walk over books, and collection and delete
+ // the collection get_data instance lists !!
+ // without this we have a memory leak !!
+ g_hash_table_foreach_remove (gobjectParamTable, clear_table, NULL);
+ g_hash_table_destroy (gobjectParamTable);
+#endif
+}
+
+/* =================================================================== */
+
+#define GOBJECT_TABLE "GobjectTable"
+
+void
+qof_gobject_register_instance (QofBook *book, QofType type, GObject *gob)
+{
+ if (!book || !type) return;
+
+ QofCollection *coll = qof_book_get_collection (book, type);
+
+ GSList * instance_list = qof_collection_get_data (coll);
+ instance_list = g_slist_prepend (instance_list, gob);
+ qof_collection_set_data (coll, instance_list);
+}
+
+/* =================================================================== */
+
+static gpointer
+qof_gobject_getter (gpointer data, QofParam *getter)
+{
+ GObject *gob = data;
+
+ GParamSpec *gps = getter->param_userdata;
+
+ /* Note that the return type must actually be of type
+ * getter->param_type but we just follow the hard-coded
+ * mapping below ... */
+ if (G_IS_PARAM_SPEC_STRING(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_STRING);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ const char * str = g_value_get_string (&gval);
+ return (gpointer) str;
+ }
+ else
+ if (G_IS_PARAM_SPEC_INT(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_INT);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ int ival = g_value_get_int (&gval);
+ return (gpointer) ival;
+ }
+ else
+ if (G_IS_PARAM_SPEC_UINT(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_UINT);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ int ival = g_value_get_uint (&gval);
+ return (gpointer) ival;
+ }
+ else
+ if (G_IS_PARAM_SPEC_BOOLEAN(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_BOOLEAN);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ int ival = g_value_get_boolean (&gval);
+ return (gpointer) ival;
+ }
+
+ PWARN ("unhandled parameter type %s for paramter %s",
+ G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
+ return NULL;
+}
+
+static double
+qof_gobject_double_getter (gpointer data, QofParam *getter)
+{
+ GObject *gob = data;
+
+ GParamSpec *gps = getter->param_userdata;
+
+ /* Note that the return type must actually be of type
+ * getter->param_type but we just follow the hard-coded
+ * mapping below ... */
+ if (G_IS_PARAM_SPEC_FLOAT(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_FLOAT);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ double fval = g_value_get_float (&gval);
+ return fval;
+ }
+ else
+ if (G_IS_PARAM_SPEC_DOUBLE(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_DOUBLE);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ double fval = g_value_get_double (&gval);
+ return fval;
+ }
+
+ PWARN ("unhandled parameter type %s for paramter %s",
+ G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
+ return 0.0;
+}
+
+/* =================================================================== */
+/* Loop over every instance of the given type in the collection
+ * of instances that we have on hand.
+ */
+static void
+qof_gobject_foreach (QofCollection *coll, QofEntityForeachCB cb, gpointer ud)
+{
+ GSList *n;
+ n = qof_collection_get_data (coll);
+ for (; n; n=n->next)
+ {
+ cb (n->data, ud);
+ }
+}
+
+/* =================================================================== */
+
+void
+qof_gobject_register (QofType e_type, GObjectClass *obclass)
+{
+
+ /* Get the GObject properties, convert to QOF properties */
+ GParamSpec **prop_list;
+ int n_props;
+ prop_list = g_object_class_list_properties (obclass, &n_props);
+
+ QofParam * qof_param_list = g_new0 (QofParam, n_props);
+ paramList = g_slist_prepend (paramList, qof_param_list);
+
+ PINFO ("object %s has %d props", e_type, n_props);
+ int i, j=0;
+ for (i=0; i<n_props; i++)
+ {
+ GParamSpec *gparam = prop_list[i];
+ QofParam *qpar = &qof_param_list[j];
+
+ PINFO ("param %d %s is type %s",
+ i, gparam->name, G_PARAM_SPEC_TYPE_NAME(gparam));
+
+ qpar->param_name = g_param_spec_get_name (gparam);
+ qpar->param_getfcn = qof_gobject_getter;
+ qpar->param_setfcn = NULL;
+ qpar->param_userdata = gparam;
+ if ((G_IS_PARAM_SPEC_INT(gparam)) ||
+ (G_IS_PARAM_SPEC_UINT(gparam)) ||
+ (G_IS_PARAM_SPEC_ENUM(gparam)) ||
+ (G_IS_PARAM_SPEC_FLAGS(gparam)))
+ {
+ qpar->param_type = QOF_TYPE_INT32;
+ j++;
+ }
+ else
+ if ((G_IS_PARAM_SPEC_INT64(gparam)) ||
+ (G_IS_PARAM_SPEC_UINT64(gparam)))
+ {
+ qpar->param_type = QOF_TYPE_INT64;
+ j++;
+ }
+ else
+ if (G_IS_PARAM_SPEC_BOOLEAN(gparam))
+ {
+ qpar->param_type = QOF_TYPE_BOOLEAN;
+ j++;
+ }
+ else
+ if (G_IS_PARAM_SPEC_STRING(gparam))
+ {
+ qpar->param_type = QOF_TYPE_STRING;
+ j++;
+ }
+ else
+ if ((G_IS_PARAM_SPEC_POINTER(gparam)) ||
+ (G_IS_PARAM_SPEC_OBJECT(gparam)))
+ {
+ /* No-op, silently ignore. Someday we should handle this ... */
+ }
+ else
+ if ((G_IS_PARAM_SPEC_FLOAT(gparam)) ||
+ (G_IS_PARAM_SPEC_DOUBLE(gparam)))
+ {
+ qpar->param_getfcn = (QofAccessFunc) qof_gobject_double_getter;
+ qpar->param_type = QOF_TYPE_DOUBLE;
+ j++;
+ }
+ else
+ if (G_IS_PARAM_SPEC_CHAR(gparam))
+ {
+ qpar->param_type = QOF_TYPE_CHAR;
+ j++;
+ }
+ else
+ {
+ PWARN ("Unknown/unhandled parameter type %s on %s:%s\n",
+ G_PARAM_SPEC_TYPE_NAME(gparam), e_type, qpar->param_name);
+ }
+ }
+
+ /* NULL-terminated list! */
+ qof_param_list[j].param_type = NULL;
+
+ qof_class_register (e_type, NULL, qof_param_list);
+
+ /* ------------------------------------------------------ */
+ /* Now do the class itself */
+ QofObject *class_def = g_new0 (QofObject, 1);
+ classList = g_slist_prepend (classList, class_def);
+
+ class_def->interface_version = QOF_OBJECT_VERSION;
+ class_def->e_type = e_type;
+ /* We could let the user specify a "nick" here, but
+ * the actual class name seems reasonable, e.g. for debugging. */
+ class_def->type_label = G_OBJECT_CLASS_NAME (obclass);
+ class_def->book_begin = NULL;
+ class_def->book_end = NULL;
+ class_def->is_dirty = NULL;
+ class_def->mark_clean = NULL;
+ class_def->foreach = qof_gobject_foreach;
+ class_def->printable = NULL;
+
+ qof_object_register (class_def);
+}
+
+/* ======================= END OF FILE ================================ */
Index: Transaction.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Transaction.c,v
retrieving revision 1.261.4.4
retrieving revision 1.261.4.5
diff -Lsrc/engine/Transaction.c -Lsrc/engine/Transaction.c -u -r1.261.4.4 -r1.261.4.5
--- src/engine/Transaction.c
+++ src/engine/Transaction.c
@@ -3095,7 +3095,7 @@
val = kvp_frame_get_string(tr->inst.kvp_data, void_time_str);
if(val)
{
- void_time = gnc_iso8601_to_timespec_local(val);
+ void_time = gnc_iso8601_to_timespec_gmt(val);
}
return void_time;
@@ -3196,7 +3196,7 @@
};
static gpointer
-split_account_guid_getter (gpointer obj)
+split_account_guid_getter (gpointer obj, const QofParam *p)
{
Split *s = obj;
Account *acc;
@@ -3214,7 +3214,8 @@
return gnc_numeric_to_double(xaccSplitGetAmount(split));
}
-static gpointer no_op (gpointer obj)
+static gpointer
+no_op (gpointer obj, const QofParam *p)
{
return obj;
}
@@ -3251,7 +3252,8 @@
{ SPLIT_TRANS, GNC_ID_TRANS, (QofAccessFunc)xaccSplitGetParent, NULL },
{ SPLIT_ACCOUNT, GNC_ID_ACCOUNT, (QofAccessFunc)xaccSplitGetAccount, NULL },
{ SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, NULL },
-/* XXX why are these no-ops ?? ahh, to register sort func only ?? */
+/* these are no-ops to register the parameter names (for sorting) but
+ they return an allocated object which getters cannot do. */
{ SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, NULL },
{ SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
{ SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
--- /dev/null
+++ src/engine/qofquery-deserial.h
@@ -0,0 +1,42 @@
+/********************************************************************\
+ * qofquery-deserial.h -- Convert Qof-Query XML to QofQuery *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+/** @file qofquery-deserial.h
+ @breif Convert Qof-Query XML to QofQuery
+
+ Qof Queries can be convrted to and from XML so that they
+ can be sent from here to there. This file implements the
+ routine needed to convert the XML back into a C struct.
+
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
+*/
+
+#ifndef QOF_QUERY_DESERIAL_H
+#define QOF_QUERY_DESERIAL_H
+
+#include <qof/qofquery.h>
+#include <libxml/tree.h>
+
+/** Given an XML tree, reconstruct and return the equivalent query. */
+QofQuery *qof_query_from_xml (xmlNodePtr);
+
+#endif /* QOF_QUERY_DESERIAL_H */
--- /dev/null
+++ src/engine/qofquery-serialize.h
@@ -0,0 +1,41 @@
+/********************************************************************\
+ * qofquery-serialize.h -- Convert QofQuery to XML *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+/** @file qofquery-serialize.h
+ @breif Convert QofQuery to XML
+ @author Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org>
+ */
+
+#ifndef QOF_QUERY_SERIALIZE_H
+#define QOF_QUERY_SERIALIZE_H
+
+#include <qof/qofquery.h>
+#include <libxml/tree.h>
+
+/** Take the query passed as input, and serialize it into XML.
+ * The DTD used will be a very qofquery specific DTD
+ * This is NOT the XQuery XML.
+ */
+xmlNodePtr qof_query_to_xml (QofQuery *q);
+
+#endif /* QOF_QUERY_SERIALIZE_H */
Index: qofsession.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.c,v
retrieving revision 1.2.4.4
retrieving revision 1.2.4.5
diff -Lsrc/engine/qofsession.c -Lsrc/engine/qofsession.c -u -r1.2.4.4 -r1.2.4.5
--- src/engine/qofsession.c
+++ src/engine/qofsession.c
@@ -1140,6 +1140,7 @@
void
gnc_run_rpc_server (void)
{
+#ifdef GNUCASH
const char * dll_err;
void * dll_handle;
int (*rpc_run)(short);
@@ -1172,6 +1173,7 @@
ret = (*rpc_run)(0);
/* XXX How do we force an exit? */
+#endif /* GNUCASH */
}
/* =================== END OF FILE ====================================== */
Index: FreqSpec.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/FreqSpec.c,v
retrieving revision 1.28.4.4
retrieving revision 1.28.4.5
diff -Lsrc/engine/FreqSpec.c -Lsrc/engine/FreqSpec.c -u -r1.28.4.4 -r1.28.4.5
--- src/engine/FreqSpec.c
+++ src/engine/FreqSpec.c
@@ -138,6 +138,7 @@
{
static gchar wday_name[WDAY_BUF_WIDTH];
struct tm t;
+ memset( &t, 0, sizeof( t ) );
t.tm_wday = day;
strftime(wday_name, WDAY_NAME_WIDTH, "%A", &t);
return wday_name;
@@ -160,6 +161,7 @@
{
static gchar month_name[WDAY_BUF_WIDTH];
struct tm t;
+ memset( &t, 0, sizeof( t ) );
t.tm_mon = month;
strftime(month_name, WDAY_NAME_WIDTH, "%b", &t);
return month_name;
@@ -240,7 +242,7 @@
{
g_return_val_if_fail( fs, INVALID );
/* Is this really a fail? */
- g_return_val_if_fail( fs->type != INVALID, INVALID );
+ //g_return_val_if_fail( fs->type != INVALID, INVALID );
return fs->type;
}
@@ -452,6 +454,14 @@
*/
void
+xaccFreqSpecSetNone( FreqSpec *fs )
+{
+ g_return_if_fail( fs );
+ xaccFreqSpecCleanUp( fs );
+ fs->type = INVALID;
+}
+
+void
xaccFreqSpecSetOnceDate( FreqSpec *fs, const GDate* when )
{
g_return_if_fail( fs );
@@ -709,6 +719,10 @@
memset( freqStrBuf, 0, MAX_FREQ_STR_SIZE + 1 );
switch( xaccFreqSpecGetUIType( fs ) ) {
+ case UIFREQ_NONE:
+ snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("None") );
+ break;
+
case UIFREQ_ONCE:
tmpStr = g_new0( char, GDATE_STRING_BUF_SIZE );
/* this is now a GDate. */
@@ -778,6 +792,7 @@
if ( xaccFreqSpecGetType(tmpFS) != WEEKLY ) {
snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
"error: UIFREQ_WEEKLY doesn't contain weekly children" );
+ g_free( tmpStr );
return;
}
if ( tmpInt == -1 ) {
@@ -785,7 +800,7 @@
}
/* put the first letter of the weekday name in
the appropriate position. */
- dowIdx = tmpFS->s.weekly.offset_from_epoch;
+ dowIdx = tmpFS->s.weekly.offset_from_epoch % 7;
tmpStr[dowIdx] = *(get_wday_name(dowIdx));
}
--- /dev/null
+++ src/engine/qofgobj.h
@@ -0,0 +1,82 @@
+/********************************************************************\
+ * qofgobj.h -- QOF to GLib GObject mapping *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+#ifndef QOF_GOBJ_H
+#define QOF_GOBJ_H
+
+/** @addtogroup Engine
+ @{ */
+/** @file qofgobj.h
+ @brief QOF to GLib GObject mapping
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
+*/
+
+/** The API defined in this file allows a user to register any
+ * GLib GObject (and any object derived from one, e.g. GTK/Gnome)
+ * with the QOF system so that it becomes searchable.
+ *
+ * XXX Only GObject properties are searchable, data and other
+ * hanging off the GObject is not. Fix this.
+ */
+
+#include <glib-object.h>
+#include <qof/qofbook.h>
+#include <qof/qofclass.h>
+
+/** Initalize and shut down this subsystem. */
+void qof_gobject_init(void);
+void qof_gobject_shutdown (void);
+
+/** Register a GObject class with the QOF subsystem.
+ * Doing this will make the properties associated with
+ * this GObject searchable using the QOF subsystem.
+ *
+ * The QofType can be any string you desire, although typically
+ * you might want to set it to G_OBJECT_CLASS_NAME() of the
+ * object class. Note that this type will become the name of
+ * the "table" that is searched by SQL queries:
+ * e.g. in order to be able to say "SELECT * FROM MyStuff;"
+ * you must first say:
+ * qof_gobject_register ("MyStuff", gobj_class);
+ */
+void qof_gobject_register (QofType type, GObjectClass *obclass);
+
+/** Register an instance of a GObject with the QOF subsystem.
+ *
+ * The QofType can be any string you desire, although typically
+ * you might want to set it to G_OBJECT_CLASS_NAME() of the
+ * object class. Note that this type will become the name of
+ * the "table" that is searched by SQL queries:
+ * e.g. in order to be able to say "SELECT * FROM MyStuff;"
+ * you must first say:
+ * qof_gobject_register_instance (book, "MyStuff", obj);
+ *
+ * The 'book' argument specifies an anchor point for the collection
+ * of all of the registered instances. By working with disjoint books,
+ * you can have multiple disjoint searchable sets of objects.
+ */
+
+void qof_gobject_register_instance (QofBook *book, QofType, GObject *);
+
+#endif /* QOF_GOBJ_H */
+/** @} */
+
Index: gnc-date.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-date.h,v
retrieving revision 1.6.2.2
retrieving revision 1.6.2.3
diff -Lsrc/engine/gnc-date.h -Lsrc/engine/gnc-date.h -u -r1.6.2.2 -r1.6.2.3
--- src/engine/gnc-date.h
+++ src/engine/gnc-date.h
@@ -34,7 +34,22 @@
applications, besides just GnuCash, use this file. In particular,
GnoTime (gttr.sourcefore.net) uses this file, and this file is
formally a part of QOF (qof.sourceforge.net).
- *
+
+ An important note about time-keeping: The general goal of any
+ program that works with numeric time values SHOULD BE to always
+ stores and use UNIVERSAL TIME internally. Universal time is the
+ 'one true time' that is independent of one's location on planet
+ Earth. It is measured in seconds from midnight January 1, 1970
+ in localtime-Grenwich (GMT). If one wants to display the local
+ time, then the display-print routine should make all final
+ tweaks to print the local time. The local time *must not* be
+ kept as a numeric value anywhere in the program. If one wants
+ to parse a user's input string as if it were local time, then
+ the output of the parse routine MUST BE universal time.
+ A sane program must never ever store (to file or db) a time
+ that is not Universal Time. Break these rules, and you will
+ rue the day...
+
@author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
@author Copyright (C) 1998-2001,2003 Linas Vepstas <linas at linas.org>
*/
@@ -173,25 +188,40 @@
/** Same as gnc_dmy2timespec, but last second of the day */
Timespec gnc_dmy2timespec_end (int day, int month, int year);
-/** The gnc_iso8601_to_timespec_local() routine converts an ISO-8601 style
- * date/time string to Timespec.
- * For example: 1998-07-17 11:00:00.68-05
- * is 680 milliseconds after 11 o'clock, central daylight time
- * \return The time in local time.*/
-Timespec gnc_iso8601_to_timespec_local(const char *);
-
/** The gnc_iso8601_to_timespec_gmt() routine converts an ISO-8601 style
- * date/time string to Timespec.
- * For example: 1998-07-17 11:00:00.68-05
+ * date/time string to Timespec. Please note that ISO-8601 strings
+ * are a representation of Universal Time (UTC), and as such, they
+ * 'store' UTC. To make them human readable, they show timezone
+ * information along with a local-time string. But fundamentally,
+ * they *are* UTC. Thus, thir routine takes a UTC input, and
+ * returns a UTC output.
+ *
+ * For example: 1998-07-17 11:00:00.68-0500
* is 680 milliseconds after 11 o'clock, central daylight time
- * \return The time in gmt. */
+ * It is also 680 millisecs after 16:00:00 hours UTC.
+ * \return The universl time.
+ *
+ * XXX Caution: this routine does not handle strings that specify
+ * times before January 1 1970.
+ */
Timespec gnc_iso8601_to_timespec_gmt(const char *);
-/** The gnc_timespec_to_iso8601_buff() routine prints a Timespec
-* as an ISO-8601 style string. The buffer must be long enough
-* to contain the NULL-terminated string (32 characters + NUL). This
-* routine returns a pointer to the null terminator (and can
-* thus be used in the 'stpcpy' metaphor of string concatenation).*/
+/** The gnc_timespec_to_iso8601_buff() routine takes the input
+ * UTC Timespec value and prints it as an ISO-8601 style string.
+ * The buffer must be long enough to contain the NULL-terminated
+ * string (32 characters + NUL). This routine returns a pointer
+ * to the null terminator (and can thus be used in the 'stpcpy'
+ * metaphor of string concatenation).
+ *
+ * Please note that ISO-8601 strings are a representation of
+ * Universal Time (UTC), and as such, they 'store' UTC. To make them
+ * human readable, they show timezone information along with a
+ * local-time string. But fundamentally, they *are* UTC. Thus,
+ * this routine takes a UTC input, and returns a UTC output.
+ *
+ * The string generated by this routine uses the local timezone
+ * on the machine on which it is executing to create the timestring.
+ */
char * gnc_timespec_to_iso8601_buff (Timespec ts, char * buff);
/** DOCUMENT ME! FIXME: Probably similar to xaccDMYToSec() this date
@@ -206,7 +236,12 @@
/** \warning hack alert XXX FIXME -- these date routines return incorrect
* values for dates before 1970. Most of them are good only up
- * till 2038. This needs fixing ... */
+ * till 2038. This needs fixing ...
+ *
+ * XXX This routine should be modified to assume that the
+ * the user wanted the time at noon, localtime. The returned
+ * time_t should be seconds (at GMT) of the local noon-time.
+*/
time_t xaccDMYToSec (int day, int month, int year);
/** The gnc_timezone function returns the number of seconds *west*
--- /dev/null
+++ src/engine/qofquery-serialize.c
@@ -0,0 +1,555 @@
+/********************************************************************\
+ * qofquery-serialize.c -- Convert QofQuery to XML *
+ * Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 at gnu.org *
+ * *
+\********************************************************************/
+
+#include "config.h"
+
+#include "qofquery-serialize.h"
+#include "qofquery-p.h"
+#include "qofquerycore-p.h"
+#include "kvp_frame.h"
+
+/* ======================================================= */
+
+#define PUT_STR(TOK,VAL) { \
+ xmlNodePtr node; \
+ const char * str = (VAL); \
+ if (str && 0 != str[0]) \
+ { \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+ } \
+}
+
+#define PUT_INT32(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ g_snprintf (buff, sizeof(buff), "%d", (VAL)); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_INT64(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ g_snprintf (buff, sizeof(buff), "%lld", (VAL)); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_DBL(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ g_snprintf (buff, sizeof(buff), "%.18g", (VAL)); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_GUID(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ guid_to_string_buff ((VAL), buff); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_DATE(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ gnc_timespec_to_iso8601_buff ((VAL), buff); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_NUMERIC(TOK,VAL) { \
+ xmlNodePtr node; \
+ char *str; \
+ str = gnc_numeric_to_string (VAL); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ g_free (str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_BOOL(TOK,VAL) { \
+ xmlNodePtr node; \
+ gboolean boll = (VAL); \
+ node = xmlNewNode (NULL, TOK); \
+ if (boll) { \
+ xmlNodeAddContent(node, "T"); \
+ } else { \
+ xmlNodeAddContent(node, "F"); \
+ } \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_HOW(TOK,VAL,A,B,C,D,E,F) { \
+ xmlNodePtr node; \
+ const char * str = "EQUAL"; \
+ switch (VAL) \
+ { \
+ case QOF_COMPARE_##A: str = #A; break; \
+ case QOF_COMPARE_##B: str = #B; break; \
+ case QOF_COMPARE_##C: str = #C; break; \
+ case QOF_COMPARE_##D: str = #D; break; \
+ case QOF_COMPARE_##E: str = #E; break; \
+ case QOF_COMPARE_##F: str = #F; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_MATCH2(TOK,VAL,PFX,A,B) { \
+ xmlNodePtr node; \
+ const char * str = #A; \
+ switch (VAL) \
+ { \
+ case QOF_##PFX##_##A: str = #A; break; \
+ case QOF_##PFX##_##B: str = #B; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_MATCH3(TOK,VAL,PFX,A,B,C) { \
+ xmlNodePtr node; \
+ const char * str = #A; \
+ switch (VAL) \
+ { \
+ case QOF_##PFX##_##A: str = #A; break; \
+ case QOF_##PFX##_##B: str = #B; break; \
+ case QOF_##PFX##_##C: str = #C; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_MATCH5(TOK,VAL,PFX,A,B,C,D,E) { \
+ xmlNodePtr node; \
+ const char * str = #A; \
+ switch (VAL) \
+ { \
+ case QOF_##PFX##_##A: str = #A; break; \
+ case QOF_##PFX##_##B: str = #B; break; \
+ case QOF_##PFX##_##C: str = #C; break; \
+ case QOF_##PFX##_##D: str = #D; break; \
+ case QOF_##PFX##_##E: str = #E; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+/* ======================================================= */
+
+static void
+qof_kvp_value_to_xml (KvpValue *kval, xmlNodePtr topnode)
+{
+ KvpValueType kvt = kvp_value_get_type (kval);
+
+ switch (kvt)
+ {
+ case KVP_TYPE_GINT64:
+ PUT_INT64 ("qofquery:int64", kvp_value_get_gint64(kval));
+ break;
+ case KVP_TYPE_DOUBLE:
+ PUT_DBL ("qofquery:double", kvp_value_get_double(kval));
+ break;
+ case KVP_TYPE_NUMERIC:
+ PUT_NUMERIC ("qofquery:numeric", kvp_value_get_numeric(kval));
+ break;
+ case KVP_TYPE_GUID:
+ PUT_GUID ("qofquery:guid", kvp_value_get_guid(kval));
+ break;
+ case KVP_TYPE_STRING:
+ PUT_STR ("qofquery:string", kvp_value_get_string(kval));
+ break;
+ case KVP_TYPE_TIMESPEC:
+ PUT_DATE ("qofquery:date", kvp_value_get_timespec(kval));
+ break;
+ case KVP_TYPE_BINARY:
+ case KVP_TYPE_GLIST:
+ case KVP_TYPE_FRAME:
+ // XXX don't know how to support these.
+ break;
+ }
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_pred_data_to_xml (QofQueryPredData *pd)
+{
+
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-guid");
+ /* GUID Predicate doesn't do a PUT_HOW */
+
+ GList *n;
+ query_guid_t pdata = (query_guid_t) pd;
+ PUT_MATCH5("qofquery:guid-match", pdata->options,
+ GUID_MATCH, ANY, ALL, NONE, NULL, LIST_ANY);
+
+ for (n = pdata->guids; n; n = n->next)
+ {
+ PUT_GUID ("qofquery:guid", n->data);
+ }
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-string");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_string_t pdata = (query_string_t) pd;
+ PUT_MATCH2("qofquery:string-match", pdata->options,
+ STRING_MATCH, NORMAL, CASEINSENSITIVE);
+ PUT_BOOL ("qofquery:is-regex", pdata->is_regex);
+ PUT_STR ("qofquery:string", pdata->matchstring);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_numeric_t pdata = (query_numeric_t) pd;
+ PUT_MATCH3("qofquery:numeric-match", pdata->options,
+ NUMERIC_MATCH, DEBIT, CREDIT, ANY);
+
+ PUT_NUMERIC ("qofquery:numeric", pdata->amount);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_kvp_t pdata = (query_kvp_t) pd;
+
+ GSList *n;
+ for (n=pdata->path; n; n=n->next)
+ {
+ PUT_STR ("qofquery:kvp-path", n->data);
+ }
+ qof_kvp_value_to_xml (pdata->value, topnode);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-date");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_date_t pdata = (query_date_t) pd;
+
+ PUT_MATCH2("qofquery:date-match", pdata->options,
+ DATE_MATCH, NORMAL, ROUNDED);
+
+ PUT_DATE ("qofquery:date", pdata->date);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-int64");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_int64_t pdata = (query_int64_t) pd;
+ PUT_INT64 ("qofquery:int64", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-int32");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_int32_t pdata = (query_int32_t) pd;
+
+ PUT_INT32 ("qofquery:int32", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-double");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_double_t pdata = (query_double_t) pd;
+
+ PUT_DBL ("qofquery:double", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_boolean_t pdata = (query_boolean_t) pd;
+
+ PUT_BOOL ("qofquery:boolean", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-char");
+ /* There is no PUT_HOW for char-match */
+ query_char_t pdata = (query_char_t) pd;
+
+ PUT_MATCH2("qofquery:char-match", pdata->options,
+ CHAR_MATCH, ANY, NONE);
+
+ PUT_STR ("qofquery:char-list", pdata->char_list);
+ return topnode;
+ }
+ return NULL;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_param_path_to_xml (GSList *param_path)
+{
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:param-path");
+ GSList *n = param_path;
+ for ( ; n; n=n->next)
+ {
+ QofIdTypeConst path = n->data;
+ if (!path) continue;
+ PUT_STR ("qofquery:param", path);
+ }
+ return topnode;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_one_term_to_xml (QofQueryTerm *qt)
+{
+ xmlNodePtr node;
+ xmlNodePtr term = xmlNewNode (NULL, "qofquery:term");
+
+ gboolean invert = qof_query_term_is_inverted (qt);
+ GSList *path = qof_query_term_get_param_path (qt);
+ QofQueryPredData *pd = qof_query_term_get_pred_data (qt);
+
+ xmlNodePtr topnode = term;
+ if (invert)
+ {
+ /* inverter becomes new top mode */
+ topnode = xmlNewNode (NULL, "qofquery:invert");
+ xmlAddChild (term, topnode);
+ }
+
+ node = qof_query_param_path_to_xml (path);
+ if (node) xmlAddChild (topnode, node);
+
+ node = qof_query_pred_data_to_xml (pd);
+ if (node) xmlAddChild (topnode, node);
+
+ return term;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_and_terms_to_xml (GList *and_terms)
+{
+ xmlNodePtr terms = xmlNewNode (NULL, "qofquery:and-terms");
+ GList *n = and_terms;
+ for ( ; n; n=n->next)
+ {
+ QofQueryTerm *qt = n->data;
+ if (!qt) continue;
+
+ xmlNodePtr t = qof_query_one_term_to_xml (n->data);
+ if (t) xmlAddChild (terms, t);
+ }
+ return terms;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_terms_to_xml (QofQuery *q)
+{
+ xmlNodePtr terms = NULL;
+ GList *n = qof_query_get_terms (q);
+
+ if (!n) return NULL;
+ terms = xmlNewNode (NULL, "qofquery:or-terms");
+
+ for ( ; n; n=n->next)
+ {
+ xmlNodePtr andt = qof_query_and_terms_to_xml (n->data);
+ if (andt) xmlAddChild (terms, andt);
+ }
+ return terms;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_sorts_to_xml (QofQuery *q)
+{
+ QofQuerySort *s[3];
+ qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
+
+ if (NULL == s[0]) return NULL;
+
+ xmlNodePtr sortlist = xmlNewNode (NULL, "qofquery:sort-list");
+ int i;
+ for (i=0; i<3; i++)
+ {
+ if (NULL == s[i]) continue;
+
+ GSList *plist = qof_query_sort_get_param_path (s[i]);
+ if (!plist) continue;
+
+ xmlNodePtr sort = xmlNewNode (NULL, "qofquery:sort");
+ xmlAddChild (sortlist, sort);
+
+ xmlNodePtr topnode = sort;
+
+ gboolean increasing = qof_query_sort_get_increasing (s[i]);
+ PUT_STR ("qofquery:order", increasing ? "DESCENDING" : "ASCENDING");
+
+ gint opt = qof_query_sort_get_sort_options (s[i]);
+ PUT_INT32 ("qofquery:options", opt);
+
+ xmlNodePtr pl = qof_query_param_path_to_xml (plist);
+ if (pl) xmlAddChild (sort, pl);
+ }
+
+ return sortlist;
+}
+
+/* ======================================================= */
+
+static void
+do_qof_query_to_xml (QofQuery *q, xmlNodePtr topnode)
+{
+ QofIdType search_for = qof_query_get_search_for (q);
+ PUT_STR ("qofquery:search-for", search_for);
+
+ xmlNodePtr terms = qof_query_terms_to_xml(q);
+ if (terms) xmlAddChild (topnode, terms);
+
+ xmlNodePtr sorts = qof_query_sorts_to_xml (q);
+ if (sorts) xmlAddChild (topnode, sorts);
+
+ gint max_results = qof_query_get_max_results (q);
+ PUT_INT32 ("qofquery:max-results", max_results);
+}
+
+/* ======================================================= */
+
+xmlNodePtr
+qof_query_to_xml (QofQuery *q)
+{
+ xmlNodePtr topnode;
+ xmlNodePtr node;
+ xmlNsPtr ns;
+
+ topnode = xmlNewNode(NULL, "qof:qofquery");
+ xmlSetProp(topnode, "version", "1.0.1");
+
+ // XXX path to DTD is wrong
+ // ns = xmlNewNs (topnode, "file:" "/usr/share/lib" "/qofquery.dtd", "qof");
+
+ do_qof_query_to_xml (q, topnode);
+
+ return topnode;
+}
+
+/* =============================================================== */
+
+#ifdef UNIT_TEST
+
+#include <stdio.h>
+#include <qof/qofsql.h>
+
+int main (int argc, char * argv[])
+{
+ QofQuery *q;
+ QofSqlQuery *sq;
+
+ qof_query_init();
+ qof_object_initialize ();
+
+ static QofParam params[] = {
+ { "adate", QOF_TYPE_DATE, NULL, NULL},
+ { "aint", QOF_TYPE_INT32, NULL, NULL},
+ { "aint64", QOF_TYPE_INT64, NULL, NULL},
+ { "astr", QOF_TYPE_STRING, NULL, NULL},
+ { NULL },
+ };
+
+ qof_class_register ("GncABC", NULL, params);
+ sq = qof_sql_query_new();
+
+ qof_sql_query_parse (sq,
+ "SELECT * from GncABC WHERE aint = 123 "
+ "or not astr=\'asdf\' "
+ "and aint64 = 9876123456789;");
+ // qof_sql_query_parse (sq, "SELECT * from GncABC;");
+ q = qof_sql_query_get_query (sq);
+
+ qof_query_print (q);
+
+ xmlDocPtr doc = doc = xmlNewDoc("1.0");
+ xmlNodePtr topnode = qof_query_to_xml (q);
+ xmlDocSetRootElement(doc,topnode);
+
+ xmlChar *xbuf;
+ int bufsz;
+ xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
+
+ printf ("%s\n", xbuf);
+ xmlFree (xbuf);
+ xmlFreeDoc(doc);
+
+#if 0
+printf ("duude\n");
+ // xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
+ xmlOutputBufferPtr xbuf = xmlOutputBufferCreateFile (stdout, NULL);
+printf ("duude\n");
+
+ xbuf = xmlOutputBufferCreateFd (1, NULL);
+printf ("duude\n");
+ xmlNodeDumpOutput (xbuf, NULL, topnode, 99, 99, "iso-8859-1");
+ // xmlElemDump (stdout, NULL, topnode);
+#endif
+
+ return 0;
+}
+
+#endif /* UNIT_TEST */
+
+/* ======================== END OF FILE =================== */
Index: gnc-date.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-date.c,v
retrieving revision 1.6.2.2
retrieving revision 1.6.2.3
diff -Lsrc/engine/gnc-date.c -Lsrc/engine/gnc-date.c -u -r1.6.2.2 -r1.6.2.3
--- src/engine/gnc-date.c
+++ src/engine/gnc-date.c
@@ -962,8 +962,8 @@
/* hack alert -- this routine returns incorrect values for
* dates before 1970 */
-static Timespec
-gnc_iso8601_to_timespec(const char *str, int do_localtime)
+Timespec
+gnc_iso8601_to_timespec_gmt(const char *str)
{
char buf[4];
Timespec ts;
@@ -987,7 +987,7 @@
str = strchr (str, ':'); if (str) { str++; } else { return ts; }
stm.tm_sec = atoi (str);
- /* the decimal point, optionally present ... */
+ /* The decimal point, optionally present ... */
/* hack alert -- this algo breaks if more than 9 decimal places present */
if (strchr (str, '.'))
{
@@ -999,7 +999,7 @@
}
stm.tm_isdst = -1;
- /* timezone format can be +hh or +hhmm or +hh.mm (or -) (or not present) */
+ /* Timezone format can be +hh or +hhmm or +hh.mm (or -) (or not present) */
str += strcspn (str, "+-");
if (str)
{
@@ -1024,8 +1024,12 @@
}
}
- /* adjust for the local timezone */
- if (do_localtime)
+ /* Note that mktime returns 'local seconds' which is the true time
+ * minus the timezone offset. We don't want to work with local
+ * seconds, since they swim around acording to daylight savings, etc.
+ * We want to work with universal time. Thus, add an offset
+ * to undo the damage that mktime causes.
+ */
{
struct tm tmp_tm;
struct tm *tm;
@@ -1054,25 +1058,12 @@
stm.tm_isdst = tmp_tm.tm_isdst;
}
- /* compute number of seconds */
ts.tv_sec = mktime (&stm);
ts.tv_nsec = nsec;
return ts;
}
-Timespec
-gnc_iso8601_to_timespec_local(const char *str)
-{
- return gnc_iso8601_to_timespec(str, 1);
-}
-
-Timespec
-gnc_iso8601_to_timespec_gmt(const char *str)
-{
- return gnc_iso8601_to_timespec(str, 0);
-}
-
/********************************************************************\
\********************************************************************/
@@ -1093,8 +1084,8 @@
if (0>tz_min) { tz_min +=60; tz_hour --; }
if (60<=tz_min) { tz_min -=60; tz_hour ++; }
- /* we also have to print the sign by hand, to work around a bug
- * in the glibc 2.1.3 printf (where %+02d fails to zero-pad)
+ /* We also have to print the sign by hand, to work around a bug
+ * in the glibc 2.1.3 printf (where %+02d fails to zero-pad).
*/
cyn = '-';
if (0>tz_hour) { cyn = '+'; tz_hour = -tz_hour; }
@@ -1111,7 +1102,7 @@
tz_hour,
tz_min);
- /* return pointer to end of string */
+ /* Return pointer to end of string. */
buff += len;
return buff;
}
Index: qofclass.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.h,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -Lsrc/engine/qofclass.h -Lsrc/engine/qofclass.h -u -r1.1 -r1.1.6.1
--- src/engine/qofclass.h
+++ src/engine/qofclass.h
@@ -56,14 +56,24 @@
/** Type of Paramters (String, Date, Numeric, GUID, etc.) */
typedef const char * QofType;
+typedef struct _QofParam QofParam;
+
/** The QofAccessFunc defines an arbitrary function pointer
* for access functions. This is needed because C doesn't have
* templates, so we just cast a lot. Real functions must be of
* the form:
*
- * param_type getter_func (object_type *self);
+ * param_type getter_func (object_type *self);
+ * or
+ * param_type getter_func (object_type *self, QofParam *param);
+ *
+ * The additional argument 'param' allows generic getter functions
+ * to be implemented, because this argument provides for a way to
+ * identify the expected getter_func return type at runtime. It
+ * also provides a place for the user to hang additional user-defined
+ * data.
*/
-typedef gpointer (*QofAccessFunc)(gpointer);
+typedef gpointer (*QofAccessFunc)(gpointer object, const QofParam *param);
/** The QofSetterFunc defines an function pointer for parameter
* setters. Real functions must be of the form:
@@ -79,16 +89,24 @@
* object (QofIdType) or it can be a core data type (QofType).
* -- param_getfcn is the function to actually obtain the parameter
* -- param_setfcn is the function to actually set the parameter
+ * -- param_userdata is a place where the user can place any desiered
+ * user-defined data (and thus can be used by the user-defined
+ * setter/getter).
*
* Either the getter or the setter may be NULL.
+ *
+ * XXX todo/fixme: need to define a destroy callback, so that when
+ * the param memory is freed, the callback can be used to release the
+ * user-defined data.
*/
-typedef struct _QofParam
+struct _QofParam
{
const char * param_name;
QofType param_type;
QofAccessFunc param_getfcn;
QofSetterFunc param_setfcn;
-} QofParam;
+ gpointer param_userdata;
+};
/** This function is the default sort function for a particular object type */
typedef int (*QofSortFunc)(gpointer, gpointer);
@@ -126,6 +144,11 @@
*
* qof_class_register ("myObjectName", myObjectCompare, &myParams);
*/
+
+/** Return true if the the indicated type is registered,
+ * else return FALSE.
+ */
+gboolean qof_class_is_registered (QofIdTypeConst obj_name);
/** Return the core datatype of the specified object's parameter */
QofType qof_class_get_parameter_type (QofIdTypeConst obj_name,
Index: guid.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/guid.h,v
retrieving revision 1.15.6.3
retrieving revision 1.15.6.4
diff -Lsrc/engine/guid.h -Lsrc/engine/guid.h -u -r1.15.6.3 -r1.15.6.4
--- src/engine/guid.h
+++ src/engine/guid.h
@@ -134,6 +134,9 @@
* 'a' through 'f'. The encoding will always be GUID_ENCODING_LENGTH
* characters long.
*
+ * XXX This routine is not thread safe and is deprecated. Please
+ * use the routine guid_to_string_buff() instead.
+ *
* @param guid The guid to print.
*
* @return A pointer to the starting character of the string. The
Index: qofobject.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofobject.c,v
retrieving revision 1.6.4.2
retrieving revision 1.6.4.3
diff -Lsrc/engine/qofobject.c -Lsrc/engine/qofobject.c -u -r1.6.4.2 -r1.6.4.3
--- src/engine/qofobject.c
+++ src/engine/qofobject.c
@@ -135,6 +135,11 @@
ENTER ("type=%s", type_name);
obj = qof_object_lookup (type_name);
+ if (!obj)
+ {
+ PERR ("No object of type %s", type_name);
+ return;
+ }
col = qof_book_get_collection (book, obj->e_type);
PINFO ("lookup obj=%p for type=%s", obj, type_name);
if (!obj) return;
Index: FreqSpec.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/FreqSpec.h,v
retrieving revision 1.10.4.2
retrieving revision 1.10.4.3
diff -Lsrc/engine/FreqSpec.h -Lsrc/engine/FreqSpec.h -u -r1.10.4.2 -r1.10.4.3
--- src/engine/FreqSpec.h
+++ src/engine/FreqSpec.h
@@ -126,6 +126,8 @@
UIFreqType xaccFreqSpecGetUIType( FreqSpec *fs );
+void xaccFreqSpecSetNone( FreqSpec *fs );
+
/**
* Sets the type to once-off, and initialises the
* date it occurs on.
Index: .cvsignore
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/.cvsignore,v
retrieving revision 1.13.4.2
retrieving revision 1.13.4.3
diff -Lsrc/engine/test/.cvsignore -Lsrc/engine/test/.cvsignore -u -r1.13.4.2 -r1.13.4.3
--- src/engine/test/.cvsignore
+++ src/engine/test/.cvsignore
@@ -9,6 +9,7 @@
test-freq-spec
test-guid
test-group-vs-book
+test-link
test-lots
test-object
test-period
Index: test-date.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-date.c,v
retrieving revision 1.1.6.2
retrieving revision 1.1.6.3
diff -Lsrc/engine/test/test-date.c -Lsrc/engine/test/test-date.c -u -r1.1.6.2 -r1.1.6.3
--- src/engine/test/test-date.c
+++ src/engine/test/test-date.c
@@ -1,3 +1,7 @@
+/*
+ * -- fix borken timezone test -- linas May 2004
+ */
+
#include <ctype.h>
#include <glib.h>
#include <time.h>
@@ -21,14 +25,19 @@
gnc_timespec_to_iso8601_buff (ts, str);
- ts_2 = gnc_iso8601_to_timespec_local (str);
+ /* The time, in seconds, everywhere on the planet, is always
+ * the same, and is independent of location. In particular,
+ * the time, in seconds, is identical to the local time in
+ * Greewich (GMT).
+ */
+ ts_2 = gnc_iso8601_to_timespec_gmt (str);
ok = timespec_equal (&ts, &ts_2);
if (!ok || always_print)
{
fprintf (stderr,
- "%lld:%lld -> %s -> %lld:%lld "
+ "\n%lld:%lld -> %s ->\n\t%lld:%lld "
"(diff of %lld secs %lld nsecs)\n",
(long long int) ts.tv_sec,
(long long int) ts.tv_nsec,
@@ -40,65 +49,339 @@
if (!ok)
{
- failure ("timespecs don't match");
+ failure ("timespec to iso8601 string conversion failed");
return FALSE;
}
}
- success ("timespecs match");
+ success ("timespec to iso8601 string conversion passes");
return TRUE;
}
+static gboolean
+check_conversion (const char * str, Timespec expected_ts)
+{
+ Timespec ts;
+
+ ts = gnc_iso8601_to_timespec_gmt (str);
+
+ if ((expected_ts.tv_sec != ts.tv_sec) || (expected_ts.tv_nsec != ts.tv_nsec))
+ {
+ fprintf (stderr,
+ "\nmis-converted \"%s\" to %lld.%09ld seconds\n"
+ "\twas expecting %lld.%09ld seconds\n",
+ str, ts.tv_sec, ts.tv_nsec,
+ expected_ts.tv_sec, expected_ts.tv_nsec);
+ failure ("misconverted timespec");
+ return FALSE;
+ }
+ success ("good conversion");
+ return TRUE;
+}
+
static void
run_test (void)
{
Timespec ts;
int i;
+ gboolean do_print = FALSE;
+
+ /* All of the following strings are equivalent
+ * representations of zero seconds. Note, zero seconds
+ * is the same world-wide, independent of timezone.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ check_conversion ("1969-12-31 15:00:00.000000 -0900", ts);
+ check_conversion ("1969-12-31 16:00:00.000000 -0800", ts);
+ check_conversion ("1969-12-31 17:00:00.000000 -0700", ts);
+ check_conversion ("1969-12-31 18:00:00.000000 -0600", ts);
+ check_conversion ("1969-12-31 19:00:00.000000 -0500", ts);
+ check_conversion ("1969-12-31 20:00:00.000000 -0400", ts);
+ check_conversion ("1969-12-31 21:00:00.000000 -0300", ts);
+ check_conversion ("1969-12-31 22:00:00.000000 -0200", ts);
+ check_conversion ("1969-12-31 23:00:00.000000 -0100", ts);
+
+ check_conversion ("1970-01-01 00:00:00.000000 -0000", ts);
+ check_conversion ("1970-01-01 00:00:00.000000 +0000", ts);
+
+ check_conversion ("1970-01-01 01:00:00.000000 +0100", ts);
+ check_conversion ("1970-01-01 02:00:00.000000 +0200", ts);
+ check_conversion ("1970-01-01 03:00:00.000000 +0300", ts);
+ check_conversion ("1970-01-01 04:00:00.000000 +0400", ts);
+ check_conversion ("1970-01-01 05:00:00.000000 +0500", ts);
+ check_conversion ("1970-01-01 06:00:00.000000 +0600", ts);
+ check_conversion ("1970-01-01 07:00:00.000000 +0700", ts);
+ check_conversion ("1970-01-01 08:00:00.000000 +0800", ts);
+
+ /* check minute-offsets as well */
+ check_conversion ("1970-01-01 08:01:00.000000 +0801", ts);
+ check_conversion ("1970-01-01 08:02:00.000000 +0802", ts);
+ check_conversion ("1970-01-01 08:03:00.000000 +0803", ts);
+ check_conversion ("1970-01-01 08:23:00.000000 +0823", ts);
+ check_conversion ("1970-01-01 08:35:00.000000 +0835", ts);
+ check_conversion ("1970-01-01 08:47:00.000000 +0847", ts);
+ check_conversion ("1970-01-01 08:59:00.000000 +0859", ts);
+
+ check_conversion ("1969-12-31 15:01:00.000000 -0859", ts);
+ check_conversion ("1969-12-31 15:02:00.000000 -0858", ts);
+ check_conversion ("1969-12-31 15:03:00.000000 -0857", ts);
+ check_conversion ("1969-12-31 15:23:00.000000 -0837", ts);
+ check_conversion ("1969-12-31 15:45:00.000000 -0815", ts);
+
+ /* Now leaving the 60's:
+ *
+ * Black Panthers
+ * Weather Underground
+ * Kent State
+ * Evacuation of Vietnam
+ * Impeachment
+ * Gas Crisis
+ * New York Garbage Crisis
+ * Stagflation
+ * Delapidated Bicentennial
+ * Sex Pistols
+ * Punk Rock
+ *
+ * Of course, anything had to be better than the miserable 70's,
+ * which explains why Reagan was elected. Food for thought.
+ */
+ ts.tv_sec = 10*365*24*3600 + 2*24*3600;
+ ts.tv_nsec = 0;
+ check_conversion ("1979-12-31 15:00:00.000000 -0900", ts);
+ check_conversion ("1979-12-31 16:00:00.000000 -0800", ts);
+ check_conversion ("1979-12-31 17:00:00.000000 -0700", ts);
+ check_conversion ("1979-12-31 18:00:00.000000 -0600", ts);
+ check_conversion ("1979-12-31 19:00:00.000000 -0500", ts);
+ check_conversion ("1979-12-31 20:00:00.000000 -0400", ts);
+ check_conversion ("1979-12-31 21:00:00.000000 -0300", ts);
+ check_conversion ("1979-12-31 22:00:00.000000 -0200", ts);
+ check_conversion ("1979-12-31 23:00:00.000000 -0100", ts);
+
+ check_conversion ("1980-01-01 00:00:00.000000 -0000", ts);
+ check_conversion ("1980-01-01 00:00:00.000000 +0000", ts);
+
+ check_conversion ("1980-01-01 01:00:00.000000 +0100", ts);
+ check_conversion ("1980-01-01 02:00:00.000000 +0200", ts);
+ check_conversion ("1980-01-01 03:00:00.000000 +0300", ts);
+ check_conversion ("1980-01-01 04:00:00.000000 +0400", ts);
+ check_conversion ("1980-01-01 05:00:00.000000 +0500", ts);
+ check_conversion ("1980-01-01 06:00:00.000000 +0600", ts);
+ check_conversion ("1980-01-01 07:00:00.000000 +0700", ts);
+ check_conversion ("1980-01-01 08:00:00.000000 +0800", ts);
+
+ /* check minute-offsets as well */
+ check_conversion ("1980-01-01 08:01:00.000000 +0801", ts);
+ check_conversion ("1980-01-01 08:02:00.000000 +0802", ts);
+ check_conversion ("1980-01-01 08:03:00.000000 +0803", ts);
+ check_conversion ("1980-01-01 08:23:00.000000 +0823", ts);
+ check_conversion ("1980-01-01 08:35:00.000000 +0835", ts);
+ check_conversion ("1980-01-01 08:47:00.000000 +0847", ts);
+ check_conversion ("1980-01-01 08:59:00.000000 +0859", ts);
+
+ check_conversion ("1979-12-31 15:01:00.000000 -0859", ts);
+ check_conversion ("1979-12-31 15:02:00.000000 -0858", ts);
+ check_conversion ("1979-12-31 15:03:00.000000 -0857", ts);
+ check_conversion ("1979-12-31 15:23:00.000000 -0837", ts);
+ check_conversion ("1979-12-31 15:45:00.000000 -0815", ts);
+
+
+ /* The 90's */
+ ts.tv_sec = 20*365*24*3600 + 5*24*3600;
+ ts.tv_nsec = 0;
+ check_conversion ("1989-12-31 15:00:00.000000 -0900", ts);
+ check_conversion ("1989-12-31 16:00:00.000000 -0800", ts);
+ check_conversion ("1989-12-31 17:00:00.000000 -0700", ts);
+ check_conversion ("1989-12-31 18:00:00.000000 -0600", ts);
+ check_conversion ("1989-12-31 19:00:00.000000 -0500", ts);
+ check_conversion ("1989-12-31 20:00:00.000000 -0400", ts);
+ check_conversion ("1989-12-31 21:00:00.000000 -0300", ts);
+ check_conversion ("1989-12-31 22:00:00.000000 -0200", ts);
+ check_conversion ("1989-12-31 23:00:00.000000 -0100", ts);
+
+ check_conversion ("1990-01-01 00:00:00.000000 -0000", ts);
+ check_conversion ("1990-01-01 00:00:00.000000 +0000", ts);
+
+ check_conversion ("1990-01-01 01:00:00.000000 +0100", ts);
+ check_conversion ("1990-01-01 02:00:00.000000 +0200", ts);
+ check_conversion ("1990-01-01 03:00:00.000000 +0300", ts);
+ check_conversion ("1990-01-01 04:00:00.000000 +0400", ts);
+ check_conversion ("1990-01-01 05:00:00.000000 +0500", ts);
+ check_conversion ("1990-01-01 06:00:00.000000 +0600", ts);
+ check_conversion ("1990-01-01 07:00:00.000000 +0700", ts);
+ check_conversion ("1990-01-01 08:00:00.000000 +0800", ts);
+
+ /* check minute-offsets as well */
+ check_conversion ("1990-01-01 08:01:00.000000 +0801", ts);
+ check_conversion ("1990-01-01 08:02:00.000000 +0802", ts);
+ check_conversion ("1990-01-01 08:03:00.000000 +0803", ts);
+ check_conversion ("1990-01-01 08:23:00.000000 +0823", ts);
+ check_conversion ("1990-01-01 08:35:00.000000 +0835", ts);
+ check_conversion ("1990-01-01 08:47:00.000000 +0847", ts);
+ check_conversion ("1990-01-01 08:59:00.000000 +0859", ts);
+
+ check_conversion ("1989-12-31 15:01:00.000000 -0859", ts);
+ check_conversion ("1989-12-31 15:02:00.000000 -0858", ts);
+ check_conversion ("1989-12-31 15:03:00.000000 -0857", ts);
+ check_conversion ("1989-12-31 15:23:00.000000 -0837", ts);
+ check_conversion ("1989-12-31 15:45:00.000000 -0815", ts);
+
+
+ /* The naughties */
+ ts.tv_sec = 30*365*24*3600 + 7*24*3600;
+ ts.tv_nsec = 0;
+ check_conversion ("1999-12-31 15:00:00.000000 -0900", ts);
+ check_conversion ("1999-12-31 16:00:00.000000 -0800", ts);
+ check_conversion ("1999-12-31 17:00:00.000000 -0700", ts);
+ check_conversion ("1999-12-31 18:00:00.000000 -0600", ts);
+ check_conversion ("1999-12-31 19:00:00.000000 -0500", ts);
+ check_conversion ("1999-12-31 20:00:00.000000 -0400", ts);
+ check_conversion ("1999-12-31 21:00:00.000000 -0300", ts);
+ check_conversion ("1999-12-31 22:00:00.000000 -0200", ts);
+ check_conversion ("1999-12-31 23:00:00.000000 -0100", ts);
+
+ check_conversion ("2000-01-01 00:00:00.000000 -0000", ts);
+ check_conversion ("2000-01-01 00:00:00.000000 +0000", ts);
+
+ check_conversion ("2000-01-01 01:00:00.000000 +0100", ts);
+ check_conversion ("2000-01-01 02:00:00.000000 +0200", ts);
+ check_conversion ("2000-01-01 03:00:00.000000 +0300", ts);
+ check_conversion ("2000-01-01 04:00:00.000000 +0400", ts);
+ check_conversion ("2000-01-01 05:00:00.000000 +0500", ts);
+ check_conversion ("2000-01-01 06:00:00.000000 +0600", ts);
+ check_conversion ("2000-01-01 07:00:00.000000 +0700", ts);
+ check_conversion ("2000-01-01 08:00:00.000000 +0800", ts);
+
+ /* check minute-offsets as well */
+ check_conversion ("2000-01-01 08:01:00.000000 +0801", ts);
+ check_conversion ("2000-01-01 08:02:00.000000 +0802", ts);
+ check_conversion ("2000-01-01 08:03:00.000000 +0803", ts);
+ check_conversion ("2000-01-01 08:23:00.000000 +0823", ts);
+ check_conversion ("2000-01-01 08:35:00.000000 +0835", ts);
+ check_conversion ("2000-01-01 08:47:00.000000 +0847", ts);
+ check_conversion ("2000-01-01 08:59:00.000000 +0859", ts);
+
+ check_conversion ("1999-12-31 15:01:00.000000 -0859", ts);
+ check_conversion ("1999-12-31 15:02:00.000000 -0858", ts);
+ check_conversion ("1999-12-31 15:03:00.000000 -0857", ts);
+ check_conversion ("1999-12-31 15:23:00.000000 -0837", ts);
+ check_conversion ("1999-12-31 15:45:00.000000 -0815", ts);
+
+
+ /* The nows */
+ ts.tv_sec = 35*365*24*3600 + 9*24*3600;
+ ts.tv_nsec = 0;
+ check_conversion ("2004-12-31 15:00:00.000000 -0900", ts);
+ check_conversion ("2004-12-31 16:00:00.000000 -0800", ts);
+ check_conversion ("2004-12-31 17:00:00.000000 -0700", ts);
+ check_conversion ("2004-12-31 18:00:00.000000 -0600", ts);
+ check_conversion ("2004-12-31 19:00:00.000000 -0500", ts);
+ check_conversion ("2004-12-31 20:00:00.000000 -0400", ts);
+ check_conversion ("2004-12-31 21:00:00.000000 -0300", ts);
+ check_conversion ("2004-12-31 22:00:00.000000 -0200", ts);
+ check_conversion ("2004-12-31 23:00:00.000000 -0100", ts);
+
+ check_conversion ("2005-01-01 00:00:00.000000 -0000", ts);
+ check_conversion ("2005-01-01 00:00:00.000000 +0000", ts);
+
+ check_conversion ("2005-01-01 01:00:00.000000 +0100", ts);
+ check_conversion ("2005-01-01 02:00:00.000000 +0200", ts);
+ check_conversion ("2005-01-01 03:00:00.000000 +0300", ts);
+ check_conversion ("2005-01-01 04:00:00.000000 +0400", ts);
+ check_conversion ("2005-01-01 05:00:00.000000 +0500", ts);
+ check_conversion ("2005-01-01 06:00:00.000000 +0600", ts);
+ check_conversion ("2005-01-01 07:00:00.000000 +0700", ts);
+ check_conversion ("2005-01-01 08:00:00.000000 +0800", ts);
+
+ /* check minute-offsets as well */
+ check_conversion ("2005-01-01 08:01:00.000000 +0801", ts);
+ check_conversion ("2005-01-01 08:02:00.000000 +0802", ts);
+ check_conversion ("2005-01-01 08:03:00.000000 +0803", ts);
+ check_conversion ("2005-01-01 08:23:00.000000 +0823", ts);
+ check_conversion ("2005-01-01 08:35:00.000000 +0835", ts);
+ check_conversion ("2005-01-01 08:47:00.000000 +0847", ts);
+ check_conversion ("2005-01-01 08:59:00.000000 +0859", ts);
+
+ check_conversion ("2004-12-31 15:01:00.000000 -0859", ts);
+ check_conversion ("2004-12-31 15:02:00.000000 -0858", ts);
+ check_conversion ("2004-12-31 15:03:00.000000 -0857", ts);
+ check_conversion ("2004-12-31 15:23:00.000000 -0837", ts);
+ check_conversion ("2004-12-31 15:45:00.000000 -0815", ts);
+
+
+ /* Various leap-year days and near-leap times. */
+ ts = gnc_iso8601_to_timespec_gmt ("1980-02-29 00:00:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("1979-02-28 00:00:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("1990-02-28 00:00:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("2000-02-29 00:00:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("2004-02-29 00:00:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("2008-02-29 00:00:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("2008-02-29 00:01:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("2008-02-29 02:02:00.000000 -0000");
+ check_time (ts, do_print);
+
+ ts = gnc_iso8601_to_timespec_gmt ("2008-02-28 23:23:23.000000 -0000");
+ check_time (ts, do_print);
+ /* Various 'special' times. What makes these so special? */
ts.tv_sec = 152098136;
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1162088421;
ts.tv_nsec = 12548000;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 325659000 - 6500;
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1143943200;
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1603591171;
ts.tv_nsec = 595311000;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1738909365;
ts.tv_nsec = 204102000;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1603591171;
ts.tv_nsec = 595311000;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1143943200 - 1;
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1143943200;
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1143943200 + (7 * 60 * 60);
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts.tv_sec = 1143943200 + (8 * 60 * 60);
ts.tv_nsec = 0;
- check_time (ts, FALSE);
+ check_time (ts, do_print);
ts = *get_random_timespec ();
Index: gnc-ledger-display.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/ledger-core/gnc-ledger-display.c,v
retrieving revision 1.24.4.2
retrieving revision 1.24.4.3
diff -Lsrc/register/ledger-core/gnc-ledger-display.c -Lsrc/register/ledger-core/gnc-ledger-display.c -u -r1.24.4.2 -r1.24.4.3
--- src/register/ledger-core/gnc-ledger-display.c
+++ src/register/ledger-core/gnc-ledger-display.c
@@ -488,7 +488,7 @@
}
ld = gnc_ledger_display_internal (NULL, q, LD_GL,
- GENERAL_LEDGER,
+ SEARCH_LEDGER,
REG_STYLE_JOURNAL,
FALSE, TRUE); /* TRUE : template mode */
Index: dialog-sx-from-trans.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/dialog-sx-from-trans.c,v
retrieving revision 1.26.4.1
retrieving revision 1.26.4.2
diff -Lsrc/gnome/dialog-sx-from-trans.c -Lsrc/gnome/dialog-sx-from-trans.c -u -r1.26.4.1 -r1.26.4.2
--- src/gnome/dialog-sx-from-trans.c
+++ src/gnome/dialog-sx-from-trans.c
@@ -38,6 +38,7 @@
#include "gnc-book.h"
#include "gnc-date-edit.h"
#include "gnc-engine-util.h"
+#include "gnc-ui.h"
#include "gnc-ui-util.h"
#include "gnc-dense-cal.h"
@@ -60,6 +61,9 @@
#define SX_OPT_STR "Scheduled Transactions"
+#define SXFTD_ERRNO_UNBALANCED_XACTION 3
+#define SXFTD_ERRNO_OPEN_XACTION -3
+
#define SXFTD_EXCAL_NUM_MONTHS 4
#define SXFTD_EXCAL_MONTHS_PER_COL 4
@@ -212,14 +216,17 @@
{
Transaction *tr = sxfti->trans;
- GList *tt_list= NULL;
+ GList *tt_list = NULL;
GList *splits, *template_splits = NULL;
TTInfo *tti = gnc_ttinfo_malloc();
TTSplitInfo *ttsi;
Split *sp;
+ gnc_numeric runningBalance;
gnc_numeric split_value;
const char *tmpStr;
+ runningBalance = gnc_numeric_zero();
+
gnc_ttinfo_set_description(tti, xaccTransGetDescription(tr));
gnc_ttinfo_set_num(tti, xaccTransGetNum(tr));
gnc_ttinfo_set_currency(tti, xaccTransGetCurrency(tr));
@@ -232,6 +239,9 @@
split_value = xaccSplitGetValue(sp);
gnc_ttsplitinfo_set_memo(ttsi, xaccSplitGetMemo(sp));
+ runningBalance = gnc_numeric_add( runningBalance, split_value,
+ 100, (GNC_DENOM_AUTO | GNC_DENOM_LCD) );
+
if(gnc_numeric_positive_p(split_value))
{
tmpStr = xaccPrintAmount( split_value,
@@ -252,6 +262,17 @@
template_splits = g_list_append(template_splits, ttsi);
}
+ if ( ! gnc_numeric_zero_p( runningBalance )
+ && !gnc_verify_dialog( (gncUIWidget)sxfti->dialog,
+ FALSE, "%s",
+ _("The Scheduled Transaction Editor "
+ "cannot automatically\nbalance "
+ "this transaction. "
+ "Should it still be "
+ "entered?") ) ) {
+ return SXFTD_ERRNO_UNBALANCED_XACTION;
+ }
+
gnc_ttinfo_set_template_splits(tti, template_splits);
tt_list = g_list_append(tt_list, tti);
@@ -338,7 +359,10 @@
if ( ! sxfti->trans ) {
return -2;
}
-
+ if ( xaccTransIsOpen( sxfti->trans ) ) {
+ return SXFTD_ERRNO_OPEN_XACTION;
+ }
+
sxfti_attach_callbacks(sxfti);
/* Setup the example calendar and related data structures. */
@@ -512,7 +536,10 @@
xaccSchedXactionSetAdvanceReminder( sx, daysInAdvance );
}
- sxftd_add_template_trans( sxfti );
+ if ( sxftd_add_template_trans( sxfti ) != 0 )
+ {
+ sxftd_errno = SXFTD_ERRNO_UNBALANCED_XACTION;
+ }
return sxftd_errno;
}
@@ -540,13 +567,20 @@
GList *sx_list;
guint sx_error = sxftd_compute_sx(sxfti);
- if (sx_error != 0)
+ if (sx_error != 0
+ && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION)
{
PERR( "Error in sxftd_compute_sx after ok_clicked [%d]", sx_error );
}
else
{
SchedXactionDialog *sxd;
+
+ if ( sx_error == SXFTD_ERRNO_UNBALANCED_XACTION ) {
+ gnc_error_dialog( gnc_ui_get_toplevel(),
+ _( "The Scheduled Transaction is unbalanced.\n"
+ "You are strongly encouraged to correct this situation." ) );
+ }
book = gnc_get_current_book ();
sx_list = gnc_book_get_schedxactions(book);
sx_list = g_list_append(sx_list, sxfti->sx);
@@ -609,10 +643,13 @@
SchedXactionDialog *adv_dlg;
SchedXactionEditorDialog *adv_edit_dlg;
- if (sx_error != 0)
+ if ( sx_error != 0
+ && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION )
{
- PWARN( "something bad happened in sxftd_compute_sx [%d]", sx_error );
- return;
+ // unbalanced-xaction is "okay", since this is also checked for by
+ // the advanced editor.
+ PWARN( "something bad happened in sxftd_compute_sx [%d]", sx_error );
+ return;
}
gtk_widget_hide( sxfti->dialog );
/* force a gui update. */
@@ -645,7 +682,20 @@
sxfti->sx = xaccSchedXactionMalloc(gnc_get_current_book ());
if ( (errno = sxftd_init( sxfti )) < 0 ) {
- PERR( "Error in sxftd_init: %d", errno );
+ if ( errno == SXFTD_ERRNO_OPEN_XACTION )
+ {
+ gnc_error_dialog( gnc_ui_get_toplevel(),
+ _( "Cannot create a Scheduled Transaction "
+ "from a Transaction currently\n"
+ "being edited. Please Enter the "
+ "Transaction before Scheduling." ) );
+ sxftd_close( sxfti, TRUE );
+ return;
+ }
+ else
+ {
+ PERR( "Error in sxftd_init: %d", errno );
+ }
}
gtk_widget_show_all(sxfti->dialog);
Index: druid-loan.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/druid-loan.c,v
retrieving revision 1.17.4.4
retrieving revision 1.17.4.5
diff -Lsrc/gnome/druid-loan.c -Lsrc/gnome/druid-loan.c -u -r1.17.4.4 -r1.17.4.5
--- src/gnome/druid-loan.c
+++ src/gnome/druid-loan.c
@@ -419,6 +419,39 @@
/* non-gladeable widget setup */
{
+ int i;
+ // LIABILITY
+ GList *liabilityAcct;
+ // BANK, CASH, CREDIT, ASSET + LIABILITY
+ GList *paymentFromAccts;
+ // EXPENSE, LIABILITY, + payment-froms.
+ GList *paymentToAccts;
+ int fromLen = 5;
+ GNCAccountType paymentFroms[] = { BANK, CASH, CREDIT, ASSET, LIABILITY };
+ int toLen = 2;
+ GNCAccountType paymentTos[] = { EXPENSE };
+
+ liabilityAcct = NULL;
+ paymentFromAccts = NULL;
+ paymentToAccts = NULL;
+
+ liabilityAcct = g_list_append( liabilityAcct,
+ GINT_TO_POINTER( LIABILITY ) );
+ for ( i = 0; i < fromLen; i++ )
+ {
+ paymentFromAccts
+ = g_list_append( paymentFromAccts,
+ GINT_TO_POINTER( paymentFroms[i] ) );
+ paymentToAccts
+ = g_list_append( paymentToAccts,
+ GINT_TO_POINTER( paymentFroms[i] ) );
+ }
+
+ for ( i = 0; i < toLen; i++ )
+ {
+ paymentToAccts = g_list_append( paymentToAccts,
+ GINT_TO_POINTER( paymentTos[i] ) );
+ }
/* All of the GncAccountSel[ectors]... */
{
@@ -430,16 +463,17 @@
GtkTable *table;
gboolean newAcctAbility;
int left, right, top, bottom;
+ GList *allowableAccounts;
} gas_data[] = {
/* These ints are the GtkTable boundries */
- { &ldd->prmAccountGAS, ldd->prmTable, TRUE, 1, 4, 0, 1 },
- { &ldd->repAssetsFromGAS, ldd->repTable, TRUE, 1, 4, 2, 3 },
- { &ldd->repPrincToGAS, ldd->repTable, TRUE, 1, 2, 3, 4 },
- { &ldd->repIntToGAS, ldd->repTable, TRUE, 3, 4, 3, 4 },
- { &ldd->payAcctFromGAS, ldd->payTable, TRUE, 1, 2, 4, 5 },
- { &ldd->payAcctEscToGAS, ldd->payTable, FALSE, 3, 4, 4, 5 },
- { &ldd->payAcctEscFromGAS, ldd->payTable, FALSE, 1, 2, 5, 6 },
- { &ldd->payAcctToGAS, ldd->payTable, TRUE, 3, 4, 5, 6 },
+ { &ldd->prmAccountGAS, ldd->prmTable, TRUE, 1, 4, 0, 1, liabilityAcct },
+ { &ldd->repAssetsFromGAS, ldd->repTable, TRUE, 1, 4, 2, 3, paymentFromAccts },
+ { &ldd->repPrincToGAS, ldd->repTable, TRUE, 1, 2, 3, 4, paymentToAccts },
+ { &ldd->repIntToGAS, ldd->repTable, TRUE, 3, 4, 3, 4, paymentToAccts },
+ { &ldd->payAcctFromGAS, ldd->payTable, TRUE, 1, 2, 4, 5, paymentFromAccts },
+ { &ldd->payAcctEscToGAS, ldd->payTable, FALSE, 3, 4, 4, 5, paymentToAccts },
+ { &ldd->payAcctEscFromGAS, ldd->payTable, FALSE, 1, 2, 5, 6, paymentFromAccts },
+ { &ldd->payAcctToGAS, ldd->payTable, TRUE, 3, 4, 5, 6, paymentToAccts },
{ NULL }
};
@@ -459,6 +493,10 @@
gas = GNC_ACCOUNT_SEL(gnc_account_sel_new());
gnc_account_sel_set_new_account_ability(
gas, gas_data[i].newAcctAbility );
+ if ( gas_data[i].allowableAccounts != NULL ) {
+ gnc_account_sel_set_acct_filters(
+ gas, gas_data[i].allowableAccounts );
+ }
gtk_container_add( GTK_CONTAINER(a),
GTK_WIDGET(gas) );
gtk_table_attach( gas_data[i].table,
@@ -2515,11 +2553,18 @@
void
ld_get_loan_range( LoanDruidData *ldd, GDate *start, GDate *end )
{
+ int monthsTotal;
+ struct tm *endDateMath;
+
*start = *ldd->ld.startDate;
- *end = *start;
- g_date_add_months( end,
- ldd->ld.numPer - 1
- * ( ldd->ld.perSize == MONTHS ? 1 : 12 ) );
+
+ endDateMath = g_new0( struct tm, 1 );
+ g_date_to_struct_tm( ldd->ld.startDate, endDateMath );
+ monthsTotal = ( (ldd->ld.numPer - 1)
+ * ( ldd->ld.perSize == MONTHS ? 1 : 12 ) );
+ endDateMath->tm_mon += monthsTotal;
+ g_date_set_time( end, mktime( endDateMath ) );
+ g_free( endDateMath );
}
static
@@ -2551,6 +2596,7 @@
PERR( "Unknown review date range option %d", range );
break;
}
+
}
static
Index: dialog-scheduledxaction.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/dialog-scheduledxaction.c,v
retrieving revision 1.71.2.8
retrieving revision 1.71.2.9
diff -Lsrc/gnome/dialog-scheduledxaction.c -Lsrc/gnome/dialog-scheduledxaction.c -u -r1.71.2.8 -r1.71.2.9
--- src/gnome/dialog-scheduledxaction.c
+++ src/gnome/dialog-scheduledxaction.c
@@ -105,6 +105,16 @@
END_OCCUR,
} EndType;
+/* Runtime/dialog information about a particular SX. */
+typedef struct _SxRuntimeInfo
+{
+ SchedXaction *sx;
+ // the gnc-dense-cal mark-tag
+ gint markTag;
+ // which row in the GTK CList this SX is.
+ gint row;
+} SxRuntimeInfo;
+
struct _SchedXactionDialog
{
GtkWidget *dialog;
@@ -216,6 +226,10 @@
static gboolean editor_component_sx_equality( gpointer find_data,
gpointer user_data );
+static SxRuntimeInfo* _new_sx_runtime_info( SchedXaction *sx );
+static void _clear_runtime_info_row( gpointer key, gpointer value, gpointer user_data );
+
+
static void gnc_sxed_cmd_edit_cut (EggAction *action, SchedXactionEditorDialog *sxed);
static void gnc_sxed_cmd_edit_copy (EggAction *action, SchedXactionEditorDialog *sxed);
static void gnc_sxed_cmd_edit_paste (EggAction *action, SchedXactionEditorDialog *sxed);
@@ -253,6 +267,15 @@
gtk_widget_hide( sxd->dialog );
}
+static
+void
+_clear_runtime_info_row( gpointer key, gpointer value, gpointer user_data )
+{
+ SxRuntimeInfo *sxri;
+ sxri = (SxRuntimeInfo*)value;
+ sxri->row = -1;
+}
+
void
gnc_sxd_list_refresh( SchedXactionDialog *sxd )
{
@@ -262,9 +285,13 @@
/* Update the clist. */
cl = GTK_CLIST( glade_xml_get_widget( sxd->gxml, SX_LIST ) );
gtk_clist_freeze( cl );
+
gtk_clist_clear( cl );
+ // Also, flush the row-numbers from storage
+ g_hash_table_foreach( sxd->sxData, _clear_runtime_info_row, NULL );
sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
g_list_foreach( sxList, putSchedXactionInDialog, sxd );
+
gtk_clist_thaw( cl );
}
@@ -369,9 +396,10 @@
sxList = gnc_book_get_schedxactions( book );
sxList = g_list_append( sxList, sxed->sx );
gnc_book_set_schedxactions( book, sxList );
- sxed->sx = NULL;
sxed->newsxP = FALSE;
}
+ // regardless, do this so the close handler won't complain.
+ sxed->sx = NULL;
/* update lists */
/* We now do this by getting the list of SX Lists and updating them
@@ -636,7 +664,7 @@
gboolean
gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
{
- gint ttVarCount;
+ gint ttVarCount, splitCount;
FreqSpec *fs;
/* Do checks on validity and such, interrupting the user if
@@ -659,6 +687,7 @@
*/
ttVarCount = 0;
+ splitCount = 0;
{
static const int NUM_ITERS_WITH_VARS = 5;
static const int NUM_ITERS_NO_VARS = 1;
@@ -714,8 +743,11 @@
(gpointer)vars );
g_hash_table_foreach( txns, set_sums_to_zero, NULL );
tmp = gnc_numeric_zero();
- for ( splitList = xaccSchedXactionGetSplits( sxed->sx );
- splitList; splitList = splitList->next )
+
+ splitList = xaccSchedXactionGetSplits( sxed->sx );
+ splitCount += g_list_length( splitList );
+
+ for ( ; splitList; splitList = splitList->next )
{
txnCreditDebitSums *tcds;
s = (Split*)splitList->data;
@@ -740,9 +772,17 @@
&& (str = kvp_value_get_string(v))
&& strlen( str ) != 0 ) {
if ( parse_vars_from_formula( str, vars, &tmp ) < 0 ) {
- PERR( "Couldn't parse credit formula for "
- "\"%s\" on second pass",
- xaccSchedXactionGetName( sxed->sx ) );
+ GString *errStr;
+
+ errStr = g_string_sized_new( 32 );
+ g_string_sprintf( errStr,
+ _( "Couldn't parse credit formula for "
+ "split \"%s\"." ),
+ xaccSplitGetMemo( s ) );
+ gnc_error_dialog( GTK_WIDGET(sxed->dialog),
+ errStr->str );
+ g_string_free( errStr, TRUE );
+
return FALSE;
}
tcds->creditSum =
@@ -758,9 +798,17 @@
&& (str = kvp_value_get_string(v))
&& strlen(str) != 0 ) {
if ( parse_vars_from_formula( str, vars, &tmp ) < 0 ) {
- PERR( "Couldn't parse debit formula for "
- "\"%s\" on second pass",
- xaccSchedXactionGetName( sxed->sx ) );
+ GString *errStr;
+
+ errStr = g_string_sized_new( 32 );
+ g_string_sprintf( errStr,
+ _( "Couldn't parse debit formula for "
+ "split \"%s\"." ),
+ xaccSplitGetMemo( s ) );
+ gnc_error_dialog( GTK_WIDGET(sxed->dialog),
+ (gchar*)errStr->str );
+ g_string_free( errStr, TRUE );
+
return FALSE;
}
tcds->debitSum = gnc_numeric_add( tcds->debitSum, tmp, 100,
@@ -864,6 +912,15 @@
"cannot be automatically created.") );
return FALSE;
}
+
+ /* Fix for part of Bug#121740 -- auto-create transactions are
+ * only valid if there's actually a transaction to create. */
+ if ( autocreateState && splitCount == 0 ) {
+ gnc_warning_dialog( sxed->dialog,
+ _("Scheduled Transactions without a template\n"
+ "transaction cannot be automatically created.") );
+ return FALSE;
+ }
}
/* deal with time. */
@@ -1035,10 +1092,15 @@
{
FreqSpec *fs;
GDate gdate;
+ GString *str;
fs = xaccSchedXactionGetFreqSpec( sxed->sx );
gnc_frequency_save_state( sxed->gncfreq, fs, &gdate );
+ str = g_string_new( "" );
+ xaccFreqSpecGetFreqStr( fs, str );
+ DEBUG( "fs: %s", str->str );
+
/* now that we have it, set the start date */
xaccSchedXactionSetStartDate( sxed->sx, &gdate );
}
@@ -1084,6 +1146,8 @@
gnc_unregister_gui_component_by_data
(DIALOG_SCHEDXACTION_CM_CLASS, sxd);
+ // FIXME: um. We should free memory and stuff, here.
+
g_free( sxd );
}
@@ -1179,6 +1243,8 @@
gtk_signal_connect( GTK_OBJECT(w), "click-column",
GTK_SIGNAL_FUNC(gnc_sxd_row_click_handler), sxd );
+ // gtk_clist_column_titles_active( GTK_CLIST( w ) );
+
/* Default to sorting by ascending next-instance date. */
sxd->currentSortCol = 2;
sxd->currentSortType = GTK_SORT_ASCENDING;
@@ -1434,6 +1500,10 @@
gtk_widget_set_sensitive( GTK_WIDGET(sxed->remindSpin), FALSE );
gtk_widget_set_sensitive( GTK_WIDGET(sxed->endCountEntry), FALSE );
gtk_widget_set_sensitive( GTK_WIDGET(sxed->endRemainEntry), FALSE );
+
+ gtk_editable_set_editable( GTK_EDITABLE(sxed->advanceSpin), TRUE );
+ gtk_editable_set_editable( GTK_EDITABLE(sxed->remindSpin), TRUE );
+
/* Allow grow, allow shrink, auto-shrink */
gtk_window_set_policy (GTK_WINDOW(sxed->dialog), TRUE, TRUE, FALSE);
@@ -1832,18 +1902,19 @@
book = gnc_get_current_book ();
sxList = gnc_book_get_schedxactions( book );
for ( sel = cl->selection; sel; sel = sel->next ) {
- gint tag;
- gint *p_tag = &tag;
+ SxRuntimeInfo *sxri;
+ SxRuntimeInfo **p_sxri = &sxri;
gpointer unused;
gboolean foundP;
sx = (SchedXaction*)gtk_clist_get_row_data( cl, (int)sel->data );
sxList = g_list_remove( sxList, (gpointer)sx );
foundP = g_hash_table_lookup_extended( sxd->sxData, sx,
- &unused, (gpointer*)p_tag );
+ &unused,
+ (gpointer*)p_sxri );
g_assert( foundP );
- if ( tag != -1 ) {
- gnc_dense_cal_mark_remove( sxd->gdcal, tag );
+ if ( sxri->markTag != -1 ) {
+ gnc_dense_cal_mark_remove( sxd->gdcal, sxri->markTag );
}
g_hash_table_remove( sxd->sxData, sx );
xaccSchedXactionFree( sx );
@@ -1936,6 +2007,19 @@
}
static
+SxRuntimeInfo*
+_new_sx_runtime_info( SchedXaction *sx )
+{
+ SxRuntimeInfo *sxri;
+
+ sxri = g_new0( SxRuntimeInfo, 1 );
+ sxri->sx = sx;
+ sxri->row = -1;
+ sxri->markTag = -1;
+ return sxri;
+}
+
+static
void
putSchedXactionInDialog( gpointer data, gpointer user_data )
{
@@ -1945,14 +2029,17 @@
char *text[3];
GString *freqStr;
GString *nextDate;
- gint row;
int i;
GDate *nextInstDate = NULL, *calEndDate;
int instArraySize;
GDate **instArray;
GList *instList;
- gint gdcMarkTag, oldMarkTag;
- gint *p_oldMarkTag = &oldMarkTag;
+ gpointer unused;
+ SxRuntimeInfo *sxri = NULL;
+ SxRuntimeInfo **p_sxri = &sxri;
+ gboolean foundP;
+ gint gdcMarkTag;
+ gint row;
sx = (SchedXaction*)data;
sxd = (SchedXactionDialog*)user_data;
@@ -2023,38 +2110,47 @@
nextInstDate = NULL;
}
+ foundP = g_hash_table_lookup_extended( sxd->sxData,
+ (gpointer)sx,
+ &unused,
+ (gpointer*)p_sxri );
+ if ( ! foundP )
+ {
+ // new SX -- create runtime storage for it
+ sxri = _new_sx_runtime_info( sx );
+ sxri->markTag = gdcMarkTag;
+ }
+ else
+ {
+ // existing SX; remove it's
+ if ( sxri->markTag != -1 ) {
+ gnc_dense_cal_mark_remove( sxd->gdcal, sxri->markTag );
+ sxri->markTag = gdcMarkTag;
+ }
+ }
+
+
text[0] = xaccSchedXactionGetName( sx );
text[1] = freqStr->str;
text[2] = nextDate->str;
clist = GTK_CLIST( glade_xml_get_widget( sxd->gxml, SX_LIST ) );
gtk_clist_freeze( clist );
- row = gtk_clist_find_row_from_data( clist, sx );
- if ( row != -1 ) {
- gpointer unused;
- gboolean foundP =
- g_hash_table_lookup_extended( sxd->sxData,
- (gpointer)sx,
- &unused,
- (gpointer*)p_oldMarkTag );
- g_assert( foundP );
- }
- if ( row == -1 ) {
+
+ row = gtk_clist_find_row_from_data( clist, (gpointer)sx );
+ if ( sxri->row == -1 ) {
/* new item to be inserted */
- row = gtk_clist_append( clist, text );
- gtk_clist_set_row_data( clist, row, sx );
+ sxri->row = gtk_clist_append( clist, text );
+ gtk_clist_set_row_data( clist, sxri->row, sx );
} else {
- /* old item being replaced. */
- if ( oldMarkTag != -1 ) {
- gnc_dense_cal_mark_remove( sxd->gdcal, oldMarkTag );
- }
for ( i=0; i<3; i++ ) {
- gtk_clist_set_text( clist, row, i, text[i] );
+ gtk_clist_set_text( clist, sxri->row, i, text[i] );
}
}
gtk_clist_sort( clist );
gtk_clist_thaw( clist );
- g_hash_table_insert( sxd->sxData, (gpointer)sx, (gpointer)gdcMarkTag );
+ g_hash_table_insert( sxd->sxData, (gpointer)sx, (gpointer)sxri );
+ sxri = NULL;
g_string_free( freqStr, TRUE );
g_string_free( nextDate, TRUE );
@@ -2311,10 +2407,8 @@
}
i = 0;
- gnc_dense_cal_set_month( sxed->example_cal,
- g_date_month( &d ) );
- gnc_dense_cal_set_year( sxed->example_cal,
- g_date_year( &d ) );
+ gnc_dense_cal_set_month( sxed->example_cal, g_date_month( &d ) );
+ gnc_dense_cal_set_year( sxed->example_cal, g_date_year( &d ) );
while ( (i < EX_CAL_NUM_MONTHS * 31)
&& g_date_valid( &d )
/* Restrict based on end date */
@@ -2346,8 +2440,12 @@
sxed->cal_marks,
name, info->str );
gtk_widget_queue_draw( GTK_WIDGET( sxed->example_cal ) );
- g_free( name );
+
g_string_free( info, TRUE );
+ if ( name != NULL )
+ {
+ g_free( name );
+ }
}
xaccFreqSpecFree( fs );
Index: formulacell.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/register-core/formulacell.c,v
retrieving revision 1.2.4.2
retrieving revision 1.2.4.3
diff -Lsrc/register/register-core/formulacell.c -Lsrc/register/register-core/formulacell.c -u -r1.2.4.2 -r1.2.4.3
--- src/register/register-core/formulacell.c
+++ src/register/register-core/formulacell.c
@@ -123,7 +123,7 @@
{
FormulaCell *cell = (FormulaCell *)_cell;
struct lconv *lc = gnc_localeconv ();
- const char *toks = "+-*/=()_";
+ const char *toks = "+-*/=()_:";
unsigned char decimal_point;
unsigned char thousands_sep;
const char *c;
Index: report-system.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/report-system.scm,v
retrieving revision 1.20
retrieving revision 1.20.4.1
diff -Lsrc/report/report-system/report-system.scm -Lsrc/report/report-system/report-system.scm -u -r1.20 -r1.20.4.1
--- src/report/report-system/report-system.scm
+++ src/report/report-system/report-system.scm
@@ -16,8 +16,6 @@
(use-modules (g-wrap gw-glib))
(require 'hash-table)
-(if (not (defined? 'simple-format))
- (require 'format))
(gnc:module-load "gnucash/engine" 0)
(gnc:module-load "gnucash/app-utils" 0)
Index: html-utilities.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/html-utilities.scm,v
retrieving revision 1.8
retrieving revision 1.8.4.1
diff -Lsrc/report/report-system/html-utilities.scm -Lsrc/report/report-system/html-utilities.scm -u -r1.8 -r1.8.4.1
--- src/report/report-system/html-utilities.scm
+++ src/report/report-system/html-utilities.scm
@@ -426,7 +426,7 @@
(and show-subaccts?
(let ((parent (gnc:account-get-parent-account a)))
(and parent
- (show-acct? parent))))))
+ (use-acct? parent))))))
;; Show this account? Only if nonzero amount or appropriate
;; preference.
Index: sched-xact.glade
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/glade/sched-xact.glade,v
retrieving revision 1.42.2.8
retrieving revision 1.42.2.9
diff -Lsrc/gnome/glade/sched-xact.glade -Lsrc/gnome/glade/sched-xact.glade -u -r1.42.2.8 -r1.42.2.9
--- src/gnome/glade/sched-xact.glade
+++ src/gnome/glade/sched-xact.glade
@@ -302,7 +302,7 @@
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">True</property>
<property name="wrap">False</property>
- <property name="adjustment">0 0 100 1 10 10</property>
+ <property name="adjustment">0 0 365 1 30 30</property>
</widget>
<packing>
<property name="padding">0</property>
@@ -387,7 +387,7 @@
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">True</property>
<property name="wrap">False</property>
- <property name="adjustment">0 0 100 1 10 10</property>
+ <property name="adjustment">0 0 365 1 30 30</property>
</widget>
<packing>
<property name="padding">0</property>
@@ -5608,18 +5608,6 @@
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkStatusbar" id="ledger_status">
- <property name="visible">True</property>
- <property name="has_resize_grip">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
</packing>
</child>
</widget>
Index: pnl.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/standard-reports/pnl.scm,v
retrieving revision 1.12
retrieving revision 1.12.4.1
diff -Lsrc/report/standard-reports/pnl.scm -Lsrc/report/standard-reports/pnl.scm -u -r1.12 -r1.12.4.1
--- src/report/standard-reports/pnl.scm
+++ src/report/standard-reports/pnl.scm
@@ -56,6 +56,7 @@
(define optname-report-currency (N_ "Report's currency"))
(define optname-price-source (N_ "Price Source"))
(define optname-show-rates (N_ "Show Exchange Rates"))
+(define optname-show-zeros (N_ "Show accounts with a 0.0 total"))
;; options generator
(define (pnl-options-generator)
@@ -116,6 +117,12 @@
gnc:pagename-display optname-show-rates
"f" (N_ "Show the exchange rates used") #t))
+ (gnc:register-option
+ options
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-show-zeros
+ "g" (N_ "Show account with 0.0 balance") #t))
+
;; Set the general page as default option tab
(gnc:options-set-default-section options gnc:pagename-general)
@@ -156,6 +163,8 @@
optname-price-source))
(show-rates? (get-option gnc:pagename-display
optname-show-rates))
+ (show-zeros? (get-option gnc:pagename-display
+ optname-show-zeros))
(to-date-tp (gnc:timepair-end-day-time
(gnc:date-option-absolute-time
(get-option gnc:pagename-general
@@ -197,7 +206,7 @@
#t gnc:accounts-get-comm-total-profit
(_ "Profit") do-grouping?
show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn #t))
+ show-fcur? report-currency exchange-fn show-zeros?))
;; add the table
(gnc:html-document-add-object! doc table)
Index: balance-sheet.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/standard-reports/balance-sheet.scm,v
retrieving revision 1.11.4.1
retrieving revision 1.11.4.2
diff -Lsrc/report/standard-reports/balance-sheet.scm -Lsrc/report/standard-reports/balance-sheet.scm -u -r1.11.4.1 -r1.11.4.2
--- src/report/standard-reports/balance-sheet.scm
+++ src/report/standard-reports/balance-sheet.scm
@@ -52,6 +52,7 @@
(define optname-price-source (N_ "Price Source"))
(define optname-show-foreign (N_ "Show Foreign Currencies"))
(define optname-show-rates (N_ "Show Exchange Rates"))
+(define optname-show-zeros (N_ "Show accounts with zero balance"))
;; Moderatly ugly hack here, i.e. this depends on the internal
;; structure of html-table -- if that is changed, this might break.
@@ -153,6 +154,12 @@
gnc:pagename-display optname-show-rates
"f" (N_ "Show the exchange rates used") #f))
+ (gnc:register-option
+ options
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-show-zeros
+ "g" (N_ "Show accounts with a 0.0 total") #t))
+
;; Set the general page as default option tab
(gnc:options-set-default-section options gnc:pagename-general)
@@ -190,6 +197,8 @@
optname-price-source))
(show-rates? (get-option gnc:pagename-display
optname-show-rates))
+ (show-zeros? (get-option gnc:pagename-display
+ optname-show-zeros))
(from-date-printable (gnc:date-option-absolute-time
(get-option gnc:pagename-general
optname-from-date)))
@@ -315,7 +324,7 @@
30 20
#f #f #f #f #f
show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn #t))
+ show-fcur? report-currency exchange-fn show-zeros?))
(set! liability-table
(gnc:html-build-acct-table
#f to-date-tp
@@ -324,7 +333,7 @@
50 20
#f #f #f #f #f
show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn #t))
+ show-fcur? report-currency exchange-fn show-zeros?))
(set! equity-table
(gnc:html-build-acct-table
#f to-date-tp
@@ -333,7 +342,7 @@
70 10
#f #f #f #f #f
show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn #t))
+ show-fcur? report-currency exchange-fn show-zeros?))
(net-profit-balance 'minusmerge
neg-net-profit-balance
Index: gnc-general-search.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-search/gnc-general-search.c,v
retrieving revision 1.1.4.6
retrieving revision 1.1.4.7
diff -Lsrc/gnome-search/gnc-general-search.c -Lsrc/gnome-search/gnc-general-search.c -u -r1.1.4.6 -r1.1.4.7
--- src/gnome-search/gnc-general-search.c
+++ src/gnome-search/gnc-general-search.c
@@ -62,7 +62,7 @@
GNCSearchCB search_cb;
gpointer user_data;
GNCSearchWindow * sw;
- QueryAccess get_guid;
+ const QofParam * get_guid;
gint component_id;
};
@@ -297,11 +297,11 @@
GNCSearchCB search_cb, gpointer user_data)
{
GNCGeneralSearch *gsl;
- QueryAccess get_guid;
+ const QofParam *get_guid;
g_return_val_if_fail (type && label && search_cb, NULL);
- get_guid = gncQueryObjectGetParameterGetter (type, QUERY_PARAM_GUID);
+ get_guid = qof_class_get_parameter (type, QOF_QUERY_PARAM_GUID);
g_return_val_if_fail (get_guid, NULL);
gsl = g_object_new (gnc_general_search_get_type (), NULL);
@@ -343,9 +343,11 @@
gnc_gui_component_clear_watches (gsl->priv->component_id);
- if (selection) {
- gsl->priv->guid = * ((GUID *)(gsl->priv->get_guid
- (gsl->selected_item)));
+ if (selection)
+ {
+ const QofParam *get_guid = gsl->priv->get_guid;
+ gsl->priv->guid = * ((GUID *)(get_guid->param_getfcn
+ (gsl->selected_item, get_guid)));
gnc_gui_component_watch_entity
(gsl->priv->component_id, &(gsl->priv->guid),
GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);
Index: dialog-search.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-search/dialog-search.c,v
retrieving revision 1.35.4.13
retrieving revision 1.35.4.14
diff -Lsrc/gnome-search/dialog-search.c -Lsrc/gnome-search/dialog-search.c -u -r1.35.4.13 -r1.35.4.14
--- src/gnome-search/dialog-search.c
+++ src/gnome-search/dialog-search.c
@@ -89,7 +89,7 @@
/* What we're searching for, and how */
GNCIdTypeConst search_for;
GNCSearchType grouping; /* Match Any, Match All */
- QueryAccess get_guid; /* Function to GetGUID from the object */
+ const QofParam * get_guid; /* Function to GetGUID from the object */
int search_type; /* New, Narrow, Add, Delete */
/* Our query status */
@@ -475,14 +475,15 @@
res = (sw->new_item_cb)(sw->user_data);
- if (res) {
- const GUID *guid = (const GUID *) ((sw->get_guid)(res));
+ if (res)
+ {
+ const GUID *guid = (const GUID *) ((sw->get_guid->param_getfcn)(res, sw->get_guid));
QueryOp op = QUERY_OR;
if (!sw->q) {
if (!sw->start_q) {
- sw->start_q = gncQueryCreateFor (sw->search_for);
- gncQuerySetBook (sw->start_q, gnc_get_current_book ());
+ sw->start_q = gncQueryCreateFor (sw->search_for);
+ gncQuerySetBook (sw->start_q, gnc_get_current_book ());
}
sw->q = gncQueryCopy (sw->start_q);
op = QUERY_AND;
@@ -917,8 +918,8 @@
sw->free_cb = free_cb;
/* Grab the get_guid function */
- sw->get_guid = gncQueryObjectGetParameterGetter (sw->search_for,
- QUERY_PARAM_GUID);
+ sw->get_guid = qof_class_get_parameter (sw->search_for,
+ QOF_QUERY_PARAM_GUID);
if (start_query)
sw->start_q = gncQueryCopy (start_query);
sw->q = show_start_query;
Index: iframe-url.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/utility-reports/iframe-url.scm,v
retrieving revision 1.7
retrieving revision 1.7.4.1
diff -Lsrc/report/utility-reports/iframe-url.scm -Lsrc/report/utility-reports/iframe-url.scm -u -r1.7 -r1.7.4.1
--- src/report/utility-reports/iframe-url.scm
+++ src/report/utility-reports/iframe-url.scm
@@ -4,7 +4,6 @@
(use-modules (ice-9 slib))
(use-modules (gnucash gnc-module))
-(require 'format)
(gnc:module-load "gnucash/report/report-system" 0)
(define (options-generator)
Index: search-param.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/search-param.c,v
retrieving revision 1.1.2.6
retrieving revision 1.1.2.7
diff -Lsrc/gnome-utils/search-param.c -Lsrc/gnome-utils/search-param.c -u -r1.1.2.6 -r1.1.2.7
--- src/gnome-utils/search-param.c
+++ src/gnome-utils/search-param.c
@@ -175,7 +175,7 @@
break;
/* Save the converter */
- converters = g_slist_prepend (converters, objDef->param_getfcn);
+ converters = g_slist_prepend (converters, (gpointer) objDef);
/* And reset for the next parameter */
type = search_type = objDef->param_type;
@@ -378,13 +378,13 @@
else
{
GSList *converters = gnc_search_param_get_converters (param);
- QueryAccess fcn = NULL;
gpointer res = object;
/* Do all the object conversions */
- for (; converters; converters = converters->next) {
- fcn = converters->data;
- res = fcn (res);
+ for (; converters; converters = converters->next)
+ {
+ QofParam *qp = converters->data;
+ res = (qp->param_getfcn) (res, qp);
}
return res;
Index: gnc-dense-cal.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/gnc-dense-cal.c,v
retrieving revision 1.11.4.7
retrieving revision 1.11.4.8
diff -Lsrc/gnome-utils/gnc-dense-cal.c -Lsrc/gnome-utils/gnc-dense-cal.c -u -r1.11.4.7 -r1.11.4.8
--- src/gnome-utils/gnc-dense-cal.c
+++ src/gnome-utils/gnc-dense-cal.c
@@ -172,6 +172,8 @@
struct tm my_tm;
int i;
+ memset( buf, 0, MONTH_NAME_BUFSIZE );
+ memset( &my_tm, 0, sizeof( struct tm ) );
my_tm.tm_mon = mon;
i = strftime (buf, MONTH_NAME_BUFSIZE-1, "%b", &my_tm);
return buf;
@@ -188,6 +190,8 @@
struct tm my_tm;
int i;
+ memset( buf, 0, MONTH_NAME_BUFSIZE );
+ memset( &my_tm, 0, sizeof( struct tm ) );
my_tm.tm_wday = wday;
i = strftime (buf, MONTH_NAME_BUFSIZE-1, "%a", &my_tm);
/* Wild hack to use only the first two letters */
@@ -475,6 +479,13 @@
g_return_if_fail (GNC_IS_DENSE_CAL (object));
dcal = GNC_DENSE_CAL(object);
+
+ if ( GTK_WIDGET_REALIZED( dcal->transPopup ) ) {
+ gtk_widget_hide( GTK_WIDGET(dcal->transPopup) );
+ gtk_widget_destroy( GTK_WIDGET(dcal->transPopup) );
+ dcal->transPopup = NULL;
+ }
+
if ( dcal->drawbuf ) {
gdk_pixmap_unref( dcal->drawbuf );
dcal->drawbuf = NULL;
@@ -796,13 +807,13 @@
dcal->label_width,
dcal->label_height, -1 );
gdk_draw_rectangle( dcal->monthLabels[i],
- widget->style->bg_gc[widget->state],
+ widget->style->white_gc,
TRUE, 0, 0,
dcal->label_width,
dcal->label_height );
gdk_draw_rectangle( tmpPix,
- widget->style->bg_gc[widget->state],
+ widget->style->white_gc,
TRUE, 0, 0,
dcal->label_height,
dcal->label_width );
@@ -817,7 +828,7 @@
dcal->label_width );
/* now, (transpose the pixel matrix)==(do a 90-degree
- * counter-clocwise rotation) */
+ * counter-clockwise rotation) */
for ( x=0; x < dcal->label_height; x++ ) {
for ( y=0; y < dcal->label_width; y++ ) {
if ( gdk_image_get_pixel( tmpImg, x, y )
@@ -989,7 +1000,7 @@
g_date_add_days( &d, 1 ), doc++ ) {
doc_coords( dcal, doc, &x1, &y1, &x2, &y2 );
memset( dayNumBuf, 0, 3 );
- sprintf( dayNumBuf, "%d", g_date_get_day( &d ) );
+ snprintf( dayNumBuf, 3, "%d", g_date_get_day( &d ) );
numW = gdk_string_width( dcal->dayLabelFont, dayNumBuf );
numH = gdk_string_height( dcal->dayLabelFont, dayNumBuf );
w = (x2 - x1)+1;
@@ -1052,6 +1063,8 @@
rowText[1] = gdcmd->info;
gtk_clist_insert( cl, row++, rowText );
}
+
+ // FIXME: free 'date'?
}
}
@@ -1255,6 +1268,7 @@
startD = g_date_new();
endD = g_date_new();
+ // FIXME: clean these up?
/* Calculate the number of weeks in the column before the month we're
* interested in. */
@@ -1583,6 +1597,7 @@
/* Ignore non-realistic marks */
if ( (gint)markToRemove == -1 ) {
+ DEBUG( "markToRemove = -1" );
return;
}
@@ -1594,6 +1609,7 @@
}
g_assert( l != NULL );
if ( l == NULL ) {
+ DEBUG( "l == null" );
return;
}
g_assert( gdcmd != NULL );
Index: gnc-query-list.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/gnc-query-list.c,v
retrieving revision 1.8.2.3
retrieving revision 1.8.2.4
diff -Lsrc/gnome-utils/gnc-query-list.c -Lsrc/gnome-utils/gnc-query-list.c -u -r1.8.2.3 -r1.8.2.4
--- src/gnome-utils/gnc-query-list.c
+++ src/gnome-utils/gnc-query-list.c
@@ -43,9 +43,10 @@
LAST_SIGNAL
};
-struct _GNCQueryListPriv {
- QueryAccess get_guid;
- gint component_id;
+struct _GNCQueryListPriv
+{
+ const QofParam * get_guid;
+ gint component_id;
};
/* Impossible to get at runtime. Assume this is a reasonable number */
@@ -125,8 +126,8 @@
/* cache the function to get the guid of this query type */
list->priv->get_guid =
- gncQueryObjectGetParameterGetter (gncQueryGetSearchFor (query),
- QUERY_PARAM_GUID);
+ qof_class_get_parameter (qof_query_get_search_for(query),
+ QOF_QUERY_PARAM_GUID);
/* Initialize the CList */
gnc_query_list_init_clist(list);
@@ -779,6 +780,7 @@
{
GList *node;
gint row;
+ QofParam *qp= NULL;
for (i = 0, node = list->column_params; node; node = node->next)
{
@@ -786,33 +788,35 @@
GSList *converters = gnc_search_param_get_converters (param);
const char *type = gnc_search_param_get_param_type (param);
gpointer res = item->data;
- QueryAccess fcn = NULL;
/* if this is a boolean, ignore it now -- we'll use a checkmark later */
if (!safe_strcmp (type, QUERYCORE_BOOLEAN)) {
- strings[i++] = g_strdup("");
- continue;
+ strings[i++] = g_strdup("");
+ continue;
}
/* Do all the object conversions */
- for (; converters; converters = converters->next) {
- fcn = converters->data;
-
- if (converters->next)
- res = fcn (res);
+ for (; converters; converters = converters->next)
+ {
+ qp = converters->data;
+ if (converters->next)
+ {
+ res = (qp->param_getfcn)(res, qp);
+ }
}
/* Now convert this to a text value for the row */
if (!safe_strcmp(type, QUERYCORE_DEBCRED) ||
- !safe_strcmp(type, QUERYCORE_NUMERIC))
+ !safe_strcmp(type, QUERYCORE_NUMERIC))
{
- gnc_numeric (*nfcn)(gpointer) = (gnc_numeric(*)(gpointer))fcn;
- gnc_numeric value = nfcn(res);
- if (list->numeric_abs)
- value = gnc_numeric_abs (value);
- strings[i++] = g_strdup(xaccPrintAmount(value,gnc_default_print_info(FALSE)));
+ gnc_numeric (*nfcn)(gpointer, QofParam *) =
+ (gnc_numeric(*)(gpointer, QofParam *))(qp->param_getfcn);
+ gnc_numeric value = nfcn(res, qp);
+ if (list->numeric_abs)
+ value = gnc_numeric_abs (value);
+ strings[i++] = g_strdup(xaccPrintAmount(value,gnc_default_print_info(FALSE)));
} else
- strings[i++] = gncQueryCoreToString (type, res, fcn);
+ strings[i++] = gncQueryCoreToString (type, res, qp);
}
row = gtk_clist_append (GTK_CLIST(list), (gchar **) strings);
@@ -821,14 +825,15 @@
/* Free up our strings */
for (i = 0; i < list->num_columns; i++) {
if (strings[i])
- g_free (strings[i]);
+ g_free (strings[i]);
}
/* Now update any checkmarks */
update_booleans (list, row);
/* and set a watcher on this item */
- guid = (const GUID*)((list->priv->get_guid)(item->data));
+ const QofParam *gup = list->priv->get_guid;
+ guid = (const GUID*)((gup->param_getfcn)(item->data, gup));
gnc_gui_component_watch_entity (list->priv->component_id, guid,
GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);
Index: dialog-hbcitrans.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/hbci/dialog-hbcitrans.h,v
retrieving revision 1.3.4.2
retrieving revision 1.3.4.3
diff -Lsrc/import-export/hbci/dialog-hbcitrans.h -Lsrc/import-export/hbci/dialog-hbcitrans.h -u -r1.3.4.2 -r1.3.4.3
--- src/import-export/hbci/dialog-hbcitrans.h
+++ src/import-export/hbci/dialog-hbcitrans.h
@@ -1,6 +1,8 @@
/********************************************************************\
* dialog-hbcitrans.h -- dialog for HBCI transaction data *
* Copyright (C) 2002 Christian Stimming *
+ * Copyright (C) 2004 Bernd Wagner (changes for *
+ * online transaction templates) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -68,6 +70,8 @@
GtkWidget *gnc_hbci_dialog_get_parent(const HBCITransDialog *td);
/** Return the GList of transaction templates. */
GList *gnc_hbci_dialog_get_templ(const HBCITransDialog *td);
+/** Return the change status of the template list */
+gboolean gnc_hbci_dialog_get_templ_changed(const HBCITransDialog *td) ;
/** Return the HBCI_Transaction. */
const HBCI_Transaction *gnc_hbci_dialog_get_htrans(const HBCITransDialog *td);
/** Return the gnucash Transaction. */
Index: gnc-hbci-transfer.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/hbci/gnc-hbci-transfer.c,v
retrieving revision 1.7.4.3
retrieving revision 1.7.4.4
diff -Lsrc/import-export/hbci/gnc-hbci-transfer.c -Lsrc/import-export/hbci/gnc-hbci-transfer.c -u -r1.7.4.3 -r1.7.4.4
--- src/import-export/hbci/gnc-hbci-transfer.c
+++ src/import-export/hbci/gnc-hbci-transfer.c
@@ -1,6 +1,8 @@
/********************************************************************\
* gnc-hbci-transfer.c -- hbci transfer functions *
* Copyright (C) 2002 Christian Stimming *
+ * Copyright (C) 2004 Bernd Wagner (minor changes for *
+ * online transaction templates) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -84,7 +86,6 @@
gnc_trans_templ_glist_from_kvp_glist
( gnc_hbci_get_book_template_list
( xaccAccountGetBook(gnc_acc)));
- unsigned nr_templates;
int result;
gboolean successful;
HBCITransDialog *td;
@@ -99,16 +100,14 @@
/* Repeat until HBCI action was successful or user pressed cancel */
do {
- nr_templates = g_list_length(template_list);
-
/* Let the user enter the values. If cancel is pressed, -1 is returned. */
result = gnc_hbci_dialog_run_until_ok(td, h_acc);
/* Set the template list in case it got modified. */
template_list = gnc_hbci_dialog_get_templ(td);
- /* New templates? If yes, store them */
- if (nr_templates < g_list_length(template_list))
- maketrans_save_templates(parent, gnc_acc, template_list, (result >= 0));
+ /* templates changed? If yes, store them */
+ if (gnc_hbci_dialog_get_templ_changed(td) )
+ maketrans_save_templates(parent, gnc_acc, template_list, (result >= 0));
if (result < 0) {
break;
@@ -184,9 +183,9 @@
(parent,
FALSE,
"%s",
- _("You have created a new online transfer template, but \n"
- "you cancelled the transfer dialog. Do you nevertheless \n"
- "want to store the new online transfer template?"))) {
+ _("You have changed the list of online transfer templates,\n"
+ "but you cancelled the transfer dialog.\n"
+ "Do you nevertheless want to store the changes?"))) {
GList *kvp_list = gnc_trans_templ_kvp_glist_from_glist (template_list);
/*printf ("Now having %d templates. List: '%s'\n",
g_list_length(template_list),
Index: dialog-hbcitrans.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/hbci/dialog-hbcitrans.c,v
retrieving revision 1.9.4.8
retrieving revision 1.9.4.9
diff -Lsrc/import-export/hbci/dialog-hbcitrans.c -Lsrc/import-export/hbci/dialog-hbcitrans.c -u -r1.9.4.8 -r1.9.4.9
--- src/import-export/hbci/dialog-hbcitrans.c
+++ src/import-export/hbci/dialog-hbcitrans.c
@@ -1,6 +1,8 @@
/********************************************************************\
* dialog-hbcitrans.c -- dialog for hbci transaction *
* Copyright (C) 2002 Christian Stimming *
+ * Copyright (C) 2004 Bernd Wagner (changes for *
+ * online transaction templates) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -67,12 +69,18 @@
/* Recipient's bank name (may be filled in automatically sometime later) */
GtkWidget *recp_bankname_label;
- /* The template choosing option menu */
- GtkWidget *template_option;
+ /* The template choosing GtkList */
+ GtkWidget *template_gtk_list;
+ /* The selected template in the list */
+ GtkWidget *selected_template;
+
/* GList of GNCTransTempl */
GList *templ;
+ /* Flag, if template list has been changed */
+ gboolean templ_changed;
+
/* The HBCI transaction that got created here */
HBCI_Transaction *hbci_trans;
@@ -98,6 +106,8 @@
if (td->hbci_trans)
HBCI_Transaction_delete (td->hbci_trans);
+ td->selected_template = NULL;
+
gtk_widget_destroy (GTK_WIDGET (td->dialog));
#if HAVE_KTOBLZCHECK_H
AccountNumberCheck_delete(td->blzcheck);
@@ -124,6 +134,11 @@
g_assert(td);
return td->gnc_trans;
}
+gboolean gnc_hbci_dialog_get_templ_changed(const HBCITransDialog *td)
+{
+ g_assert(td);
+ return td->templ_changed;
+}
void gnc_hbci_dialog_hide(HBCITransDialog *td)
{
g_assert(td);
@@ -146,8 +161,17 @@
check_ktoblzcheck(GtkWidget *parent, const HBCITransDialog *td,
const HBCI_Transaction *trans);
+void on_template_list_select_child(GtkList *list, GtkWidget *widget, gpointer user_data);
+void on_template_list_selection_changed(GtkList *list, gpointer user_data);
+void on_template_list_unselect_child(GtkList *list, GtkWidget *widget, gpointer user_data);
+
void template_selection_cb(GtkButton *b, gpointer user_data);
void add_template_cb(GtkButton *b, gpointer user_data);
+void moveup_template_cb(GtkButton *button, gpointer user_data);
+void movedown_template_cb(GtkButton *button, gpointer user_data);
+void sort_template_cb(GtkButton *button, gpointer user_data);
+void del_template_cb(GtkButton *button, gpointer user_data);
+
void blz_changed_cb(GtkEditable *e, gpointer user_data);
@@ -162,20 +186,20 @@
* constructor
*/
-static void fill_template_menu_func(gpointer data, gpointer user_data)
+static void fill_template_list_func(gpointer data, gpointer user_data)
{
GNCTransTempl *templ = data;
- GtkMenu *menu = user_data;
+ GtkList *list = user_data;
GtkWidget *item;
g_assert(templ);
- g_assert(menu);
+ g_assert(list);
- item = gtk_menu_item_new_with_label(gnc_trans_templ_get_name(templ));
+ item = gtk_list_item_new_with_label(gnc_trans_templ_get_name(templ));
g_assert(item);
gtk_object_set_user_data(GTK_OBJECT(item), templ);
- gtk_menu_append(menu, item);
+ gtk_container_add(GTK_CONTAINER(list), item );
}
HBCITransDialog *
@@ -226,29 +250,63 @@
GtkWidget *orig_bankcode_heading;
GtkWidget *exec_later_button;
GtkWidget *add_templ_button;
+ GtkWidget *moveup_templ_button;
+ GtkWidget *movedown_templ_button;
+ GtkWidget *sort_templ_button;
+ GtkWidget *del_templ_button;
- heading_label = glade_xml_get_widget (xml, "heading_label");
- td->recp_name_entry = glade_xml_get_widget (xml, "recp_name_entry");
- recp_name_heading = glade_xml_get_widget (xml, "recp_name_heading");
- td->recp_account_entry = glade_xml_get_widget (xml, "recp_account_entry");
- recp_account_heading = glade_xml_get_widget (xml, "recp_account_heading");
- td->recp_bankcode_entry = glade_xml_get_widget (xml, "recp_bankcode_entry");
- recp_bankcode_heading = glade_xml_get_widget (xml, "recp_bankcode_heading");
- td->recp_bankname_label = glade_xml_get_widget (xml, "recp_bankname_label");
- amount_hbox = glade_xml_get_widget (xml, "amount_hbox");
- td->purpose_entry = glade_xml_get_widget (xml, "purpose_entry");
- td->purpose_cont_entry = glade_xml_get_widget (xml, "purpose_cont_entry");
- orig_name_label = glade_xml_get_widget (xml, "orig_name_label");
- orig_account_label = glade_xml_get_widget (xml, "orig_account_label");
- orig_bankname_label = glade_xml_get_widget (xml, "orig_bankname_label");
- orig_bankcode_label = glade_xml_get_widget (xml, "orig_bankcode_label");
- orig_name_heading = glade_xml_get_widget (xml, "orig_name_heading");
- orig_account_heading = glade_xml_get_widget (xml, "orig_account_heading");
- orig_bankname_heading = glade_xml_get_widget (xml, "orig_bankname_heading");
- orig_bankcode_heading = glade_xml_get_widget (xml, "orig_bankcode_heading");
- exec_later_button = glade_xml_get_widget (xml, "exec_later_button");
- td->template_option = glade_xml_get_widget (xml, "template_optionmenu");
- add_templ_button = glade_xml_get_widget (xml, "add_templ_button");
+ g_assert
+ ((heading_label = glade_xml_get_widget (xml, "heading_label")) != NULL);
+ g_assert
+ ((td->recp_name_entry = glade_xml_get_widget (xml, "recp_name_entry")) != NULL);
+ g_assert
+ ((recp_name_heading = glade_xml_get_widget (xml, "recp_name_heading")) != NULL);
+ g_assert
+ ((td->recp_account_entry = glade_xml_get_widget (xml, "recp_account_entry")) != NULL);
+ g_assert
+ ((recp_account_heading = glade_xml_get_widget (xml, "recp_account_heading")) != NULL);
+ g_assert
+ ((td->recp_bankcode_entry = glade_xml_get_widget (xml, "recp_bankcode_entry")) != NULL);
+ g_assert
+ ((recp_bankcode_heading = glade_xml_get_widget (xml, "recp_bankcode_heading")) != NULL);
+ g_assert
+ ((td->recp_bankname_label = glade_xml_get_widget (xml, "recp_bankname_label")) != NULL);
+ g_assert
+ ((amount_hbox = glade_xml_get_widget (xml, "amount_hbox")) != NULL);
+ g_assert
+ ((td->purpose_entry = glade_xml_get_widget (xml, "purpose_entry")) != NULL);
+ g_assert
+ ((td->purpose_cont_entry = glade_xml_get_widget (xml, "purpose_cont_entry")) != NULL);
+ g_assert
+ ((orig_name_label = glade_xml_get_widget (xml, "orig_name_label")) != NULL);
+ g_assert
+ ((orig_account_label = glade_xml_get_widget (xml, "orig_account_label")) != NULL);
+ g_assert
+ ((orig_bankname_label = glade_xml_get_widget (xml, "orig_bankname_label")) != NULL);
+ g_assert
+ ((orig_bankcode_label = glade_xml_get_widget (xml, "orig_bankcode_label")) != NULL);
+ g_assert
+ ((orig_name_heading = glade_xml_get_widget (xml, "orig_name_heading")) != NULL);
+ g_assert
+ ((orig_account_heading = glade_xml_get_widget (xml, "orig_account_heading")) != NULL);
+ g_assert
+ ((orig_bankname_heading = glade_xml_get_widget (xml, "orig_bankname_heading")) != NULL);
+ g_assert
+ ((orig_bankcode_heading = glade_xml_get_widget (xml, "orig_bankcode_heading")) != NULL);
+ g_assert
+ ((exec_later_button = glade_xml_get_widget (xml, "exec_later_button")) != NULL);
+ g_assert
+ ((td->template_gtk_list = glade_xml_get_widget (xml, "template_list")) != NULL);
+ g_assert
+ ((add_templ_button = glade_xml_get_widget (xml, "add_templ_button")) != NULL);
+ g_assert
+ ((moveup_templ_button = glade_xml_get_widget (xml, "moveup_templ_button")) != NULL);
+ g_assert
+ ((movedown_templ_button = glade_xml_get_widget (xml, "movedown_templ_button")) != NULL);
+ g_assert
+ ((sort_templ_button = glade_xml_get_widget (xml, "sort_templ_button")) != NULL);
+ g_assert
+ ((del_templ_button = glade_xml_get_widget (xml, "del_templ_button")) != NULL);
td->amount_edit = gnc_amount_edit_new();
gtk_box_pack_start_defaults(GTK_BOX(amount_hbox), td->amount_edit);
@@ -308,17 +366,41 @@
gtk_label_set_text (GTK_LABEL (orig_bankcode_label),
HBCI_Bank_bankCode (bank));
- /* fill OptionMenu for choosing a transaction template */
- g_list_foreach(td->templ, fill_template_menu_func,
- gtk_option_menu_get_menu
- ( GTK_OPTION_MENU (td->template_option)));
+ /* fill list for choosing a transaction template */
+ g_list_foreach(td->templ, fill_template_list_func,
+ GTK_LIST (td->template_gtk_list));
+
+ td->selected_template = NULL;
+ td->templ_changed = FALSE;
/* Connect signals */
- gnc_option_menu_init_w_signal (td->template_option,
+/* gnc_option_menu_init_w_signal (td->template_option,
GTK_SIGNAL_FUNC(template_selection_cb),
- td);
+ td); */
+ gtk_signal_connect (GTK_OBJECT (td->template_gtk_list), "select_child",
+ GTK_SIGNAL_FUNC (on_template_list_select_child),
+ td);
+
gtk_signal_connect(GTK_OBJECT (add_templ_button), "clicked",
GTK_SIGNAL_FUNC(add_template_cb), td);
+
+ gtk_signal_connect (GTK_OBJECT (moveup_templ_button), "clicked",
+ GTK_SIGNAL_FUNC (moveup_template_cb),
+ td);
+
+ gtk_signal_connect (GTK_OBJECT (movedown_templ_button), "clicked",
+ GTK_SIGNAL_FUNC (movedown_template_cb),
+ td);
+
+ gtk_signal_connect (GTK_OBJECT (sort_templ_button), "clicked",
+ GTK_SIGNAL_FUNC (sort_template_cb),
+ td);
+
+ gtk_signal_connect (GTK_OBJECT (del_templ_button), "clicked",
+ GTK_SIGNAL_FUNC (del_template_cb),
+ td);
+
+
gtk_signal_connect(GTK_OBJECT (td->recp_bankcode_entry), "changed",
GTK_SIGNAL_FUNC(blz_changed_cb), td);
@@ -593,31 +675,53 @@
gtk_entry_set_text (GTK_ENTRY (entry), str ? str : "");
}
-void template_selection_cb(GtkButton *b,
- gpointer user_data)
+
+void
+on_template_list_select_child (GtkList *list,
+ GtkWidget *widget,
+ gpointer user_data)
{
HBCITransDialog *td = user_data;
- unsigned index;
+ GNCTransTempl *templ = gtk_object_get_user_data (GTK_OBJECT(widget)) ;
+
g_assert(td);
- index = gnc_option_menu_get_active (td->template_option);
- /*printf("template_selection_cd: %d is active \n", index);*/
- if ((index > 0) && (index <= g_list_length(td->templ)))
- {
- GNCTransTempl *templ = g_list_nth_data(td->templ, index-1);
- /*printf("template_selection_cd: using template %s \n",
- gnc_trans_templ_get_name(templ));*/
+
+ td->selected_template = widget;
fill_entry(gnc_trans_templ_get_recp_name(templ), td->recp_name_entry);
fill_entry(gnc_trans_templ_get_recp_account(templ), td->recp_account_entry);
fill_entry(gnc_trans_templ_get_recp_bankcode(templ), td->recp_bankcode_entry);
fill_entry(gnc_trans_templ_get_purpose(templ), td->purpose_entry);
fill_entry(gnc_trans_templ_get_purpose_cont(templ), td->purpose_cont_entry);
-
- gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (td->amount_edit),
+
+ gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (td->amount_edit),
gnc_trans_templ_get_amount (templ));
- }
+
}
+
+void
+on_template_list_selection_changed (GtkList *list,
+ gpointer user_data)
+{
+
+}
+
+
+void
+on_template_list_unselect_child (GtkList *list,
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ HBCITransDialog *td = user_data;
+ g_assert(td);
+
+ td->selected_template = NULL;
+
+}
+
+
+
void blz_changed_cb(GtkEditable *e, gpointer user_data)
{
#if HAVE_KTOBLZCHECK_H
@@ -668,6 +772,8 @@
GtkWidget *dlg;
char *name;
int retval = -1;
+ GNCTransTempl *t;
+ gint index;
g_assert(td);
dlg = gnome_request_dialog(FALSE,
@@ -687,21 +793,166 @@
gtk_entry_get_text (GTK_ENTRY (td->purpose_entry)),
gtk_entry_get_text (GTK_ENTRY (td->purpose_cont_entry)));
- /* Append new template to the list. */
- td->templ = g_list_append(td->templ, r);
+ if (td->selected_template) {
+ t = gtk_object_get_user_data(GTK_OBJECT(td->selected_template));
+
+ index = 1+gtk_list_child_position(GTK_LIST(td->template_gtk_list), td->selected_template);
+ }
+ else index = 0;
+
+ td->templ = g_list_insert(td->templ, r, index);
- /* Also append that template to the OptionMenu */
- fill_template_menu_func(r,
- gtk_option_menu_get_menu
- ( GTK_OPTION_MENU (td->template_option)));
- /* the show_all is necessary since otherwise the new item doesn't show up */
- gtk_widget_show_all (GTK_WIDGET (gtk_option_menu_get_menu
- ( GTK_OPTION_MENU (td->template_option))));
- gnc_option_menu_init_w_signal (td->template_option,
- GTK_SIGNAL_FUNC(template_selection_cb),
- td);
+ td->templ_changed = TRUE;
+
+ gtk_list_clear_items(GTK_LIST(td->template_gtk_list), 0, -1);
+
+ /* fill list for choosing a transaction template */
+ g_list_foreach(td->templ, fill_template_list_func,
+ GTK_LIST (td->template_gtk_list));
+
+ gtk_list_select_item(GTK_LIST(td->template_gtk_list), index);
+
+ /* the show_all is necessary since otherwise the new item doesn't show up */
+ gtk_widget_show_all (GTK_WIDGET ( GTK_LIST (td->template_gtk_list)));
}
}
+
+
+void
+moveup_template_cb(GtkButton *button,
+ gpointer user_data)
+{
+ HBCITransDialog *td = user_data;
+ GNCTransTempl *t;
+ gint index;
+ g_assert(td);
+
+ if (td->selected_template) {
+ t = gtk_object_get_user_data(GTK_OBJECT(td->selected_template));
+
+ index = gtk_list_child_position(GTK_LIST(td->template_gtk_list), td->selected_template);
+
+ if (index > 0) {
+ td->templ = g_list_remove( td->templ, t);
+ td->templ = g_list_insert( td->templ, t, index-1);
+
+ td->templ_changed = TRUE;
+ gtk_list_clear_items(GTK_LIST(td->template_gtk_list), 0, -1);
+
+ /* fill list for choosing a transaction template */
+ g_list_foreach(td->templ, fill_template_list_func,
+ GTK_LIST (td->template_gtk_list));
+
+ gtk_list_select_item(GTK_LIST(td->template_gtk_list), index-1);
+
+ gtk_widget_show_all (GTK_WIDGET ( GTK_LIST (td->template_gtk_list)));
+ }
+ }
+}
+
+
+void
+movedown_template_cb(GtkButton *button,
+ gpointer user_data)
+{
+ HBCITransDialog *td = user_data;
+ GNCTransTempl *t;
+ gint index;
+ g_assert(td);
+
+ if (td->selected_template) {
+ t = gtk_object_get_user_data(GTK_OBJECT(td->selected_template));
+
+ index = gtk_list_child_position(GTK_LIST(td->template_gtk_list), td->selected_template);
+
+ if (index < g_list_length(td->templ)-1) {
+ td->templ = g_list_remove( td->templ, t);
+ td->templ = g_list_insert( td->templ, t, index+1);
+
+ td->templ_changed = TRUE;
+ gtk_list_clear_items(GTK_LIST(td->template_gtk_list), 0, -1);
+
+ /* fill list for choosing a transaction template */
+ g_list_foreach(td->templ, fill_template_list_func,
+ GTK_LIST (td->template_gtk_list));
+
+ gtk_list_select_item(GTK_LIST(td->template_gtk_list), index+1);
+
+ gtk_widget_show_all (GTK_WIDGET ( GTK_LIST (td->template_gtk_list)));
+ }
+ }
+}
+
+static gint comparefunc(const gconstpointer e1,
+ const gconstpointer e2)
+{
+ return g_strcasecmp(gnc_trans_templ_get_name((GNCTransTempl*)e1),
+ gnc_trans_templ_get_name((GNCTransTempl*)e2));
+
+}
+
+void
+sort_template_cb(GtkButton *button,
+ gpointer user_data)
+{
+ HBCITransDialog *td = user_data;
+ g_assert(td);
+
+ if (gnc_verify_dialog (td->parent,
+ FALSE, "%s", _("Do you really want to sort the list of templates?"))) {
+
+ td->templ = g_list_sort( td->templ, comparefunc);
+
+ td->templ_changed = TRUE;
+
+ gtk_list_clear_items(GTK_LIST(td->template_gtk_list), 0, -1);
+
+ /* fill list for choosing a transaction template */
+ g_list_foreach(td->templ, fill_template_list_func,
+ GTK_LIST (td->template_gtk_list));
+
+ gtk_list_unselect_all ( GTK_LIST (td->template_gtk_list) );
+
+ gtk_widget_show_all (GTK_WIDGET ( GTK_LIST (td->template_gtk_list)));
+ }
+}
+
+
+
+void
+del_template_cb(GtkButton *button,
+ gpointer user_data)
+{
+ HBCITransDialog *td = user_data;
+ GNCTransTempl *t;
+ gint index;
+ g_assert(td);
+
+ if (td->selected_template) {
+
+ t = gtk_object_get_user_data(GTK_OBJECT(td->selected_template));
+
+ index = gtk_list_child_position(GTK_LIST(td->template_gtk_list), td->selected_template);
+
+ if (gnc_verify_dialog (td->parent,
+ FALSE, _("Do you really want to delete the template '%s'?"),
+ gnc_trans_templ_get_name(g_list_nth_data(td->templ, index)))) {
+ gtk_list_clear_items(GTK_LIST(td->template_gtk_list), index, index+1);
+
+ td->templ = g_list_remove( td->templ, t);
+ td->templ_changed = TRUE;
+
+ gnc_trans_templ_delete(t);
+
+ gtk_list_unselect_all ( GTK_LIST (td->template_gtk_list) );
+
+ gtk_widget_show_all (GTK_WIDGET ( GTK_LIST (td->template_gtk_list)));
+
+ }
+ }
+}
+
+
void gnc_hbci_dialog_xfer_cb(Transaction *trans, gpointer user_data)
{
Index: main.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/main.scm,v
retrieving revision 1.109.2.6
retrieving revision 1.109.2.7
diff -Lsrc/scm/main.scm -Lsrc/scm/main.scm -u -r1.109.2.6 -r1.109.2.7
--- src/scm/main.scm
+++ src/scm/main.scm
@@ -356,7 +356,7 @@
(_ "This is a development version. It may or may not work.\n")
(_ "Report bugs and other problems to gnucash-devel at gnucash.org.\n")
(_ "You can also lookup and file bug reports at http://bugzilla.gnome.org\n")
- (_ "The last stable version was ") "GnuCash 1.8.8" "\n"
+ (_ "The last stable version was ") "GnuCash 1.8.9" "\n"
(_ "The next stable version will be ") "GnuCash 2.0"
"\n\n"))))
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/Makefile.am,v
retrieving revision 1.38
retrieving revision 1.38.4.1
diff -Lsrc/scm/Makefile.am -Lsrc/scm/Makefile.am -u -r1.38 -r1.38.4.1
--- src/scm/Makefile.am
+++ src/scm/Makefile.am
@@ -44,7 +44,7 @@
## brackets here, instead of the usual @... at . This prevents autoconf
## from substituting the values directly into the left-hand sides of
## the sed substitutions. *sigh*
-build-config.scm: build-config.scm.in Makefile
+build-config.scm: ${srcdir}/build-config.scm.in Makefile
rm -f $@.tmp
sed < $< > $@.tmp \
-e 's:@-VERSION-@:${VERSION}:' \
More information about the Gnucash-changes
mailing list