[Gnucash-changes] Sync the g2 branch with the gnome2-merge-9 tag.
David Hampton
hampton at cvs.gnucash.org
Wed Jul 7 00:11:08 EDT 2004
Log Message:
-----------
Sync the g2 branch with the gnome2-merge-9 tag. (2004-07-05)
Tags:
----
gnucash-gnome2-dev
Modified Files:
--------------
gnucash:
ChangeLog
GNOME2_STATUS
Makefile.am
README.patches
acinclude.m4
configure.in
gnucash.m4
make-gnucash-patch.in
gnucash/src:
guile-mappings.h
gnucash/src/app-file:
gnc-file.c
gnucash/src/app-utils:
gnc-component-manager.c
guile-util.c
option-util.c
gnucash/src/app-utils/test:
test-print-parse-amount.c
gnucash/src/backend/file:
gnc-backend-file.c
gnc-backend-file.h
io-gncbin-r.c
io-gncxml-v1.c
io-gncxml-v2.c
sixtp-utils.c
gnucash/src/backend/postgres:
PostgresBackend.c
book.c
builder.c
gncquery.c
price.c
putil.h
table.m4
gnucash/src/business/business-core:
gncAddress.h
gncBillTerm.c
gncBillTerm.h
gncBusGuile.c
gncBusiness.h
gncCustomer.c
gncCustomer.h
gncEmployee.c
gncEmployee.h
gncEntry.c
gncEntry.h
gncInvoice.c
gncInvoice.h
gncJob.c
gncJob.h
gncOrder.c
gncOrder.h
gncOwner.c
gncOwner.h
gncTaxTable.c
gncTaxTable.h
gncVendor.c
gncVendor.h
gnucash/src/business/business-gnome:
business-urls.c
dialog-invoice.c
gnucash/src/business/business-ledger:
gncEntryLedgerLoad.c
gnucash/src/business/business-reports:
business-reports.scm
gnucash/src/doc:
Makefile.am
doxygen.cfg.in
lots.txt
gnucash/src/doc/design:
engine.texinfo
gnucash/src/engine:
Account.c
Account.h
FreqSpec.c
FreqSpec.h
GNCId.h
Group.c
Group.h
Makefile.am
Period.c
Period.h
Query.c
QueryNew.h
SX-book.c
SX-book.h
SchedXaction.h
Scrub.c
Scrub.h
Scrub2.c
Scrub2.h
Scrub3.c
Scrub3.h
TransLog.h
Transaction.c
Transaction.h
cap-gains.c
cap-gains.h
engine-helpers.c
glib-helpers.c
gnc-commodity.c
gnc-commodity.h
gnc-date.h
gnc-engine-util.h
gnc-engine.c
gnc-engine.h
gnc-lot.c
gnc-lot.h
gnc-numeric.c
gnc-numeric.h
gnc-pricedb-p.h
gnc-pricedb.c
gnc-pricedb.h
gnc-session-scm.c
gnc-trace.c
gnc-trace.h
guid.h
gw-engine-spec.scm
iso-currencies-to-c
kvp-scm.c
kvp-util-p.h
kvp-util.c
kvp-util.h
kvp_frame.c
kvp_frame.h
policy.c
policy.h
qof.h
qofbackend-p.h
qofbackend.c
qofbackend.h
qofbook-p.h
qofbook.c
qofbook.h
qofclass-p.h
qofclass.c
qofclass.h
qofgobj.c
qofgobj.h
qofid-p.h
qofid.c
qofid.h
qofinstance-p.h
qofinstance.c
qofinstance.h
qofobject-p.h
qofobject.c
qofobject.h
qofquery-deserial.h
qofquery-serialize.h
qofquery.c
qofquery.h
qofquerycore.c
qofquerycore.h
qofsession-p.h
qofsession.c
qofsession.h
qofsql.c
qofsql.h
xlate.pl
gnucash/src/engine/test:
.cvsignore
Makefile.am
test-lots.c
test-object.c
test-query.c
test-resolve-file-path.c
test-split-vs-account.c
test-transaction-reversal.c
gnucash/src/engine/test-core:
test-engine-stuff.c
test-engine-stuff.h
gnucash/src/gnc-module:
gnc-module.scm
gnucash/src/gnome:
dialog-print-check.c
dialog-progress.c
druid-stock-split.c
top-level.c
gnucash/src/gnome/glade:
print.glade
gnucash/src/gnome-search:
dialog-search.c
gnc-general-search.c
gnucash/src/gnome-utils:
Makefile.am
QuickFill.c
QuickFill.h
argv-list-converters.c
dialog-options.c
gnc-menu-extensions.c
gnc-query-list.c
gnucash/src/import-export:
import-match-map.c
gnucash/src/import-export/qif-import:
dialog-account-picker.c
druid-qif-import.c
gnucash/src/register/ledger-core:
gnc-ledger-display.c
split-register-layout.c
split-register-layout.h
split-register-load.c
split-register.c
split-register.h
gnucash/src/register/register-core:
combocell.h
gnucash/src/register/register-gnome:
combocell-gnome.c
gnucash/src/report/locale-specific/us:
taxtxf.scm
gnucash/src/report/report-gnome:
dialog-column-view.c
dialog-style-sheet.c
report-gnome.scm
window-report.c
gnucash/src/report/report-system:
Makefile.am
commodity-utilities.scm
html-table.scm
html-utilities.scm
report-system.scm
report-utilities.scm
report.scm
gnucash/src/report/report-system/doc:
report-html.txt
gnucash/src/report/standard-reports:
Makefile.am
balance-sheet.scm
standard-reports.scm
transaction.scm
gnucash/src/scm:
main.scm
path.scm
gnucash/src/scm/printing:
print-check.scm
gnucash/src/test-core:
test-stuff.c
Added Files:
-----------
gnucash/src/backend/dwi:
qofmap.c
qofmap.h
gnucash/src/engine:
gnc-filepath-utils.c
gnc-filepath-utils.h
qof-be-utils.h
qofmath128.c
qofmath128.h
gnucash/src/engine/test:
test-numeric.c
gnucash/src/gnome-utils:
account-quickfill.c
account-quickfill.h
gnucash/src/report/report-system:
html-acct-table.scm
gnucash/src/report/standard-reports:
equity-statement.scm
Removed Files:
-------------
gnucash/src/doc:
query-api.txt
gnucash/src/engine:
gnc-be-utils.h
Revision Data
-------------
Index: druid-qif-import.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/qif-import/druid-qif-import.c,v
retrieving revision 1.22.4.9
retrieving revision 1.22.4.10
diff -Lsrc/import-export/qif-import/druid-qif-import.c -Lsrc/import-export/qif-import/druid-qif-import.c -u -r1.22.4.9 -r1.22.4.10
--- src/import-export/qif-import/druid-qif-import.c
+++ src/import-export/qif-import/druid-qif-import.c
@@ -154,20 +154,20 @@
gtk_widget_destroy(window->window);
- scm_unprotect_object(window->imported_files);
- scm_unprotect_object(window->selected_file);
- scm_unprotect_object(window->gnc_acct_info);
- scm_unprotect_object(window->cat_display_info);
- scm_unprotect_object(window->cat_map_info);
- scm_unprotect_object(window->memo_display_info);
- scm_unprotect_object(window->memo_map_info);
- scm_unprotect_object(window->acct_display_info);
- scm_unprotect_object(window->acct_map_info);
- scm_unprotect_object(window->stock_hash);
- scm_unprotect_object(window->new_stocks);
- scm_unprotect_object(window->ticker_map);
- scm_unprotect_object(window->imported_account_group);
- scm_unprotect_object(window->match_transactions);
+ scm_gc_unprotect_object(window->imported_files);
+ scm_gc_unprotect_object(window->selected_file);
+ scm_gc_unprotect_object(window->gnc_acct_info);
+ scm_gc_unprotect_object(window->cat_display_info);
+ scm_gc_unprotect_object(window->cat_map_info);
+ scm_gc_unprotect_object(window->memo_display_info);
+ scm_gc_unprotect_object(window->memo_map_info);
+ scm_gc_unprotect_object(window->acct_display_info);
+ scm_gc_unprotect_object(window->acct_map_info);
+ scm_gc_unprotect_object(window->stock_hash);
+ scm_gc_unprotect_object(window->new_stocks);
+ scm_gc_unprotect_object(window->ticker_map);
+ scm_gc_unprotect_object(window->imported_account_group);
+ scm_gc_unprotect_object(window->match_transactions);
g_free(window);
}
@@ -479,9 +479,9 @@
scm_qiffile = scm_call_0(make_qif_file);
imported_files = scm_cons(scm_qiffile, imported_files);
- scm_unprotect_object(wind->selected_file);
+ scm_gc_unprotect_object(wind->selected_file);
wind->selected_file = scm_qiffile;
- scm_protect_object(wind->selected_file);
+ scm_gc_protect_object(wind->selected_file);
/* load the file */
load_return = scm_call_3(qif_file_load, SCM_CAR(imported_files),
@@ -517,9 +517,9 @@
imported_files =
scm_call_2(unload_qif_file, scm_qiffile, imported_files);
- scm_unprotect_object(wind->imported_files);
+ scm_gc_unprotect_object(wind->imported_files);
wind->imported_files = imported_files;
- scm_protect_object(wind->imported_files);
+ scm_gc_protect_object(wind->imported_files);
return TRUE;
}
@@ -590,9 +590,9 @@
}
}
- scm_unprotect_object(wind->imported_files);
+ scm_gc_unprotect_object(wind->imported_files);
wind->imported_files = imported_files;
- scm_protect_object(wind->imported_files);
+ scm_gc_protect_object(wind->imported_files);
/* turn back the cursor */
gnc_unset_busy_cursor(NULL);
@@ -677,10 +677,10 @@
if(SCM_LISTP(wind->imported_files) &&
(scm_ilength(wind->imported_files) > row)) {
- scm_unprotect_object(wind->selected_file);
+ scm_gc_unprotect_object(wind->selected_file);
wind->selected_file = scm_list_ref(wind->imported_files,
scm_int2num(row));
- scm_protect_object(wind->selected_file);
+ scm_gc_protect_object(wind->selected_file);
}
}
@@ -741,13 +741,13 @@
imported_files =
scm_call_2(unload_qif_file, wind->selected_file, wind->imported_files);
- scm_unprotect_object(wind->imported_files);
+ scm_gc_unprotect_object(wind->imported_files);
wind->imported_files = imported_files;
- scm_protect_object(wind->imported_files);
+ scm_gc_protect_object(wind->imported_files);
- scm_unprotect_object(wind->selected_file);
+ scm_gc_unprotect_object(wind->selected_file);
wind->selected_file = SCM_BOOL_F;
- scm_protect_object(wind->selected_file);
+ scm_gc_protect_object(wind->selected_file);
update_file_page(wind);
}
@@ -847,13 +847,13 @@
files_list = scm_call_2(unload, wind->selected_file, wind->imported_files);
- scm_unprotect_object(wind->imported_files);
+ scm_gc_unprotect_object(wind->imported_files);
wind->imported_files = files_list;
- scm_protect_object(wind->imported_files);
+ scm_gc_protect_object(wind->imported_files);
- scm_unprotect_object(wind->selected_file);
+ scm_gc_unprotect_object(wind->selected_file);
wind->selected_file = SCM_BOOL_F;
- scm_protect_object(wind->selected_file);
+ scm_gc_protect_object(wind->selected_file);
gnome_druid_set_page(GNOME_DRUID(wind->druid),
get_named_page(wind, "load_file_page"));
@@ -894,9 +894,9 @@
map_info,
wind->gnc_acct_info);
- scm_unprotect_object(*display_info);
+ scm_gc_unprotect_object(*display_info);
*display_info = accts_left;
- scm_protect_object(*display_info);
+ scm_gc_protect_object(*display_info);
gtk_clist_column_titles_passive (GTK_CLIST(list));
@@ -1183,14 +1183,14 @@
_("An error occurred while importing "
"QIF transactions into GnuCash. Your "
"accounts are unchanged."));
- scm_unprotect_object(wind->imported_account_group);
+ scm_gc_unprotect_object(wind->imported_account_group);
wind->imported_account_group = SCM_BOOL_F;
- scm_protect_object(wind->imported_account_group);
+ scm_gc_protect_object(wind->imported_account_group);
}
else {
- scm_unprotect_object(wind->imported_account_group);
+ scm_gc_unprotect_object(wind->imported_account_group);
wind->imported_account_group = retval;
- scm_protect_object(wind->imported_account_group);
+ scm_gc_protect_object(wind->imported_account_group);
/* now detect duplicate transactions */
gnc_set_busy_cursor(NULL, TRUE);
@@ -1199,9 +1199,9 @@
wind->imported_account_group);
gnc_unset_busy_cursor(NULL);
- scm_unprotect_object(wind->match_transactions);
+ scm_gc_unprotect_object(wind->match_transactions);
wind->match_transactions = retval;
- scm_protect_object(wind->match_transactions);
+ scm_gc_protect_object(wind->match_transactions);
/* skip to the last page if we couldn't find duplicates
* in the new group */
@@ -1278,10 +1278,10 @@
else {
/* if we need to look at stocks, do that, otherwise import
* xtns and go to the duplicates page */
- scm_unprotect_object(wind->new_stocks);
+ scm_gc_unprotect_object(wind->new_stocks);
wind->new_stocks = scm_call_3(update_stock, wind->stock_hash,
wind->ticker_map, wind->acct_map_info);
- scm_protect_object(wind->new_stocks);
+ scm_gc_protect_object(wind->new_stocks);
if(wind->new_stocks != SCM_BOOL_F) {
if(wind->show_doc_pages) {
@@ -1334,10 +1334,10 @@
int show_matches;
gnc_set_busy_cursor(NULL, TRUE);
- scm_unprotect_object(wind->new_stocks);
+ scm_gc_unprotect_object(wind->new_stocks);
wind->new_stocks = scm_call_3(update_stock, wind->stock_hash,
wind->ticker_map, wind->acct_map_info);
- scm_protect_object(wind->new_stocks);
+ scm_gc_protect_object(wind->new_stocks);
if(wind->new_stocks != SCM_BOOL_F) {
if(wind->show_doc_pages) {
@@ -2005,20 +2005,20 @@
create_ticker_map = scm_c_eval_string("make-ticker-map");
retval->ticker_map = scm_call_0(create_ticker_map);
- scm_protect_object(retval->imported_files);
- scm_protect_object(retval->selected_file);
- scm_protect_object(retval->gnc_acct_info);
- scm_protect_object(retval->cat_display_info);
- scm_protect_object(retval->cat_map_info);
- scm_protect_object(retval->memo_display_info);
- scm_protect_object(retval->memo_map_info);
- scm_protect_object(retval->acct_display_info);
- scm_protect_object(retval->acct_map_info);
- scm_protect_object(retval->stock_hash);
- scm_protect_object(retval->new_stocks);
- scm_protect_object(retval->ticker_map);
- scm_protect_object(retval->imported_account_group);
- scm_protect_object(retval->match_transactions);
+ scm_gc_protect_object(retval->imported_files);
+ scm_gc_protect_object(retval->selected_file);
+ scm_gc_protect_object(retval->gnc_acct_info);
+ scm_gc_protect_object(retval->cat_display_info);
+ scm_gc_protect_object(retval->cat_map_info);
+ scm_gc_protect_object(retval->memo_display_info);
+ scm_gc_protect_object(retval->memo_map_info);
+ scm_gc_protect_object(retval->acct_display_info);
+ scm_gc_protect_object(retval->acct_map_info);
+ scm_gc_protect_object(retval->stock_hash);
+ scm_gc_protect_object(retval->new_stocks);
+ scm_gc_protect_object(retval->ticker_map);
+ scm_gc_protect_object(retval->imported_account_group);
+ scm_gc_protect_object(retval->match_transactions);
/* set a default currency for new accounts */
gnc_ui_update_commodity_picker(retval->currency_picker,
Index: dialog-account-picker.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/qif-import/dialog-account-picker.c,v
retrieving revision 1.2.6.3
retrieving revision 1.2.6.4
diff -Lsrc/import-export/qif-import/dialog-account-picker.c -Lsrc/import-export/qif-import/dialog-account-picker.c -u -r1.2.6.3 -r1.2.6.4
--- src/import-export/qif-import/dialog-account-picker.c
+++ src/import-export/qif-import/dialog-account-picker.c
@@ -266,7 +266,7 @@
wind->selected_name = g_strdup(scmname);
free(scmname);
- scm_protect_object(wind->map_entry);
+ scm_gc_protect_object(wind->map_entry);
gtk_signal_connect(GTK_OBJECT(wind->treeview), "tree_select_row",
GTK_SIGNAL_FUNC(gnc_ui_qif_account_picker_select_cb),
@@ -292,7 +292,7 @@
} while (response == GNC_RESPONSE_NEW);
gtk_widget_destroy(wind->dialog);
- scm_unprotect_object(wind->map_entry);
+ scm_gc_unprotect_object(wind->map_entry);
g_free(wind->selected_name);
g_free(wind);
Index: gnc-backend-file.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/gnc-backend-file.h,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -Lsrc/backend/file/gnc-backend-file.h -Lsrc/backend/file/gnc-backend-file.h -u -r1.1 -r1.1.2.1
--- src/backend/file/gnc-backend-file.h
+++ src/backend/file/gnc-backend-file.h
@@ -57,4 +57,6 @@
GNC_BOOK_XML2_FILE,
} QofBookFileType;
+QofBackend * libgncmod_backend_file_LTX_gnc_backend_new(void);
+
#endif /* GNC_BACKEND_FILE_H_ */
Index: io-gncxml-v1.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/io-gncxml-v1.c,v
retrieving revision 1.20.4.4
retrieving revision 1.20.4.5
diff -Lsrc/backend/file/io-gncxml-v1.c -Lsrc/backend/file/io-gncxml-v1.c -u -r1.20.4.4 -r1.20.4.5
--- src/backend/file/io-gncxml-v1.c
+++ src/backend/file/io-gncxml-v1.c
@@ -389,11 +389,6 @@
xaccSetAccountGroup(book, global_parse_status.account_group);
- if(global_parse_status.pricedb)
- {
- gnc_pricedb_set_db(book, global_parse_status.pricedb);
- }
-
/* Fix account and transaction commodities */
xaccGroupScrubCommodities (gnc_book_get_group(book));
Index: io-gncxml-v2.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/io-gncxml-v2.c,v
retrieving revision 1.24.4.4
retrieving revision 1.24.4.5
diff -Lsrc/backend/file/io-gncxml-v2.c -Lsrc/backend/file/io-gncxml-v2.c -u -r1.24.4.4 -r1.24.4.5
--- src/backend/file/io-gncxml-v2.c
+++ src/backend/file/io-gncxml-v2.c
@@ -305,13 +305,7 @@
static gboolean
add_pricedb_local(sixtp_gdv2 *data, GNCPriceDB *db)
{
- QofBook *book;
-
- book = data->book;
-
/* gnc_pricedb_print_contents(db, stdout); */
- gnc_pricedb_set_db(book, db);
-
return TRUE;
}
Index: sixtp-utils.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/sixtp-utils.c,v
retrieving revision 1.7.4.2
retrieving revision 1.7.4.3
diff -Lsrc/backend/file/sixtp-utils.c -Lsrc/backend/file/sixtp-utils.c -u -r1.7.4.2 -r1.7.4.3
--- src/backend/file/sixtp-utils.c
+++ src/backend/file/sixtp-utils.c
@@ -177,7 +177,7 @@
if(!ready) {
string_to_number = scm_c_eval_string("string->number");
- scm_protect_object(string_to_number);
+ scm_gc_protect_object(string_to_number);
ready = TRUE;
}
Index: gnc-backend-file.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/gnc-backend-file.c,v
retrieving revision 1.23.4.3
retrieving revision 1.23.4.4
diff -Lsrc/backend/file/gnc-backend-file.c -Lsrc/backend/file/gnc-backend-file.c -u -r1.23.4.3 -r1.23.4.4
--- src/backend/file/gnc-backend-file.c
+++ src/backend/file/gnc-backend-file.c
@@ -46,6 +46,7 @@
#include "gnc-date.h"
#include "gnc-trace.h"
#include "gnc-engine-util.h"
+#include "gnc-filepath-utils.h"
#include "io-gncxml.h"
#include "io-gncbin.h"
@@ -63,18 +64,6 @@
static int file_retention_days = 0;
static gboolean file_compression = FALSE;
-static void gnc_file_be_load_from_file(QofBackend *, QofBook *);
-
-static gboolean gnc_file_be_get_file_lock (FileBackend *be);
-static gboolean gnc_file_be_write_to_file(FileBackend *be, QofBook *,
- const gchar *filepath,
- gboolean make_backup);
-static void gnc_file_be_write_accounts_to_file(QofBackend *be,
- QofBook *book);
-static void gnc_file_be_remove_old_files(FileBackend *be);
-
-QofBackend * libgncmod_backend_file_LTX_gnc_backend_new(void);
-
void
gnc_file_be_set_retention_days (int days)
{
@@ -89,6 +78,106 @@
/* ================================================================= */
+static gboolean
+gnc_file_be_get_file_lock (FileBackend *be)
+{
+ struct stat statbuf;
+ char pathbuf[PATH_MAX];
+ char *path = NULL;
+ int rc;
+ QofBackendError be_err;
+
+ rc = stat (be->lockfile, &statbuf);
+ if (!rc)
+ {
+ /* oops .. file is locked by another user .. */
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ return FALSE;
+ }
+
+ be->lockfd = open (be->lockfile, O_RDWR | O_CREAT | O_EXCL , 0);
+ if (be->lockfd < 0)
+ {
+ /* oops .. we can't create the lockfile .. */
+ switch (errno) {
+ case EACCES:
+ case EROFS:
+ case ENOSPC:
+ be_err = ERR_BACKEND_READONLY;
+ break;
+ default:
+ be_err = ERR_BACKEND_LOCKED;
+ break;
+ }
+ qof_backend_set_error ((QofBackend*)be, be_err);
+ return FALSE;
+ }
+
+ /* OK, now work around some NFS atomic lock race condition
+ * mumbo-jumbo. We do this by linking a unique file, and
+ * then examing the link count. At least that's what the
+ * NFS programmers guide suggests.
+ * Note: the "unique filename" must be unique for the
+ * triplet filename-host-process, otherwise accidental
+ * aliases can occur.
+ */
+
+ /* apparently, even this code may not work for some NFS
+ * implementations. In the long run, I am told that
+ * ftp.debian.org
+ * /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
+ * provides a better long-term solution.
+ */
+
+ strcpy (pathbuf, be->lockfile);
+ path = strrchr (pathbuf, '.');
+ sprintf (path, ".%lx.%d.LNK", gethostid(), getpid());
+
+ rc = link (be->lockfile, pathbuf);
+ if (rc)
+ {
+ /* If hard links aren't supported, just allow the lock. */
+ if (errno == EOPNOTSUPP || errno == EPERM)
+ {
+ be->linkfile = NULL;
+ return TRUE;
+ }
+
+ /* Otherwise, something else is wrong. */
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ unlink (pathbuf);
+ close (be->lockfd);
+ unlink (be->lockfile);
+ return FALSE;
+ }
+
+ rc = stat (be->lockfile, &statbuf);
+ if (rc)
+ {
+ /* oops .. stat failed! This can't happen! */
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ unlink (pathbuf);
+ close (be->lockfd);
+ unlink (be->lockfile);
+ return FALSE;
+ }
+
+ if (statbuf.st_nlink != 2)
+ {
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ unlink (pathbuf);
+ close (be->lockfd);
+ unlink (be->lockfile);
+ return FALSE;
+ }
+
+ be->linkfile = g_strdup (pathbuf);
+
+ return TRUE;
+}
+
+/* ================================================================= */
+
static void
file_session_begin(QofBackend *be_start, QofSession *session,
const char *book_id,
@@ -100,8 +189,14 @@
ENTER (" ");
/* Make sure the directory is there */
- be->dirname = g_strdup (qof_session_get_file_path (session));
+ be->dirname = xaccResolveFilePath(book_id);
+ if (NULL == be->dirname)
+ {
+ qof_backend_set_error (be_start, ERR_FILEIO_FILE_NOT_FOUND);
+ return;
+ }
be->fullpath = g_strdup (be->dirname);
+ be->be.fullpath = be->fullpath;
p = strrchr (be->dirname, '/');
if (p && p != be->dirname)
{
@@ -180,479 +275,305 @@
g_free(be);
}
-static void
-file_sync_all(QofBackend* be, QofBook *book)
+/* ================================================================= */
+/* Write the financial data in a book to a file, returning FALSE on
+ error and setting the error_result to indicate what went wrong if
+ it's not NULL. This function does not manage file locks in any
+ way.
+
+ If make_backup is true, write out a time-stamped copy of the file
+ into the same directory as the indicated file, with a filename of
+ "file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
+ current year/month/day/hour/minute/second. */
+
+static gboolean
+copy_file(const char *orig, const char *bkup)
{
- FileBackend *fbe = (FileBackend *) be;
- ENTER ("book=%p, primary=%p", book, fbe->primary_book);
+ static int buf_size = 1024;
+ char buf[buf_size];
+ int orig_fd;
+ int bkup_fd;
+ ssize_t count_write;
+ ssize_t count_read;
- /* We make an important assumption here, that we might want to change
- * in the future: when the user says 'save', we really save the one,
- * the only, the current open book, and nothing else. We do this
- * because we assume that any other books that we are dealing with
- * are 'read-only', non-editable, because they are closed books.
- * If we ever want to have more than one book open read-write,
- * this will have to change.
- */
- if (NULL == fbe->primary_book) fbe->primary_book = book;
- if (book != fbe->primary_book) return;
+ orig_fd = open(orig, O_RDONLY);
+ if(orig_fd == -1)
+ {
+ return FALSE;
+ }
+ bkup_fd = creat(bkup, 0600);
+ if(bkup_fd == -1)
+ {
+ close(orig_fd);
+ return FALSE;
+ }
- gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
- gnc_file_be_remove_old_files (fbe);
- LEAVE ("book=%p", book);
-}
+ do
+ {
+ count_read = read(orig_fd, buf, buf_size);
+ if(count_read == -1 && errno != EINTR)
+ {
+ close(orig_fd);
+ close(bkup_fd);
+ return FALSE;
+ }
+
+ if(count_read > 0)
+ {
+ count_write = write(bkup_fd, buf, count_read);
+ if(count_write == -1)
+ {
+ close(orig_fd);
+ close(bkup_fd);
+ return FALSE;
+ }
+ }
+ } while(count_read > 0);
+ close(orig_fd);
+ close(bkup_fd);
+
+ return TRUE;
+}
+
/* ================================================================= */
-/* Routines to deal with the creation of multiple books.
- * The core design assumption here is that the book
- * begin-edit/commit-edit routines are used solely to write out
- * closed accounting periods to files. They're not currently
- * designed to do anything other than this. (Although they could be).
- */
-static char *
-build_period_filepath (FileBackend *fbe, QofBook *book)
+static gboolean
+gnc_int_link_or_make_backup(FileBackend *be, const char *orig, const char *bkup)
{
- int len;
- char *str, *p, *q;
-
- len = strlen (fbe->fullpath) + GUID_ENCODING_LENGTH + 14;
- str = g_new (char, len);
- strcpy (str, fbe->fullpath);
+ int err_ret = link(orig, bkup);
+ if(err_ret != 0)
+ {
+ if(errno == EPERM || errno == EOPNOTSUPP)
+ {
+ err_ret = copy_file(orig, bkup);
+ }
- /* XXX it would be nice for the user if we made the book
- * closing date and/or title part of the file-name. */
- p = strrchr (str, '/');
- p++;
- p = stpcpy (p, "book-");
- p = guid_to_string_buff (qof_book_get_guid(book), p);
- p = stpcpy (p, "-");
- q = strrchr (fbe->fullpath, '/');
- q++;
- p = stpcpy (p, q);
- p = stpcpy (p, ".gml");
+ if(!err_ret)
+ {
+ qof_backend_set_error((QofBackend*)be, ERR_FILEIO_BACKUP_ERROR);
+ PWARN ("unable to make file backup from %s to %s: %s",
+ orig, bkup, strerror(errno) ? strerror(errno) : "");
+ return FALSE;
+ }
+ }
- return str;
+ return TRUE;
}
-static void
-file_begin_edit (QofBackend *be, QofIdTypeConst typ, gpointer gp)
+/* ================================================================= */
+
+static gboolean
+is_gzipped_file(const gchar *name)
{
- FileBackend *fbe = (FileBackend *) be;
- QofBook *book = gp;
- const char * filepath;
+ unsigned char buf[2];
+ int fd = open(name, O_RDONLY);
- if (strcmp (GNC_ID_PERIOD, typ)) return;
- filepath = build_period_filepath(fbe, book);
- PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
+ if(fd == 0)
+ {
+ return FALSE;
+ }
- if (NULL == fbe->primary_book)
+ if(read(fd, buf, 2) != 2)
{
- PERR ("You should have saved the data "
- "at least once before closing the books!\n");
+ return FALSE;
}
- /* XXX To be anal about it, we should really be checking to see
- * if there already is a file with this book GUID, and disallowing
- * further progress. This is because we are not allowed to
- * modify books that are closed (They should be treated as
- * 'read-only').
- */
-}
-static void
-file_rollback_edit (QofBackend *be, QofIdTypeConst typ, gpointer gp)
-{
- QofBook *book = gp;
-
- if (strcmp (GNC_ID_PERIOD, typ)) return;
- PINFO ("book=%p", book);
+ if(buf[0] == 037 && buf[1] == 0213)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
}
-
-static void
-file_commit_edit (QofBackend *be, QofIdTypeConst typ, gpointer gp)
+
+static QofBookFileType
+gnc_file_be_determine_file_type(const char *path)
{
- FileBackend *fbe = (FileBackend *) be;
- QofBook *book = gp;
- const char * filepath;
-
- if (strcmp (GNC_ID_PERIOD, typ)) return;
- filepath = build_period_filepath(fbe, book);
- PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
- gnc_file_be_write_to_file(fbe, book, filepath, FALSE);
-
- /* We want to force a save of the current book at this point,
- * because if we don't, and the user forgets to do so, then
- * there'll be the same transactions in the closed book,
- * and also in the current book. */
- gnc_file_be_write_to_file (fbe, fbe->primary_book, fbe->fullpath, TRUE);
+ if(gnc_is_xml_data_file_v2(path)) {
+ return GNC_BOOK_XML2_FILE;
+ } else if(gnc_is_xml_data_file(path)) {
+ return GNC_BOOK_XML1_FILE;
+ } else if(is_gzipped_file(path)) {
+ return GNC_BOOK_XML2_FILE;
+ } else {
+ return GNC_BOOK_BIN_FILE;
+ }
}
-/* ================================================================= */
-QofBackend *
-libgncmod_backend_file_LTX_gnc_backend_new(void)
+static gboolean
+gnc_file_be_backup_file(FileBackend *be)
{
- FileBackend *fbe;
- QofBackend *be;
-
- fbe = g_new0(FileBackend, 1);
- be = (QofBackend*)fbe;
- qof_backend_init(be);
-
- be->session_begin = file_session_begin;
- be->session_end = file_session_end;
- be->destroy_backend = file_destroy_backend;
-
- be->load = gnc_file_be_load_from_file;
-
- /* The file backend treats accounting periods transactionally. */
- be->begin = file_begin_edit;
- be->commit = file_commit_edit;
- be->rollback = file_rollback_edit;
-
- /* The file backend always loads all data ... */
- be->compile_query = NULL;
- be->free_query = NULL;
- be->run_query = NULL;
- be->price_lookup = NULL;
-
- be->counter = NULL;
+ gboolean bkup_ret;
+ char *timestamp;
+ char *backup;
+ const char *datafile;
+ struct stat statbuf;
+ int rc;
- /* The file backend will never be multi-user... */
- be->events_pending = NULL;
- be->process_events = NULL;
+ datafile = be->fullpath;
+
+ rc = stat (datafile, &statbuf);
+ if (rc)
+ return (errno == ENOENT);
- be->sync = file_sync_all;
- be->export = gnc_file_be_write_accounts_to_file;
+ if(gnc_file_be_determine_file_type(datafile) == GNC_BOOK_BIN_FILE)
+ {
+ /* make a more permament safer backup */
+ const char *back = "-binfmt.bkup";
+ char *bin_bkup = g_new(char, strlen(datafile) + strlen(back) + 1);
+ strcpy(bin_bkup, datafile);
+ strcat(bin_bkup, back);
+ bkup_ret = gnc_int_link_or_make_backup(be, datafile, bin_bkup);
+ g_free(bin_bkup);
+ if(!bkup_ret)
+ {
+ return FALSE;
+ }
+ }
- fbe->dirname = NULL;
- fbe->fullpath = NULL;
- fbe->lockfile = NULL;
- fbe->linkfile = NULL;
- fbe->lockfd = -1;
+ timestamp = xaccDateUtilGetStampNow ();
+ backup = g_new (char, strlen (datafile) + strlen (timestamp) + 6);
+ strcpy (backup, datafile);
+ strcat (backup, ".");
+ strcat (backup, timestamp);
+ strcat (backup, ".xac");
+ g_free (timestamp);
- fbe->primary_book = NULL;
+ bkup_ret = gnc_int_link_or_make_backup(be, datafile, backup);
+ g_free(backup);
- return be;
+ return bkup_ret;
}
/* ================================================================= */
-
+
static gboolean
-gnc_file_be_get_file_lock (FileBackend *be)
+gnc_file_be_write_to_file(FileBackend *fbe,
+ QofBook *book,
+ const gchar *datafile,
+ gboolean make_backup)
{
+ QofBackend *be = &fbe->be;
+ char *tmp_name;
struct stat statbuf;
- char pathbuf[PATH_MAX];
- char *path = NULL;
int rc;
QofBackendError be_err;
- rc = stat (be->lockfile, &statbuf);
- if (!rc)
+ ENTER (" book=%p file=%s", book, datafile);
+
+ /* If the book is 'clean', recently saved, then don't save again. */
+ /* XXX this is currently broken due to faulty 'Save As' logic. */
+ /* if (FALSE == qof_book_not_saved (book)) return FALSE; */
+
+ tmp_name = g_new(char, strlen(datafile) + 12);
+ strcpy(tmp_name, datafile);
+ strcat(tmp_name, ".tmp-XXXXXX");
+
+ if(!mktemp(tmp_name))
{
- /* oops .. file is locked by another user .. */
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ qof_backend_set_error(be, ERR_BACKEND_MISC);
return FALSE;
}
-
- be->lockfd = open (be->lockfile, O_RDWR | O_CREAT | O_EXCL , 0);
- if (be->lockfd < 0)
+
+ if(make_backup)
{
- /* oops .. we can't create the lockfile .. */
- switch (errno) {
- case EACCES:
- case EROFS:
- case ENOSPC:
- be_err = ERR_BACKEND_READONLY;
- break;
- default:
- be_err = ERR_BACKEND_LOCKED;
- break;
+ if(!gnc_file_be_backup_file(fbe))
+ {
+ return FALSE;
}
- qof_backend_set_error ((QofBackend*)be, be_err);
- return FALSE;
}
-
- /* OK, now work around some NFS atomic lock race condition
- * mumbo-jumbo. We do this by linking a unique file, and
- * then examing the link count. At least that's what the
- * NFS programmers guide suggests.
- * Note: the "unique filename" must be unique for the
- * triplet filename-host-process, otherwise accidental
- * aliases can occur.
- */
-
- /* apparently, even this code may not work for some NFS
- * implementations. In the long run, I am told that
- * ftp.debian.org
- * /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
- * provides a better long-term solution.
- */
-
- strcpy (pathbuf, be->lockfile);
- path = strrchr (pathbuf, '.');
- sprintf (path, ".%lx.%d.LNK", gethostid(), getpid());
-
- rc = link (be->lockfile, pathbuf);
- if (rc)
+
+ if(gnc_book_write_to_xml_file_v2(book, tmp_name, file_compression))
{
- /* If hard links aren't supported, just allow the lock. */
- if (errno == EOPNOTSUPP || errno == EPERM)
+ /* Record the file's permissions before unlinking it */
+ rc = stat(datafile, &statbuf);
+ if(rc == 0)
{
- be->linkfile = NULL;
- return TRUE;
+ /* Use the permissions from the original data file */
+ if(chmod(tmp_name, statbuf.st_mode) != 0)
+ {
+ qof_backend_set_error(be, ERR_BACKEND_PERM);
+ PWARN("unable to chmod filename %s: %s",
+ datafile ? datafile : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+#if VFAT_DOESNT_SUCK /* chmod always fails on vfat fs */
+ g_free(tmp_name);
+ return FALSE;
+#endif
+ }
+ if(chown(tmp_name, statbuf.st_uid, statbuf.st_gid) != 0)
+ {
+ qof_backend_set_error(be, ERR_BACKEND_PERM);
+ PWARN("unable to chown filename %s: %s",
+ datafile ? datafile : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+#if VFAT_DOESNT_SUCK /* chown always fails on vfat fs */
+ g_free(tmp_name);
+ return FALSE;
+#endif
+ }
+ }
+ if(unlink(datafile) != 0 && errno != ENOENT)
+ {
+ qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
+ PWARN("unable to unlink filename %s: %s",
+ datafile ? datafile : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+ g_free(tmp_name);
+ return FALSE;
+ }
+ if(!gnc_int_link_or_make_backup(fbe, tmp_name, datafile))
+ {
+ qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
+ g_free(tmp_name);
+ return FALSE;
+ }
+ if(unlink(tmp_name) != 0)
+ {
+ qof_backend_set_error(be, ERR_BACKEND_PERM);
+ PWARN("unable to unlink temp filename %s: %s",
+ tmp_name ? tmp_name : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+ g_free(tmp_name);
+ return FALSE;
}
+ g_free(tmp_name);
- /* Otherwise, something else is wrong. */
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- unlink (pathbuf);
- close (be->lockfd);
- unlink (be->lockfile);
- return FALSE;
+ /* Since we successfully saved the book,
+ * we should mark it clean. */
+ qof_book_mark_saved (book);
+ LEAVE (" sucessful save of book=%p to file=%s", book, datafile);
+ return TRUE;
}
-
- rc = stat (be->lockfile, &statbuf);
- if (rc)
+ else
{
- /* oops .. stat failed! This can't happen! */
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- unlink (pathbuf);
- close (be->lockfd);
- unlink (be->lockfile);
- return FALSE;
- }
-
- if (statbuf.st_nlink != 2)
- {
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- unlink (pathbuf);
- close (be->lockfd);
- unlink (be->lockfile);
- return FALSE;
- }
-
- be->linkfile = g_strdup (pathbuf);
-
- return TRUE;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static gboolean
-is_gzipped_file(const gchar *name)
-{
- unsigned char buf[2];
- int fd = open(name, O_RDONLY);
-
- if(fd == 0)
- {
- return FALSE;
- }
-
- if(read(fd, buf, 2) != 2)
- {
- return FALSE;
- }
-
- if(buf[0] == 037 && buf[1] == 0213)
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-static QofBookFileType
-gnc_file_be_determine_file_type(const char *path)
-{
- if(gnc_is_xml_data_file_v2(path)) {
- return GNC_BOOK_XML2_FILE;
- } else if(gnc_is_xml_data_file(path)) {
- return GNC_BOOK_XML1_FILE;
- } else if(is_gzipped_file(path)) {
- return GNC_BOOK_XML2_FILE;
- } else {
- return GNC_BOOK_BIN_FILE;
- }
-}
-
-
-/* Load financial data from a file into the book, automtically
- detecting the format of the file, if possible. Return FALSE on
- error, and set the error parameter to indicate what went wrong if
- it's not NULL. This function does not manage file locks in any
- way. */
-
-static void
-gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
-{
- QofBackendError error = ERR_BACKEND_NO_ERR;
- gboolean rc;
- FileBackend *be = (FileBackend *) bend;
-
- be->primary_book = book;
-
- switch (gnc_file_be_determine_file_type(be->fullpath))
- {
- case GNC_BOOK_XML2_FILE:
- rc = qof_session_load_from_xml_file_v2 (be, book);
- if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
- break;
-
- case GNC_BOOK_XML1_FILE:
- rc = qof_session_load_from_xml_file (book, be->fullpath);
- if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
- break;
-
- case GNC_BOOK_BIN_FILE:
- /* presume it's an old-style binary file */
- qof_session_load_from_binfile(book, be->fullpath);
- error = gnc_get_binfile_io_error();
- break;
-
- default:
- PWARN("File not any known type");
- error = ERR_FILEIO_UNKNOWN_FILE_TYPE;
- break;
- }
-
- if(error != ERR_BACKEND_NO_ERR)
- {
- qof_backend_set_error(bend, error);
- }
-
- /* We just got done loading, it can't possibly be dirty !! */
- qof_book_mark_saved (book);
-}
-
-/* ---------------------------------------------------------------------- */
-/* Write the financial data in a book to a file, returning FALSE on
- error and setting the error_result to indicate what went wrong if
- it's not NULL. This function does not manage file locks in any
- way.
-
- If make_backup is true, write out a time-stamped copy of the file
- into the same directory as the indicated file, with a filename of
- "file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
- current year/month/day/hour/minute/second. */
-
-static gboolean
-copy_file(const char *orig, const char *bkup)
-{
- static int buf_size = 1024;
- char buf[buf_size];
- int orig_fd;
- int bkup_fd;
- ssize_t count_write;
- ssize_t count_read;
-
- orig_fd = open(orig, O_RDONLY);
- if(orig_fd == -1)
- {
- return FALSE;
- }
- bkup_fd = creat(bkup, 0600);
- if(bkup_fd == -1)
- {
- close(orig_fd);
- return FALSE;
- }
-
- do
- {
- count_read = read(orig_fd, buf, buf_size);
- if(count_read == -1 && errno != EINTR)
- {
- close(orig_fd);
- close(bkup_fd);
- return FALSE;
- }
-
- if(count_read > 0)
+ if(unlink(tmp_name) != 0)
{
- count_write = write(bkup_fd, buf, count_read);
- if(count_write == -1)
- {
- close(orig_fd);
- close(bkup_fd);
- return FALSE;
+ switch (errno) {
+ case ENOENT: /* tmp_name doesn't exist? Assume "RO" error */
+ case EACCES:
+ case EPERM:
+ case EROFS:
+ be_err = ERR_BACKEND_READONLY;
+ break;
+ default:
+ be_err = ERR_BACKEND_MISC;
}
+ qof_backend_set_error(be, be_err);
+ PWARN("unable to unlink temp_filename %s: %s",
+ tmp_name ? tmp_name : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+ /* already in an error just flow on through */
}
- } while(count_read > 0);
-
- close(orig_fd);
- close(bkup_fd);
-
- return TRUE;
-}
-
-static gboolean
-gnc_int_link_or_make_backup(FileBackend *be, const char *orig, const char *bkup)
-{
- int err_ret = link(orig, bkup);
- if(err_ret != 0)
- {
- if(errno == EPERM || errno == EOPNOTSUPP)
- {
- err_ret = copy_file(orig, bkup);
- }
-
- if(!err_ret)
- {
- qof_backend_set_error((QofBackend*)be, ERR_FILEIO_BACKUP_ERROR);
- PWARN ("unable to make file backup from %s to %s: %s",
- orig, bkup, strerror(errno) ? strerror(errno) : "");
- return FALSE;
- }
+ g_free(tmp_name);
+ return FALSE;
}
-
return TRUE;
}
-static gboolean
-gnc_file_be_backup_file(FileBackend *be)
-{
- gboolean bkup_ret;
- char *timestamp;
- char *backup;
- const char *datafile;
- struct stat statbuf;
- int rc;
-
- datafile = be->fullpath;
-
- rc = stat (datafile, &statbuf);
- if (rc)
- return (errno == ENOENT);
-
- if(gnc_file_be_determine_file_type(datafile) == GNC_BOOK_BIN_FILE)
- {
- /* make a more permament safer backup */
- const char *back = "-binfmt.bkup";
- char *bin_bkup = g_new(char, strlen(datafile) + strlen(back) + 1);
- strcpy(bin_bkup, datafile);
- strcat(bin_bkup, back);
- bkup_ret = gnc_int_link_or_make_backup(be, datafile, bin_bkup);
- g_free(bin_bkup);
- if(!bkup_ret)
- {
- return FALSE;
- }
- }
-
- timestamp = xaccDateUtilGetStampNow ();
- backup = g_new (char, strlen (datafile) + strlen (timestamp) + 6);
- strcpy (backup, datafile);
- strcat (backup, ".");
- strcat (backup, timestamp);
- strcat (backup, ".xac");
- g_free (timestamp);
-
- bkup_ret = gnc_int_link_or_make_backup(be, datafile, backup);
- g_free(backup);
-
- return bkup_ret;
-}
+/* ================================================================= */
static int
gnc_file_be_select_files (const struct dirent *d)
@@ -758,132 +679,189 @@
closedir (dir);
}
-/* ---------------------------------------------------------------------- */
-
-static gboolean
-gnc_file_be_write_to_file(FileBackend *fbe,
- QofBook *book,
- const gchar *datafile,
- gboolean make_backup)
+static void
+file_sync_all(QofBackend* be, QofBook *book)
{
- QofBackend *be = &fbe->be;
- char *tmp_name;
- struct stat statbuf;
- int rc;
- QofBackendError be_err;
+ FileBackend *fbe = (FileBackend *) be;
+ ENTER ("book=%p, primary=%p", book, fbe->primary_book);
- ENTER (" book=%p file=%s", book, datafile);
+ /* We make an important assumption here, that we might want to change
+ * in the future: when the user says 'save', we really save the one,
+ * the only, the current open book, and nothing else. We do this
+ * because we assume that any other books that we are dealing with
+ * are 'read-only', non-editable, because they are closed books.
+ * If we ever want to have more than one book open read-write,
+ * this will have to change.
+ */
+ if (NULL == fbe->primary_book) fbe->primary_book = book;
+ if (book != fbe->primary_book) return;
- /* If the book is 'clean', recently saved, then don't save again. */
- /* XXX this is currently broken due to faulty 'Save As' logic. */
- /* if (FALSE == qof_book_not_saved (book)) return FALSE; */
+ gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
+ gnc_file_be_remove_old_files (fbe);
+ LEAVE ("book=%p", book);
+}
- tmp_name = g_new(char, strlen(datafile) + 12);
- strcpy(tmp_name, datafile);
- strcat(tmp_name, ".tmp-XXXXXX");
+/* ================================================================= */
+/* Routines to deal with the creation of multiple books.
+ * The core design assumption here is that the book
+ * begin-edit/commit-edit routines are used solely to write out
+ * closed accounting periods to files. They're not currently
+ * designed to do anything other than this. (Although they could be).
+ */
- if(!mktemp(tmp_name))
- {
- qof_backend_set_error(be, ERR_BACKEND_MISC);
- return FALSE;
- }
-
- if(make_backup)
+static char *
+build_period_filepath (FileBackend *fbe, QofBook *book)
+{
+ int len;
+ char *str, *p, *q;
+
+ len = strlen (fbe->fullpath) + GUID_ENCODING_LENGTH + 14;
+ str = g_new (char, len);
+ strcpy (str, fbe->fullpath);
+
+ /* XXX it would be nice for the user if we made the book
+ * closing date and/or title part of the file-name. */
+ p = strrchr (str, '/');
+ p++;
+ p = stpcpy (p, "book-");
+ p = guid_to_string_buff (qof_book_get_guid(book), p);
+ p = stpcpy (p, "-");
+ q = strrchr (fbe->fullpath, '/');
+ q++;
+ p = stpcpy (p, q);
+ p = stpcpy (p, ".gml");
+
+ return str;
+}
+
+static void
+file_begin_edit (QofBackend *be, QofInstance *inst)
+{
+ if (0) build_period_filepath(0, 0);
+#if BORKEN_FOR_NOW
+ FileBackend *fbe = (FileBackend *) be;
+ QofBook *book = gp;
+ const char * filepath;
+
+ QofIdTypeConst typ = QOF_ENTITY(inst)->e_type;
+ if (strcmp (GNC_ID_PERIOD, typ)) return;
+ filepath = build_period_filepath(fbe, book);
+ PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
+
+ if (NULL == fbe->primary_book)
{
- if(!gnc_file_be_backup_file(fbe))
- {
- return FALSE;
- }
+ PERR ("You should have saved the data "
+ "at least once before closing the books!\n");
}
-
- if(gnc_book_write_to_xml_file_v2(book, tmp_name, file_compression))
- {
- /* Record the file's permissions before unlinking it */
- rc = stat(datafile, &statbuf);
- if(rc == 0)
- {
- /* Use the permissions from the original data file */
- if(chmod(tmp_name, statbuf.st_mode) != 0)
- {
- qof_backend_set_error(be, ERR_BACKEND_PERM);
- PWARN("unable to chmod filename %s: %s",
- datafile ? datafile : "(null)",
- strerror(errno) ? strerror(errno) : "");
-#if VFAT_DOESNT_SUCK /* chmod always fails on vfat fs */
- g_free(tmp_name);
- return FALSE;
+ /* XXX To be anal about it, we should really be checking to see
+ * if there already is a file with this book GUID, and disallowing
+ * further progress. This is because we are not allowed to
+ * modify books that are closed (They should be treated as
+ * 'read-only').
+ */
#endif
- }
- if(chown(tmp_name, statbuf.st_uid, statbuf.st_gid) != 0)
- {
- qof_backend_set_error(be, ERR_BACKEND_PERM);
- PWARN("unable to chown filename %s: %s",
- datafile ? datafile : "(null)",
- strerror(errno) ? strerror(errno) : "");
-#if VFAT_DOESNT_SUCK /* chown always fails on vfat fs */
- g_free(tmp_name);
- return FALSE;
+}
+
+static void
+file_rollback_edit (QofBackend *be, QofInstance *inst)
+{
+#if BORKEN_FOR_NOW
+ QofBook *book = gp;
+
+ if (strcmp (GNC_ID_PERIOD, typ)) return;
+ PINFO ("book=%p", book);
#endif
- }
- }
- if(unlink(datafile) != 0 && errno != ENOENT)
- {
- qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
- PWARN("unable to unlink filename %s: %s",
- datafile ? datafile : "(null)",
- strerror(errno) ? strerror(errno) : "");
- g_free(tmp_name);
- return FALSE;
- }
- if(!gnc_int_link_or_make_backup(fbe, tmp_name, datafile))
- {
- qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
- g_free(tmp_name);
- return FALSE;
- }
- if(unlink(tmp_name) != 0)
- {
- qof_backend_set_error(be, ERR_BACKEND_PERM);
- PWARN("unable to unlink temp filename %s: %s",
- tmp_name ? tmp_name : "(null)",
- strerror(errno) ? strerror(errno) : "");
- g_free(tmp_name);
- return FALSE;
- }
- g_free(tmp_name);
+}
- /* Since we successfully saved the book,
- * we should mark it clean. */
- qof_book_mark_saved (book);
- LEAVE (" sucessful save of book=%p to file=%s", book, datafile);
- return TRUE;
+static void
+file_commit_edit (QofBackend *be, QofInstance *inst)
+{
+#if BORKEN_FOR_NOW
+ FileBackend *fbe = (FileBackend *) be;
+ QofBook *book = gp;
+ const char * filepath;
+
+ if (strcmp (GNC_ID_PERIOD, typ)) return;
+ filepath = build_period_filepath(fbe, book);
+ PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
+ gnc_file_be_write_to_file(fbe, book, filepath, FALSE);
+
+ /* We want to force a save of the current book at this point,
+ * because if we don't, and the user forgets to do so, then
+ * there'll be the same transactions in the closed book,
+ * and also in the current book. */
+ gnc_file_be_write_to_file (fbe, fbe->primary_book, fbe->fullpath, TRUE);
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+/* Load financial data from a file into the book, automtically
+ detecting the format of the file, if possible. Return FALSE on
+ error, and set the error parameter to indicate what went wrong if
+ it's not NULL. This function does not manage file locks in any
+ way. */
+
+static void
+gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
+{
+ QofBackendError error = ERR_BACKEND_NO_ERR;
+ gboolean rc;
+ FileBackend *be = (FileBackend *) bend;
+
+ be->primary_book = book;
+
+ switch (gnc_file_be_determine_file_type(be->fullpath))
+ {
+ case GNC_BOOK_XML2_FILE:
+ rc = qof_session_load_from_xml_file_v2 (be, book);
+ if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
+ break;
+
+ case GNC_BOOK_XML1_FILE:
+ rc = qof_session_load_from_xml_file (book, be->fullpath);
+ if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
+ break;
+
+ case GNC_BOOK_BIN_FILE:
+ /* presume it's an old-style binary file */
+ qof_session_load_from_binfile(book, be->fullpath);
+ error = gnc_get_binfile_io_error();
+ break;
+
+ default:
+ PWARN("File not any known type");
+ error = ERR_FILEIO_UNKNOWN_FILE_TYPE;
+ break;
}
- else
+
+ if(error != ERR_BACKEND_NO_ERR)
{
- if(unlink(tmp_name) != 0)
- {
- switch (errno) {
- case ENOENT: /* tmp_name doesn't exist? Assume "RO" error */
- case EACCES:
- case EPERM:
- case EROFS:
- be_err = ERR_BACKEND_READONLY;
- break;
- default:
- be_err = ERR_BACKEND_MISC;
- }
- qof_backend_set_error(be, be_err);
- PWARN("unable to unlink temp_filename %s: %s",
- tmp_name ? tmp_name : "(null)",
- strerror(errno) ? strerror(errno) : "");
- /* already in an error just flow on through */
- }
- g_free(tmp_name);
- return FALSE;
+ qof_backend_set_error(bend, error);
}
- return TRUE;
+
+ /* We just got done loading, it can't possibly be dirty !! */
+ qof_book_mark_saved (book);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static gboolean
+gnc_file_be_save_may_clobber_data (QofBackend *bend)
+{
+ struct stat statbuf;
+
+ if (!bend->fullpath) return FALSE;
+
+ /* FIXME: Make sure this doesn't need more sophisticated semantics
+ * in the face of special file, devices, pipes, symlinks, etc. */
+ if (stat(bend->fullpath, &statbuf) == 0) return TRUE;
+
+ return FALSE;
}
+
static void
gnc_file_be_write_accounts_to_file(QofBackend *be, QofBook *book)
{
@@ -893,4 +871,54 @@
gnc_book_write_accounts_to_xml_file_v2(be, book, datafile);
}
+/* ================================================================= */
+
+QofBackend *
+libgncmod_backend_file_LTX_gnc_backend_new(void)
+{
+ FileBackend *fbe;
+ QofBackend *be;
+
+ fbe = g_new0(FileBackend, 1);
+ be = (QofBackend*)fbe;
+ qof_backend_init(be);
+
+ be->session_begin = file_session_begin;
+ be->session_end = file_session_end;
+ be->destroy_backend = file_destroy_backend;
+
+ be->load = gnc_file_be_load_from_file;
+ be->save_may_clobber_data = gnc_file_be_save_may_clobber_data;
+
+ /* The file backend treats accounting periods transactionally. */
+ be->begin = file_begin_edit;
+ be->commit = file_commit_edit;
+ be->rollback = file_rollback_edit;
+
+ /* The file backend always loads all data ... */
+ be->compile_query = NULL;
+ be->free_query = NULL;
+ be->run_query = NULL;
+ be->price_lookup = NULL;
+
+ be->counter = NULL;
+
+ /* The file backend will never be multi-user... */
+ be->events_pending = NULL;
+ be->process_events = NULL;
+
+ be->sync = file_sync_all;
+ be->export = gnc_file_be_write_accounts_to_file;
+
+ fbe->dirname = NULL;
+ fbe->fullpath = NULL;
+ fbe->lockfile = NULL;
+ fbe->linkfile = NULL;
+ fbe->lockfd = -1;
+
+ fbe->primary_book = NULL;
+
+ return be;
+}
+
/* ========================== END OF FILE ===================== */
Index: io-gncbin-r.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/io-gncbin-r.c,v
retrieving revision 1.15.2.4
retrieving revision 1.15.2.5
diff -Lsrc/backend/file/io-gncbin-r.c -Lsrc/backend/file/io-gncbin-r.c -u -r1.15.2.4 -r1.15.2.5
--- src/backend/file/io-gncbin-r.c
+++ src/backend/file/io-gncbin-r.c
@@ -509,10 +509,8 @@
{
GNCPriceDB *tmpdb;
- if(cvt_potential_prices_to_pricedb_and_cleanup(&tmpdb, book))
+ if(!cvt_potential_prices_to_pricedb_and_cleanup(&tmpdb, book))
{
- gnc_pricedb_set_db(book, tmpdb);
- } else {
PWARN("pricedb import failed.");
error_code = ERR_BACKEND_MISC;
gnc_pricedb_destroy(tmpdb);
Index: gnucash.m4
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/gnucash.m4,v
retrieving revision 1.7
retrieving revision 1.7.4.1
diff -Lgnucash.m4 -Lgnucash.m4 -u -r1.7 -r1.7.4.1
--- gnucash.m4
+++ gnucash.m4
@@ -6,7 +6,7 @@
dnl Test for GnuCash, and define GNUCASH_CFLAGS and GNUCASH_LIBS, if "gmodule" or
dnl gthread is specified in MODULES, pass to gnucash-config
dnl
-AC_DEFUN(AM_PATH_GNUCASH,
+AC_DEFUN([AM_PATH_GNUCASH],
[dnl
dnl Get the cflags and libraries from the gnucash-config script
dnl
Index: README.patches
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/README.patches,v
retrieving revision 1.4.6.1
retrieving revision 1.4.6.2
diff -LREADME.patches -LREADME.patches -u -r1.4.6.1 -r1.4.6.2
--- README.patches
+++ README.patches
@@ -1,5 +1,5 @@
############################################################
- Gnucash 1.7.x README.patches file.
+ Gnucash 1.9.x README.patches file.
NOTE: THIS IS A DEVELOPMENT RELEASE!!! THIS VERSION HAS NOT
BEEN TESTED PROPERLY AND MAY DO ABSOLUTELY ANYTHING!
@@ -13,9 +13,20 @@
Submitting a Patch:
Once you have done some work that you would like to submit, you need
- to send a patch. There is a perl script called make-gnucash-patch
- provided with the distribution that you can use to create the
- patch. Here is how to use that perl script.
+ to send a patch. There are two ways to submit a patch. First, if
+ you're using CVS and only made changes to existing CVS files you
+ can generate the patch using:
+
+ cvs -q diff -u > /tmp/mypatch
+
+ and send /tmp/mypatch into the developers. Note that this ONLY WORKS
+ if you have NOT added any new files to the source tree. If you've
+ added new files then you should use a script called "make-gnucash-patch"
+ to help you create the patch for submission.
+
+ The script make-gnucash-patch is a perl script provided with the
+ gnucash distribution that you can use to create your patch. The
+ rest of this file explains how to use that perl script.
This file comes in two parts:
- A quick summary of the common ways to use make-gnucash-patch; and
Index: configure.in
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/configure.in,v
retrieving revision 1.359.2.33
retrieving revision 1.359.2.34
diff -Lconfigure.in -Lconfigure.in -u -r1.359.2.33 -r1.359.2.34
--- configure.in
+++ configure.in
@@ -90,6 +90,13 @@
STRUCT_TM_GMTOFF_CHECK
SCANF_LLD_CHECK
+if test $am_cv_scanf_lld = "no"; then
+ SCANF_QD_CHECK
+
+ if test $am_cv_scanf_qs = "no"; then
+ AC_MSG_ERROR([cannot continue, no long long conversion support in scanf])
+ fi
+fi
AC_CHECK_HEADERS(ltdl.h)
if test "x$ac_cv_header_ltdl_h" = xno; then
@@ -937,30 +944,6 @@
fi
AC_SUBST(LC_MESSAGES_ENUM)
-if test $am_cv_scanf_lld = "no"; then
- AC_MSG_CHECKING(if scanf supports %qd conversion)
- AC_TRY_RUN([
-#include <stdio.h>
-#include <stdlib.h>
-
-int main ()
-{
- long long int d;
- d = 0;
- if ((sscanf ("10000000000", "%qd", &d) != 1) || (d != 10000000000))
- exit (1);
- exit (0);
-}
-],[
- AC_DEFINE(HAVE_SCANF_QD, 1,
- [Define if scanf supports %qd conversions.])
- AC_MSG_RESULT(yes)
- ],[
- AC_MSG_RESULT(no)
- AC_MSG_ERROR([cannot continue, no long long conversion support in scanf])
- ])
-fi
-
### --------------------------------------------------------------------------
### GnuCash flags and libs configuration
@@ -1040,6 +1023,18 @@
esac],
[ warnFLAGS="${warnFLAGS} -Werror" ])
+ # For gcc >= 3.4.x, specifically enable the new warning switch
+ # -Wdeclaration-after-statement in order to preserve source code
+ # compatibility to gcc 2.95 and other compilers.
+ GCC_VERSION=`${CC} -dumpversion`
+ if test `echo ${GCC_VERSION} | cut -d. -f1` -ge 3; then
+ # This is gcc >= 3.x.x
+ if test `echo ${GCC_VERSION} | cut -d. -f2` -ge 4; then
+ # This is gcc >= 3.4.x
+ warnFLAGS="${warnFLAGS} -Wdeclaration-after-statement"
+ fi
+ fi
+
CFLAGS="${CFLAGS} ${warnFLAGS}"
else
Index: ChangeLog
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/ChangeLog,v
retrieving revision 1.1487.2.133
retrieving revision 1.1487.2.134
diff -LChangeLog -LChangeLog -u -r1.1487.2.133 -r1.1487.2.134
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,8 @@
+2004-07-06 David Hampton <hampton at employees.org>
+
+ * various files: Merge in changes to HEAD from 2004-05-02
+ (gnome2-merge-8) through yesterday (gnome2-merge-9).
+
2004-06-13 Derek Atkins <derek at ihtfp.com>
* configure.in: add support for gtkhtml-3.1, remove src/experimental
@@ -2682,6 +2687,163 @@
-=-=-=- cvs HEAD ChangeLog is below this line -=-=-=-
+2004-07-04 Derek Atkins <derek at ihtfp.com>
+
+ * acinclude.m4: create a SCANF_QD_CHECK and make sure both
+ that and SCANF_LLD_CHECK are "long long" constant-safe
+ * configure.in: use the new SCANF_QD_CHECK and use it
+ earlier in the configuration.
+
+2004-07-02 Derek Atkins <derek at ihtfp.com>
+
+ * src/gnome/dialog-print-check.c:
+ * src/gnome/glade/print.glade:
+ * src/scm/printing/print-check.scm:
+ Apply David Reiser's patch for Quicken(tm) cheques with stub.
+
+ * src/engine/gnc-commodity.c:
+ Apply David Grant's patch to add TD Efunds. Fixes #145297.
+
+2004-06-30 Christian Stimming <stimming at tuhh.de>
+
+ * src/report/report-gnome/window-report.c: Add toolbar element for
+ saving the current report.
+
+ * src/report/report-system/report.scm, report-system.scm: Add
+ function for saving one particular report to the
+ ~/.gnucash/saved-reports-1.8 file. Add extra menu only for
+ customized reports.
+
+ * src/scm/main-window.scm, src/scm/main.scm: Remove the previous
+ function for saving all reports since it is no longer necessary.
+
+2004-06-26 Derek Atkins <derek at ihtfp.com>
+
+ * src/gnc-module/gnc-module.scm: create (and export) a re-export macro
+ is guile doesn't already provide one. Then re-export the symbols
+ instead of exporting them. Fixes some deprecated guile warnings.
+ * src/guile-mappings.h: convert scm_gc_{un,}protect_object() back
+ to its pre-1.6 type for earlier guiles, but upconvert to the new
+ type to fix a deprecated warning. Note that g-wrap is still
+ outputting deprecated code.
+ * lots of other files:
+ convert scm_{un,}protect_object -> scm_gc_{un,}protect_object because
+ the former is now deprecated in guile. Fixes a bunch of
+ GUILE_WARN_DEPRECATED warnings (but probably not all of them).
+
+2004-06-25 Derek Atkins <derek at ihtfp.com>
+
+ * src/engine/gnc-numeric.c: small change to the 128-bit math
+ routines to actually mark a 'carry bit' to denote numbers
+ >= 2^63 to fix bug #144980.
+
+2004-06-24 Derek Atkins <derek at ihtfp.com>
+
+ * Makefile.am: be sure to rebuild make-gnucash-patch and
+ make-gnucash-potfiles when the Makefile changes (which means the
+ PERL paths might have changed).
+ * src/scm/paths.scm: change the default config file to 1.9, so we
+ don't screw up users of 1.8.
+
+2004-06-23 David Montenegro <sunrise2000 at comcast.net>
+
+ * src/report/report-system/html-acct-table.scm:
+ Added file implementing gnc:html-acct-table utility
+ object for easier creation of HTML reports.
+
+ * src/report/standard-reports/balance-sheet.scm:
+ Updated to use the new gnc:html-acct-table object.
+ Added many new options, including report/account
+ form option.
+
+ * src/report/standard-reports/equity-statement.scm:
+ Created Statement of Owner's Equity.
+ (Unsure if correct exchange-fn's are being used.)
+
+ * src/report/report-system/commodity-utilities.scm:
+ * src/report/report-system/html-table.scm:
+ * src/report/report-system/html-utilities.scm:
+ * src/report/report-system/report-system.scm:
+ * src/report/report-system/report-utilities.scm:
+ miscellaneous small additions and/or fixes
+ Fixes #144243.
+
+2004-06-18 Christian Stimming <stimming at tuhh.de>
+
+ * src/scm/main-window.scm, src/scm/main.scm: Added example Menu
+ item "File -> Save all reports" that will call the new report
+ saving function for all reports. Reports are appended to
+ ~/.gnucash/saved-reports-1.8 . This would need more work so that
+ not all reports are saved but only the currently selected one --
+ any volunteer may feel free to add that.
+
+ * src/report/report-system/report.scm, report-system.scm: Added
+ gnc:report-generate-saved-forms that will generate the scheme code
+ necessary to create a new report from the saved options of an old
+ report (merged from 1-8-branch).
+
+2004-06-18 Derek Atkins <derek at ihtfp.com>
+
+ * src/scm/paths.scm: create gnc:current-saved-reports, as
+ the file to store saved reports from cstim. Autoload the
+ saved-reports file at startup (after config.user/config.auto
+ is loaded).
+ * src/scm/main.scm: export gnc:current-saved-reports
+
+2004-05-29 Derek Atkins <derek at ihtfp.com>
+
+ * src/engine/Transaction.c:
+ Don't recompute balances or write to the translog when we're
+ shutting down. Destroy the parent transaction from xaccSplitDestroy()
+ if we're shutting down.
+ * src/engine/qofbook-p.h:
+ * src/engine/qofbook.h:
+ * src/engine/qofbook.c:
+ add "shutting_down" parameter and getter-method, so that
+ objects can detect when the book is shutting down and
+ ignore non-necessary reprocessing. Fixes a memory corruption
+ bug during book-closing.
+
+2004-05-24 Derek Atkins <derek at ihtfp.com>
+
+ * src/report/standard-reports/transaction.cm: applied Vasil's
+ patch to improve the transaction report for HTML export
+ purposes. Fixes bug #142942.
+
+ * src/gnome-search/dialog-search.c:
+ * src/gnome-search/gnc-general-search.c:
+ * src/gnome-utils/gnc-query-list.c:
+ Linas missed a few QOF_QUERY_PARAM_GUID -> QOF_PARAM_GUID
+ conversions.
+
+2004-05-17 Derek Atkins <derek at ihtfp.com>
+
+ * src/report/locale-specific/us/taxtxf.scm: guile-1.6 complains
+ about string->symbol when passed a symbol. Fixes #131201
+ Also add some code to handle accounts that are expected to
+ have parents but do not (also described in #131201).
+
+2004-05-15 Derek Atkins <derek at ihtfp.com>
+
+ * Luigi Ballabio's automake patch to gnucash.m4
+
+2004-05-08 Christian Stimming <stimming at tuhh.de>
+
+ * src/import-export/import-match-map.c
+ (gnc_imap_add_account_bayes): Skip the case when a token is the
+ empty string. This caused many warnings about a NULL kvp_frame
+ lookup.
+
+2004-05-07 David Hampton <hampton at employees.org>
+
+ * src/engine/gnc-commodity.c: Added quote sources for Indian
+ Mutual Funds.
+
+2004-05-05 Derek Atkins <derek at ihtfp.com>
+
+ * src/engine/iso-currencies-to-c: don't automatically try to
+ (require 'format), so gnucash will build on an slib-3 system.
+
2004-05-02 David Hampton <hampton at employees.org>
* src/business/business-core/Makefile.am:
Index: make-gnucash-patch.in
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/make-gnucash-patch.in,v
retrieving revision 1.36.4.1
retrieving revision 1.36.4.2
diff -Lmake-gnucash-patch.in -Lmake-gnucash-patch.in -u -r1.36.4.1 -r1.36.4.2
--- make-gnucash-patch.in
+++ make-gnucash-patch.in
@@ -6,6 +6,13 @@
# mailing list gnucash-patches at gnucash.org. For more info
# consult the README.
#
+# WARNING: By default, this script will checkout an entire
+# up to date copy of the source tree in ../tmp/gnucash/.
+#
+# In order to prevent patches which reverse recent changes
+# made in CVS, make sure to "cvs update" in both
+# directories before running make-gnucash-patch.
+#
# This script requires the programs 'makepatch', 'gzip',
# a 'diff' work-a-like, and 'uuencode'.
#
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/Makefile.am,v
retrieving revision 1.55.4.4
retrieving revision 1.55.4.5
diff -LMakefile.am -LMakefile.am -u -r1.55.4.4 -r1.55.4.5
--- Makefile.am
+++ Makefile.am
@@ -67,14 +67,14 @@
## brackets here, instead of the usual @... at . This prevents autoconf
## from substituting the values directly into the left-hand sides of
## the sed substitutions.
-make-gnucash-patch: make-gnucash-patch.in
+make-gnucash-patch: make-gnucash-patch.in Makefile
rm -f $@.tmp
sed < $< > $@.tmp \
-e 's:@-PERL-@:${PERL}:g'
chmod +x $@.tmp
mv $@.tmp $@
-make-gnucash-potfiles: make-gnucash-potfiles.in
+make-gnucash-potfiles: make-gnucash-potfiles.in Makefile
rm -f $@.tmp
sed < $< > $@.tmp \
-e 's:@-PERL-@:${PERL}:g'
Index: acinclude.m4
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/acinclude.m4,v
retrieving revision 1.19.4.1
retrieving revision 1.19.4.2
diff -Lacinclude.m4 -Lacinclude.m4 -u -r1.19.4.1 -r1.19.4.2
--- acinclude.m4
+++ acinclude.m4
@@ -4337,9 +4337,12 @@
int main ()
{
long long int d;
+ long long int e;
d = 0;
- if ((sscanf ("10000000000", "%lld", &d) != 1) || (d != 10000000000))
+ e = 100000;
+ e *= 100000;
+ if ((sscanf ("10000000000", "%lld", &d) != 1) || (d != e))
exit (1);
exit (0);
@@ -4352,3 +4355,33 @@
[Define if scanf supports %lld conversions.])
fi
])
+
+AC_DEFUN([SCANF_QD_CHECK],
+[
+ AC_CACHE_CHECK([if scanf supports %qd conversions],
+ am_cv_scanf_qd,
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+
+int main ()
+{
+ long long int d;
+ long long int e;
+
+ d = 0;
+ e = 100000;
+ e *= 100000;
+ if ((sscanf ("10000000000", "%qd", &d) != 1) || (d != e))
+ exit (1);
+
+ exit (0);
+}
+],
+ am_cv_scanf_qd=yes,
+ am_cv_scanf_qd=no))
+ if test $am_cv_scanf_qd = yes; then
+ AC_DEFINE(HAVE_SCANF_QD, 1,
+ [Define if scanf supports %qd conversions.])
+ fi
+])
Index: GNOME2_STATUS
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/Attic/GNOME2_STATUS,v
retrieving revision 1.1.2.24
retrieving revision 1.1.2.25
diff -LGNOME2_STATUS -LGNOME2_STATUS -u -r1.1.2.24 -r1.1.2.25
--- GNOME2_STATUS
+++ GNOME2_STATUS
@@ -13,7 +13,7 @@
names of active developers, that'd be great.
========================================
- Last sync with HEAD on 2004-05-02
+ Last sync with HEAD on 2004-07-05
========================================
========================================
Index: guile-mappings.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/guile-mappings.h,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -Lsrc/guile-mappings.h -Lsrc/guile-mappings.h -u -r1.1 -r1.1.2.1
--- src/guile-mappings.h
+++ src/guile-mappings.h
@@ -40,6 +40,8 @@
gh_new_procedure(nm,fn,req,opt,rst)
#define scm_num2long(a,b,c) scm_num2long(a, (char *)b, c)
#define scm_num2ulong(a,b,c) scm_num2ulong(a, (char *)b, c)
+ #define scm_gc_project_object(x) scm_protect_object(x)
+ #define scm_gc_unprotect_object(x) scm_unprotect_object(x)
#if ((GNC_GUILE_MAJOR_VERSION == 1) && (GNC_GUILE_MINOR_VERSION < 4))
#define scm_make_real gh_double2scm
@@ -59,6 +61,12 @@
#else
#define scm_str2symbol(a) gh_symbol2scm(a)
#endif /* Guile < 1.4 */
+#else /* Guile >= 1.6 */
+
+/* This fixes some g-wrap problems.. Once g-wrap fixes this, we can remove this */
+#define scm_protect_object(x) scm_gc_protect_object(x)
+#define scm_unprotect_object(x) scm_gc_unprotect_object(x)
+
#endif /* Guile < 1.6 */
Index: gnc-file.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-file/gnc-file.c,v
retrieving revision 1.25.4.6
retrieving revision 1.25.4.7
diff -Lsrc/app-file/gnc-file.c -Lsrc/app-file/gnc-file.c -u -r1.25.4.6 -r1.25.4.7
--- src/app-file/gnc-file.c
+++ src/app-file/gnc-file.c
@@ -36,6 +36,7 @@
#include "gnc-file-dialog.h"
#include "gnc-file-history.h"
#include "gnc-file-p.h"
+#include "gnc-filepath-utils.h"
#include "gnc-gui-query.h"
#include "gnc-splash.h"
#include "gnc-ui.h"
@@ -44,6 +45,7 @@
#include "qofbook.h"
#include "qofsession.h"
#include "messages.h"
+#include "TransLog.h"
/** GLOBALS *********************************************************/
/* This static indicates the debugging module that this .o belongs to. */
@@ -290,7 +292,9 @@
SCM_BOOL_F));
gnc_close_gui_component_by_session (session);
+ xaccLogDisable();
qof_session_destroy (session);
+ xaccLogEnable();
/* start a new book */
qof_session_get_current_session ();
@@ -379,7 +383,9 @@
gw_wcp_assimilate_ptr (current_session,
scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
+ xaccLogDisable();
qof_session_destroy (current_session);
+ xaccLogEnable();
/* load the accounts from the users datafile */
/* but first, check to make sure we've got a session going. */
@@ -467,6 +473,11 @@
{
AccountGroup *new_group;
+ char * logpath = xaccResolveFilePath(newfile);
+ PINFO ("logpath=%s", logpath ? logpath : "(null)");
+ xaccLogSetBaseName (logpath);
+ xaccLogDisable();
+
if (file_percentage_func) {
file_percentage_func(_("Reading file..."), 0.0);
qof_session_load (new_session, file_percentage_func);
@@ -474,6 +485,7 @@
} else {
qof_session_load (new_session, NULL);
}
+ xaccLogEnable();
/* check for i/o error, put up appropriate error dialog */
io_err = qof_session_get_error (new_session);
@@ -495,7 +507,9 @@
/* going down -- abandon ship */
if (uh_oh)
{
+ xaccLogDisable();
qof_session_destroy (new_session);
+ xaccLogEnable();
/* well, no matter what, I think it's a good idea to have a
* topgroup around. For example, early in the gnucash startup
@@ -650,7 +664,9 @@
ok = qof_session_export (new_session, current_session, NULL);
}
gnc_unset_busy_cursor (NULL);
+ xaccLogDisable();
qof_session_destroy (new_session);
+ xaccLogEnable();
gnc_engine_resume_events();
if (!ok)
@@ -806,7 +822,9 @@
if (ERR_BACKEND_NO_ERR != io_err)
{
show_session_error (io_err, newfile);
+ xaccLogDisable();
qof_session_destroy (new_session);
+ xaccLogEnable();
g_free (newfile);
return;
}
@@ -814,7 +832,9 @@
/* if we got to here, then we've successfully gotten a new session */
/* close up the old file session (if any) */
qof_session_swap_data (session, new_session);
+ xaccLogDisable();
qof_session_destroy (session);
+ xaccLogEnable();
session = NULL;
/* XXX At this point, we should really mark the data in the new session
@@ -866,7 +886,9 @@
gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
+ xaccLogDisable();
qof_session_destroy (session);
+ xaccLogEnable();
qof_session_get_current_session ();
Index: option-util.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-utils/option-util.c,v
retrieving revision 1.19.4.2
retrieving revision 1.19.4.3
diff -Lsrc/app-utils/option-util.c -Lsrc/app-utils/option-util.c -u -r1.19.4.2 -r1.19.4.3
--- src/app-utils/option-util.c
+++ src/app-utils/option-util.c
@@ -209,7 +209,7 @@
odb = g_new0(GNCOptionDB, 1);
odb->guile_options = guile_options;
- scm_protect_object(guile_options);
+ scm_gc_protect_object(guile_options);
odb->option_sections = NULL;
odb->options_dirty = FALSE;
@@ -369,7 +369,7 @@
{
GNCOption *option = onode->data;
- scm_unprotect_object(option->guile_option);
+ scm_gc_unprotect_object(option->guile_option);
g_free (option);
}
@@ -397,7 +397,7 @@
option_dbs = NULL;
}
- scm_unprotect_object(odb->guile_options);
+ scm_gc_unprotect_object(odb->guile_options);
odb->guile_options = SCM_UNDEFINED;
g_free(odb);
@@ -458,13 +458,13 @@
if(void_type == SCM_UNDEFINED) {
void_type = scm_c_eval_string("<gw:void*>");
/* don't really need this - types are bound globally anyway. */
- if(void_type != SCM_UNDEFINED) scm_protect_object(void_type);
+ if(void_type != SCM_UNDEFINED) scm_gc_protect_object(void_type);
}
if(callback_type == SCM_UNDEFINED) {
callback_type = scm_c_eval_string("<gnc:OptionChangeCallback>");
/* don't really need this - types are bound globally anyway. */
if(callback_type != SCM_UNDEFINED)
- scm_protect_object(callback_type);
+ scm_gc_protect_object(callback_type);
}
/* Now build the args list for apply */
@@ -1461,7 +1461,7 @@
option->odb = odb;
/* Prevent guile from garbage collecting the option */
- scm_protect_object(guile_option);
+ scm_gc_protect_object(guile_option);
/* Make the section structure */
section = g_new0(GNCOptionSection, 1);
Index: gnc-component-manager.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-utils/gnc-component-manager.c,v
retrieving revision 1.13.4.2
retrieving revision 1.13.4.3
diff -Lsrc/app-utils/gnc-component-manager.c -Lsrc/app-utils/gnc-component-manager.c -u -r1.13.4.2 -r1.13.4.3
--- src/app-utils/gnc-component-manager.c
+++ src/app-utils/gnc-component-manager.c
@@ -466,10 +466,10 @@
g_return_val_if_fail (ci, NO_COMPONENT);
ci->refresh_handler_scm = refresh_handler;
- scm_protect_object (refresh_handler);
+ scm_gc_protect_object (refresh_handler);
ci->close_handler_scm = close_handler;
- scm_protect_object (close_handler);
+ scm_gc_protect_object (close_handler);
return ci->component_id;
}
@@ -575,11 +575,11 @@
ci->component_class = NULL;
if (ci->refresh_handler_scm != SCM_BOOL_F)
- scm_unprotect_object (ci->refresh_handler_scm);
+ scm_gc_unprotect_object (ci->refresh_handler_scm);
ci->refresh_handler_scm = SCM_BOOL_F;
if (ci->close_handler_scm != SCM_BOOL_F)
- scm_unprotect_object (ci->close_handler_scm);
+ scm_gc_unprotect_object (ci->close_handler_scm);
ci->close_handler_scm = SCM_BOOL_F;
g_free (ci);
Index: guile-util.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-utils/guile-util.c,v
retrieving revision 1.9.4.1
retrieving revision 1.9.4.2
diff -Lsrc/app-utils/guile-util.c -Lsrc/app-utils/guile-util.c -u -r1.9.4.1 -r1.9.4.2
--- src/app-utils/guile-util.c
+++ src/app-utils/guile-util.c
@@ -381,7 +381,7 @@
if(split_type == SCM_UNDEFINED) {
split_type = scm_c_eval_string("<gnc:Split*>");
/* don't really need this - types are bound globally anyway. */
- if(split_type != SCM_UNDEFINED) scm_protect_object(split_type);
+ if(split_type != SCM_UNDEFINED) scm_gc_protect_object(split_type);
}
arg = gw_wcp_assimilate_ptr(split, split_type);
@@ -430,7 +430,7 @@
if(split_type == SCM_UNDEFINED) {
split_type = scm_c_eval_string("<gnc:Split*>");
/* don't really need this - types are bound globally anyway. */
- if(split_type != SCM_UNDEFINED) scm_protect_object(split_type);
+ if(split_type != SCM_UNDEFINED) scm_gc_protect_object(split_type);
}
arg = gw_wcp_assimilate_ptr(split, split_type);
@@ -750,7 +750,7 @@
if(trans_type == SCM_UNDEFINED) {
trans_type = scm_c_eval_string("<gnc:Transaction*>");
/* don't really need this - types are bound globally anyway. */
- if(trans_type != SCM_UNDEFINED) scm_protect_object(trans_type);
+ if(trans_type != SCM_UNDEFINED) scm_gc_protect_object(trans_type);
}
arg = gw_wcp_assimilate_ptr(trans, trans_type);
@@ -826,7 +826,7 @@
if(trans_type == SCM_UNDEFINED) {
trans_type = scm_c_eval_string("<gnc:Transaction*>");
/* don't really need this - types are bound globally anyway. */
- if(trans_type != SCM_UNDEFINED) scm_protect_object(trans_type);
+ if(trans_type != SCM_UNDEFINED) scm_gc_protect_object(trans_type);
}
arg = gw_wcp_assimilate_ptr(trans, trans_type);
Index: test-print-parse-amount.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-utils/test/test-print-parse-amount.c,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -Lsrc/app-utils/test/test-print-parse-amount.c -Lsrc/app-utils/test/test-print-parse-amount.c -u -r1.3 -r1.3.4.1
--- src/app-utils/test/test-print-parse-amount.c
+++ src/app-utils/test/test-print-parse-amount.c
@@ -8,9 +8,9 @@
static void
-test_num_print_info (gnc_numeric n, GNCPrintAmountInfo print_info)
+test_num_print_info (gnc_numeric n, GNCPrintAmountInfo print_info, int line)
{
- gnc_numeric n_parsed;
+ gnc_numeric n_parsed = gnc_numeric_zero();
const char *s;
gboolean ok;
@@ -19,14 +19,14 @@
ok = xaccParseAmount (s, print_info.monetary, &n_parsed, NULL);
do_test_args (ok, "parsing failure", __FILE__, __LINE__,
- "num: %s, string %s", gnc_numeric_to_string (n), s);
+ "num: %s, string %s (line %d)", gnc_numeric_to_string (n), s, line);
ok = gnc_numeric_equal (n, n_parsed);
do_test_args (ok, "not equal", __FILE__, __LINE__,
- "start: %s, string %s, finish: %s",
+ "start: %s, string %s, finish: %s (line %d)",
gnc_numeric_to_string (n), s,
- gnc_numeric_to_string (n_parsed));
+ gnc_numeric_to_string (n_parsed), line);
}
static void
@@ -52,27 +52,41 @@
print_info.round = 0;
n1 = gnc_numeric_convert (n, fraction, GNC_RND_ROUND);
+ if (gnc_numeric_check(n1)) {
+ do_test_args(0, "BAD NUMERIC CONVERSION", __FILE__, __LINE__,
+ "num: %s, fraction: %d", gnc_numeric_to_string(n), fraction);
+ continue;
+ }
- test_num_print_info (n1, print_info);
+ test_num_print_info (n1, print_info, __LINE__);
print_info.monetary = 0;
- test_num_print_info (n1, print_info);
+ test_num_print_info (n1, print_info, __LINE__);
print_info.use_separators = 0;
- test_num_print_info (n1, print_info);
+ test_num_print_info (n1, print_info, __LINE__);
print_info.round = 1;
- test_num_print_info (n1, print_info);
+ test_num_print_info (n1, print_info, __LINE__);
print_info.round = 0;
print_info.force_fit = 1;
- test_num_print_info (n1, print_info);
+ test_num_print_info (n1, print_info, __LINE__);
print_info.round = 1;
- test_num_print_info (n1, print_info);
+ test_num_print_info (n1, print_info, __LINE__);
}
}
+#define IS_VALID_NUM(n,m) \
+ if (gnc_numeric_check(n)) { \
+ do_test_args(0, "BAD NUMERIC", __FILE__, __LINE__, \
+ "num: %s (from %s)", \
+ gnc_numeric_to_string(n), \
+ gnc_numeric_to_string(m)); \
+ continue; \
+ } else { m = n; }
+
static void
run_tests (void)
{
@@ -81,14 +95,18 @@
for (i = 0; i < 50; i++)
{
gnc_numeric n;
+ gnc_numeric n1;
n = get_random_gnc_numeric ();
+ IS_VALID_NUM(n,n);
test_num (n);
- n = gnc_numeric_mul (n, n, n.denom, GNC_RND_ROUND);
+ n1 = gnc_numeric_mul (n, n, n.denom, GNC_RND_ROUND);
+ IS_VALID_NUM(n1,n);
test_num (n);
- n = gnc_numeric_mul (n, n, n.denom, GNC_RND_ROUND);
+ n1 = gnc_numeric_mul (n, n, n.denom, GNC_RND_ROUND);
+ IS_VALID_NUM(n1,n);
test_num (n);
}
}
--- /dev/null
+++ src/backend/dwi/qofmap.h
@@ -0,0 +1,96 @@
+/********************************************************************\
+ * qofmap.h -- Map QOF object to SQL tables, and back. *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org> *
+ * http://dwi.sourceforge.net *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version.
+ * *
+ * This library 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 Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser 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 qofmap.h
+ * Prototype for a new QOF DWI backend .... under development.
+ *
+ * A QofMap defines how the properties of a QOF Object are mapped
+ * to an SQL table. The QofMap is used store specific Qof Instances
+ * as SQL records, and vice-versa: create Qof Instances from SQL
+ * records. The QofMap API consists of two parts: a set of routines
+ * used to define the map itself, and a second set of routines to
+ * use that map in various ways.
+ */
+
+#ifndef QOF_MAP_H_
+#define QOF_MAP_H_
+
+#include <qof/qofbook.h>
+#include <qof/qofinstance.h>
+#include <qof/guid.h>
+#include "database.h"
+
+typedef struct QofMap_s QofMap;
+
+/** Arguments: name of entity (entity type) and SQL table name */
+QofMap * qof_map_new (const char *etype, const char *tabname);
+
+/** @{
+ * Routines to define a QofMap
+ */
+/** Add a link between an SQL fieldname (SQL column name) and QOF property
+ name. These will be linked so that the one is stored into the other
+ when the object is sync to the database.
+ */
+void qof_map_add_field (QofMap *qm, const char *fieldname, const char * property);
+
+/** Add a term that uniquely identifies the QOF Object & SQL record.
+ * This will be the GUID (that is all that is supported at this time).
+ */
+void qof_map_add_match (QofMap *qm, const char *fieldname, const char * property);
+
+/** Add a term that indicates the version of the QOF Object/SQL record.
+ * This is used to determine whether the object in local memory is newer
+ * or older than the corresponding record in the database. Currently,
+ * the only supported type of the version field is a date-time stamp.
+ */
+void qof_map_add_version_cmp (QofMap *qm, const char *fieldname, const char * property);
+
+/** @} */
+
+/** Set the book in which the object instance will live.
+ * The book can be set at any time, there is little penalty
+ * to changing the book often.
+ */
+void qof_map_set_book (QofMap *qm, QofBook *book);
+
+/** Specify the database that will eb used to make the connection */
+void qof_map_set_database (QofMap *qm, DuiDatabase *db);
+
+/** Get record from DB, find or create the matching QOF object. */
+void qof_map_copy_from_db (QofMap *qm, const GUID *guid);
+
+/** Execute the SQL statement, which is expected to return zero
+ * or more records holding QOF objects. Find or create the
+ * the corresponding QOF objects.
+ */
+void qof_map_copy_multiple_from_db (QofMap *qm, const char * sql_stmt);
+
+/** 'Copy' a QOF Entity from local memory to the SQL database.
+ * Pass in the Guid of the entity that is to be saved to SQL.
+ * 'how' should be either "insert" or "update", corresponding to
+ * the SQL INSERT or UPDATE query types.
+ */
+void qof_map_copy_to_db(QofMap *qm, const GUID *guid, const char * how);
+
+#endif /* QOF_MAP_H_ */
--- /dev/null
+++ src/backend/dwi/qofmap.c
@@ -0,0 +1,415 @@
+/********************************************************************\
+ * qofmap.c -- Map QOF object to SQL tables, and back. *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org> *
+ * http://dwi.sourceforge.net *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version.
+ * *
+ * This library 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 Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser 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 qofmap.c
+ * Prototype for a new QOF DWI backend .... under development.
+ *
+ * Basic parsing works basic, copyin, copyout works.
+ */
+
+#include <qof/qofinstance-p.h>
+#include "qofmap.h"
+
+#include "database.h"
+#include "duifield-qof.h"
+#include "duifield-sql.h"
+#include "duifieldmap.h"
+#include "duiresolver.h"
+#include "duitxnquery.h"
+#include "duitxnreport.h"
+#include "perr.h"
+
+/* ============================================================== */
+
+struct QofMap_s
+{
+ char *entity_type; /**< instance type */
+ char *table_name; /**< SQL table name */
+
+ /** The 'txnquery' will be used when writing to the database,
+ * we use it to construct the SQL for us, such as INSERT INTO
+ * and UPDATE .. WHERE
+ */
+ DuiTxnQuery *goto_db;
+
+ /** The 'txnreport' will be used when fetching from the DB.
+ * We will manually generate the SELECT * FROM, and use the
+ * report to copy from the sql recordset to the QOF object.
+ */
+ DuiTxnReport *from_db;
+
+ /** When going to/from the database, we need to match records.
+ * These will always be GUID's on the object side. We use
+ * the match_fieldname to store teh name of the SQL field that
+ * holds the GUID. */
+ char *match_fieldname;
+ char *match_property;
+ DuiFieldMap *goto_db_sqlmatch;
+ DuiFieldMap *goto_db_qofmatch;
+ DuiFieldMap *from_db_qofmatch;
+
+ /** Versioning */
+ DuiFieldMap *xxxfrom_db_version;
+
+ QofBook *book; /**< The book in which instance lives */
+ DuiDatabase *db; /**< Handle to the SQL database */
+ DuiDBConnection *db_conn;
+ DuiResolver *resolver;
+
+ QofBook *tmp_book; /**< Temp staging area for write-outs */
+};
+
+/* ============================================================== */
+
+QofMap *
+qof_map_new (const char *etype, const char *tabname)
+{
+ QofMap *qm;
+
+ if (!etype || !tabname) return NULL;
+
+ qm = g_new0 (QofMap, 1);
+ qm->entity_type = g_strdup (etype);
+ qm->table_name = g_strdup (tabname);
+
+ qm->goto_db = dui_txnquery_new();
+ qm->from_db = dui_txnreport_new("from", 0);
+
+ qm->goto_db_sqlmatch = NULL;
+ qm->goto_db_qofmatch = NULL;
+ qm->from_db_qofmatch = NULL;
+
+ dui_txnquery_set_tablename (qm->goto_db, tabname);
+
+ qm->resolver = dui_resolver_new();
+ dui_txnquery_set_resolver (qm->goto_db, qm->resolver);
+ dui_txnreport_set_resolver (qm->from_db, qm->resolver);
+
+ /* Initialize the more complex parts */
+ qm->tmp_book = qof_book_new();
+
+ return qm;
+}
+
+/* ============================================================== */
+
+void
+qof_map_destroy (QofMap *qm)
+{
+ if (!qm) return;
+
+ if (qm->entity_type) g_free (qm->entity_type);
+ if (qm->table_name) g_free (qm->table_name);
+ if (qm->match_fieldname) g_free (qm->match_fieldname);
+ if (qm->match_property) g_free (qm->match_property);
+
+ if (qm->goto_db) dui_txnquery_destroy (qm->goto_db);
+ if (qm->from_db) dui_txnreport_destroy (qm->from_db);
+ if (qm->resolver) dui_resolver_destroy (qm->resolver);
+
+ if (qm->goto_db_sqlmatch) dui_field_map_destroy (qm->goto_db_sqlmatch);
+ if (qm->goto_db_qofmatch) dui_field_map_destroy (qm->goto_db_qofmatch);
+ if (qm->from_db_qofmatch) dui_field_map_destroy (qm->from_db_qofmatch);
+
+ // XXX close db connection ???
+
+ qof_book_destroy (qm->tmp_book);
+ g_free (qm);
+}
+
+/* ============================================================== */
+
+void
+qof_map_add_field (QofMap *qm, const char *fieldname, const char * property)
+{
+ /* Create bi-drectional set of maps */
+ DuiFieldMap *from_db_fm = dui_field_map_new();
+ DuiFieldMap *goto_db_fm = dui_field_map_new();
+
+ dui_field_set_qof (&from_db_fm->target, qm->entity_type, property);
+ dui_field_set_qof (&goto_db_fm->source, qm->entity_type, property);
+
+ dui_field_set_sql (&from_db_fm->source, fieldname);
+ dui_field_set_sql (&goto_db_fm->target, fieldname);
+
+ dui_txnreport_add_term (qm->from_db, from_db_fm);
+ dui_txnquery_add_term (qm->goto_db, goto_db_fm);
+}
+
+/* ============================================================== */
+
+void
+qof_map_add_match (QofMap *qm, const char *fieldname, const char * property)
+{
+ if (!qm || !fieldname) return;
+
+ if (NULL != qm->goto_db_sqlmatch)
+ {
+ PERR ("Only one match term per map is supported");
+ return;
+ }
+
+ qm->match_fieldname = g_strdup (fieldname);
+ qm->match_property = g_strdup (property);
+
+ qm->goto_db_sqlmatch = dui_field_map_new();
+ qm->goto_db_qofmatch = dui_field_map_new();
+ qm->from_db_qofmatch = dui_field_map_new();
+
+ /* When copying to the DB, we need to indicate which object
+ * is to be copied. The source for the match will be set
+ * during actual runtime
+ */
+ DuiFieldMap *to_sqlmatch = qm->goto_db_sqlmatch;
+ DuiFieldMap *to_qofmatch = qm->goto_db_qofmatch;
+ dui_field_set_where (&to_sqlmatch->target, fieldname, "=");
+ dui_field_set_qof_match (&to_qofmatch->target, qm->entity_type, property);
+
+ dui_txnquery_add_source_match_term (qm->goto_db, to_qofmatch);
+ dui_txnquery_add_term (qm->goto_db, to_sqlmatch);
+
+ /* As above, but for copying from the DB. */
+ DuiFieldMap *fr_match = qm->from_db_qofmatch;
+ dui_field_set_qof_match (&fr_match->target, qm->entity_type, property);
+ dui_txnreport_add_match_term (qm->from_db, fr_match);
+}
+
+/* ============================================================== */
+
+void
+qof_map_add_version_cmp (QofMap *qm, const char *fieldname, const char * property)
+{
+ if (!qm || !fieldname) return;
+
+ /* XXX At this time, this behaves just like an ordinary field ... */
+ qof_map_add_field (qm, fieldname, property);
+}
+
+/* ============================================================== */
+
+void
+qof_map_set_book (QofMap *qm, QofBook *book)
+{
+ qm->book = book;
+
+ /* Each qof field needs to know the book as well. */
+ dui_resolver_resolve_qof (qm->resolver, book);
+}
+
+void
+qof_map_set_database (QofMap *qm, DuiDatabase *db)
+{
+ qm->db = db;
+
+ /* The SQL writer needs to know the database */
+ dui_txnquery_set_database (qm->goto_db, db);
+
+ /* Open the db connection too. */
+ qm->db_conn = dui_database_do_realize (db);
+}
+
+/* ============================================================== */
+/* Get possibly multiple records from DB, and update or create the
+ * matching QOF objects. */
+
+void
+qof_map_copy_multiple_from_db (QofMap *qmap, const char * sql_stmt)
+{
+ if (!qmap || !sql_stmt || 0==sql_stmt[0]) return;
+
+ if (NULL == qmap->from_db_qofmatch)
+ {
+ PERR ("No match term specified, can't copy");
+ return;
+ }
+
+ /* Fetch all from the requested table */
+ DuiDBRecordSet *recs;
+ recs = dui_connection_exec(qmap->db_conn, sql_stmt);
+
+ if (!recs) return;
+ if (0 == dui_recordset_rewind (recs))
+ {
+ dui_recordset_free (recs);
+ return;
+ }
+
+ /* Take the returned SQL records, and update or create the
+ * matching QOF objects. We do this with a duitxnreport report.
+ */
+ DuiField *fld;
+ fld = &qmap->from_db_qofmatch->source;
+ dui_field_set_sql (fld, qmap->match_fieldname);
+
+ dui_txnreport_run (qmap->from_db, recs);
+ dui_recordset_free (recs);
+}
+
+/* ============================================================== */
+/* Get record from DB, find or create the matching QOF object. */
+
+void
+qof_map_copy_from_db (QofMap *qmap, const GUID *guid)
+{
+ if (!qmap || !guid) return;
+
+ if (NULL == qmap->from_db_qofmatch)
+ {
+ PERR ("No match term specified, can't copy");
+ return;
+ }
+
+ char guidstr[GUID_ENCODING_LENGTH+1];
+ guid_to_string_buff (guid, guidstr);
+
+ char * query = g_strdup_printf (
+ "SELECT * FROM %s WHERE %s=\'%s\';",
+ qmap->table_name,
+ qmap->match_fieldname,
+ guidstr);
+
+ /* Fetch all from the requested table */
+ DuiDBRecordSet *recs;
+ recs = dui_connection_exec(qmap->db_conn, query);
+ g_free (query);
+
+ if (!recs) return;
+ if (0 == dui_recordset_rewind (recs))
+ {
+ dui_recordset_free (recs);
+ return;
+ }
+
+ /* Take the returned SQL record, and create a matching QOF object.
+ * We do this with a duitxnreport report.
+ */
+ DuiField *fld;
+ fld = &qmap->from_db_qofmatch->source;
+ dui_field_set_const (fld, guidstr);
+
+ dui_txnreport_run (qmap->from_db, recs);
+ dui_recordset_free (recs);
+}
+
+/* ============================================================== */
+/* 'Copy' a QOF Entity from local memory to the SQL database.
+ * Pass in the Guid of the entity that is to be saved to SQL.
+ */
+void
+qof_map_copy_to_db(QofMap *qmap, const GUID *guid, const char *how)
+{
+ if (!qmap || !guid) return;
+
+ if (NULL == qmap->goto_db_qofmatch)
+ {
+ PERR ("No match term specified, can't copy");
+ return;
+ }
+ /* 'how' should be either "insert" or "update" */
+ dui_txnquery_set_querytype (qmap->goto_db, how);
+
+ char buff[GUID_ENCODING_LENGTH+1];
+ guid_to_string_buff (guid, buff);
+
+ /* We use the GUID as our primary key for all lookups/matches */
+ DuiField *fld;
+ fld = &qmap->goto_db_qofmatch->source;
+ dui_field_set_const (fld, buff);
+
+ fld = &qmap->goto_db_sqlmatch->source;
+ dui_field_set_const (fld, buff);
+
+ /* Do it: issue the SQL insert/update. */
+ DuiDBRecordSet *recs = dui_txnquery_run (qmap->goto_db);
+ dui_recordset_free (recs);
+}
+
+/* ============================================================== */
+/*
+write-out sequence:
+
+lock table
+get version
+if (not exist) insert ;
+else
+ cmp version
+ if (newer) update;
+ else copy-from, including rollback.
+
+unlock table
+*/
+
+void
+write_out (QofMap *qm, QofInstance *inst)
+{
+ if (!inst) return;
+
+ GUID *guid = &QOF_ENTITY(inst)->guid;
+
+ dui_connection_lock(qm->db_conn, qm->table_name);
+ /* Use a temp book when loading from the database */
+ dui_resolver_resolve_qof (qm->resolver, qm->tmp_book);
+ qof_map_copy_from_db (qm, guid);
+
+ /* restore the 'real' book */
+ dui_resolver_resolve_qof (qm->resolver, qm->book);
+
+ /* See if we got something back from the DB */
+ QofCollection *col;
+ col = qof_book_get_collection (qm->tmp_book, QOF_ENTITY(inst)->e_type);
+ QofEntity * db_ent = qof_collection_lookup_entity (col, guid);
+ QofInstance *db_inst = QOF_INSTANCE(db_ent);
+
+ /* If its not already in the database, then insert it in */
+ if (NULL == db_ent)
+ {
+ struct timespec ts = dui_connection_get_now(qm->db_conn);
+ Timespec qts;
+ qts.tv_sec = ts.tv_sec;
+ qts.tv_nsec = ts.tv_nsec;
+ qof_instance_set_last_update (inst, qts);
+ qof_map_copy_to_db (qm, guid, "insert");
+ }
+ else
+ {
+ /* Found it in the database; but who's got the newer version? */
+ int cmp = qof_instance_version_cmp (db_inst, inst);
+ if (0 >= cmp)
+ {
+ struct timespec ts = dui_connection_get_now(qm->db_conn);
+ Timespec qts;
+ qts.tv_sec = ts.tv_sec;
+ qts.tv_nsec = ts.tv_nsec;
+ qof_instance_set_last_update (inst, qts);
+ qof_map_copy_to_db (qm, guid, "update");
+ }
+ else
+ {
+printf ("duude rollback\n");
+ }
+ }
+ dui_connection_unlock(qm->db_conn, qm->table_name);
+}
+
+/* ======================== END OF FILE ========================= */
+/* ============================================================== */
Index: gncEmployee.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncEmployee.c,v
retrieving revision 1.15.4.2
retrieving revision 1.15.4.3
diff -Lsrc/business/business-core/gncEmployee.c -Lsrc/business/business-core/gncEmployee.c -u -r1.15.4.2 -r1.15.4.3
--- src/business/business-core/gncEmployee.c
+++ src/business/business-core/gncEmployee.c
@@ -32,6 +32,7 @@
#include <string.h>
#include "guid.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -47,7 +48,6 @@
#include "gnc-commodity.h"
#include "gnc-engine-util.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
#include "gncAddressP.h"
#include "gncBusiness.h"
@@ -349,7 +349,7 @@
void gncEmployeeBeginEdit (GncEmployee *employee)
{
- GNC_BEGIN_EDIT (&employee->inst);
+ QOF_BEGIN_EDIT (&employee->inst);
}
static inline void gncEmployeeOnError (QofInstance *employee, QofBackendError errcode)
@@ -372,8 +372,8 @@
void gncEmployeeCommitEdit (GncEmployee *employee)
{
- GNC_COMMIT_EDIT_PART1 (&employee->inst);
- GNC_COMMIT_EDIT_PART2 (&employee->inst, gncEmployeeOnError,
+ QOF_COMMIT_EDIT_PART1 (&employee->inst);
+ QOF_COMMIT_EDIT_PART2 (&employee->inst, gncEmployeeOnError,
gncEmployeeOnDone, emp_free);
}
@@ -403,12 +403,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Employee",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
printable: _gncEmployeePrintable,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncEmployeeRegister (void)
@@ -417,9 +419,9 @@
{ EMPLOYEE_ID, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetID, NULL },
{ EMPLOYEE_USERNAME, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetUsername, NULL },
{ EMPLOYEE_ADDR, GNC_ADDRESS_MODULE_NAME, (QofAccessFunc)gncEmployeeGetAddr, NULL },
- { QOF_QUERY_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEmployeeGetActive, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEmployeeGetActive, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncBusGuile.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncBusGuile.c,v
retrieving revision 1.1.4.2
retrieving revision 1.1.4.3
diff -Lsrc/business/business-core/gncBusGuile.c -Lsrc/business/business-core/gncBusGuile.c -u -r1.1.4.2 -r1.1.4.3
--- src/business/business-core/gncBusGuile.c
+++ src/business/business-core/gncBusGuile.c
@@ -35,7 +35,7 @@
if(account_type == SCM_UNDEFINED) {
account_type = scm_c_eval_string("<gnc:Account*>");
/* don't really need this - types are bound globally anyway. */
- if(account_type != SCM_UNDEFINED) scm_protect_object(account_type);
+ if(account_type != SCM_UNDEFINED) scm_gc_protect_object(account_type);
}
return account_type;
Index: gncBillTerm.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncBillTerm.h,v
retrieving revision 1.3.4.2
retrieving revision 1.3.4.3
diff -Lsrc/business/business-core/gncBillTerm.h -Lsrc/business/business-core/gncBillTerm.h -u -r1.3.4.2 -r1.3.4.3
--- src/business/business-core/gncBillTerm.h
+++ src/business/business-core/gncBillTerm.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup BillTerm
+ @{ */
+/** @file gncBillTerm.h
+ @brief Billing Term interface
+ @author Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_BILLTERM_H_
#define GNC_BILLTERM_H_
@@ -41,7 +44,7 @@
#define GNC_IS_BILLTERM(obj) (QOF_CHECK_TYPE((obj), GNC_ID_BILLTERM))
#define GNC_BILLTERM(obj) (QOF_CHECK_CAST((obj), GNC_ID_BILLTERM, GncBillTerm))
-/*
+/**
* How to interpret the amount.
* You can interpret it as a VALUE or a PERCENT.
* ??? huh?
@@ -51,11 +54,19 @@
GNC_TERM_TYPE_PROXIMO,
} GncBillTermType;
-/* Create/Destroy Functions */
+/** @name Create/Destroy Functions */
+/** @{ */
GncBillTerm * gncBillTermCreate (QofBook *book);
void gncBillTermDestroy (GncBillTerm *term);
+void gncBillTermIncRef (GncBillTerm *term);
+void gncBillTermDecRef (GncBillTerm *term);
+
+void gncBillTermChanged (GncBillTerm *term);
+void gncBillTermBeginEdit (GncBillTerm *term);
+void gncBillTermCommitEdit (GncBillTerm *term);
+/** @} */
-/* Set Functions */
+/** @name Set Functions */
void gncBillTermSetName (GncBillTerm *term, const char *name);
void gncBillTermSetDescription (GncBillTerm *term, const char *name);
void gncBillTermSetType (GncBillTerm *term, GncBillTermType type);
@@ -64,15 +75,10 @@
void gncBillTermSetDiscount (GncBillTerm *term, gnc_numeric discount);
void gncBillTermSetCutoff (GncBillTerm *term, gint cutoff);
-void gncBillTermIncRef (GncBillTerm *term);
-void gncBillTermDecRef (GncBillTerm *term);
-
-void gncBillTermChanged (GncBillTerm *term);
-void gncBillTermBeginEdit (GncBillTerm *term);
-void gncBillTermCommitEdit (GncBillTerm *term);
-
-/* Get Functions */
+/** @} */
+/** @name Get Functions */
+/** @{ */
/** Return a pointer to the instance gncBillTerm that is identified
* by the guid, and is residing in the book. Returns NULL if the
* instance can't be found.
@@ -100,6 +106,7 @@
GncBillTerm *gncBillTermReturnChild (GncBillTerm *term, gboolean make_new);
#define gncBillTermGetChild(t) gncBillTermReturnChild((t),FALSE)
gint64 gncBillTermGetRefcount (GncBillTerm *term);
+/** @} */
int gncBillTermCompare (GncBillTerm *a, GncBillTerm *b);
@@ -114,3 +121,5 @@
#define gncBillTermGetGUID(x) qof_instance_get_guid (QOF_INSTANCE(x))
#endif /* GNC_BILLTERM_H_ */
+/** @} */
+/** @} */
Index: gncCustomer.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncCustomer.h,v
retrieving revision 1.13.4.3
retrieving revision 1.13.4.4
diff -Lsrc/business/business-core/gncCustomer.h -Lsrc/business/business-core/gncCustomer.h -u -r1.13.4.3 -r1.13.4.4
--- src/business/business-core/gncCustomer.h
+++ src/business/business-core/gncCustomer.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001,2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Customer
+ @{ */
+/** @file gncCustomer.h
+ @brief Core Customer Interface
+ @author Copyright (C) 2001,2002 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_CUSTOMER_H_
#define GNC_CUSTOMER_H_
@@ -45,12 +48,16 @@
#define GNC_IS_CUSTOMER(obj) (QOF_CHECK_TYPE((obj), GNC_ID_CUSTOMER))
#define GNC_CUSTOMER(obj) (QOF_CHECK_CAST((obj), GNC_ID_CUSTOMER, GncCustomer))
-/* Create/Destroy Functions */
-
+/** @name Create/Destroy Functions */
+/** @{ */
GncCustomer *gncCustomerCreate (QofBook *book);
void gncCustomerDestroy (GncCustomer *customer);
+void gncCustomerBeginEdit (GncCustomer *customer);
+void gncCustomerCommitEdit (GncCustomer *customer);
+/** @} */
-/* Set Functions */
+/** @name Set Functions */
+/** @{ */
void gncCustomerSetID (GncCustomer *customer, const char *id);
void gncCustomerSetName (GncCustomer *customer, const char *name);
@@ -67,11 +74,10 @@
void gncCustomerAddJob (GncCustomer *customer, GncJob *job);
void gncCustomerRemoveJob (GncCustomer *customer, GncJob *job);
+/** @} */
-void gncCustomerBeginEdit (GncCustomer *customer);
-void gncCustomerCommitEdit (GncCustomer *customer);
-
-/* Get Functions */
+/** @name Get Functions */
+/** @{ */
/** Return a pointer to the instance gncCustomer that is identified
* by the guid, and is residing in the book. Returns NULL if the
* instance can't be found.
@@ -98,6 +104,7 @@
KvpFrame *gncCustomerGetSlots (GncCustomer *customer);
GList * gncCustomerGetJoblist (GncCustomer *customer, gboolean show_all);
+/** @} */
@@ -109,10 +116,12 @@
#define CUSTOMER_ADDR "addr"
#define CUSTOMER_SHIPADDR "shipaddr"
-/* deprecated functions, should be removed */
+/** @deprecated functions, should be removed */
#define gncCustomerGetGUID(x) qof_instance_get_guid(QOF_INSTANCE(x))
#define gncCustomerRetGUID(x) (x ? *(qof_instance_get_guid(QOF_INSTANCE(x))) : *(guid_null()))
#define gncCustomerGetBook(x) qof_instance_get_book(QOF_INSTANCE(x))
#define gncCustomerLookupDirect(g,b) gncCustomerLookup((b), &(g))
#endif /* GNC_CUSTOMER_H_ */
+/** @} */
+/** @} */
Index: gncInvoice.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncInvoice.c,v
retrieving revision 1.56.4.4
retrieving revision 1.56.4.5
diff -Lsrc/business/business-core/gncInvoice.c -Lsrc/business/business-core/gncInvoice.c -u -r1.56.4.4 -r1.56.4.5
--- src/business/business-core/gncInvoice.c
+++ src/business/business-core/gncInvoice.c
@@ -30,6 +30,7 @@
#include <glib.h>
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -49,7 +50,6 @@
#include "gnc-event-p.h"
#include "gnc-lot.h"
-#include "gnc-be-utils.h"
#include "gncBusiness.h"
#include "gncBillTermP.h"
@@ -1295,7 +1295,7 @@
void gncInvoiceBeginEdit (GncInvoice *invoice)
{
- GNC_BEGIN_EDIT (&invoice->inst);
+ QOF_BEGIN_EDIT (&invoice->inst);
}
static inline void gncInvoiceOnError (QofInstance *inst, QofBackendError errcode)
@@ -1313,8 +1313,8 @@
void gncInvoiceCommitEdit (GncInvoice *invoice)
{
- GNC_COMMIT_EDIT_PART1 (&invoice->inst);
- GNC_COMMIT_EDIT_PART2 (&invoice->inst, gncInvoiceOnError,
+ QOF_COMMIT_EDIT_PART1 (&invoice->inst);
+ QOF_COMMIT_EDIT_PART2 (&invoice->inst, gncInvoiceOnError,
gncInvoiceOnDone, invoice_free);
}
@@ -1363,12 +1363,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Invoice",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
printable: _gncInvoicePrintable,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
static void
@@ -1413,9 +1415,9 @@
{ INVOICE_TYPE, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetType, NULL },
{ INVOICE_TERMS, GNC_ID_BILLTERM, (QofAccessFunc)gncInvoiceGetTerms, NULL },
{ INVOICE_BILLTO, GNC_ID_OWNER, (QofAccessFunc)gncInvoiceGetBillTo, NULL },
- { QOF_QUERY_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceGetActive, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceGetActive, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncEmployee.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncEmployee.h,v
retrieving revision 1.8.4.3
retrieving revision 1.8.4.4
diff -Lsrc/business/business-core/gncEmployee.h -Lsrc/business/business-core/gncEmployee.h -u -r1.8.4.3 -r1.8.4.4
--- src/business/business-core/gncEmployee.h
+++ src/business/business-core/gncEmployee.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Employee
+ @{ */
+/** @file gncEmployee.h
+ @brief Employee Interface
+ @author Copyright (C) 2001 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_EMPLOYEE_H_
#define GNC_EMPLOYEE_H_
@@ -40,13 +43,17 @@
#define GNC_IS_EMPLOYEE(obj) (QOF_CHECK_TYPE((obj), GNC_ID_EMPLOYEE))
#define GNC_EMPLOYEE(obj) (QOF_CHECK_CAST((obj), GNC_ID_EMPLOYEE, GncEmployee))
-/* Create/Destroy Functions */
-
+/** @name Create/Destroy Functions */
+/** @{ */
GncEmployee *gncEmployeeCreate (QofBook *book);
void gncEmployeeDestroy (GncEmployee *employee);
+void gncEmployeeBeginEdit (GncEmployee *employee);
+void gncEmployeeCommitEdit (GncEmployee *employee);
+int gncEmployeeCompare (GncEmployee *a, GncEmployee *b);
+/** @} */
-/* Set Functions */
-
+/** @name Set Functions */
+/** @{ */
void gncEmployeeSetID (GncEmployee *employee, const char *id);
void gncEmployeeSetUsername (GncEmployee *employee, const char *username);
void gncEmployeeSetLanguage (GncEmployee *employee, const char *language);
@@ -56,9 +63,10 @@
void gncEmployeeSetCurrency (GncEmployee *employee, gnc_commodity * currency);
void gncEmployeeSetActive (GncEmployee *employee, gboolean active);
void gncEmployeeSetCCard (GncEmployee *employee, Account* ccard_acc);
+/** @} */
-/* Get Functions */
-
+/** @name Get Functions */
+/** @{ */
QofBook * gncEmployeeGetBook (GncEmployee *employee);
const char * gncEmployeeGetID (GncEmployee *employee);
const char * gncEmployeeGetUsername (GncEmployee *employee);
@@ -70,6 +78,7 @@
gnc_commodity * gncEmployeeGetCurrency (GncEmployee *employee);
gboolean gncEmployeeGetActive (GncEmployee *employee);
Account * gncEmployeeGetCCard (GncEmployee *employee);
+/** @} */
/** Return a pointer to the instance gncEmployee that is identified
@@ -84,9 +93,6 @@
gboolean gncEmployeeIsDirty (GncEmployee *employee);
-void gncEmployeeBeginEdit (GncEmployee *employee);
-void gncEmployeeCommitEdit (GncEmployee *employee);
-int gncEmployeeCompare (GncEmployee *a, GncEmployee *b);
#define EMPLOYEE_ID "id"
#define EMPLOYEE_USERNAME "username"
@@ -98,3 +104,5 @@
#define gncEmployeeLookupDirect(G,B) gncEmployeeLookup((B),&(G))
#endif /* GNC_EMPLOYEE_H_ */
+/** @} */
+/** @} */
Index: gncVendor.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncVendor.h,v
retrieving revision 1.14.4.3
retrieving revision 1.14.4.4
diff -Lsrc/business/business-core/gncVendor.h -Lsrc/business/business-core/gncVendor.h -u -r1.14.4.3 -r1.14.4.4
--- src/business/business-core/gncVendor.h
+++ src/business/business-core/gncVendor.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001, 2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Vendor
+ @{ */
+/** @file gncVendor.h
+ @brief Vendor Interface
+ @author Copyright (C) 2001,2002 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_VENDOR_H_
#define GNC_VENDOR_H_
@@ -107,3 +110,5 @@
#define gncVendorLookupDirect(G,B) gncVendorLookup((B),&(G))
#endif /* GNC_VENDOR_H_ */
+/** @} */
+/** @} */
Index: gncOrder.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncOrder.h,v
retrieving revision 1.13.4.2
retrieving revision 1.13.4.3
diff -Lsrc/business/business-core/gncOrder.h -Lsrc/business/business-core/gncOrder.h -u -r1.13.4.2 -r1.13.4.3
--- src/business/business-core/gncOrder.h
+++ src/business/business-core/gncOrder.h
@@ -19,11 +19,17 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
+/* NOTE: Removed from doxygen by warlord on 2004-05-07 because
+ * this module is not fully implemented at this time.
*/
+/* @addtogroup Business
+ @{ */
+/* @addtogroup Order
+ @{ */
+/* @file gncOrder.h
+ @brief Business Order Interface
+ @author Copyright (C) 2001 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_ORDER_H_
#define GNC_ORDER_H_
@@ -101,3 +107,5 @@
#define gncOrderGetBook(x) qof_instance_get_book(QOF_INSTANCE(x))
#endif /* GNC_ORDER_H_ */
+/** @} */
+/** @} */
Index: gncAddress.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncAddress.h,v
retrieving revision 1.4.4.2
retrieving revision 1.4.4.3
diff -Lsrc/business/business-core/gncAddress.h -Lsrc/business/business-core/gncAddress.h -u -r1.4.4.2 -r1.4.4.3
--- src/business/business-core/gncAddress.h
+++ src/business/business-core/gncAddress.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Address
+ @{ */
+/** @file gncAddress.h
+ @brief an Address object
+ @author Copyright (C) 2001 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_ADDRESS_H_
#define GNC_ADDRESS_H_
@@ -35,11 +38,14 @@
typedef struct _gncAddress GncAddress;
-/* Create/Destroy functions */
+/** @name Create/Destroy functions */
+/** @{ */
GncAddress * gncAddressCreate (QofBook *book, QofEntity *parent);
void gncAddressDestroy (GncAddress *addr);
+/** @} */
-/* Set functions */
+/** @name Set functions */
+/** @{ */
void gncAddressSetName (GncAddress *addr, const char *name);
void gncAddressSetAddr1 (GncAddress *addr, const char *addr1);
@@ -50,8 +56,10 @@
void gncAddressSetFax (GncAddress *addr, const char *fax);
void gncAddressSetEmail (GncAddress *addr, const char *email);
void gncAddressClearDirty (GncAddress *address);
+/** @} */
-/* Get Functions */
+/** @name Get Functions */
+/** @{ */
const char * gncAddressGetName (const GncAddress *addr);
const char * gncAddressGetAddr1 (const GncAddress *addr);
@@ -61,6 +69,8 @@
const char * gncAddressGetPhone (const GncAddress *addr);
const char * gncAddressGetFax (const GncAddress *addr);
const char * gncAddressGetEmail (const GncAddress *addr);
+/** @} */
+
gboolean gncAddressIsDirty (const GncAddress *addr);
int gncAddressCompare (const GncAddress *a, const GncAddress *b);
@@ -71,3 +81,5 @@
#define ADDRESS_EMAIL "email"
#endif /* GNC_ADDRESS_H_ */
+/** @} */
+/** @} */
Index: gncBusiness.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncBusiness.h,v
retrieving revision 1.8.4.2
retrieving revision 1.8.4.3
diff -Lsrc/business/business-core/gncBusiness.h -Lsrc/business/business-core/gncBusiness.h -u -r1.8.4.2 -r1.8.4.3
--- src/business/business-core/gncBusiness.h
+++ src/business/business-core/gncBusiness.h
@@ -1,7 +1,4 @@
-/*
- * gncBusiness.h -- Business Helper Functions
- * Copyright (C) 2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
+/* gncBusiness.h -- Business Helper Functions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -19,15 +16,26 @@
* 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
- *
- * Currently mostly not used ...
+ */
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup Business
+ The Business Engine provides a set of structures for
+ that provide small-business accounting features.
+ @{ */
+
+/** @file gncBusiness.h -- Business Helper Functions
+ * @author Copyright (C) 2002 Derek Atkins
+ * @author Derek Atkins <warlord at MIT.EDU>
*/
+/** @} */
+/** @} */
#ifndef GNC_BUSINESS_H_
#define GNC_BUSINESS_H_
-/* deprecated backwards-compat definitions */
+/* @deprecated backwards-compat definitions */
#define GNC_BILLTERM_MODULE_NAME GNC_ID_BILLTERM
#define GNC_CUSTOMER_MODULE_NAME GNC_ID_CUSTOMER
#define GNC_EMPLOYEE_MODULE_NAME GNC_ID_EMPLOYEE
Index: gncInvoice.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncInvoice.h,v
retrieving revision 1.29.4.3
retrieving revision 1.29.4.4
diff -Lsrc/business/business-core/gncInvoice.h -Lsrc/business/business-core/gncInvoice.h -u -r1.29.4.3 -r1.29.4.4
--- src/business/business-core/gncInvoice.h
+++ src/business/business-core/gncInvoice.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Invoice
+ @{ */
+/** @file gncInvoice.h
+ @brief Business Invoice Interface
+ @author Copyright (C) 2001 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_INVOICE_H_
#define GNC_INVOICE_H_
@@ -43,13 +46,14 @@
#define GNC_IS_INVOICE(obj) (QOF_CHECK_TYPE((obj), GNC_ID_INVOICE))
#define GNC_INVOICE(obj) (QOF_CHECK_CAST((obj), GNC_ID_INVOICE, GncInvoice))
-/* Create/Destroy Functions */
-
+/** @name Create/Destroy Functions */
+/** @{ */
GncInvoice *gncInvoiceCreate (QofBook *book);
void gncInvoiceDestroy (GncInvoice *invoice);
+/** @} */
-/* Set Functions */
-
+/** @name Set Functions */
+/** @{ */
void gncInvoiceSetID (GncInvoice *invoice, const char *id);
void gncInvoiceSetOwner (GncInvoice *invoice, GncOwner *owner);
void gncInvoiceSetDateOpened (GncInvoice *invoice, Timespec date);
@@ -61,16 +65,17 @@
void gncInvoiceSetActive (GncInvoice *invoice, gboolean active);
void gncInvoiceSetBillTo (GncInvoice *invoice, GncOwner *billto);
void gncInvoiceSetToChargeAmount (GncInvoice *invoice, gnc_numeric amount);
+/** @} */
void gncInvoiceAddEntry (GncInvoice *invoice, GncEntry *entry);
void gncInvoiceRemoveEntry (GncInvoice *invoice, GncEntry *entry);
-/* Call this function when adding an entry to a bill instead of an invoice */
+/** Call this function when adding an entry to a bill instead of an invoice */
void gncBillAddEntry (GncInvoice *bill, GncEntry *entry);
void gncBillRemoveEntry (GncInvoice *bill, GncEntry *entry);
-/* Get Functions */
-
+/** @name Get Functions */
+/** @{ */
const char * gncInvoiceGetID (GncInvoice *invoice);
GncOwner * gncInvoiceGetOwner (GncInvoice *invoice);
Timespec gncInvoiceGetDateOpened (GncInvoice *invoice);
@@ -88,8 +93,9 @@
GNCLot * gncInvoiceGetPostedLot (GncInvoice *invoice);
Transaction * gncInvoiceGetPostedTxn (GncInvoice *invoice);
Account * gncInvoiceGetPostedAcc (GncInvoice *invoice);
+/** @} */
-/* return the "total" amount of the invoice */
+/** return the "total" amount of the invoice */
gnc_numeric gncInvoiceGetTotal (GncInvoice *invoice);
gnc_numeric gncInvoiceGetTotalOf (GncInvoice *invoice, GncEntryPaymentType type);
gnc_numeric gncInvoiceGetTotalSubtotal (GncInvoice *invoice);
@@ -97,7 +103,7 @@
GList * gncInvoiceGetEntries (GncInvoice *invoice);
-/* Post this invoice to an account. Returns the new Transaction
+/** Post this invoice to an account. Returns the new Transaction
* that is tied to this invoice. The transaction is set with
* the supplied posted date, due date, and memo. The Transaction
* description is set to the name of the company.
@@ -107,7 +113,7 @@
Timespec *posted_date, Timespec *due_date,
const char *memo);
-/*
+/**
* UNpost this invoice. This will destroy the posted transaction and
* return the invoice to its unposted state. It may leave empty lots
* out there. If reset_tax_tables is TRUE, then it will also revert
@@ -120,7 +126,7 @@
gboolean
gncInvoiceUnpost (GncInvoice *invoice, gboolean reset_tax_tables);
-/*
+/**
* Apply a payment of "amount" for the owner, between the xfer_account
* (bank or other asset) and the posted_account (A/R or A/P).
*
@@ -133,10 +139,10 @@
const char *memo, const char *num);
-/* Given a transaction, find and return the Invoice */
+/** Given a transaction, find and return the Invoice */
GncInvoice * gncInvoiceGetInvoiceFromTxn (Transaction *txn);
-/* Given a LOT, find and return the Invoice attached to the lot */
+/** Given a LOT, find and return the Invoice attached to the lot */
GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot);
/** Return a pointer to the instance gncInvoice that is identified
@@ -181,3 +187,5 @@
#define gncInvoiceLookupDirect(G,B) gncInvoiceLookup((B),&(G))
#endif /* GNC_INVOICE_H_ */
+/** @} */
+/** @} */
Index: gncOwner.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncOwner.h,v
retrieving revision 1.12.4.2
retrieving revision 1.12.4.3
diff -Lsrc/business/business-core/gncOwner.h -Lsrc/business/business-core/gncOwner.h -u -r1.12.4.2 -r1.12.4.3
--- src/business/business-core/gncOwner.h
+++ src/business/business-core/gncOwner.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001, 2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Owner
+ @{ */
+/** @file gncOwner.h
+ @brief Business Interface: Object OWNERs
+ @author Copyright (C) 2001,2002 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_OWNER_H_
#define GNC_OWNER_H_
@@ -78,23 +81,23 @@
const char * gncOwnerGetName (GncOwner *owner);
gnc_commodity * gncOwnerGetCurrency (GncOwner *owner);
-/* Get the GUID of the immediate owner */
+/** Get the GUID of the immediate owner */
const GUID * gncOwnerGetGUID (GncOwner *owner);
GUID gncOwnerRetGUID (GncOwner *owner);
gboolean gncOwnerIsValid (GncOwner *owner);
-/*
+/**
* Get the "parent" Owner or GUID thereof. The "parent" owner
* is the Customer or Vendor, or the Owner of a Job
*/
GncOwner * gncOwnerGetEndOwner (GncOwner *owner);
const GUID * gncOwnerGetEndGUID (GncOwner *owner);
-/* attach an owner to a lot */
+/** attach an owner to a lot */
void gncOwnerAttachToLot (GncOwner *owner, GNCLot *lot);
-/* Get the owner from the lot. If an owner is found in the lot,
+/** Get the owner from the lot. If an owner is found in the lot,
* fill in "owner" and return TRUE. Otherwise return FALSE.
*/
gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner);
@@ -110,7 +113,7 @@
#define OWNER_FROM_LOT "owner-from-lot"
-/*
+/**
* These two functions are mainly for the convenience of scheme code.
* Normal C code has no need to ever use these two functions, and rather
* can just use a GncOwner directly and just pass around a pointer to it.
@@ -119,3 +122,5 @@
void gncOwnerDestroy (GncOwner *owner);
#endif /* GNC_OWNER_H_ */
+/** @} */
+/** @} */
Index: gncTaxTable.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncTaxTable.h,v
retrieving revision 1.7.4.3
retrieving revision 1.7.4.4
diff -Lsrc/business/business-core/gncTaxTable.h -Lsrc/business/business-core/gncTaxTable.h -u -r1.7.4.3 -r1.7.4.4
--- src/business/business-core/gncTaxTable.h
+++ src/business/business-core/gncTaxTable.h
@@ -19,10 +19,12 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Business-Engine
+/** @addtogroup Business
+ @{ */
+/** @addtogroup TaxTable
@{ */
/** @file gncTaxTable.h
- @breif Tax Table programming interface
+ @brief Tax Table programming interface
@author Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU>
*/
@@ -67,7 +69,8 @@
const char * gncTaxIncludedTypeToString (GncTaxIncluded type);
gboolean gncTaxIncludedStringToType (const char *str, GncTaxIncluded *type);
-/** Create/Destroy Functions */
+/** @name Create/Destroy Functions */
+/** @{ */
GncTaxTable * gncTaxTableCreate (QofBook *book);
void gncTaxTableDestroy (GncTaxTable *table);
GncTaxTableEntry * gncTaxTableEntryCreate (void);
@@ -88,8 +91,10 @@
void gncTaxTableChanged (GncTaxTable *table);
void gncTaxTableBeginEdit (GncTaxTable *table);
void gncTaxTableCommitEdit (GncTaxTable *table);
+/** @} */
-/** Get Functions */
+/** @name Get Functions */
+/** @{ */
/** Return a pointer to the instance gncTaxTable that is identified
* by the guid, and is residing in the book. Returns NULL if the
@@ -115,6 +120,7 @@
Account * gncTaxTableEntryGetAccount (GncTaxTableEntry *entry);
GncAmountType gncTaxTableEntryGetType (GncTaxTableEntry *entry);
gnc_numeric gncTaxTableEntryGetAmount (GncTaxTableEntry *entry);
+/** @} */
int gncTaxTableCompare (GncTaxTable *a, GncTaxTable *b);
int gncTaxTableEntryCompare (GncTaxTableEntry *a, GncTaxTableEntry *b);
@@ -141,10 +147,11 @@
/** Destroy a list of accountvalues */
void gncAccountValueDestroy (GList *list);
-/** deprecated routine */
+/** @deprecated routine */
#define gncTaxTableGetGUID(x) qof_instance_get_guid(QOF_INSTANCE(x))
#define gncTaxTableRetGUID(x) (x ? *(qof_instance_get_guid(QOF_INSTANCE(x))) : *(guid_null()))
#define gncTaxTableLookupDirect(G,B) gncTaxTableLookup((B), &(G))
#endif /* GNC_TAXTABLE_H_ */
/** @} */
+/** @} */
Index: gncOwner.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncOwner.c,v
retrieving revision 1.15.4.2
retrieving revision 1.15.4.3
diff -Lsrc/business/business-core/gncOwner.c -Lsrc/business/business-core/gncOwner.c -u -r1.15.4.2 -r1.15.4.3
--- src/business/business-core/gncOwner.c
+++ src/business/business-core/gncOwner.c
@@ -406,7 +406,7 @@
{ OWNER_PARENT, GNC_ID_OWNER, (QofAccessFunc)gncOwnerGetEndOwner, NULL },
{ OWNER_PARENTG, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetEndGUID, NULL },
{ OWNER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncOwnerGetName, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetGUID, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetGUID, NULL },
{ NULL },
};
Index: gncJob.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncJob.h,v
retrieving revision 1.9.4.3
retrieving revision 1.9.4.4
diff -Lsrc/business/business-core/gncJob.h -Lsrc/business/business-core/gncJob.h -u -r1.9.4.3 -r1.9.4.4
--- src/business/business-core/gncJob.h
+++ src/business/business-core/gncJob.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001, 2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Job
+ @{ */
+/** @file gncJob.h
+ @brief Job Interface
+ @author Copyright (C) 2001, 2002 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_JOB_H_
#define GNC_JOB_H_
@@ -90,3 +93,5 @@
#define gncJobLookupDirect(G,B) gncJobLookup((B),&(G))
#endif /* GNC_JOB_H_ */
+/** @} */
+/** @} */
Index: gncEntry.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncEntry.h,v
retrieving revision 1.22.4.2
retrieving revision 1.22.4.3
diff -Lsrc/business/business-core/gncEntry.h -Lsrc/business/business-core/gncEntry.h -u -r1.22.4.2 -r1.22.4.3
--- src/business/business-core/gncEntry.h
+++ src/business/business-core/gncEntry.h
@@ -19,11 +19,14 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * Copyright (C) 2001,2002 Derek Atkins
- * Author: Derek Atkins <warlord at MIT.EDU>
- */
+/** @addtogroup Business
+ @{ */
+/** @addtogroup Entry
+ @{ */
+/** @file gncEntry.h
+ @brief Business Entry Interface
+ @author Copyright (C) 2001,2002 Derek Atkins <warlord at MIT.EDU>
+*/
#ifndef GNC_ENTRY_H_
#define GNC_ENTRY_H_
@@ -54,7 +57,7 @@
#define GNC_IS_ENTRY(obj) (QOF_CHECK_TYPE((obj), GNC_ID_ENTRY))
#define GNC_ENTRY(obj) (QOF_CHECK_CAST((obj), GNC_ID_ENTRY, GncEntry))
-/* How to apply the discount and taxes. There are three distinct ways to
+/** How to apply the discount and taxes. There are three distinct ways to
* apply them:
*
* Type: discount tax
@@ -69,22 +72,26 @@
const char * gncEntryPaymentTypeToString (GncEntryPaymentType type);
gboolean gncEntryPaymentStringToType (const char *str, GncEntryPaymentType *type);
-/* Create/Destroy Functions */
-
+/** @name Create/Destroy Functions */
+/** @{ */
GncEntry *gncEntryCreate (QofBook *book);
void gncEntryDestroy (GncEntry *entry);
+/** @} */
/* SET FUNCTIONS */
-/* Generic (shared) data */
+/** @name Generic (shared) data */
+/** @{ */
void gncEntrySetDate (GncEntry *entry, Timespec date);
void gncEntrySetDateEntered (GncEntry *entry, Timespec date);
void gncEntrySetDescription (GncEntry *entry, const char *desc);
void gncEntrySetAction (GncEntry *entry, const char *action);
void gncEntrySetNotes (GncEntry *entry, const char *notes);
void gncEntrySetQuantity (GncEntry *entry, gnc_numeric quantity);
+/** @} */
-/* Customer Invoices */
+/** @name Customer Invoices */
+/** @{ */
void gncEntrySetInvAccount (GncEntry *entry, Account *acc);
void gncEntrySetInvPrice (GncEntry *entry, gnc_numeric price);
void gncEntrySetInvTaxable (GncEntry *entry, gboolean taxable);
@@ -93,8 +100,10 @@
void gncEntrySetInvDiscount (GncEntry *entry, gnc_numeric discount);
void gncEntrySetInvDiscountType (GncEntry *entry, GncAmountType type);
void gncEntrySetInvDiscountHow (GncEntry *entry, GncDiscountHow how);
+/** @} */
-/* Vendor Bills (and Employee Expenses) */
+/** @name Vendor Bills (and Employee Expenses) */
+/** @{ */
void gncEntrySetBillAccount (GncEntry *entry, Account *acc);
void gncEntrySetBillPrice (GncEntry *entry, gnc_numeric price);
void gncEntrySetBillTaxable (GncEntry *entry, gboolean taxable);
@@ -102,20 +111,26 @@
void gncEntrySetBillTaxTable (GncEntry *entry, GncTaxTable *table);
void gncEntrySetBillable (GncEntry *entry, gboolean billable);
void gncEntrySetBillTo (GncEntry *entry, GncOwner *billto);
+/** @} */
-/* employee-stuff */
+/** @name employee-stuff */
+/** @{ */
void gncEntrySetBillPayment (GncEntry *entry, GncEntryPaymentType type);
+/** @} */
/* GET FUNCTIONS */
-/* Generic (shared) data */
+/** @name Generic (shared) data */
+/** @{ */
Timespec gncEntryGetDate (GncEntry *entry);
Timespec gncEntryGetDateEntered (GncEntry *entry);
const char * gncEntryGetDescription (GncEntry *entry);
const char * gncEntryGetAction (GncEntry *entry);
const char * gncEntryGetNotes (GncEntry *notes);
gnc_numeric gncEntryGetQuantity (GncEntry *entry);
+/** @} */
-/* Customer Invoices */
+/** @name Customer Invoices */
+/** @{ */
Account * gncEntryGetInvAccount (GncEntry *entry);
gnc_numeric gncEntryGetInvPrice (GncEntry *entry);
gnc_numeric gncEntryGetInvDiscount (GncEntry *entry);
@@ -124,8 +139,10 @@
gboolean gncEntryGetInvTaxable (GncEntry *entry);
gboolean gncEntryGetInvTaxIncluded (GncEntry *entry);
GncTaxTable * gncEntryGetInvTaxTable (GncEntry *entry);
+/** @} */
-/* Vendor Bills (and Employee Expenses) */
+/** @name Vendor Bills (and Employee Expenses) */
+/** @{ */
Account * gncEntryGetBillAccount (GncEntry *entry);
gnc_numeric gncEntryGetBillPrice (GncEntry *entry);
gboolean gncEntryGetBillTaxable (GncEntry *entry);
@@ -135,10 +152,13 @@
GncOwner *gncEntryGetBillTo (GncEntry *entry);
GncEntryPaymentType gncEntryGetBillPayment (GncEntry* entry);
+/** @} */
void gncEntryCopy (const GncEntry *src, GncEntry *dest);
-/* The first three return the rounded values -- the last returns the
+/** @name Getting Values */
+/** @{ */
+/** The first three return the rounded values -- the last returns the
* list of unrounded account-values. The list belongs to the entry
* and will be destroyed, so use it quickly.
*/
@@ -147,7 +167,7 @@
gnc_numeric gncEntryReturnTaxValue (GncEntry *entry, gboolean is_inv);
GList * gncEntryReturnTaxValues (GncEntry *entry, gboolean is_inv);
-/* Compute the Entry value, tax-value, and discount_value, based on
+/** Compute the Entry value, tax-value, and discount_value, based on
* the quantity, price, discount, tax-table, and types. The value is
* the amount the merchant gets, the taxes are what the gov't gets,
* and the discount is how much the customer saved.
@@ -168,6 +188,8 @@
gnc_numeric *value, gnc_numeric *discount_value,
GList **tax_values);
+/** @} */
+
GncOrder * gncEntryGetOrder (GncEntry *entry);
GncInvoice * gncEntryGetInvoice (GncEntry *entry);
GncInvoice * gncEntryGetBill (GncEntry *entry);
@@ -206,3 +228,5 @@
#define gncEntryGetGUID(x) qof_instance_get_guid(QOF_INSTANCE(x))
#endif /* GNC_ENTRY_H_ */
+/** @} */
+/** @} */
Index: gncCustomer.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncCustomer.c,v
retrieving revision 1.20.4.2
retrieving revision 1.20.4.3
diff -Lsrc/business/business-core/gncCustomer.c -Lsrc/business/business-core/gncCustomer.c -u -r1.20.4.2 -r1.20.4.3
--- src/business/business-core/gncCustomer.c
+++ src/business/business-core/gncCustomer.c
@@ -36,8 +36,8 @@
#include "gnc-commodity.h"
#include "gnc-numeric.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid-p.h"
@@ -377,7 +377,7 @@
void gncCustomerBeginEdit (GncCustomer *cust)
{
- GNC_BEGIN_EDIT (&cust->inst);
+ QOF_BEGIN_EDIT (&cust->inst);
}
static inline void gncCustomerOnError (QofInstance *inst, QofBackendError errcode)
@@ -400,8 +400,8 @@
void gncCustomerCommitEdit (GncCustomer *cust)
{
- GNC_COMMIT_EDIT_PART1 (&cust->inst);
- GNC_COMMIT_EDIT_PART2 (&cust->inst, gncCustomerOnError,
+ QOF_COMMIT_EDIT_PART1 (&cust->inst);
+ QOF_COMMIT_EDIT_PART2 (&cust->inst, gncCustomerOnError,
gncCustomerOnDone, cust_free);
}
@@ -536,12 +536,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Customer",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
printable: _gncCustomerPrintable,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncCustomerRegister (void)
@@ -551,9 +553,9 @@
{ CUSTOMER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncCustomerGetName, NULL },
{ CUSTOMER_ADDR, GNC_ADDRESS_MODULE_NAME, (QofAccessFunc)gncCustomerGetAddr, NULL },
{ CUSTOMER_SHIPADDR, GNC_ADDRESS_MODULE_NAME, (QofAccessFunc)gncCustomerGetShipAddr, NULL },
- { QOF_QUERY_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetActive, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetActive, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncVendor.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncVendor.c,v
retrieving revision 1.21.4.2
retrieving revision 1.21.4.3
diff -Lsrc/business/business-core/gncVendor.c -Lsrc/business/business-core/gncVendor.c -u -r1.21.4.2 -r1.21.4.3
--- src/business/business-core/gncVendor.c
+++ src/business/business-core/gncVendor.c
@@ -32,6 +32,7 @@
#include <string.h>
#include "guid.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -46,7 +47,6 @@
#include "gnc-commodity.h"
#include "gnc-engine-util.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
#include "gncAddressP.h"
#include "gncBillTermP.h"
@@ -409,7 +409,7 @@
void gncVendorBeginEdit (GncVendor *vendor)
{
- GNC_BEGIN_EDIT (&vendor->inst);
+ QOF_BEGIN_EDIT (&vendor->inst);
}
static inline void gncVendorOnError (QofInstance *vendor, QofBackendError errcode)
@@ -431,8 +431,8 @@
void gncVendorCommitEdit (GncVendor *vendor)
{
- GNC_COMMIT_EDIT_PART1 (&vendor->inst);
- GNC_COMMIT_EDIT_PART2 (&vendor->inst, gncVendorOnError,
+ QOF_COMMIT_EDIT_PART1 (&vendor->inst);
+ QOF_COMMIT_EDIT_PART2 (&vendor->inst, gncVendorOnError,
gncVendorOnDone, vendor_free);
}
@@ -486,12 +486,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Vendor",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
- printable: _gncVendorPrintable
+ printable: _gncVendorPrintable,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncVendorRegister (void)
@@ -500,9 +502,9 @@
{ VENDOR_ID, QOF_TYPE_STRING, (QofAccessFunc)gncVendorGetID, NULL },
{ VENDOR_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncVendorGetName, NULL },
{ VENDOR_ADDR, GNC_ADDRESS_MODULE_NAME, (QofAccessFunc)gncVendorGetAddr, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
- { QOF_QUERY_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncVendorGetActive, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncVendorGetActive, NULL },
{ NULL },
};
Index: gncBillTerm.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncBillTerm.c,v
retrieving revision 1.6.4.2
retrieving revision 1.6.4.3
diff -Lsrc/business/business-core/gncBillTerm.c -Lsrc/business/business-core/gncBillTerm.c -u -r1.6.4.2 -r1.6.4.3
--- src/business/business-core/gncBillTerm.c
+++ src/business/business-core/gncBillTerm.c
@@ -36,9 +36,9 @@
#include "gnc-engine-util.h"
#include "qofquerycore.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
#include "kvp_frame.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -404,7 +404,7 @@
void gncBillTermBeginEdit (GncBillTerm *term)
{
- GNC_BEGIN_EDIT (&term->inst);
+ QOF_BEGIN_EDIT (&term->inst);
}
static void gncBillTermOnError (QofInstance *inst, QofBackendError errcode)
@@ -422,8 +422,8 @@
void gncBillTermCommitEdit (GncBillTerm *term)
{
- GNC_COMMIT_EDIT_PART1 (&term->inst);
- GNC_COMMIT_EDIT_PART2 (&term->inst, gncBillTermOnError,
+ QOF_COMMIT_EDIT_PART1 (&term->inst);
+ QOF_COMMIT_EDIT_PART2 (&term->inst, gncBillTermOnError,
on_done, bill_free);
}
@@ -678,19 +678,21 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Billing Term",
+ create: NULL,
book_begin: _gncBillTermCreate,
book_end: _gncBillTermDestroy,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
- printable: NULL
+ printable: NULL,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncBillTermRegister (void)
{
static QofParam params[] = {
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncJob.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncJob.c,v
retrieving revision 1.18.4.3
retrieving revision 1.18.4.4
diff -Lsrc/business/business-core/gncJob.c -Lsrc/business/business-core/gncJob.c -u -r1.18.4.3 -r1.18.4.4
--- src/business/business-core/gncJob.c
+++ src/business/business-core/gncJob.c
@@ -36,8 +36,8 @@
#include "gnc-engine-util.h"
#include "gnc-numeric.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofinstance.h"
@@ -271,7 +271,7 @@
void gncJobBeginEdit (GncJob *job)
{
- GNC_BEGIN_EDIT (&job->inst);
+ QOF_BEGIN_EDIT (&job->inst);
}
static void gncJobOnError (QofInstance *inst, QofBackendError errcode)
@@ -289,8 +289,8 @@
void gncJobCommitEdit (GncJob *job)
{
- GNC_COMMIT_EDIT_PART1 (&job->inst);
- GNC_COMMIT_EDIT_PART2 (&job->inst, gncJobOnError,
+ QOF_COMMIT_EDIT_PART1 (&job->inst);
+ QOF_COMMIT_EDIT_PART2 (&job->inst, gncJobOnError,
gncJobOnDone, job_free);
}
@@ -353,12 +353,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Job",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
- printable: _gncJobPrintable
+ printable: _gncJobPrintable,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncJobRegister (void)
@@ -369,9 +371,9 @@
{ JOB_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncJobGetActive, NULL },
{ JOB_REFERENCE, QOF_TYPE_STRING, (QofAccessFunc)gncJobGetReference, NULL },
{ JOB_OWNER, GNC_ID_OWNER, (QofAccessFunc)gncJobGetOwner, NULL },
- { QOF_QUERY_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncJobGetActive, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncJobGetActive, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncEntry.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncEntry.c,v
retrieving revision 1.32.4.2
retrieving revision 1.32.4.3
diff -Lsrc/business/business-core/gncEntry.c -Lsrc/business/business-core/gncEntry.c -u -r1.32.4.2 -r1.32.4.3
--- src/business/business-core/gncEntry.c
+++ src/business/business-core/gncEntry.c
@@ -34,8 +34,8 @@
#include "gnc-engine-util.h"
#include "gnc-event-p.h"
#include "gnc-numeric.h"
-#include "gnc-be-utils.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -1115,7 +1115,7 @@
void gncEntryBeginEdit (GncEntry *entry)
{
- GNC_BEGIN_EDIT (&entry->inst);
+ QOF_BEGIN_EDIT (&entry->inst);
}
static inline void gncEntryOnError (QofInstance *entry, QofBackendError errcode)
@@ -1133,8 +1133,8 @@
void gncEntryCommitEdit (GncEntry *entry)
{
- GNC_COMMIT_EDIT_PART1 (&entry->inst);
- GNC_COMMIT_EDIT_PART2 (&entry->inst, gncEntryOnError,
+ QOF_COMMIT_EDIT_PART1 (&entry->inst);
+ QOF_COMMIT_EDIT_PART2 (&entry->inst, gncEntryOnError,
gncEntryOnDone, entry_free);
}
@@ -1169,12 +1169,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Order/Invoice/Bill Entry",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
printable: NULL,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncEntryRegister (void)
@@ -1193,8 +1195,8 @@
{ ENTRY_BILLABLE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEntryGetBillable, NULL },
{ ENTRY_BILLTO, GNC_ID_OWNER, (QofAccessFunc)gncEntryGetBillTo, NULL },
{ ENTRY_ORDER, GNC_ID_ORDER, (QofAccessFunc)gncEntryGetOrder, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncTaxTable.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncTaxTable.c,v
retrieving revision 1.9.4.2
retrieving revision 1.9.4.3
diff -Lsrc/business/business-core/gncTaxTable.c -Lsrc/business/business-core/gncTaxTable.c -u -r1.9.4.2 -r1.9.4.3
--- src/business/business-core/gncTaxTable.c
+++ src/business/business-core/gncTaxTable.c
@@ -34,8 +34,8 @@
#include "gnc-numeric.h"
#include "gnc-engine-util.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -527,7 +527,7 @@
void gncTaxTableBeginEdit (GncTaxTable *table)
{
- GNC_BEGIN_EDIT (&table->inst);
+ QOF_BEGIN_EDIT (&table->inst);
}
static inline void gncTaxTableOnError (QofInstance *inst, QofBackendError errcode)
@@ -545,8 +545,8 @@
void gncTaxTableCommitEdit (GncTaxTable *table)
{
- GNC_COMMIT_EDIT_PART1 (&table->inst);
- GNC_COMMIT_EDIT_PART2 (&table->inst, gncTaxTableOnError,
+ QOF_COMMIT_EDIT_PART1 (&table->inst);
+ QOF_COMMIT_EDIT_PART2 (&table->inst, gncTaxTableOnError,
gncTaxTableOnDone, table_free);
}
@@ -799,19 +799,21 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Tax Table",
+ create: NULL,
book_begin: _gncTaxTableCreate,
book_end: _gncTaxTableDestroy,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
printable: NULL,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncTaxTableRegister (void)
{
static QofParam params[] = {
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncOrder.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-core/gncOrder.c,v
retrieving revision 1.23.4.2
retrieving revision 1.23.4.3
diff -Lsrc/business/business-core/gncOrder.c -Lsrc/business/business-core/gncOrder.c -u -r1.23.4.2 -r1.23.4.3
--- src/business/business-core/gncOrder.c
+++ src/business/business-core/gncOrder.c
@@ -34,6 +34,7 @@
#include "kvp_frame.h"
#include "gnc-engine-util.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofid.h"
@@ -45,7 +46,6 @@
#include "qofquerycore.h"
#include "gnc-event-p.h"
-#include "gnc-be-utils.h"
#include "gncBusiness.h"
#include "gncEntry.h"
@@ -356,7 +356,7 @@
void gncOrderBeginEdit (GncOrder *order)
{
- GNC_BEGIN_EDIT (&order->inst);
+ QOF_BEGIN_EDIT (&order->inst);
}
static inline void gncOrderOnError (QofInstance *order, QofBackendError errcode)
@@ -374,8 +374,8 @@
void gncOrderCommitEdit (GncOrder *order)
{
- GNC_COMMIT_EDIT_PART1 (&order->inst);
- GNC_COMMIT_EDIT_PART2 (&order->inst, gncOrderOnError,
+ QOF_COMMIT_EDIT_PART1 (&order->inst);
+ QOF_COMMIT_EDIT_PART2 (&order->inst, gncOrderOnError,
gncOrderOnDone, order_free);
}
@@ -425,12 +425,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: _GNC_MOD_NAME,
type_label: "Order",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: qof_collection_is_dirty,
mark_clean: qof_collection_mark_clean,
foreach: qof_collection_foreach,
printable: _gncOrderPrintable,
+ version_cmp: (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
};
gboolean gncOrderRegister (void)
@@ -443,9 +445,9 @@
{ ORDER_IS_CLOSED, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncOrderIsClosed, NULL },
{ ORDER_CLOSED, QOF_TYPE_DATE, (QofAccessFunc)gncOrderGetDateClosed, NULL },
{ ORDER_NOTES, QOF_TYPE_STRING, (QofAccessFunc)gncOrderGetNotes, NULL },
- { QOF_QUERY_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncOrderGetActive, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncOrderGetActive, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ NULL },
};
Index: gncquery.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/gncquery.c,v
retrieving revision 1.29.4.3
retrieving revision 1.29.4.4
diff -Lsrc/backend/postgres/gncquery.c -Lsrc/backend/postgres/gncquery.c -u -r1.29.4.3 -r1.29.4.4
--- src/backend/postgres/gncquery.c
+++ src/backend/postgres/gncquery.c
@@ -314,7 +314,7 @@
}
/* =========================================================== */
-/* Macro for QOF_QUERYCORE_STRING query types
+/* Macro for QOF_TYPE_STRING query types
* Note that postgres supports both case-sensitive and
* case-insensitve string searches, and it also supports
* regex! yahooo!
@@ -346,7 +346,7 @@
}
/* =========================================================== */
-/* Macro for QOF_QUERYCORE_NUMERIC type terms. The logic used here in the
+/* Macro for QOF_TYPE_NUMERIC type terms. The logic used here in the
* SQL exactly matches that used in the qofquery.c code. If
* that code is incorrect or has changed, then the code below is
* broken as well.
@@ -756,7 +756,7 @@
need_entry = TRUE;
need_trans_commodity = TRUE;
} else if (!safe_strcmp(pd->type_name, QOF_TYPE_GUID)) {
- if (!safe_strcmp(path->data, QOF_QUERY_PARAM_GUID))
+ if (!safe_strcmp(path->data, QOF_PARAM_GUID))
need_entry = TRUE;
else if (!safe_strcmp(path->data, SPLIT_ACCOUNT)) {
need_account = TRUE;
@@ -862,17 +862,17 @@
PINFO("term is QOF_TYPE_GUID");
- if (!safe_strcmp(path->data, QOF_QUERY_PARAM_GUID)) {
+ if (!safe_strcmp(path->data, QOF_PARAM_GUID)) {
field = "gncSplit.splitGuid";
g_assert(pdata->options != QOF_GUID_MATCH_ALL);
} else if (!safe_strcmp(path->data, SPLIT_TRANS) &&
- !safe_strcmp(path->next->data, QOF_QUERY_PARAM_GUID)) {
+ !safe_strcmp(path->next->data, QOF_PARAM_GUID)) {
field = "gncSplit.transGUID";
g_assert(pdata->options != QOF_GUID_MATCH_ALL);
} else if (!safe_strcmp(path->data, SPLIT_ACCOUNT) &&
- !safe_strcmp(path->next->data, QOF_QUERY_PARAM_GUID)) {
+ !safe_strcmp(path->next->data, QOF_PARAM_GUID)) {
field = "gncSplit.accountGUID";
g_assert(pdata->options != QOF_GUID_MATCH_ALL);
@@ -883,8 +883,8 @@
field = "gncSplit.accountGUID";
g_assert(pdata->options == QOF_GUID_MATCH_ALL);
- } else if (!safe_strcmp(path->data, QOF_QUERY_PARAM_BOOK) &&
- !safe_strcmp(path->next->data, QOF_QUERY_PARAM_GUID)) {
+ } else if (!safe_strcmp(path->data, QOF_PARAM_BOOK) &&
+ !safe_strcmp(path->next->data, QOF_PARAM_GUID)) {
/* XXX: Need to support the Book GUID? (gncAccount.bookGUID) */
field = "gncAccount.bookGUID";
g_assert(pdata->options != QOF_GUID_MATCH_ALL);
Index: table.m4
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/table.m4,v
retrieving revision 1.7.4.3
retrieving revision 1.7.4.4
diff -Lsrc/backend/postgres/table.m4 -Lsrc/backend/postgres/table.m4 -u -r1.7.4.3 -r1.7.4.4
--- src/backend/postgres/table.m4
+++ src/backend/postgres/table.m4
@@ -294,7 +294,7 @@
GET_RESULTS (be->connection, result);
IF_ONE_ROW (result, nrows, i) {
- /* compared queried values to input values */
+ /* Compare queried values to input values. */
cmp_fields($@)
}
Index: price.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/price.c,v
retrieving revision 1.17.4.5
retrieving revision 1.17.4.6
diff -Lsrc/backend/postgres/price.c -Lsrc/backend/postgres/price.c -u -r1.17.4.5 -r1.17.4.6
--- src/backend/postgres/price.c
+++ src/backend/postgres/price.c
@@ -463,7 +463,7 @@
void
pgend_price_begin_edit (QofBackend * bend, GNCPrice *pr)
{
- if (pr && pr->db && pr->db->dirty)
+ if (pr && pr->db && pr->db->inst.dirty)
{
PERR ("price db is unexpectedly dirty");
}
@@ -528,7 +528,7 @@
SEND_QUERY (be,bufp,);
FINISH_QUERY(be->connection);
- if (pr->db) pr->db->dirty = FALSE;
+ if (pr->db) pr->db->inst.dirty = FALSE;
LEAVE ("commited");
return;
Index: builder.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/builder.c,v
retrieving revision 1.3.6.1
retrieving revision 1.3.6.2
diff -Lsrc/backend/postgres/builder.c -Lsrc/backend/postgres/builder.c -u -r1.3.6.1 -r1.3.6.2
--- src/backend/postgres/builder.c
+++ src/backend/postgres/builder.c
@@ -36,6 +36,8 @@
* -- check for buffer overflow at end of each setter
*/
+#include "config.h"
+
#define _GNU_SOURCE
#include <glib.h>
#include <string.h>
Index: putil.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/putil.h,v
retrieving revision 1.10.4.4
retrieving revision 1.10.4.5
diff -Lsrc/backend/postgres/putil.h -Lsrc/backend/postgres/putil.h -u -r1.10.4.4 -r1.10.4.5
--- src/backend/postgres/putil.h
+++ src/backend/postgres/putil.h
@@ -146,13 +146,13 @@
result = PQgetResult (conn); \
if (!result) break; \
status = PQresultStatus(result); \
- msg = PQresultErrorMessage(result); \
if ((PGRES_COMMAND_OK != status) && \
(PGRES_TUPLES_OK != status)) \
{ \
+ msg = PQresultErrorMessage(result); \
PERR("failed to get result to query:\n\t%s", msg); \
PQclear (result); \
- qof_backend_set_message (&be->be, msg); \
+ qof_backend_set_message (&be->be, msg); \
qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR);\
break; \
} \
@@ -362,7 +362,7 @@
for (node=be->blist; node; node=node->next) \
{ \
book = node->data; \
- if (guid_equal (&book->entity.guid, &book_guid)) break; \
+ if (guid_equal (&book->inst.entity.guid, &book_guid)) break; \
book = NULL; \
} \
if (!book) return data; \
Index: book.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/book.c,v
retrieving revision 1.6.4.3
retrieving revision 1.6.4.4
diff -Lsrc/backend/postgres/book.c -Lsrc/backend/postgres/book.c -u -r1.6.4.3 -r1.6.4.4
--- src/backend/postgres/book.c
+++ src/backend/postgres/book.c
@@ -97,7 +97,7 @@
if (book->idata)
{
pgendKVPDelete (be, book->idata);
- pgendKVPStore (be, book->idata, book->kvp_data);
+ pgendKVPStore (be, book->idata, book->inst.kvp_data);
}
LEAVE(" ");
}
@@ -172,7 +172,7 @@
if (0 != book->idata)
{
- book->kvp_data = pgendKVPFetch (be, book->idata, book->kvp_data);
+ book->inst.kvp_data = pgendKVPFetch (be, book->idata, book->inst.kvp_data);
}
LEAVE (" ");
@@ -200,7 +200,7 @@
for (node=blist; node; node=node->next)
{
book = node->data;
- if (guid_equal (&book->entity.guid, &guid)) break;
+ if (guid_equal (&book->inst.entity.guid, &guid)) break;
book = NULL;
}
@@ -237,7 +237,7 @@
QofBook *book = node->data;
if (0 != book->idata)
{
- book->kvp_data = pgendKVPFetch (be, book->idata, book->kvp_data);
+ book->inst.kvp_data = pgendKVPFetch (be, book->idata, book->inst.kvp_data);
}
}
Index: PostgresBackend.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/postgres/PostgresBackend.c,v
retrieving revision 1.43.4.5
retrieving revision 1.43.4.6
diff -Lsrc/backend/postgres/PostgresBackend.c -Lsrc/backend/postgres/PostgresBackend.c -u -r1.43.4.5 -r1.43.4.6
--- src/backend/postgres/PostgresBackend.c
+++ src/backend/postgres/PostgresBackend.c
@@ -1643,20 +1643,21 @@
}
static void
-pgend_do_begin (QofBackend *bend, QofIdTypeConst type, gpointer object)
+pgend_do_begin (QofBackend *bend, QofInstance *inst)
{
PGBackend *be = (PGBackend*)bend;
+ QofIdTypeConst type = inst->entity.e_type;
ENTER ("be=%p, type=%s", bend, type);
- if (!safe_strcmp (type, GNC_ID_PERIOD))
- return pgend_book_transfer_begin (bend, object);
+ // if (!safe_strcmp (type, GNC_ID_PERIOD))
+ // return pgend_book_transfer_begin (bend, object);
switch (be->session_mode) {
case MODE_EVENT:
case MODE_POLL:
case MODE_SINGLE_UPDATE:
if (!safe_strcmp (type, GNC_ID_PRICE))
- return pgend_price_begin_edit (bend, object);
+ return pgend_price_begin_edit (bend, (GNCPrice *) inst);
case MODE_SINGLE_FILE:
case MODE_NONE:
@@ -1668,13 +1669,14 @@
}
static void
-pgend_do_commit (QofBackend *bend, QofIdTypeConst type, gpointer object)
+pgend_do_commit (QofBackend *bend, QofInstance *inst)
{
PGBackend *be = (PGBackend*)bend;
+ QofIdTypeConst type = inst->entity.e_type;
ENTER ("be=%p, type=%s", bend, type);
- if (!safe_strcmp (type, GNC_ID_PERIOD))
- return pgend_book_transfer_commit (bend, object);
+ // if (!safe_strcmp (type, GNC_ID_PERIOD))
+ // return pgend_book_transfer_commit (bend, object);
switch (be->session_mode) {
case MODE_EVENT:
@@ -1682,15 +1684,15 @@
case MODE_SINGLE_UPDATE:
if (!safe_strcmp (type, GNC_ID_TRANS)) {
- Transaction *txn = (Transaction*) object;
+ Transaction *txn = (Transaction*) inst;
return pgend_trans_commit_edit (bend, txn, txn->orig);
}
if (!safe_strcmp (type, GNC_ID_PRICE))
- return pgend_price_commit_edit (bend, object);
+ return pgend_price_commit_edit (bend, (GNCPrice *) inst);
if (!safe_strcmp (type, GNC_ID_ACCOUNT))
- return pgend_account_commit_edit (bend, object);
+ return pgend_account_commit_edit (bend, (Account *) inst);
case MODE_SINGLE_FILE:
case MODE_NONE:
@@ -1703,9 +1705,10 @@
}
static void
-pgend_do_rollback (QofBackend *bend, QofIdTypeConst type, gpointer object)
+pgend_do_rollback (QofBackend *bend, QofInstance *inst)
{
PGBackend *be = (PGBackend*)bend;
+ QofIdTypeConst type = inst->entity.e_type;
ENTER ("be=%p, type=%s", bend, type);
switch (be->session_mode) {
@@ -1713,7 +1716,7 @@
case MODE_POLL:
if (!safe_strcmp (type, GNC_ID_TRANS))
- return pgend_trans_rollback_edit (bend, object);
+ return pgend_trans_rollback_edit (bend, (Transaction *)inst);
case MODE_SINGLE_UPDATE:
case MODE_SINGLE_FILE:
Index: dialog-invoice.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-gnome/dialog-invoice.c,v
retrieving revision 1.81.4.10
retrieving revision 1.81.4.11
diff -Lsrc/business/business-gnome/dialog-invoice.c -Lsrc/business/business-gnome/dialog-invoice.c -u -r1.81.4.10 -r1.81.4.11
--- src/business/business-gnome/dialog-invoice.c
+++ src/business/business-gnome/dialog-invoice.c
@@ -594,13 +594,13 @@
arg = gw_wcp_assimilate_ptr (invoice, scm_c_eval_string("<gnc:GncInvoice*>"));
args = scm_cons (arg, args);
- /* scm_protect_object(func); */
+ /* scm_gc_protect_object(func); */
arg = scm_apply (func, args, SCM_EOL);
g_return_if_fail (SCM_EXACTP (arg));
report_id = scm_num2int (arg, SCM_ARG1, __FUNCTION__);
- /* scm_unprotect_object(func); */
+ /* scm_gc_unprotect_object(func); */
if (report_id >= 0)
reportWindow (report_id);
}
Index: business-urls.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-gnome/business-urls.c,v
retrieving revision 1.2.4.2
retrieving revision 1.2.4.3
diff -Lsrc/business/business-gnome/business-urls.c -Lsrc/business/business-gnome/business-urls.c -u -r1.2.4.2 -r1.2.4.3
--- src/business/business-gnome/business-urls.c
+++ src/business/business-gnome/business-urls.c
@@ -31,6 +31,7 @@
#include "gnc-engine-util.h"
#include "gncCustomer.h"
+#include "gncJob.h"
#include "gncVendor.h"
#include "gncEmployee.h"
#include "gncInvoice.h"
@@ -41,215 +42,134 @@
#include "dialog-vendor.h"
#include "dialog-invoice.h"
+#define HANDLE_TYPE(URL_TYPE_STR,OBJ_TYPE) { \
+ QofBook *book; \
+ GUID guid; \
+ QofCollection *coll; \
+ \
+ g_return_val_if_fail (location != NULL, FALSE); \
+ g_return_val_if_fail (result != NULL, FALSE); \
+ result->load_to_stream = FALSE; \
+ \
+ if (strncmp (URL_TYPE_STR, location, strlen(URL_TYPE_STR))) \
+ { \
+ result->error_message = \
+ g_strdup_printf (_("Badly formed URL %s"), location); \
+ return FALSE; \
+ } \
+ if (!string_to_guid (location + strlen(URL_TYPE_STR), &guid)) \
+ { \
+ result->error_message = g_strdup_printf (_("Bad URL: %s"), location); \
+ return FALSE; \
+ } \
+ \
+ book = gnc_get_current_book(); \
+ coll = qof_book_get_collection (book, OBJ_TYPE); \
+ entity = qof_collection_lookup_entity (coll, &guid); \
+ if (NULL == entity) \
+ { \
+ result->error_message = g_strdup_printf (_("No such entity: %s"), \
+ location); \
+ return FALSE; \
+ } \
+}
+
static gboolean
customerCB (const char *location, const char *label,
- gboolean new_window, GNCURLResult * result)
+ gboolean new_window, GNCURLResult * result)
{
- g_return_val_if_fail (location != NULL, FALSE);
- g_return_val_if_fail (result != NULL, FALSE);
+ QofEntity *entity;
+ GncCustomer *customer;
- result->load_to_stream = FALSE;
-
- /* href="...:guid=<guid>" */
- if (strncmp ("guid=", location, 5) == 0) {
- GUID guid;
- GNCIdType id_type;
- GncCustomer *customer;
-
- if (!string_to_guid (location + 5, &guid)) {
- result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
- return FALSE;
- }
-
- id_type = xaccGUIDType (&guid, gnc_get_current_book ());
- if (id_type == GNC_ID_NONE || !safe_strcmp (id_type, GNC_ID_NULL))
- {
- result->error_message = g_strdup_printf (_("No such entity: %s"),
- location);
- return FALSE;
- }
- else if (!safe_strcmp (id_type, GNC_CUSTOMER_MODULE_NAME))
- {
- customer = gncCustomerLookup (gnc_get_current_book (), &guid);
- gnc_ui_customer_edit (customer);
- }
- else
- {
- result->error_message =
- g_strdup_printf (_("Entity type does not match Customer: %s"),
- location);
- return FALSE;
- }
- }
- else
- {
- result->error_message = g_strdup_printf (_("Badly formed URL %s"),
- location);
- return FALSE;
- }
+ /* href="...:customer=<guid>" */
+ HANDLE_TYPE ("customer=", GNC_ID_CUSTOMER);
+ customer = (GncCustomer *) entity;
+ gnc_ui_customer_edit (customer);
return TRUE;
}
static gboolean
vendorCB (const char *location, const char *label,
- gboolean new_window, GNCURLResult * result)
+ gboolean new_window, GNCURLResult * result)
{
- g_return_val_if_fail (location != NULL, FALSE);
- g_return_val_if_fail (result != NULL, FALSE);
-
- result->load_to_stream = FALSE;
+ QofEntity *entity;
+ GncVendor *vendor;
- /* href="...:guid=<guid>" */
- if (strncmp ("guid=", location, 5) == 0) {
- GUID guid;
- GNCIdType id_type;
- GncVendor *vendor;
-
- if (!string_to_guid (location + 5, &guid)) {
- result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
- return FALSE;
- }
-
- id_type = xaccGUIDType (&guid, gnc_get_current_book ());
- if (id_type == GNC_ID_NONE || !safe_strcmp (id_type, GNC_ID_NULL))
- {
- result->error_message = g_strdup_printf (_("No such entity: %s"),
- location);
- return FALSE;
- }
- else if (!safe_strcmp (id_type, GNC_VENDOR_MODULE_NAME))
- {
- vendor = gncVendorLookup (gnc_get_current_book (), &guid);
- gnc_ui_vendor_edit (vendor);
- }
- else
- {
- result->error_message =
- g_strdup_printf (_("Entity type does not match Vendor: %s"),
- location);
- return FALSE;
- }
- }
- else
- {
- result->error_message = g_strdup_printf (_("Badly formed URL %s"),
- location);
- return FALSE;
- }
+ /* href="...:vendor=<guid>" */
+ HANDLE_TYPE ("vendor=", GNC_ID_VENDOR);
+ vendor = (GncVendor *) entity;
+ gnc_ui_vendor_edit (vendor);
return TRUE;
}
static gboolean
employeeCB (const char *location, const char *label,
- gboolean new_window, GNCURLResult * result)
+ gboolean new_window, GNCURLResult * result)
{
- g_return_val_if_fail (location != NULL, FALSE);
- g_return_val_if_fail (result != NULL, FALSE);
+ QofEntity *entity;
+ GncEmployee *employee;
- result->load_to_stream = FALSE;
-
- /* href="...:guid=<guid>" */
- if (strncmp ("guid=", location, 5) == 0) {
- GUID guid;
- GNCIdType id_type;
- GncEmployee *employee;
+ /* href="...:employee=<guid>" */
+ HANDLE_TYPE ("employee=", GNC_ID_EMPLOYEE);
- if (!string_to_guid (location + 5, &guid)) {
- result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
- return FALSE;
- }
-
- id_type = xaccGUIDType (&guid, gnc_get_current_book ());
- if (id_type == GNC_ID_NONE || !safe_strcmp (id_type, GNC_ID_NULL))
- {
- result->error_message = g_strdup_printf (_("No such entity: %s"),
- location);
- return FALSE;
- }
- else if (!safe_strcmp (id_type, GNC_EMPLOYEE_MODULE_NAME))
- {
- employee = gncEmployeeLookup (gnc_get_current_book (), &guid);
- gnc_ui_employee_edit (employee);
- }
- else
- {
- result->error_message =
- g_strdup_printf (_("Entity type does not match Employee: %s"),
- location);
- return FALSE;
- }
- }
- else
- {
- result->error_message = g_strdup_printf (_("Badly formed URL %s"),
- location);
- return FALSE;
- }
+ employee = (GncEmployee *) entity;
+ gnc_ui_employee_edit (employee);
return TRUE;
}
static gboolean
invoiceCB (const char *location, const char *label,
- gboolean new_window, GNCURLResult * result)
+ gboolean new_window, GNCURLResult * result)
{
- g_return_val_if_fail (location != NULL, FALSE);
- g_return_val_if_fail (result != NULL, FALSE);
+ QofEntity *entity;
+ GncInvoice *invoice;
- result->load_to_stream = FALSE;
+ /* href="...:invoice=<guid>" */
+ HANDLE_TYPE ("invoice=", GNC_ID_INVOICE);
+ invoice = (GncInvoice *) entity;
+ gnc_ui_invoice_edit (invoice);
- /* href="...:guid=<guid>" */
- if (strncmp ("guid=", location, 5) == 0) {
- GUID guid;
- GNCIdType id_type;
- GncInvoice *invoice;
+ return TRUE;
+}
- if (!string_to_guid (location + 5, &guid)) {
- result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
- return FALSE;
- }
+#if 0 // whats up w/ that ?
+static gboolean
+jobCB (const char *location, const char *label,
+ gboolean new_window, GNCURLResult * result)
+{
+ QofEntity *entity;
+ GncJob *job;
- id_type = xaccGUIDType (&guid, gnc_get_current_book ());
- if (id_type == GNC_ID_NONE || !safe_strcmp (id_type, GNC_ID_NULL))
- {
- result->error_message = g_strdup_printf (_("No such entity: %s"),
- location);
- return FALSE;
- }
- else if (!safe_strcmp (id_type, GNC_INVOICE_MODULE_NAME))
- {
- invoice = gncInvoiceLookup (gnc_get_current_book (), &guid);
- gnc_ui_invoice_edit (invoice);
- }
- else
- {
- result->error_message =
- g_strdup_printf (_("Entity type does not match Invoice: %s"),
- location);
- return FALSE;
- }
- }
- else
- {
- result->error_message = g_strdup_printf (_("Badly formed URL %s"),
- location);
- return FALSE;
- }
+ /* href="...:job=<guid>" */
+ HANDLE_TYPE ("job=", GNC_ID_INVOICE);
+ job = (GncJob *) entity;
+ gnc_ui_job_edit (job);
return TRUE;
}
+#endif
+
+/* ================================================================= */
+
+#define RETURN_IF_NULL(inst) \
+ if (NULL == inst) \
+ { \
+ result->error_message = \
+ g_strdup_printf (_("No such owner entity: %s"), location); \
+ return FALSE; \
+ }
static gboolean
ownerreportCB (const char *location, const char *label,
- gboolean new_window, GNCURLResult * result)
+ gboolean new_window, GNCURLResult * result)
{
const char *ownerptr;
const char *acctptr;
GUID guid;
GncOwner owner;
- GNCIdType id_type;
GncOwnerType type;
char *etype = NULL;
Account *acc = NULL;
@@ -294,45 +214,44 @@
return FALSE;
}
- id_type = xaccGUIDType (&guid, gnc_get_current_book ());
- if (id_type == GNC_ID_NONE || !safe_strcmp (id_type, GNC_ID_NULL))
- {
- result->error_message = g_strdup_printf (_("No such owner entity: %s"),
- location);
- return FALSE;
- }
switch (type) {
- case GNC_OWNER_CUSTOMER:
- if (!safe_strcmp (id_type, GNC_CUSTOMER_MODULE_NAME))
- gncOwnerInitCustomer (&owner,
- gncCustomerLookup (gnc_get_current_book (),
- &guid));
- etype = "Customer";
- break;
- case GNC_OWNER_VENDOR:
- if (!safe_strcmp (id_type, GNC_VENDOR_MODULE_NAME))
- gncOwnerInitVendor (&owner,
- gncVendorLookup (gnc_get_current_book (),
- &guid));
- etype = "Vendor";
- break;
- case GNC_OWNER_EMPLOYEE:
- if (!safe_strcmp (id_type, GNC_EMPLOYEE_MODULE_NAME))
- gncOwnerInitEmployee (&owner,
- gncEmployeeLookup (gnc_get_current_book (),
- &guid));
- etype = "Employee";
- break;
- default:
- etype = "OTHER";
+ case GNC_OWNER_CUSTOMER:
+ {
+ GncCustomer *customer =
+ gncCustomerLookup (gnc_get_current_book (), &guid);
+ RETURN_IF_NULL (customer);
+ gncOwnerInitCustomer (&owner, customer);
+ etype = "Customer";
+ break;
+ }
+ case GNC_OWNER_VENDOR:
+ {
+ GncVendor *vendor =
+ gncVendorLookup (gnc_get_current_book (), &guid);
+ RETURN_IF_NULL (vendor);
+ gncOwnerInitVendor (&owner, vendor);
+ etype = "Vendor";
+ break;
+ }
+ case GNC_OWNER_EMPLOYEE:
+ {
+ GncEmployee *employee =
+ gncEmployeeLookup (gnc_get_current_book (), &guid);
+ RETURN_IF_NULL(employee);
+ gncOwnerInitEmployee (&owner, employee);
+ etype = "Employee";
+ break;
+ }
+ default:
+ etype = "OTHER";
}
if (owner.owner.undefined == NULL)
{
result->error_message =
g_strdup_printf (_("Entity type does not match %s: %s"),
- etype, location);
+ etype, location);
return FALSE;
}
@@ -350,22 +269,13 @@
return FALSE;
}
- id_type = xaccGUIDType (&guid, gnc_get_current_book ());
- if (id_type == GNC_ID_NONE || !safe_strcmp (id_type, GNC_ID_NULL))
+ acc = xaccAccountLookup (&guid, gnc_get_current_book ());
+ if (NULL == acc)
{
result->error_message = g_strdup_printf (_("No such Account entity: %s"),
- location);
+ location);
return FALSE;
}
-
- if (safe_strcmp (id_type, GNC_ID_ACCOUNT) != 0)
- {
- result->error_message =
- g_strdup_printf (_("Entity is not Account entity: %s"), location);
- return FALSE;
- }
-
- acc = xaccAccountLookup (&guid, gnc_get_current_book ());
}
/* Ok, let's run this report */
@@ -379,14 +289,14 @@
{
int i;
static struct {
- URLType urltype;
- char * protocol;
+ URLType urltype;
+ char * protocol;
GncHTMLUrlCB handler;
} types[] = {
- { GNC_CUSTOMER_MODULE_NAME, GNC_CUSTOMER_MODULE_NAME, customerCB },
- { GNC_VENDOR_MODULE_NAME, GNC_VENDOR_MODULE_NAME, vendorCB },
- { GNC_EMPLOYEE_MODULE_NAME, GNC_EMPLOYEE_MODULE_NAME, employeeCB },
- { GNC_INVOICE_MODULE_NAME, GNC_INVOICE_MODULE_NAME, invoiceCB },
+ { GNC_ID_CUSTOMER, GNC_ID_CUSTOMER, customerCB },
+ { GNC_ID_VENDOR, GNC_ID_VENDOR, vendorCB },
+ { GNC_ID_EMPLOYEE, GNC_ID_EMPLOYEE, employeeCB },
+ { GNC_ID_INVOICE, GNC_ID_INVOICE, invoiceCB },
{ URL_TYPE_OWNERREPORT, "gnc-ownerreport", ownerreportCB },
{ NULL, NULL }
};
@@ -399,3 +309,5 @@
gnc_html_register_url_handler (types[i].urltype, types[i].handler);
}
+
+/* =========================== END OF FILE ========================= */
Index: gncEntryLedgerLoad.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-ledger/gncEntryLedgerLoad.c,v
retrieving revision 1.28.4.2
retrieving revision 1.28.4.3
diff -Lsrc/business/business-ledger/gncEntryLedgerLoad.c -Lsrc/business/business-ledger/gncEntryLedgerLoad.c -u -r1.28.4.2 -r1.28.4.3
--- src/business/business-ledger/gncEntryLedgerLoad.c
+++ src/business/business-ledger/gncEntryLedgerLoad.c
@@ -29,13 +29,15 @@
#include <libguile.h>
#include "Account.h"
-#include "gnc-ui-util.h"
-#include "recncell.h"
+#include "account-quickfill.h"
#include "combocell.h"
-#include "messages.h"
#include "global-options.h"
-#include "business-options.h"
#include "gnc-component-manager.h"
+#include "gnc-ui-util.h"
+#include "messages.h"
+#include "recncell.h"
+
+#include "business-options.h"
#include "gncEntry.h"
#include "gncEntryLedger.h"
@@ -122,42 +124,86 @@
gnc_combo_cell_add_menu_item (cell, _("Charge"));
}
-static void load_xfer_cell (ComboCell * cell, AccountGroup * grp,
- GncEntryLedgerType ledger_type)
+/* ==================================================================== */
+/* Return TRUE if we don't want to add this account to the xfer menu */
+
+static gboolean
+skip_expense_acct_cb (Account *account, gpointer user_data)
{
- GList *list;
- GList *node;
+ GNCAccountType type;
- if (!grp) return;
+ /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
+ type = xaccAccountGetType (account);
+ if (type == PAYABLE || type == RECEIVABLE ||
+ type == CASH || type == BANK || type == EQUITY)
+ {
+ return TRUE;
+ }
- /* Build the xfer menu out of account names. */
+ /* If this is an ORDER or INVOICE, then leave out the expenses. */
+ if (type == EXPENSE) return TRUE;
- list = xaccGroupGetSubAccounts (grp);
+ /* Don't add placeholder accounts */
+ if (xaccAccountGetPlaceholder (account)) return TRUE;
- for (node = list; node; node = node->next) {
- Account *account = node->data;
- char *name;
- GNCAccountType type;
+ return FALSE;
+}
- /* Don't add placeholder accounts */
- if (xaccAccountGetPlaceholder (account))
- continue;
+static gboolean
+skip_income_acct_cb (Account *account, gpointer user_data)
+{
+ GNCAccountType type;
- /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
- type = xaccAccountGetType (account);
- if (type == PAYABLE || type == RECEIVABLE ||
- type == CASH || type == BANK || type == EQUITY)
- continue;
+ /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
+ type = xaccAccountGetType (account);
+ if (type == PAYABLE || type == RECEIVABLE ||
+ type == CASH || type == BANK || type == EQUITY)
+ {
+ return TRUE;
+ }
+
+ /* If this is a BILL, then leave out the incomes */
+ if (type == INCOME) return TRUE;
+
+ /* Don't add placeholder accounts */
+ if (xaccAccountGetPlaceholder (account)) return TRUE;
+
+ return FALSE;
+}
+
+/* ===================================================================== */
+/* Splat the account name into the transfer cell combobox menu */
+
+typedef struct {
+ ComboCell *cell;
+ GncEntryLedgerType ledger_type;
+} BCE;
+
+static gpointer
+load_xfer_cell_cb (Account *account, gpointer data)
+{
+ BCE *bce = data;
+ GNCAccountType type;
+ char *name;
+
+ /* Don't add A/R, A/P, Bank, Cash, or Equity accounts */
+ type = xaccAccountGetType (account);
+ if (type == PAYABLE || type == RECEIVABLE ||
+ type == CASH || type == BANK || type == EQUITY)
+ {
+ return NULL;
+ }
- /* If this is an ORDER or INVOICE, then leave out the expenses.
- * if it's a BILL, then leave out the incomes
- */
- switch (ledger_type) {
+ /* If this is an ORDER or INVOICE, then leave out the expenses.
+ * if it's a BILL, then leave out the incomes
+ */
+ switch (bce->ledger_type)
+ {
case GNCENTRY_ORDER_ENTRY:
case GNCENTRY_ORDER_VIEWER:
case GNCENTRY_INVOICE_ENTRY:
case GNCENTRY_INVOICE_VIEWER:
- if (type == EXPENSE) continue;
+ if (type == EXPENSE) return NULL;
break;
case GNCENTRY_BILL_ENTRY:
@@ -165,40 +211,81 @@
case GNCENTRY_EXPVOUCHER_ENTRY:
case GNCENTRY_EXPVOUCHER_VIEWER:
case GNCENTRY_NUM_REGISTER_TYPES:
- if (type == INCOME) continue;
+ if (type == INCOME) return NULL;
break;
- }
+ }
- name = xaccAccountGetFullName (account, gnc_get_account_separator ());
- if (name != NULL)
- gnc_combo_cell_add_menu_item (cell, name);
+ /* Don't add placeholder accounts */
+ if (xaccAccountGetPlaceholder (account)) return NULL;
- g_free(name);
- }
- g_list_free (list);
+ name = xaccAccountGetFullName (account, gnc_get_account_separator ());
+ if (NULL == name) return NULL;
+ gnc_combo_cell_add_menu_item (bce->cell, name);
+ g_free(name);
+
+ return NULL;
}
-static void load_xfer_type_cells (GncEntryLedger *ledger)
+#define EKEY "Expense Business entry quickfill"
+#define IKEY "Income Business entry quickfill"
+
+static void
+load_xfer_type_cells (GncEntryLedger *ledger)
{
+ BCE bce;
AccountGroup *group;
ComboCell *cell;
+ QuickFill *qf=NULL;
group = gnc_book_get_group (ledger->book);
- if (group == NULL)
- return;
+ if (group == NULL) return;
+
+ /* Use a common, shared quickfill. For the ORDER or INVOICE,
+ * ledgers, we don't want expense-type accounts in the menu.
+ * For BILL, etc. then leave out the income types.
+ */
+ switch (ledger->type)
+ {
+ case GNCENTRY_ORDER_ENTRY:
+ case GNCENTRY_ORDER_VIEWER:
+ case GNCENTRY_INVOICE_ENTRY:
+ case GNCENTRY_INVOICE_VIEWER:
+ qf = gnc_get_shared_account_name_quickfill (group, IKEY,
+ skip_expense_acct_cb, NULL);
+ break;
+
+ case GNCENTRY_BILL_ENTRY:
+ case GNCENTRY_BILL_VIEWER:
+ case GNCENTRY_EXPVOUCHER_ENTRY:
+ case GNCENTRY_EXPVOUCHER_VIEWER:
+ case GNCENTRY_NUM_REGISTER_TYPES:
+ qf = gnc_get_shared_account_name_quickfill (group, EKEY,
+ skip_income_acct_cb, NULL);
+ break;
+ }
cell = (ComboCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL);
gnc_combo_cell_clear_menu (cell);
- load_xfer_cell (cell, group, ledger->type);
+ gnc_combo_cell_use_quickfill_cache (cell, qf);
+
+ bce.cell = cell;
+ bce.ledger_type = ledger->type;
+ xaccGroupForEachAccount (group, load_xfer_cell_cb, &bce, TRUE);
cell = (ComboCell *)
gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL);
gnc_combo_cell_clear_menu (cell);
- load_xfer_cell (cell, group, ledger->type);
+ gnc_combo_cell_use_quickfill_cache (cell, qf);
+
+ bce.cell = cell;
+ bce.ledger_type = ledger->type;
+ xaccGroupForEachAccount (group, load_xfer_cell_cb, &bce, TRUE);
}
+/* ===================================================================== */
+
static void load_taxtable_type_cells (GncEntryLedger *ledger)
{
GList *list;
@@ -240,6 +327,10 @@
/* XXX (FIXME): This should be in a config file! */
/* Copy GncEntry information from the list to the rows of the Ledger. */
+/* XXX This code is a cut-n-paste job from the SplitRegister code;
+ * the split-regsiter should be generalized to the point where a cut-n-paste
+ * like this isn't required, and this should be trashed.
+ */
void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
{
static SCM id_book = SCM_UNDEFINED;
@@ -506,3 +597,5 @@
/* enable callback for cursor user-driven moves */
gnc_table_control_allow_move (table->control, TRUE);
}
+
+/* =========================== END OF FILE ========================== */
Index: business-reports.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-reports/business-reports.scm,v
retrieving revision 1.7.4.2
retrieving revision 1.7.4.3
diff -Lsrc/business/business-reports/business-reports.scm -Lsrc/business/business-reports/business-reports.scm -u -r1.7.4.2 -r1.7.4.3
--- src/business/business-reports/business-reports.scm
+++ src/business/business-reports/business-reports.scm
@@ -34,23 +34,23 @@
(define gnc:menuname-business-reports (N_ "Business Reports"))
-(define (guid-ref type guid)
- (gnc:html-build-url type (string-append "guid=" guid) #f))
+(define (guid-ref idstr type guid)
+ (gnc:html-build-url type (string-append idstr guid) #f))
(define (gnc:customer-anchor-text customer)
- (guid-ref gnc:url-type-customer (gnc:customer-get-guid customer)))
+ (guid-ref "customer=" gnc:url-type-customer (gnc:customer-get-guid customer)))
(define (gnc:job-anchor-text job)
- (guid-ref gnc:url-type-job (gnc:job-get-guid job)))
+ (guid-ref "job=" gnc:url-type-job (gnc:job-get-guid job)))
(define (gnc:vendor-anchor-text vendor)
- (guid-ref gnc:url-type-vendor (gnc:vendor-get-guid vendor)))
+ (guid-ref "vendor=" gnc:url-type-vendor (gnc:vendor-get-guid vendor)))
(define (gnc:employee-anchor-text employee)
- (guid-ref gnc:url-type-employee (gnc:employee-get-guid employee)))
+ (guid-ref "employee=" gnc:url-type-employee (gnc:employee-get-guid employee)))
(define (gnc:invoice-anchor-text invoice)
- (guid-ref gnc:url-type-invoice (gnc:invoice-get-guid invoice)))
+ (guid-ref "invoice=" gnc:url-type-invoice (gnc:invoice-get-guid invoice)))
(define (gnc:owner-anchor-text owner)
(let ((type (gw:enum-<gnc:GncOwnerType>-val->sym
--- src/doc/query-api.txt
+++ /dev/null
@@ -1,205 +0,0 @@
-Gnucash Query API
-
-
-BASIC QUERY API: With this API you can create arbitrary logical
-queries to find sets of splits in an account group. To make simple
-queries (1 term, such as an account query), create the appropriate
-QueryTerm structure and stick it in a Query object using
-xaccInitQuery. The QueryTerm should be malloced but the Query object
-will handle freeing it. To make compound queries, make multiple
-simple queries and combine them using xaccMergeQuery and the logical
-operations of your choice.
-
------------------------------------------------------------------
-Query * xaccMallocQuery()
-
-Allocates and initializes a Query structure which must be freed by the
-user with xaccFreeQuery. A newly-allocated Query object matches
-nothing (xaccQueryGetSplits will return NULL).
-
------------------------------------------------------------------
-void xaccInitQuery(Query * q, QueryTerm * qt)
-
-Initializes an allocated Query object with initial term qt (possibly
-NULL). Any previous query terms are freed.
-
------------------------------------------------------------------
-void xaccFreeQuery(Query * q)
-
-Frees the resources associate with a Query object.
-
------------------------------------------------------------------
-void xaccQuerySetGroup(Query * q, AccountGroup * group)
-
-Set the Gnucash account group that the query applies to.
-xaccQuerySetGroup must be called before a Query object created with
-xaccMallocQuery can be used. Queries created with xaccQueryInvert and
-xaccQueryMerge inherit the account group of the arguments to those
-functions.
-
------------------------------------------------------------------
-Query * xaccQueryInvert(Query * q)
-
-Logically invert the query. xaccInvertQuery returns a newly allocated
-Query object such that the union of the splits matched by query q and
-query (p = xaccQueryInvert(q)) is the entire account group that q
-applies to.
-
------------------------------------------------------------------
-Query * xaccQueryMerge(Query * q1, Query * q2, QueryOp how)
-
-Combine queries q1 and q2 using logical operator 'how'. 'how' must be
-one of QUERY_AND, QUERY_OR, QUERY_NAND, QUERY_NOR, QUERY_XOR. The
-account groups of q1 and q2 must be the same. xaccQueryMerge returns
-a newly-allocated Query object or NULL on error.
-
------------------------------------------------------------------
-void xaccQueryClear(Query * q)
-
-Remove all query terms from q. q matches nothing after xaccQueryClear.
-
------------------------------------------------------------------
-void xaccQueryPurgeTerms(Query * q, pd_type_t type);
-
-Remove query terms of a particular type from q. The "type" of a term
-is determined by the type of data that gets passed to the predicate
-function. The currently-supported values of 'type' are PD_DATE,
-PD_AMOUNT, PD_ACCOUNT, PD_STRING, PD_CLEARED, PD_MISC. This function
-is really only used in one place: in window-register.c, to modify
-in-place a query to remove any date tests prior to adding new ones.
-This should probably be removed from the API in favor of an extra
-argument to xaccQueryMerge specifying what to do with existing terms
-of that type.
-
-
------------------------------------------------------------------
-int xaccQueryHasTerms(Query * q)
-
-Returns the number of terms in the canonical form of the query. Can
-be used as a predicate to see if the query has been initialized
-(return value > 0) or is "blank" (return value == 0).
-
-
------------------------------------------------------------------
-
-CONVENIENCE API: The remainder of the API (in particular, any function
-called xaccQueryAdd***Match) is a set of convenience functions for
-creating and modifying specific types of queries. All of these
-functions can be duplicated using the Basic API specified above,
-directly manipulating QueryTerm objects and creating and merging
-queries as needed. One slight advantage of the convenience API is
-that it uses a standard set of predicates that are more-or-less
-opaque. This may be important later.
-
-It's probably more useful to describe the various types of
-PredicateData than the convenience functions, which are pretty
-self-explanatory once you understand what the underlying process is.
-For example, AddMemoMatch and AddDescriptionMatch are essentially the
-same function because they both use PD_STRING predicate data; they
-just use a different predicate (one compares data.string.matchstring
-with the split's Memo, one compares with the parent transaction's
-Description).
-
-Each function in the convenience API takes a Query *, some arguments
-which fill in the fields of the appropriate PredicateData type, and a
-QueryOp. The Query object is modified in place, using the logical
-operation specified by the QueryOp to combine a single new QueryTerm
-with the existing Query. This works by making a new Query of one term
-and combining with the existing Query using xaccQueryMerge and the
-specified QueryOp. If you have an existing Query (a + b + c) and
-combine using QueryOp QUERY_AND in a convenience function representing
-predicate d, you will get (ad + bd + cd).
-
-
-STRUCTURE OF A QUERY: A Query is a logical function of any number of
-QueryTerms. A QueryTerm consists of a C function pointer (the
-Predicate) and a PredicateData structure containing data passed to the
-predicate funtion. The PredicateData structure is a constant
-associated with the Term and is identical for every Split that is
-tested.
-
-The terms of the Query may represent any logical function and are
-stored in canonical form, i.e. the function is expressed as a logical
-sum of logical products. So if you have QueryTerms a, b, c, d, e and
-you have the logical function a(b+c) + !(c(d+e)), it gets stored as
-ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation
-of some functions but it's easy to store, easy to manipulate, and it
-doesn't require a complete algebra system to deal with.
-
-The representation is of a GList of GLists of QueryTerms. The
-"backbone" GList q->terms represents the OR-chain, and every item on
-the backbone is a GList of QueryTerms representing an AND-chain
-corresponding to a single product-term in the canonical
-representation. QueryTerms are duplicated when necessary to fill out
-the canonical form, and the same predicate may be evaluated multiple
-times per split for complex queries. This is a place where we could
-probably optimize.
-
-Evaluation of a Query (see xaccQueryGetSplits) is optimized as much as
-possible by short-circuited evaluation. The predicates in each
-AND-chain are sorted by predicate type, with Account queries sorted
-first to allow the evaluator to completely eliminate accounts from the
-search if there's no chance of them having splits that match.
-
-
-PREDICATE DATA TYPES: All the predicate data types are rolled up into
-the union type PredicateData. The "type" field specifies which type
-the union is. The values of type are:
-
------------------------------------------------------------------
-PD_DATE : match a date range. Specify a start date and an end date.
-
-Used in: xaccQueryAddDateMatch
- xaccQueryAddDateMatchTS
- xaccQueryAddDateMatchTT
-
------------------------------------------------------------------
-PD_AMOUNT : match a numeric amount. Specify an amount (always
-positive), a funds-flow direction (credit, debit, or either), and
-"how", specifying the type of amount comparison to be used :
-
- AMT_MATCH_ATLEAST : split >= pd amount
- AMT_MATCH_ATMOST : split >= pd amount
- AMT_MATCH_EXACTLY : split == pd amount
-
-Used in: xaccQueryAddAmountMatch
- xaccQueryAddSharePriceMatch
- xaccQueryAddSharesMatch
-
------------------------------------------------------------------
-PD_ACCOUNT : match an account or set of accounts. Specify a set
-of accounts and "how":
-
- ACCT_MATCH_ALL : a transaction must have at least one split
- affecting each account in pd.acct.accounts.
- ACCT_MATCH_ANY : a transaction must have at least one split
- affecting any account in the set
- ACCT_MATCH_NONE : a transaction may not affect any account in
- the set.
-
-Used in: xaccQueryAddAccountMatch
- xaccQueryAddSingleAccountMatch
-
------------------------------------------------------------------
-PD_STRING : match a string. Specify a string, bool signifying
-case sensitivity, bool signifying regexp or simple string.
-
-Used in: xaccQueryAddDescriptionMatch
- xaccQueryAddNumberMatch
- xaccQueryAddActionMatch
- xaccQueryAddMemoMatch
-
------------------------------------------------------------------
-PD_CLEARED : match the Cleared state of the transaction. Specify
-a bit-mask that is an OR combination of one or more of the
-following:
- CLEARED_NO (state == 'n')
- CLEARED_CLEARED (state == 'c')
- CLEARED_RECONCILED (state == 'y')
-
-Used in: xaccQueryAddClearedMatch
-
------------------------------------------------------------------
-PD_MISC : match some "other" user predicate. Not used at the moment.
-
------------------------------------------------------------------
Index: lots.txt
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/doc/lots.txt,v
retrieving revision 1.8.4.4
retrieving revision 1.8.4.5
diff -Lsrc/doc/lots.txt -Lsrc/doc/lots.txt -u -r1.8.4.4 -r1.8.4.5
--- src/doc/lots.txt
+++ src/doc/lots.txt
@@ -4,7 +4,7 @@
Architecture & Implementation Overview
Linas Vepstas <linas at linas.org>
- Last Revised August 2003
+ Last Revised May 2004
One often needs to know that the item 'bought' in one transaction
@@ -493,6 +493,10 @@
---- change lot viewer to use gnc-query-list
---- after the gnome2 port, add the 'unclaimed splits" window
to the lot viewer, this will allow it to be a simple lot editor.
+---- Add a new policy (or change the existing fifo policy) to only
+ open lots with a particular sign for the opening split. This
+ way, things like business invoice overpayments are not used
+ to start new lots, but are instead applied to new purchases.
Status
Index: doxygen.cfg.in
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/doc/doxygen.cfg.in,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -Lsrc/doc/doxygen.cfg.in -Lsrc/doc/doxygen.cfg.in -u -r1.2.4.1 -r1.2.4.2
--- src/doc/doxygen.cfg.in
+++ src/doc/doxygen.cfg.in
@@ -1,189 +1,1117 @@
-# Doxyfile 1.2.17
+# Doxyfile 1.3.6-20040222
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
#---------------------------------------------------------------------------
-# General configuration options
+# Project related configuration options
#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
PROJECT_NAME = GnuCash
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
PROJECT_NUMBER = @-VERSION-@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
OUTPUT_DIRECTORY =
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with English messages), Korean, Korean-en, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
OUTPUT_LANGUAGE = English
-EXTRACT_ALL = NO
-EXTRACT_PRIVATE = NO
-EXTRACT_STATIC = NO
-EXTRACT_LOCAL_CLASSES = NO
-HIDE_UNDOC_MEMBERS = NO
-HIDE_UNDOC_CLASSES = NO
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is used
+# as the annotated text. Otherwise, the brief description is used as-is. If left
+# blank, the following values are used ("$name" is automatically replaced with the
+# name of the entity): "The $name class" "The $name widget" "The $name file"
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
STRIP_FROM_PATH =
-INTERNAL_DOCS = NO
-STRIP_CODE_COMMENTS = YES
-CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
SHORT_NAMES = NO
-HIDE_SCOPE_NAMES = NO
-VERBATIM_HEADERS = NO
-SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
INHERIT_DOCS = YES
-INLINE_INFO = YES
-SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
GENERATE_DEPRECATEDLIST= YES
-ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
MAX_INITIALIZER_LINES = 30
-OPTIMIZE_OUTPUT_FOR_C = YES
-OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
SHOW_USED_FILES = YES
+
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
WARN_FORMAT =
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
WARN_LOGFILE = doxygen.log
+
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
INPUT = @-top_srcdir-@/src
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
EXCLUDE_SYMLINKS = YES
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
EXCLUDE_PATTERNS = *P.h
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
FILTER_SOURCE_FILES = NO
+
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
REFERENCES_RELATION = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = NO
+
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
IGNORE_PREFIX =
+
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
HTML_OUTPUT =
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
HTML_FILE_EXTENSION =
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
TREEVIEW_WIDTH = 250
+
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
LATEX_OUTPUT =
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
LATEX_CMD_NAME =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
MAKEINDEX_CMD_NAME =
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
PAPER_TYPE = letter
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
RTF_OUTPUT =
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
RTF_EXTENSIONS_FILE =
+
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
MAN_OUTPUT =
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
MAN_EXTENSION =
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
MAN_LINKS = NO
+
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
SKIP_FUNCTION_MACROS = YES
+
#---------------------------------------------------------------------------
-# Configuration::addtions related to external references
+# Configuration::additions related to external references
#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
PERL_PATH =
+
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
COLLABORATION_GRAPH = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes that
+# lay further from the root node will be omitted. Note that setting this option to
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that a graph may be further truncated if the graph's image dimensions are
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
DOT_CLEANUP = YES
+
#---------------------------------------------------------------------------
-# Configuration::addtions related to the search engine
+# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
SEARCHENGINE = NO
-CGI_NAME =
-CGI_URL =
-DOC_URL =
-DOC_ABSPATH =
-BIN_ABSPATH =
-EXT_DOC_PATHS =
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/doc/Makefile.am,v
retrieving revision 1.12.4.2
retrieving revision 1.12.4.3
diff -Lsrc/doc/Makefile.am -Lsrc/doc/Makefile.am -u -r1.12.4.2 -r1.12.4.3
--- src/doc/Makefile.am
+++ src/doc/Makefile.am
@@ -25,7 +25,6 @@
lots.txt \
multicurrency-discussion.txt \
netlogin.txt \
- query-api.txt \
guid.txt \
qif.txt \
generic-druid-framework.txt \
Index: engine.texinfo
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/doc/design/engine.texinfo,v
retrieving revision 1.48
retrieving revision 1.48.4.1
diff -Lsrc/doc/design/engine.texinfo -Lsrc/doc/design/engine.texinfo -u -r1.48 -r1.48.4.1
--- src/doc/design/engine.texinfo
+++ src/doc/design/engine.texinfo
@@ -404,6 +404,10 @@
@cindex Numeric Library
@tindex gnc_numeric
+=============== The documentation below for gnc_numeric is obsolete
+ and has been superseeded by the gnc_numeric docs in the header file.
+=========================================
+
Financial quantities in GnuCash (Split quantities and values) are stored
as exact quantities measured in the smallest denominational unit of the
appropriate currency. For example, 100.50 US Dollars would be stored as
@@ -441,6 +445,10 @@
@subsection Standard Numeric Arguments
@cindex Standard Numeric Arguments
+=============== The documentation below for gnc_numeric is obsolete
+ and has been superseeded by the gnc_numeric docs in the header file.
+=========================================
+
It is useful to specify a denominator in cases where it is known that
the output value is of constrained precision. For example, monetary
transactions must be executed in an integer number of the "smallest
@@ -467,10 +475,6 @@
@item GNC_DENOM_RECIPROCAL (n)
Use the value @code{1/n} as the denominator of the output value.
- at item GNC_DENOM_SIGFIGS (n)
-Use a value for the denominator that will keep at least @code{n}
-significant figures in the result.
-
@item GNC_DENOM_AUTO
Compute an appropriate denominator automatically. Flags in the @var{how}
argument will specify how to compute the denominator.
@@ -554,6 +558,10 @@
Round to the number of significant figures given in the rounding
instructions by the GNC_DENOM_SIGFIGS () macro.
+ at item GNC_DENOM_SIGFIGS (n)
+Use a value for the denominator that will keep at least @code{n}
+significant figures in the result.
+
@end table
@@ -569,6 +577,11 @@
@node Creating Numeric Objects, Basic Arithmetic Operations, Standard Numeric Arguments, Numeric Library
+
+=============== The documentation below for gnc_numeric is obsolete
+ and has been superseeded by the gnc_numeric docs in the header file.
+=========================================
+
@subsection Creating Numeric Objects
@cindex Creating Numeric Objects
@@ -691,6 +704,10 @@
@node Numeric Denominator Conversion, Numeric Floating Point Conversion, Numeric Comparisons and Predicates, Numeric Library
+=============== The documentation below for gnc_numeric is obsolete
+ and has been superseeded by the gnc_numeric docs in the header file.
+=========================================
+
@subsection Numeric Denominator Conversion
@cindex Numeric Denominator Conversion
@@ -780,6 +797,10 @@
@subsection Numeric Example
@cindex Numeric Example
+=============== The documentation below for gnc_numeric is obsolete
+ and has been superseeded by the gnc_numeric docs in the header file.
+=========================================
+
The following program finds the best @code{gnc_numeric} approximation to
the @file{math.h} constant @code{M_PI} given a maximum denominator. For
large denominators, the @code{gnc_numeric} approximation is accurate to
Index: main.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/main.scm,v
retrieving revision 1.109.2.7
retrieving revision 1.109.2.8
diff -Lsrc/scm/main.scm -Lsrc/scm/main.scm -u -r1.109.2.7 -r1.109.2.8
--- src/scm/main.scm
+++ src/scm/main.scm
@@ -48,9 +48,7 @@
(export gnc:debug)
(export build-path)
(export gnc:use-module-here!)
-(export hash-fold)
(export item-list->hash!)
-(export string-split)
(export string-join)
(export gnc:backtrace-if-exception)
(export gnc:find-file)
@@ -58,9 +56,13 @@
(export gnc:main)
(export gnc:safe-strcmp) ;; only used by aging.scm atm...
+(re-export hash-fold)
+(re-export string-split)
+
;; from path.scm
(export gnc:make-home-dir)
(export gnc:current-config-auto)
+(export gnc:current-saved-reports)
;; from command-line.scm
(export gnc:*config-path*)
Index: path.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/path.scm,v
retrieving revision 1.18.4.1
retrieving revision 1.18.4.2
diff -Lsrc/scm/path.scm -Lsrc/scm/path.scm -u -r1.18.4.1 -r1.18.4.2
--- src/scm/path.scm
+++ src/scm/path.scm
@@ -42,21 +42,30 @@
(define gnc:current-config-auto
(build-path (getenv "HOME") ".gnucash" "config-2.0.auto"))
+(define gnc:current-saved-reports
+ (build-path (getenv "HOME") ".gnucash" "saved-reports-2.0"))
+
(define gnc:load-user-config-if-needed
(let ((user-config-loaded? #f))
- (define (try-load file-suffix)
+ (define (try-load-no-set file-suffix)
(let ((file (build-path (getenv "HOME") ".gnucash" file-suffix)))
+ (gnc:debug "trying to load " file)
(if (access? file F_OK)
(if (false-if-exception (primitive-load file))
- (begin
- (set! user-config-loaded? #t)
- #t)
+ #t
(begin
(gnc:warn "failure loading " file)
#f))
#f)))
+ (define (try-load file-suffix)
+ (if (try-load-no-set file-suffix)
+ (begin
+ (set! user-config-loaded? #t)
+ #t)
+ #f))
+
(lambda ()
(if (not user-config-loaded?)
(begin
@@ -65,8 +74,14 @@
;; Don't continue adding to this list. When 2.0
;; rolls around bump the 1.4 (unnumbered) files
;; off the list.
- '("config-2.0.user" "config-1.8.user" "config-1.6.user"
- "config-2.0.auto" "config-1.8.auto" "config-1.6.auto")))))))
+ '("config-2.0.user" "config-1.8.user"
+ "config-1.6.user" "config.user"
+ "config-2.0.auto" "config-1.8.auto"
+ "config-1.6.auto" "config.auto"))
+ (gnc:debug "loading saved reports")
+ (or-map try-load-no-set
+ '("saved-reports-2.0" "saved-reports-1.8"))
+ )))))
;; the system config should probably be loaded from some directory
;; that wouldn't be a site wide mounted directory, like /usr/share
Index: split-register-layout.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/ledger-core/split-register-layout.h,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -Lsrc/register/ledger-core/split-register-layout.h -Lsrc/register/ledger-core/split-register-layout.h -u -r1.1 -r1.1.6.1
--- src/register/ledger-core/split-register-layout.h
+++ src/register/ledger-core/split-register-layout.h
@@ -26,6 +26,26 @@
#include "table-layout.h"
#include "split-register.h"
+/** @addtogroup Register
+ * @{
+ * @file split-register-layout.h
+ * @author Copyright (C) 1998, 2004 Linas Vepstas <linas at linas.org>
+ */
+
+/** Create the actual register visual layout: pick specific cell types
+ * to sit in specific columns, and add connections so that user can tab
+ * from one field to the next.
+ *
+ * The actual layout depends on the register type, but, typically,
+ * all of the registers have the date cell on the left, description
+ * in the middle, and monetary totals on the right.
+ *
+ * This implementation hard-codes the layout in C, although the
+ * original intent was that the layout would be fetched from a
+ * config file that could be tweaked for a specific, non-GnuCash
+ * application.
+ */
TableLayout * gnc_split_register_layout_new (SplitRegister *reg);
+/** @} */
#endif
Index: split-register-layout.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/ledger-core/split-register-layout.c,v
retrieving revision 1.14.4.2
retrieving revision 1.14.4.3
diff -Lsrc/register/ledger-core/split-register-layout.c -Lsrc/register/ledger-core/split-register-layout.c -u -r1.14.4.2 -r1.14.4.3
--- src/register/ledger-core/split-register-layout.c
+++ src/register/ledger-core/split-register-layout.c
@@ -1,5 +1,6 @@
/********************************************************************\
* split-register-layout.c -- split register layout object *
+ * Copyright (C) 1998 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 *
@@ -111,7 +112,7 @@
gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 6);
}
gnc_table_layout_set_cell (layout, curs, BALN_CELL, 0, 7);
- gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 8);
+ gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 8);
curs_last = curs;
curs = gnc_table_layout_get_cursor (layout,
@@ -132,7 +133,7 @@
gnc_table_layout_set_cell (layout, curs, TDEBT_CELL, 0, 5);
gnc_table_layout_set_cell (layout, curs, TCRED_CELL, 0, 6);
gnc_table_layout_set_cell (layout, curs, TBALN_CELL, 0, 7);
- gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 8);
+ gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 8);
curs_last = curs;
curs = gnc_table_layout_get_cursor (layout,
@@ -160,7 +161,7 @@
gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 5);
gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 6);
}
- gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 8);
+ gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 8);
break;
}
@@ -173,13 +174,13 @@
CURSOR_SINGLE_LEDGER);
gnc_table_layout_set_cell (layout, curs, DATE_CELL, 0, 0);
- gnc_table_layout_set_cell (layout, curs, TYPE_CELL, 0, 1);
- gnc_table_layout_set_cell (layout, curs, DDUE_CELL, 0, 2);
+ gnc_table_layout_set_cell (layout, curs, TYPE_CELL, 0, 1);
+ gnc_table_layout_set_cell (layout, curs, DDUE_CELL, 0, 2);
gnc_table_layout_set_cell (layout, curs, NUM_CELL, 0, 3);
gnc_table_layout_set_cell (layout, curs, DESC_CELL, 0, 4);
gnc_table_layout_set_cell (layout, curs, MXFRM_CELL, 0, 5);
- gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 6);
- gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 7);
+ gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 6);
+ gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 7);
gnc_table_layout_set_cell (layout, curs, BALN_CELL, 0, 8);
curs_last = curs;
@@ -195,8 +196,8 @@
CURSOR_SINGLE_JOURNAL);
gnc_table_layout_set_cell (layout, curs, DATE_CELL, 0, 0);
- gnc_table_layout_set_cell (layout, curs, TYPE_CELL, 0, 1);
- gnc_table_layout_set_cell (layout, curs, DDUE_CELL, 0, 2);
+ gnc_table_layout_set_cell (layout, curs, TYPE_CELL, 0, 1);
+ gnc_table_layout_set_cell (layout, curs, DDUE_CELL, 0, 2);
gnc_table_layout_set_cell (layout, curs, NUM_CELL, 0, 3);
gnc_table_layout_set_cell (layout, curs, DESC_CELL, 0, 4);
@@ -218,8 +219,8 @@
gnc_table_layout_set_cell (layout, curs, ACTN_CELL, 0, 3);
gnc_table_layout_set_cell (layout, curs, MEMO_CELL, 0, 4);
gnc_table_layout_set_cell (layout, curs, XFRM_CELL, 0, 5);
- gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 6);
- gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 7);
+ gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 6);
+ gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 7);
break;
}
@@ -247,7 +248,7 @@
gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 5);
gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 6);
}
- gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 7);
+ gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 7);
curs_last = curs;
curs = gnc_table_layout_get_cursor (layout,
@@ -267,7 +268,7 @@
gnc_table_layout_set_cell (layout, curs, DESC_CELL, 0, 2);
gnc_table_layout_set_cell (layout, curs, TDEBT_CELL, 0, 5);
gnc_table_layout_set_cell (layout, curs, TCRED_CELL, 0, 6);
- gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 7);
+ gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 7);
curs_last = curs;
curs = gnc_table_layout_get_cursor (layout,
@@ -295,7 +296,7 @@
gnc_table_layout_set_cell (layout, curs, DEBT_CELL, 0, 5);
gnc_table_layout_set_cell (layout, curs, CRED_CELL, 0, 6);
}
- gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 7);
+ gnc_table_layout_set_cell (layout, curs, RATE_CELL, 0, 7);
break;
}
@@ -522,11 +523,11 @@
gnc_register_add_cell (layout,
NUM_CELL,
NUM_CELL_TYPE_NAME,
- /* Translators: The 'sample:' items are
- strings which are not displayed, but only
- used to estimate widths. Please only
- translate the portion after the ':' and
- leave the rest ("sample:") as is. */
+ /* Translators: The 'sample:' items are
+ strings which are not displayed, but only
+ used to estimate widths. Please only
+ translate the portion after the ':' and
+ leave the rest ("sample:") as is. */
N_("sample:99999") + 7,
CELL_ALIGN_LEFT,
FALSE,
Index: split-register.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/ledger-core/split-register.c,v
retrieving revision 1.40.2.4
retrieving revision 1.40.2.5
diff -Lsrc/register/ledger-core/split-register.c -Lsrc/register/ledger-core/split-register.c -u -r1.40.2.4 -r1.40.2.5
--- src/register/ledger-core/split-register.c
+++ src/register/ledger-core/split-register.c
@@ -18,12 +18,10 @@
* *
\********************************************************************/
-/*
- * FILE:
- * split-register.c
- *
- * FUNCTION:
- * Provide view for SplitRegister object.
+/**
+ * @addtogroup Ledger
+ * @file split-register.c
+ * @brief Provide view for SplitRegister object.
*
*
* DESIGN NOTES:
@@ -90,9 +88,8 @@
* from the engine.
*
*
- * HISTORY:
- * Copyright (c) 1998-2000 Linas Vepstas
- * Copyright (c) 2000-2001 Dave Peticolas <dave at krondo.com>
+ * @author Copyright (c) 1998-2000 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2000-2001 Dave Peticolas <dave at krondo.com>
*/
#define _GNU_SOURCE
@@ -698,10 +695,10 @@
/* unprotect the old object, if any */
if (copied_item != SCM_UNDEFINED)
- scm_unprotect_object(copied_item);
+ scm_gc_unprotect_object(copied_item);
copied_item = new_item;
- scm_protect_object(copied_item);
+ scm_gc_protect_object(copied_item);
copied_class = cursor_class;
}
@@ -827,6 +824,7 @@
"Are you sure you want to do that?");
gboolean result;
+ Account * copied_leader;
const GUID *new_guid;
int trans_split_index;
int split_index;
@@ -856,10 +854,8 @@
split_index = gnc_trans_split_index(trans, split);
trans_split_index = gnc_trans_split_index(trans, trans_split);
- if ((gnc_split_register_get_default_account (reg) != NULL) &&
- (safe_strcmp (xaccGUIDType(&copied_leader_guid,
- gnc_get_current_book ()),
- GNC_ID_NULL)))
+ copied_leader = xaccAccountLookup (&copied_leader_guid, gnc_get_current_book ());
+ if (copied_leader && (gnc_split_register_get_default_account (reg) != NULL))
{
new_guid = &info->default_account;
gnc_copy_trans_scm_onto_trans_swap_accounts(copied_item, trans,
Index: split-register.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/ledger-core/split-register.h,v
retrieving revision 1.16.4.1
retrieving revision 1.16.4.2
diff -Lsrc/register/ledger-core/split-register.h -Lsrc/register/ledger-core/split-register.h -u -r1.16.4.1 -r1.16.4.2
--- src/register/ledger-core/split-register.h
+++ src/register/ledger-core/split-register.h
@@ -1,6 +1,5 @@
/********************************************************************\
* split-register.h -- split register api *
- * Copyright (C) 1998-2000 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -20,6 +19,43 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
+/** @addtogroup Ledger
+ The register is the spread-sheet-like area that looks like a
+ checkbook register. It displays transactions, and allows the
+ user to edit transactions in-place. The register does *not*
+ contain any of the other window decorations that one might want
+ to have for a fre-standing window (e.g. menubars, toolbars, etc.)
+
+ All user input to the register is handled by the 'cursor', which
+ is mapped onto one of the displayed rows in the register.
+
+ The layout of the register is configurable. There's a broad
+ variety of cell types to choose from: date cells, which know
+ how to parse dates; price cells, which know how to parse prices,
+ etc. These cells can be laid out in any column; even a multi-row
+ layout is supported. The name 'split-register' is derived from
+ the fact that this register can display multiple rows of
+ transaction splits underneath a transaction title/summary row.
+
+ The Register itself is independent of GnuCash, and is designed
+ so that it can be used with other applications.
+ The Ledger is an adaptation of the Register for use by GnuCash.
+ The Ledger sets up an explicit visual layout, putting certain
+ types of cells in specific locations (e.g. date on left, summary
+ in middle, value at right), and hooks up these cells to
+ the various GnuCash financial objects.
+
+ This code is also theoretically independent of the actual GUI
+ toolkit/widget-set (it once worked with both Motif and Gnome).
+ The actual GUI-toolkit specific code is supposed to be in a
+ GUI portability layer. Over the years, some gnome-isms may
+ have snuck in; these should also be cleaned up.
+ @{
+
+ @file split-register.h
+ @brief Checkbook Register Display Area
+ @author Copyright (C) 1998-2000 Linas Vepstas <linas at linas.org>
+*/
#ifndef SPLIT_REGISTER_H
#define SPLIT_REGISTER_H
@@ -30,10 +66,7 @@
#include "Transaction.h"
#include "table-allgui.h"
-
-/** Datatypes *******************************************************/
-
-/* Register types.
+/** Register types.
* "registers" are single-account display windows.
* "ledgers" are multiple-account display windows */
typedef enum
@@ -67,7 +100,7 @@
REG_STYLE_JOURNAL
} SplitRegisterStyle;
-/* Cell Names. T* cells are transaction summary cells */
+/** Cell Names. T* cells are transaction summary cells */
#define ACTN_CELL "action"
#define BALN_CELL "balance"
#define CRED_CELL "credit"
@@ -93,14 +126,15 @@
#define XFRM_CELL "account"
#define VNOTES_CELL "void-notes"
-/* Cursor Names */
+/** Cursor Names */
#define CURSOR_SINGLE_LEDGER "cursor-single-ledger"
#define CURSOR_DOUBLE_LEDGER "cursor-double-ledger"
#define CURSOR_SINGLE_JOURNAL "cursor-single-journal"
#define CURSOR_DOUBLE_JOURNAL "cursor-double-journal"
#define CURSOR_SPLIT "cursor-split"
-/* Types of cursors */
+
+/** Types of cursors */
typedef enum
{
CURSOR_CLASS_NONE = -1,
@@ -131,7 +165,7 @@
struct split_register
{
- /* the table itself that implements the underlying GUI. */
+ /** The table itself that implements the underlying GUI. */
Table * table;
SplitRegisterType type;
@@ -140,67 +174,67 @@
gboolean use_double_line;
gboolean is_template;
- /* private data; outsiders should not access this */
+ /** private data; outsiders should not access this */
SRInfo * sr_info;
};
-/* Callback function type */
+/** Callback function type */
typedef gncUIWidget (*SRGetParentCallback) (gpointer user_data);
-/** Prototypes ******************************************************/
+/* Prototypes ******************************************************/
-/* Create and return a new split register. */
+/** Create and return a new split register. */
SplitRegister * gnc_split_register_new (SplitRegisterType type,
SplitRegisterStyle style,
gboolean use_double_line,
gboolean is_template);
-/* Configure the split register. */
+/** Configure the split register. */
void gnc_split_register_config (SplitRegister *reg,
SplitRegisterType type,
SplitRegisterStyle style,
gboolean use_double_line);
-/* Destroy the split register. */
+/** Destroy the split register. */
void gnc_split_register_destroy (SplitRegister *reg);
-/* Make a register window read-only. */
+/** Make a register window read-only. */
void gnc_split_register_set_read_only (SplitRegister *reg, gboolean read_only);
-/* Set the template account used by template registers */
+/** Set the template account used by template registers */
void gnc_split_register_set_template_account (SplitRegister *reg,
Account *template_account);
-/* Returns the class of the current cursor */
+/** Returns the class of the current cursor */
CursorClass gnc_split_register_get_current_cursor_class (SplitRegister *reg);
-/* Returns the class of the cursor at the given virtual cell location. */
+/** Returns the class of the cursor at the given virtual cell location. */
CursorClass gnc_split_register_get_cursor_class
(SplitRegister *reg,
VirtualCellLocation vcell_loc);
-/* Sets the user data and callback hooks for the register. */
+/** Sets the user data and callback hooks for the register. */
void gnc_split_register_set_data (SplitRegister *reg, gpointer user_data,
SRGetParentCallback get_parent);
-/* Returns the transaction which is the parent of the current split. */
+/** Returns the transaction which is the parent of the current split. */
Transaction * gnc_split_register_get_current_trans (SplitRegister *reg);
-/* Returns the split at which the cursor is currently located. */
+/** Returns the split at which the cursor is currently located. */
Split * gnc_split_register_get_current_split (SplitRegister *reg);
-/* Returns the blank split or NULL if there is none. */
+/** Returns the blank split or NULL if there is none. */
Split * gnc_split_register_get_blank_split (SplitRegister *reg);
-/* Searches the split register for the given split. If found, it
+/** Searches the split register for the given split. If found, it
* returns TRUE and vcell_loc is set to the location of the
* split. Otherwise, returns FALSE. */
gboolean
gnc_split_register_get_split_virt_loc (SplitRegister *reg, Split *split,
VirtualCellLocation *vcell_loc);
-/* Searches the split register for the given split. If found, it
+/** Searches the split register for the given split. If found, it
* returns TRUE and virt_loc is set to the location of either the
* debit or credit column in the split, whichever one is
* non-blank. Otherwise, returns FALSE. */
@@ -208,64 +242,64 @@
gnc_split_register_get_split_amount_virt_loc (SplitRegister *reg, Split *split,
VirtualLocation *virt_loc);
-/* Given the current virtual location, find the split that anchors
+/** Given the current virtual location, find the split that anchors
* this transaction to the current register. Otherwise, returns NULL.
*/
Split *
gnc_split_register_get_current_trans_split (SplitRegister *reg,
VirtualCellLocation *vcell_loc);
-/* Duplicates either the current transaction or the current split
+/** Duplicates either the current transaction or the current split
* depending on the register mode and cursor position. Returns the
* split just created, or the 'main' split of the transaction just
* created, or NULL if nothing happened. */
Split * gnc_split_register_duplicate_current (SplitRegister *reg);
-/* Makes a copy of the current entity, either a split or a
+/** Makes a copy of the current entity, either a split or a
* transaction, so that it can be pasted later. */
void gnc_split_register_copy_current (SplitRegister *reg);
-/* Equivalent to copying the current entity and the deleting it with
+/** Equivalent to copying the current entity and the deleting it with
* the approriate delete method. */
void gnc_split_register_cut_current (SplitRegister *reg);
-/* Pastes a previous copied entity onto the current entity, but only
+/** Pastes a previous copied entity onto the current entity, but only
* if the copied and current entity have the same type. */
void gnc_split_register_paste_current (SplitRegister *reg);
-/* Deletes the split associated with the current cursor, if both are
+/** Deletes the split associated with the current cursor, if both are
* non-NULL. Deleting the blank split just clears cursor values. */
void gnc_split_register_delete_current_split (SplitRegister *reg);
-/* Deletes the transaction associated with the current cursor, if both
+/** Deletes the transaction associated with the current cursor, if both
* are non-NULL. */
void gnc_split_register_delete_current_trans (SplitRegister *reg);
-/* Voids the transaction associated with the current cursor, if
+/** Voids the transaction associated with the current cursor, if
* non-NULL. */
void gnc_split_register_void_current_trans (SplitRegister *reg,
const char *reason);
-/* Unvoids the transaction associated with the current cursor, if
+/** Unvoids the transaction associated with the current cursor, if
* non-NULL. */
void gnc_split_register_unvoid_current_trans (SplitRegister *reg);
-/* Deletes the non-transaction splits associated wih the current
+/** Deletes the non-transaction splits associated wih the current
* cursor, if both are non-NULL. */
void gnc_split_register_empty_current_trans_except_split (SplitRegister *reg, Split *split);
void gnc_split_register_empty_current_trans (SplitRegister *reg);
-/* Cancels any changes made to the current cursor, reloads the cursor
+/** Cancels any changes made to the current cursor, reloads the cursor
* from the engine, reloads the table from the cursor, and updates
* the GUI. The change flags are cleared. */
void gnc_split_register_cancel_cursor_split_changes (SplitRegister *reg);
-/* Cancels any changes made to the current pending transaction,
+/** Cancels any changes made to the current pending transaction,
* reloads the table from the engine, and updates the GUI. The
* change flags are cleared. */
void gnc_split_register_cancel_cursor_trans_changes (SplitRegister *reg);
-/* Copy transaction information from a list of splits to the rows of
+/** Copy transaction information from a list of splits to the rows of
* the register GUI. The third argument, default_source_acc, will
* be used to initialize the source account of a new, blank split
* appended to the tail end of the register. This "blank split" is
@@ -274,7 +308,8 @@
void gnc_split_register_load (SplitRegister *reg, GList * split_list,
Account *default_source_acc);
-/* Copy the contents of the current cursor to a split. The split and
+
+/** Copy the contents of the current cursor to a split. The split and
* transaction that are updated are the ones associated with the
* current cursor (register entry) position. If the do_commit flag
* is set, the transaction will also be committed. If it is the
@@ -283,50 +318,60 @@
* something was changed. */
gboolean gnc_split_register_save (SplitRegister *reg, gboolean do_commit);
-/* Causes a redraw of the register window associated with reg. */
+/** Causes a redraw of the register window associated with reg. */
void gnc_split_register_redraw (SplitRegister *reg);
-/* Returns TRUE if the register has changed cells. */
+/** Returns TRUE if the register has changed cells. */
gboolean gnc_split_register_changed (SplitRegister *reg);
-/* If TRUE, visually indicate the demarcation between splits with post
+/** If TRUE, visually indicate the demarcation between splits with post
* dates prior to the present, and after. This will only make sense if
* the splits are ordered primarily by post date. */
void gnc_split_register_show_present_divider (SplitRegister *reg,
gboolean show_present);
-/* Set the colors used by SplitRegisters */
+/** Set the colors used by SplitRegisters */
void gnc_split_register_set_colors (SplitRegisterColors reg_colors);
-/* If use_red is TRUE, negative amounts will be printed in red. */
+/** If use_red is TRUE, negative amounts will be printed in red. */
void gnc_split_register_colorize_negative (gboolean use_red);
-/* Expand the current transaction if it is collapsed. */
+/** Expand the current transaction if it is collapsed. */
void gnc_split_register_expand_current_trans (SplitRegister *reg,
gboolean expand);
-/* Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER. */
+/** Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER. */
gboolean gnc_split_register_current_trans_expanded (SplitRegister *reg);
-/* Return the debit and credit strings used in the register. */
+/** Return the debit string used in the register. */
const char * gnc_split_register_get_debit_string (SplitRegister *reg);
+
+/** Return the credit string used in the register. */
const char * gnc_split_register_get_credit_string (SplitRegister *reg);
-/* Private functions */
+
+/** Pop up the exchange-rate dialog, maybe, for the current split.
+ * If force_dialog is TRUE, the forces the dialog to to be called.
+ * If the dialog does not complete successfully, then return TRUE.
+ * Return FALSE in all other cases (meaning "move on")
+ */
+gboolean
+gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog);
+
+/* -------------------------------------------------------------- */
+
+/** Private function -- outsiders must not use this */
gboolean gnc_split_register_full_refresh_ok (SplitRegister *reg);
+
+/** Private function -- outsiders must not use this */
void gnc_split_register_load_xfer_cells (SplitRegister *reg,
Account *base_account);
+/** Private function -- outsiders must not use this */
void gnc_copy_trans_onto_trans (Transaction *from, Transaction *to,
gboolean use_cut_semantics,
gboolean do_commit);
-/* (maybe) pop up the exchange-rate dialog for the current split.
- * if force_dialog is TRUE, the forces the dialog to to be called.
- * If the dialog does not complete successfully, then return TRUE.
- * Return FALSE in all other cases (meaning "move on")
- */
-gboolean
-gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog);
-
#endif
+
+/** @} */
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.3
retrieving revision 1.24.4.4
diff -Lsrc/register/ledger-core/gnc-ledger-display.c -Lsrc/register/ledger-core/gnc-ledger-display.c -u -r1.24.4.3 -r1.24.4.4
--- src/register/ledger-core/gnc-ledger-display.c
+++ src/register/ledger-core/gnc-ledger-display.c
@@ -81,7 +81,7 @@
GNCLedgerDisplayType ld_type,
SplitRegisterType reg_type,
SplitRegisterStyle style,
- gboolean use_double_line,
+ gboolean use_double_line,
gboolean is_template);
static void gnc_ledger_display_refresh_internal (GNCLedgerDisplay *ld,
GList *splits);
@@ -226,8 +226,8 @@
default:
style_string = gnc_lookup_multichoice_option("Register",
- "Default Register Style",
- "ledger");
+ "Default Register Style",
+ "ledger");
if (safe_strcmp(style_string, "ledger") == 0)
new_style = REG_STYLE_LEDGER;
@@ -245,13 +245,26 @@
return new_style;
}
+static gpointer
+look_for_portfolio_cb (Account *account, gpointer data)
+{
+ GNCAccountType le_type;
+
+ le_type = xaccAccountGetType (account);
+ if ((STOCK == le_type) ||
+ (MUTUAL == le_type) ||
+ (CURRENCY == le_type))
+ {
+ return (gpointer) PORTFOLIO_LEDGER;
+ }
+ return NULL;
+}
+
static SplitRegisterType
gnc_get_reg_type (Account *leader, GNCLedgerDisplayType ld_type)
{
GNCAccountType account_type;
SplitRegisterType reg_type;
- GList *subaccounts;
- GList *node;
if (ld_type == LD_GL)
return GENERAL_LEDGER;
@@ -278,10 +291,10 @@
return LIABILITY_REGISTER;
case PAYABLE:
- return PAYABLE_REGISTER;
+ return PAYABLE_REGISTER;
case RECEIVABLE:
- return RECEIVABLE_REGISTER;
+ return RECEIVABLE_REGISTER;
case STOCK:
case MUTUAL:
@@ -311,8 +324,6 @@
return BANK_REGISTER;
}
- subaccounts = xaccGroupGetSubAccounts (xaccAccountGetChildren (leader));
-
switch (account_type)
{
case BANK:
@@ -322,25 +333,19 @@
case LIABILITY:
case RECEIVABLE:
case PAYABLE:
- /* if any of the sub-accounts have STOCK or MUTUAL types,
+ {
+ /* If any of the sub-accounts have STOCK or MUTUAL types,
* then we must use the PORTFOLIO_LEDGER ledger. Otherwise,
* a plain old GENERAL_LEDGER will do. */
+ gpointer ret;
reg_type = GENERAL_LEDGER;
- for (node = subaccounts; node; node = node->next)
- {
- GNCAccountType le_type;
-
- le_type = xaccAccountGetType (node->data);
- if ((STOCK == le_type) ||
- (MUTUAL == le_type) ||
- (CURRENCY == le_type))
- {
- reg_type = PORTFOLIO_LEDGER;
- break;
- }
- }
+ ret = xaccGroupForEachAccount (xaccAccountGetChildren (leader),
+ look_for_portfolio_cb,
+ NULL, TRUE);
+ if (ret) reg_type = PORTFOLIO_LEDGER;
break;
+ }
case STOCK:
case MUTUAL:
@@ -363,8 +368,6 @@
break;
}
- g_list_free (subaccounts);
-
return reg_type;
}
@@ -374,7 +377,7 @@
gnc_ledger_display_default_double_line (GNCLedgerDisplay *gld)
{
return (gld->use_double_line_default ||
- gnc_lookup_boolean_option ("Register", "Double Line Mode", FALSE));
+ gnc_lookup_boolean_option ("Register", "Double Line Mode", FALSE));
}
/* Opens up a register window to display a single account */
@@ -413,7 +416,7 @@
return gnc_ledger_display_internal (account, NULL, LD_SUBACCOUNT,
reg_type, REG_STYLE_JOURNAL, FALSE,
- FALSE);
+ FALSE);
}
/* Opens up a general ledger window. */
@@ -433,7 +436,7 @@
* transactions. While these are in a seperate AccountGroup just for this
* reason, the query engine makes no distinction between AccountGroups.
* See Gnome Bug 86302.
- * -- jsled */
+ * -- jsled */
{
AccountGroup *tAG;
AccountList *al;
@@ -666,7 +669,7 @@
SplitRegisterStyle style)
{
return gnc_ledger_display_internal (NULL, query, LD_GL, type, style,
- FALSE, FALSE);
+ FALSE, FALSE);
}
static GNCLedgerDisplay *
@@ -674,7 +677,7 @@
GNCLedgerDisplayType ld_type,
SplitRegisterType reg_type,
SplitRegisterStyle style,
- gboolean use_double_line,
+ gboolean use_double_line,
gboolean is_template )
{
GNCLedgerDisplay *ld;
@@ -778,7 +781,7 @@
ld->use_double_line_default = use_double_line;
ld->reg = gnc_split_register_new (reg_type, style, use_double_line,
- is_template);
+ is_template);
gnc_split_register_set_data (ld->reg, ld, gnc_ledger_display_parent);
Index: split-register-load.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/ledger-core/split-register-load.c,v
retrieving revision 1.23.4.2
retrieving revision 1.23.4.3
diff -Lsrc/register/ledger-core/split-register-load.c -Lsrc/register/ledger-core/split-register-load.c -u -r1.23.4.2 -r1.23.4.3
--- src/register/ledger-core/split-register-load.c
+++ src/register/ledger-core/split-register-load.c
@@ -1,5 +1,7 @@
/********************************************************************\
* split-register-load.c -- split register loading code *
+ * Copyright (C) 1998-2000 Linas Vepstas <linas at linas.org> *
+ * Copyright (C) 2000 Dave Peticolas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -23,6 +25,7 @@
#include "config.h"
#include "Group.h"
+#include "account-quickfill.h"
#include "combocell.h"
#include "global-options.h"
#include "gnc-component-manager.h"
@@ -36,8 +39,7 @@
/* This static indicates the debugging module that this .o belongs to. */
-static short module = MOD_LEDGER;
-
+/* static short module = MOD_LEDGER; */
static void
gnc_split_register_load_recn_cells (SplitRegister *reg)
@@ -276,6 +278,7 @@
/* get the current time and reset the dividing row */
present = gnc_timet_get_today_end ();
+
if (info->first_pass)
{
if (default_account)
@@ -292,6 +295,28 @@
has_last_num = TRUE;
}
}
+
+ /* set the completion character for the xfer cells */
+ gnc_combo_cell_set_complete_char
+ ((ComboCell *)
+ gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
+ gnc_get_account_separator ());
+
+ gnc_combo_cell_set_complete_char
+ ((ComboCell *)
+ gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL),
+ gnc_get_account_separator ());
+
+ /* set the confirmation callback for the reconcile cell */
+ gnc_recn_cell_set_confirm_cb
+ ((RecnCell *)
+ gnc_table_layout_get_cell (reg->table->layout, RECN_CELL),
+ gnc_split_register_recn_cell_confirm, reg);
+
+ /* load up account names into the transfer combobox menus */
+ gnc_split_register_load_xfer_cells (reg, default_account);
+ gnc_split_register_load_recn_cells (reg);
+ gnc_split_register_load_type_cells (reg);
}
table->model->dividing_row = -1;
@@ -512,70 +537,44 @@
gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
- /* set the completion character for the xfer cells */
- gnc_combo_cell_set_complete_char
- ((ComboCell *)
- gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
- gnc_get_account_separator ());
-
- gnc_combo_cell_set_complete_char
- ((ComboCell *)
- gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL),
- gnc_get_account_separator ());
-
- /* set the confirmation callback for the reconcile cell */
- gnc_recn_cell_set_confirm_cb
- ((RecnCell *)
- gnc_table_layout_get_cell (reg->table->layout, RECN_CELL),
- gnc_split_register_recn_cell_confirm, reg);
-
/* enable callback for cursor user-driven moves */
gnc_table_control_allow_move (table->control, TRUE);
-
- gnc_split_register_load_xfer_cells (reg, default_account);
- gnc_split_register_load_recn_cells (reg);
- gnc_split_register_load_type_cells (reg);
}
-static void
-gnc_load_xfer_cell (ComboCell * cell, AccountGroup * grp)
-{
- GList *list;
- GList *node;
-
- ENTER ("\n");
-
- if (!grp) return;
+/* ===================================================================== */
+/* Splat the account name into the transfer cell combobox menu */
- /* Build the xfer menu out of account names. */
+static gpointer
+load_xfer_cell_cb (Account *account, gpointer data)
+{
+ ComboCell *cell = data;
+ char *name;
- list = xaccGroupGetSubAccounts (grp);
+ if (xaccAccountGetPlaceholder (account)) return NULL;
- for (node = list; node; node = node->next)
- {
- Account *account = node->data;
- char *name;
+ name = xaccAccountGetFullName (account, gnc_get_account_separator ());
+ if (NULL == name) return NULL;
+ gnc_combo_cell_add_menu_item (cell, name);
+ g_free(name);
- if (xaccAccountGetPlaceholder (account))
- continue;
+ return NULL;
+}
- name = xaccAccountGetFullName (account, gnc_get_account_separator ());
- if (name != NULL)
- {
- gnc_combo_cell_add_menu_item (cell, name);
- g_free(name);
- }
- }
+/* ===================================================================== */
- g_list_free (list);
+#define QKEY "split_reg_shared_quickfill"
- LEAVE ("\n");
+static gboolean
+skip_cb (Account *account, gpointer x)
+{
+ return xaccAccountGetPlaceholder (account);
}
void
gnc_split_register_load_xfer_cells (SplitRegister *reg, Account *base_account)
{
AccountGroup *group;
+ QuickFill *qf;
ComboCell *cell;
group = xaccAccountGetRoot(base_account);
@@ -585,13 +584,19 @@
if (group == NULL)
return;
+ qf = gnc_get_shared_account_name_quickfill (group, QKEY, skip_cb, NULL);
+
cell = (ComboCell *)
gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
gnc_combo_cell_clear_menu (cell);
- gnc_load_xfer_cell (cell, group);
+ gnc_combo_cell_use_quickfill_cache (cell, qf);
+ xaccGroupForEachAccount (group, load_xfer_cell_cb, cell, TRUE);
cell = (ComboCell *)
gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL);
gnc_combo_cell_clear_menu (cell);
- gnc_load_xfer_cell (cell, group);
+ gnc_combo_cell_use_quickfill_cache (cell, qf);
+ xaccGroupForEachAccount (group, load_xfer_cell_cb, cell, TRUE);
}
+
+/* ====================== END OF FILE ================================== */
Index: print-check.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/printing/print-check.scm,v
retrieving revision 1.11.4.2
retrieving revision 1.11.4.3
diff -Lsrc/scm/printing/print-check.scm -Lsrc/scm/printing/print-check.scm -u -r1.11.4.2 -r1.11.4.3
--- src/scm/printing/print-check.scm
+++ src/scm/printing/print-check.scm
@@ -3,6 +3,8 @@
;;; print a check from a transaction.
;;;
;;; Copyright 2000 Bill Gribble <grib at billgribble.com>
+;;; June 2004 - D. Reiser - added capability to print wallet checks
+;;; with left-side stubs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(use-modules (gnucash printing number-to-words))
@@ -67,19 +69,33 @@
(memo . (100.0 73.0))
(rotate . 90.0)
(translate . (232.0 300.0))
- (offset . 0.0)))
- (quicken . ((payee . (90.0 150.0))
+ (offset . 0.0))) ;;declaration of offset preempts top/middle/bottom dialog choice
+ (quicken . ((payee . (90.0 150.0))
(amount-words . (90.0 120.0))
(amount-number . (500.0 150.0))
(date . (500.0 185.0))
- (memo . (50.0 40.0))))
+ (memo . (50.0 40.0))
+ (top . 540.0)
+ (middle . 288.0)
+ (bottom . 36.0)))
+ (wallet . ((payee . (231.0 140.0)) ;;these coord. for placement above amount-word line
+ ;;use 202.0 94.0 for placement in address area
+ (amount-words . (195.0 125.0))
+ (amount-number . (518.0 137.0))
+ (date . (504.0 151.0))
+ (memo . (216.0 37.0))
+ (date-stub . (36.0 151.0))
+ (payee-stub . (28.0 126.0))
+ (amount-stub . (50.0 90.0))
+ (memo-stub . (28.0 65.0))
+ (top . 588.0)
+ (middle . 384.0)
+ (bottom . 180.0)))
+ (custom . ((top . 540.0) ;;set default perforation location for custom print layout
+ (middle . 288.0)
+ (bottom . 36.0)))
))
-(define gnc:*stock-check-positions*
- '((top . 540.0)
- (middle . 288.0)
- (bottom . 36.0)))
-
(define (gnc:print-check format-info payee amount date memo)
(let* ((int-part (inexact->exact (truncate amount)))
(frac-part (inexact->exact
@@ -88,7 +104,9 @@
(ps (gnc:print-session-create #t))
(format #f)
(offset #f)
- (date-string ""))
+ (date-string "")
+ (payee-stub-text "")
+ (memo-stub-text ""))
(if (not (eq? (print-check-format:format format-info) 'custom))
(begin
(set! format (assq (print-check-format:format format-info)
@@ -104,7 +122,8 @@
(begin
(set! offset
(cdr (assq (print-check-format:position format-info)
- gnc:*stock-check-positions*)))
+ (cdr (assq (print-check-format:format format-info)
+ gnc:*stock-check-formats*)))))
(if (pair? offset)
(set! offset (cdr offset))))
(set! offset
@@ -155,6 +174,34 @@
(+ offset (caddr memo-pos)))
(gnc:print-session-text ps memo))
+ (if (eq? (print-check-format:format format-info) 'wallet)
+ (begin
+ (let ((memostub-pos (assq 'memo-stub format)))
+ (gnc:print-session-moveto ps (cadr memostub-pos)
+ (+ offset (caddr memostub-pos)))
+ (if (< (string-length memo) 22)
+ (set! memo-stub-text memo)
+ (set! memo-stub-text (substring memo 0 20)))
+ (gnc:print-session-text ps memo-stub-text))
+
+ (let ((datestub-pos (assq 'date-stub format)))
+ (gnc:print-session-moveto ps (cadr datestub-pos)
+ (+ offset (caddr datestub-pos)))
+ (gnc:print-session-text ps date-string))
+
+ (let ((payeestub-pos (assq 'payee-stub format)))
+ (gnc:print-session-moveto ps (cadr payeestub-pos)
+ (+ offset (caddr payeestub-pos)))
+ (if (< (string-length payee) 22)
+ (set! payee-stub-text payee)
+ (set! payee-stub-text (substring payee 0 20)))
+ (gnc:print-session-text ps payee-stub-text))
+
+ (let ((amountstub-pos (assq 'amount-stub format)))
+ (gnc:print-session-moveto ps (cadr amountstub-pos)
+ (+ offset (caddr amountstub-pos)))
+ (gnc:print-session-text ps (printable-value amount 100)))))
+
(gnc:print-session-done ps #t)
(gnc:print-session-print ps)))
Index: qofquery.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery.c,v
retrieving revision 1.10.2.4
retrieving revision 1.10.2.5
diff -Lsrc/engine/qofquery.c -Lsrc/engine/qofquery.c -u -r1.10.2.4 -r1.10.2.5
--- src/engine/qofquery.c
+++ src/engine/qofquery.c
@@ -1242,9 +1242,10 @@
if (g_list_index (q->books, book) == -1)
q->books = g_list_prepend (q->books, book);
- qof_query_add_guid_match (q, g_slist_prepend (g_slist_prepend (NULL,
- QOF_QUERY_PARAM_GUID),
- QOF_QUERY_PARAM_BOOK),
+ GSList *slist = NULL;
+ g_slist_prepend (slist, QOF_PARAM_GUID);
+ g_slist_prepend (slist, QOF_PARAM_BOOK);
+ qof_query_add_guid_match (q, slist,
qof_book_get_guid(book), QOF_QUERY_AND);
}
@@ -1720,7 +1721,7 @@
g_string_sprintfa (gs, "\n Match type %s",
qof_query_printNumericMatch (pdata->options));
g_string_sprintfa (gs, " gnc_numeric: %s",
- gnc_numeric_to_string (pdata->amount));
+ gnc_num_dbg_to_string (pdata->amount));
return;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
Index: Account.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Account.c,v
retrieving revision 1.222.4.5
retrieving revision 1.222.4.6
diff -Lsrc/engine/Account.c -Lsrc/engine/Account.c -u -r1.222.4.5 -r1.222.4.6
--- src/engine/Account.c
+++ src/engine/Account.c
@@ -32,7 +32,6 @@
#include "Group.h"
#include "GroupP.h"
#include "TransactionP.h"
-#include "gnc-be-utils.h"
#include "gnc-date.h"
#include "gnc-engine.h"
#include "gnc-engine-util.h"
@@ -48,6 +47,7 @@
#include "qofbackend.h"
#include "qofbackend-p.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofbook-p.h"
#include "qofclass.h"
@@ -318,7 +318,7 @@
void
xaccAccountBeginEdit (Account *acc)
{
- GNC_BEGIN_EDIT (&acc->inst);
+ QOF_BEGIN_EDIT (&acc->inst);
}
static inline void noop(QofInstance *inst) {}
@@ -338,7 +338,7 @@
void
xaccAccountCommitEdit (Account *acc)
{
- GNC_COMMIT_EDIT_PART1 (&acc->inst);
+ QOF_COMMIT_EDIT_PART1 (&acc->inst);
/* If marked for deletion, get rid of subaccounts first,
* and then the splits ... */
@@ -385,7 +385,7 @@
xaccGroupInsertAccount(acc->parent, acc);
}
- GNC_COMMIT_EDIT_PART2 (&acc->inst, on_err, noop, acc_free);
+ QOF_COMMIT_EDIT_PART2 (&acc->inst, on_err, noop, acc_free);
gnc_engine_gen_event (&acc->inst.entity, GNC_EVENT_MODIFY);
}
@@ -895,7 +895,7 @@
* denominator AKA 'SCU Smallest Currency Unit'. */
/* xaccSplitSetAmount(split, old_amt); */
split->amount = gnc_numeric_convert (old_amt,
- xaccAccountGetCommoditySCU(acc), GNC_RND_ROUND);
+ xaccAccountGetCommoditySCU(acc), GNC_HOW_RND_ROUND);
xaccTransCommitEdit(trans);
xaccAccountCommitEdit(acc);
LEAVE ("(acc=%p, split=%p)", acc, split);
@@ -1818,7 +1818,7 @@
balance = xaccAccountGetXxxBalanceInCurrency (account, cb->fn, cb->currency);
cb->balance = gnc_numeric_add (cb->balance, balance,
gnc_commodity_get_fraction (cb->currency),
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
return NULL;
}
@@ -2836,12 +2836,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_ACCOUNT,
type_label: "Account",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: NULL,
mark_clean: NULL,
foreach: qof_collection_foreach,
- printable: (const char* (*)(gpointer)) xaccAccountGetName
+ printable: (const char* (*)(gpointer)) xaccAccountGetName,
+ version_cmp: (int (*)(gpointer,gpointer)) qof_instance_version_cmp,
};
gboolean xaccAccountRegister (void)
@@ -2857,8 +2859,8 @@
{ ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetReconciledBalance, NULL },
{ ACCOUNT_FUTURE_MINIMUM_, QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetProjectedMinimumBalance, NULL },
{ ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN, (QofAccessFunc)xaccAccountGetTaxRelated, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_guid, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
{ ACCOUNT_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
{ NULL },
};
Index: kvp-util.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp-util.h,v
retrieving revision 1.2
retrieving revision 1.2.20.1
diff -Lsrc/engine/kvp-util.h -Lsrc/engine/kvp-util.h -u -r1.2 -r1.2.20.1
--- src/engine/kvp-util.h
+++ src/engine/kvp-util.h
@@ -20,16 +20,26 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
\********************************************************************/
-/** @file kvp-util.h @brief GnuCash KVP utility functions */
+/** @addtogroup KVP
+ @{ */
+/** @file kvp-util.h
+ @brief GnuCash KVP utility functions
+ */
+/** @name Hash Utilities */
+/* @{ */
#ifndef GNC_KVP_UTIL_H
#define GNC_KVP_UTIL_H
#include "config.h"
-/***********************************************************************\
+typedef struct {
+ gpointer key;
+ gpointer value;
+} GHashTableKVPair;
- g_hash_table_key_value_pairs(hash): Returns a GSList* of all the
+/**
+ Returns a GSList* of all the
keys and values in a given hash table. Data elements of lists are
actual hash elements, so be careful, and deallocation of the
GHashTableKVPairs in the result list are the caller's
@@ -42,14 +52,11 @@
*/
-typedef struct {
- gpointer key;
- gpointer value;
-} GHashTableKVPair;
-
GSList *g_hash_table_key_value_pairs(GHashTable *table);
void g_hash_table_kv_pair_free_gfunc(gpointer data, gpointer user_data);
/***********************************************************************/
+/* @} */
+/* @} */
#endif /* GNC_KVP_UTIL_H */
Index: gnc-pricedb.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-pricedb.h,v
retrieving revision 1.27.4.4
retrieving revision 1.27.4.5
diff -Lsrc/engine/gnc-pricedb.h -Lsrc/engine/gnc-pricedb.h -u -r1.27.4.4 -r1.27.4.5
--- src/engine/gnc-pricedb.h
+++ src/engine/gnc-pricedb.h
@@ -34,15 +34,20 @@
#include "qofid.h"
#include "qofinstance.h"
-
-/** @addtogroup Engine
+/** @addtogroup PriceDB
@{ */
-/**********************************************************************/
/** @file gnc-pricedb.h
@author Copyright (C) 2001 Rob Browning
@author Copyright (C) 2001,2003 Linas Vepstas <linas at linas.org>
@brief a simple price database for gnucash
+*/
+/** @} */
+
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup PriceDB Price Database
+ @ingroup Engine
The PriceDB is intended to be a database of price quotes, or more
specifically, a database of GNCPrices. For the time being, it is
still a fairly simple database supporting only fairly simple
@@ -54,12 +59,15 @@
Every QofBook contains a GNCPriceDB, accessable via
gnc_book_get_pricedb.
+ \warning The PriceDB does not currently use the object
+ system used elsewhere in the GnuCash Engine, i.e. it does
+ not use GUISD's, Entities and Collections. Its should.
+ In particular, this means that currently prices cannot
+ be queried with the same emchanism as everything else.
*/
-/* *********************************************************************/
-
-/** GNCPrice:
-
+/** @addtogroup Price Prices
+ @ingroup Engine
Each price in the database represents an "instantaneous" quote for
a given commodity with respect to another commodity. For example,
a given price might represent the value of LNUX in USD on
@@ -116,13 +124,18 @@
exception of the commodity field which just stores the pointer
given. It is assumed that commodities are a global resource and
are pointer unique.
+ */
+/* ================================================================ */
+
+/** @addtogroup Price
+ @{ */
- */
/** */
typedef struct gnc_price_lookup_s GNCPriceLookup;
-/****************/
-/* constructors */
+/* ------------------ */
+/** @name Constructors
+ @{ */
/** gnc_price_create - returns a newly allocated and initialized price
with a reference count of 1. */
@@ -132,9 +145,11 @@
content-wise duplicate of the given price, p. The returned clone
will have a reference count of 1. */
GNCPrice *gnc_price_clone(GNCPrice* p, QofBook *book);
+/** @} */
-/*********************/
-/* memory management */
+/* ------------------ */
+/** @name Memory Management
+ @{ */
/** gnc_price_ref - indicate your need for a given price to stick
around (i.e. increase its reference count by 1). */
@@ -143,9 +158,11 @@
/** gnc_price_ref - indicate you're finished with a price
(i.e. decrease its reference count by 1). */
void gnc_price_unref(GNCPrice *p);
+/** @} */
-/***********/
-/* setters */
+/* ------------------ */
+/** @name Setters
+ @{ */
/* As mentioned above, all of the setters store copies of the data
* given, with the exception of the commodity field which just stores
@@ -167,9 +184,11 @@
void gnc_price_set_type(GNCPrice *p, const char* type);
void gnc_price_set_value(GNCPrice *p, gnc_numeric value);
void gnc_price_set_version(GNCPrice *p, gint32 versn);
+/** @} */
-/***********/
-/* getters */
+/* ------------------ */
+/** @name Getters
+ @{ */
/** As mentioned above all of the getters return data that's internal
to the GNCPrice, not copies, so don't free these values. */
@@ -186,10 +205,10 @@
#define gnc_price_get_guid(X) qof_entity_get_guid(QOF_ENTITY(X))
#define gnc_price_return_guid(X) (*(qof_entity_get_guid(QOF_ENTITY(X))))
#define gnc_price_get_book(X) qof_instance_get_book(QOF_INSTANCE(X))
+/** @} */
-/* ******************************************************************** */
-/** GNCPrice lists:
-
+/* ================================================================ */
+/** @name GNCPrice lists
The database communicates multiple prices in and out via gnc price
lists. These are just time sorted GLists of GNCPrice pointers.
Functions for manipulating these lists are provided. These
@@ -198,7 +217,7 @@
held in a given list. I.e. insert "refs" the prices being
inserted, remove and destroy "unref" the prices that will no
longer be referred to by the list.
-
+ @{
*/
/** gnc_price_list_insert - insert a price into the given list, calling
@@ -214,10 +233,11 @@
void gnc_price_list_destroy(GList *prices);
gboolean gnc_price_list_equal(GList *prices1, GList *prices2);
+/** @} */
+/** @} end of the Price doxygen group */
-/* ******************************************************************** */
-/** GNCPriceDB
-
+/* ================================================================ */
+/** @addtogroup PriceDB
Whenever a you store a price in the pricedb, the pricedb adds its
own reference to the price, so you can safely unref that price after
inserting it into the DB if you're finished with it otherwise.
@@ -226,11 +246,11 @@
or in a price list, the price will have had a ref added for you, so
you only need to unref the price(s) when you're finished with
it/them.
-
+ @{
*/
+/** Data type */
typedef struct gnc_price_db_s GNCPriceDB;
-
/** gnc_pricedb_create - create a new pricedb. Normally you won't need
this; you will get the pricedb via gnc_pricedb_get_db. */
GNCPriceDB * gnc_pricedb_create(QofBook *book);
@@ -363,7 +383,7 @@
/** gnc_pricedb_dirty - return FALSE if the database has not been
modified. */
-gboolean gnc_pricedb_dirty(GNCPriceDB *db);
+#define gnc_pricedb_dirty(db) qof_instance_is_dirty(QOF_INSTANCE(db))
/** gnc_pricedb_get_num_prices - return the number of prices
in the database. */
@@ -388,5 +408,8 @@
#define PRICE_VALUE "price-value"
/**@}*/
+/** @} */
+
#endif /* GNC_PRICEDB_H */
/** @} */
+/** @} */
Index: gnc-numeric.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-numeric.h,v
retrieving revision 1.8.6.1
retrieving revision 1.8.6.2
diff -Lsrc/engine/gnc-numeric.h -Lsrc/engine/gnc-numeric.h -u -r1.8.6.1 -r1.8.6.2
--- src/engine/gnc-numeric.h
+++ src/engine/gnc-numeric.h
@@ -1,4 +1,5 @@
/********************************************************************
+ * gnc-numeric.h - A rational number library *
* 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 *
@@ -18,200 +19,490 @@
* *
*******************************************************************/
-/** @addtogroup Engine
- @{ */
+/** @addtogroup Numeric
+ The 'Numeric' functions provide a way of working with rational
+ numbers while maintaining strict control over rounding errors
+ when adding rationals with different denominators. The Numeric
+ class is primarily used for working with monetary amounts,
+ where the denominator typically represents the smallest fraction
+ of the currency (e.g. pennies, centimes). The numeric class
+ can handle any fraction (e.g. twelfth's) and is not limited
+ to fractions that are powers of ten.
+
+ A 'Numeric' value represents a number in rational form, with a
+ 64-bit integer as numerator and denominator. Rationals are
+ ideal for many uses, such as performing exact, roundoff-error-free
+ addition and multiplication, but 64-bit rationals do not have
+ the dynamic range of floating point numbers.
+
+@{ */
/** @file gnc-numeric.h
- @brief An exact-number library for gnucash.
+ @brief An exact-rational-number library for gnucash.
@author Copyright (C) 2000 Bill Gribble
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
*/
+/* ----------------------------------------------------------------
+
+EXAMPLE
+-------
+The following program finds the best @code{gnc_numeric} approximation to
+the @file{math.h} constant @code{M_PI} given a maximum denominator. For
+large denominators, the @code{gnc_numeric} approximation is accurate to
+more decimal places than will generally be needed, but in some cases
+this may not be good enough. For example,
+
+ at example
+ M_PI = 3.14159265358979323846
+ 245850922 / 78256779 = 3.14159265358979311599 (16 sig figs)
+ 3126535 / 995207 = 3.14159265358865047446 (12 sig figs)
+ 355 / 113 = 3.14159292035398252096 (7 sig figs)
+ at end example
+
+ at example
+#include <glib.h>
+#include "gnc-numeric.h"
+#include <math.h>
+
+int
+main(int argc, char ** argv)
+{
+ gnc_numeric approx, best;
+ double err, best_err=1.0;
+ double m_pi = M_PI;
+ gint64 denom;
+ gint64 max;
+
+ sscanf(argv[1], "%Ld", &max);
+
+ for (denom = 1; denom < max; denom++)
+ {
+ approx = double_to_gnc_numeric (m_pi, denom, GNC_RND_ROUND);
+ err = m_pi - gnc_numeric_to_double (approx);
+ if (fabs (err) < fabs (best_err))
+ {
+ best = approx;
+ best_err = err;
+ printf ("%Ld / %Ld = %.30f\n", gnc_numeric_num (best),
+ gnc_numeric_denom (best), gnc_numeric_to_double (best));
+ }
+ }
+}
+
+----------------------------------------------------------------- */
+
#ifndef GNC_NUMERIC_H
#define GNC_NUMERIC_H
#include <glib.h>
-struct _gnc_numeric {
+struct _gnc_numeric
+{
gint64 num;
gint64 denom;
};
-/** @brief An exact-number type for gnucash.
+/** @brief An rational-number type
*
- * This is a rational number, defined by nominator and denominator. */
+ * This is a rational number, defined by numerator and denominator. */
typedef struct _gnc_numeric gnc_numeric;
-/** bitmasks for HOW flags */
+/** @name Arguments
+ * @brief Standard Arguments to most functions
+
+ Most of the gnc_numeric arithmetic functions take two arguments
+ in addition to their numeric args: 'denom', which is the denominator
+ to use in the output gnc_numeric object, and 'how'. which
+ describes how the arithmetic result is to be converted to that
+ denominator. This combination of output denominator and rounding policy
+ allows the results of financial and other rational computations to be
+ properly rounded to the appropriate units.
+
+ Valid values for denom are:
+ GNC_DENOM_AUTO -- compute denominator exactly
+ integer n -- Force the denominator of teh result to be this integer
+ GNC_DENOM_RECIPROCAL -- Use 1/n as the denominator (???huh???)
+
+ Valid values for 'how' are bitwise combinations of zero or one
+ "rounding instructions" with zero or one "denominator types".
+ Valid rounding instructions are:
+ GNC_HOW_RND_FLOOR
+ GNC_HOW_RND_CEIL
+ GNC_HOW_RND_TRUNC
+ GNC_HOW_RND_PROMOTE
+ GNC_HOW_RND_ROUND_HALF_DOWN
+ GNC_HOW_RND_ROUND_HALF_UP
+ GNC_HOW_RND_ROUND
+ GNC_HOW_RND_NEVER
+
+ The denominator type specifies how to compute a denominator if
+ GNC_DENOM_AUTO is specified as the 'denom'. Valid
+ denominator types are:
+ GNC_HOW_DENOM_EXACT
+ GNC_HOW_DENOM_REDUCE
+ GNC_HOW_DENOM_LCD
+ GNC_HOW_DENOM_FIXED
+ GNC_HOW_DENOM_SIGFIGS(N)
+
+ To use traditional rational-number operational semantics (all results
+ are exact and are reduced to relatively-prime fractions) pass the
+ argument GNC_DENOM_AUTO as 'denom' and
+ GNC_HOW_DENOM_REDUCE| GNC_HOW_RND_NEVER as 'how'.
+
+ To enforce strict financial semantics (such that all operands must have
+ the same denominator as each other and as the result), use
+ GNC_DENOM_AUTO as 'denom' and
+ GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER as 'how'.
+
+ @{ */
+
+/** bitmasks for HOW flags.
+ * bits 8-15 of 'how' are reserved for the number of significant
+ * digits to use in the output with GNC_HOW_DENOM_SIGFIG
+ */
#define GNC_NUMERIC_RND_MASK 0x0000000f
#define GNC_NUMERIC_DENOM_MASK 0x000000f0
#define GNC_NUMERIC_SIGFIGS_MASK 0x0000ff00
-/** rounding/truncation modes for operations */
+/** Rounding/Truncation modes for operations.
+ * Rounding instructions control how fractional parts in the specified
+ * denominator affect the result. For example, if a computed result is
+ * "3/4" but the specified denominator for the return value is 2, should
+ * the return value be "1/2" or "2/2"?
+ *
+ * Possible rounding instructions are:
+ */
enum {
- GNC_RND_FLOOR = 0x01,
- GNC_RND_CEIL = 0x02,
- GNC_RND_TRUNC = 0x03,
- GNC_RND_PROMOTE = 0x04,
- GNC_RND_ROUND_HALF_DOWN = 0x05,
- GNC_RND_ROUND_HALF_UP = 0x06,
- GNC_RND_ROUND = 0x07,
- GNC_RND_NEVER = 0x08
+ /** Round toward -infinity */
+ GNC_HOW_RND_FLOOR = 0x01,
+
+ /** Round toward +infinity */
+ GNC_HOW_RND_CEIL = 0x02,
+
+ /** Truncate fractions (round toward zero) */
+ GNC_HOW_RND_TRUNC = 0x03,
+
+ /** Promote fractions (round away from zero) */
+ GNC_HOW_RND_PROMOTE = 0x04,
+
+ /** Round to the nearest integer, rounding toward zero
+ * when there are two equidistant nearest integers.
+ */
+ GNC_HOW_RND_ROUND_HALF_DOWN = 0x05,
+
+ /** Round to the nearest integer, rounding away from zero
+ * when there are two equidistant nearest integers.
+ */
+ GNC_HOW_RND_ROUND_HALF_UP = 0x06,
+
+ /** Use unbiased ("banker's") rounding. This rounds to the
+ * nearest integer, and to the nearest even integer when there
+ * are two equidistant nearest integers. This is generally the
+ * one you should use for financial quantities.
+ */
+ GNC_HOW_RND_ROUND = 0x07,
+
+ /** Never round at all, and signal an error if there is a
+ * fractional result in a computation.
+ */
+ GNC_HOW_RND_NEVER = 0x08
};
-/** auto-denominator types */
+/** How to compute a denominator, or'ed into the "how" field. */
enum {
- GNC_DENOM_EXACT = 0x10,
- GNC_DENOM_REDUCE = 0x20,
- GNC_DENOM_LCD = 0x30,
- GNC_DENOM_FIXED = 0x40,
- GNC_DENOM_SIGFIG = 0x50
+ /** Use any denominator which gives an exactly correct ratio of
+ * numerator to denominator. Use EXACT when you do not wish to
+ * lose any information in the result but also do not want to
+ * spend any time finding the "best" denominator.
+ */
+ GNC_HOW_DENOM_EXACT = 0x10,
+
+ /** Reduce the result value by common factor elimination,
+ * using the smallest possible value for the denominator that
+ * keeps the correct ratio. The numerator and denominator of
+ * the result are relatively prime.
+ */
+ GNC_HOW_DENOM_REDUCE = 0x20,
+
+ /** Find the least common multiple of the arguments' denominators
+ * and use that as the denominator of the result.
+ */
+ GNC_HOW_DENOM_LCD = 0x30,
+
+ /** All arguments are required to have the same denominator,
+ * that denominator is to be used in the output, and an error
+ * is to be signaled if any argument has a different denominator.
+ */
+ GNC_HOW_DENOM_FIXED = 0x40,
+
+ /** Round to the number of significant figures given in the rounding
+ * instructions by the GNC_HOW_DENOM_SIGFIGS () macro.
+ */
+ GNC_HOW_DENOM_SIGFIG = 0x50
};
-/** bits 8-15 of 'how' are reserved for the number of significant
- * digits to use in the output with GNC_DENOM_SIGFIG */
+/** Build a 'how' value that will generate a denominator that will
+ * keep at least n significant figures in the result.
+ */
+#define GNC_HOW_DENOM_SIGFIGS( n ) ( ((( n ) & 0xff) << 8) | GNC_HOW_DENOM_SIGFIG)
+#define GNC_HOW_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8)
-/** errors */
-enum {
- GNC_ERROR_OK = 0,
- GNC_ERROR_ARG = -1,
- GNC_ERROR_OVERFLOW = -2,
- GNC_ERROR_DENOM_DIFF = -3,
- GNC_ERROR_REMAINDER = -4
-};
+/** Error codes */
+typedef enum {
+ GNC_ERROR_OK = 0, /**< No error */
+ GNC_ERROR_ARG = -1, /**< Argument is not a valid number */
+ GNC_ERROR_OVERFLOW = -2, /**< Intermediate result overflow */
+
+ /** GNC_HOW_DENOM_FIXED was specified, but argument denominators differed. */
+ GNC_ERROR_DENOM_DIFF = -3,
+
+ /** GNC_HOW_RND_NEVER was specified, but the result could not be
+ * converted to the desired denominator without a remainder. */
+ GNC_ERROR_REMAINDER = -4
+} GNCNumericErrorCode;
+
+
+/** Values that can be passed as the 'denom' argument.
+ * The include a positive number n to be used as the
+ * denominator of teh output value. Other possibilities
+ * include the list below:
+ */
+/** Compute an appropriate denominator automatically. Flags in
+ * the 'how' argument will specify how to compute the denominator.
+ */
#define GNC_DENOM_AUTO 0
+/** Use the value 1/n as the denominator of the output value. */
#define GNC_DENOM_RECIPROCAL( a ) (- ( a ))
-#define GNC_DENOM_SIGFIGS( a ) ( ((( a ) & 0xff) << 8) | GNC_DENOM_SIGFIG)
-#define GNC_NUMERIC_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8)
+
+/** @} */
/** @name Constructors */
/*@{*/
-/** make a gnc_numeric from numerator and denominator */
-gnc_numeric gnc_numeric_create(gint64 num, gint64 denom);
+/** Make a gnc_numeric from numerator and denominator */
+static inline
+gnc_numeric gnc_numeric_create(gint64 num, gint64 denom) {
+ gnc_numeric out;
+ out.num = num;
+ out.denom = denom;
+ return out;
+}
/** create a zero-value gnc_numeric */
-gnc_numeric gnc_numeric_zero(void);
+static inline
+gnc_numeric gnc_numeric_zero(void) { return gnc_numeric_create(0, 1); }
-/** convert from floating-point values */
+/** Convert a floating-point number to a gnc_numeric.
+ * Both 'denom' and 'how' are used as in arithmetic,
+ * but GNC_DENOM_AUTO is not recognized; a denominator
+ * must be specified either explicitctly or through sigfigs.
+ */
gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
gint how);
-/** Read a gnc_numeric from str, skipping any leading whitespace, and
- returning a pointer to just past the last byte read. Return NULL
- on error. */
+/** Read a gnc_numeric from str, skipping any leading whitespace,
+ * and return a pointer to just past the last byte read.
+ * Return NULL on error. */
const gchar *string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
-/** make a special error-signalling gnc_numeric */
-gnc_numeric gnc_numeric_error(int error_code);
+/** Create a gnc_numeric object that signals the error condition
+ * noted by error_code, rather than a number.
+ */
+gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code);
/*@}*/
-/** @name Value accessors */
-/*@{*/
-/** Get parts */
-gint64 gnc_numeric_num(gnc_numeric a);
-/** Get parts */
-gint64 gnc_numeric_denom(gnc_numeric a);
+/** @name Value Accessors */
+/** @{*/
+/** Return numerator */
+static inline
+gint64 gnc_numeric_num(gnc_numeric a) { return a.num; }
+/** Return denominator */
+static inline
+gint64 gnc_numeric_denom(gnc_numeric a) { return a.denom; }
-/** Convert to floating-point values */
+/** Convert numeric to floating-point value. */
double gnc_numeric_to_double(gnc_numeric in);
/** Convert to string. The returned buffer is to be g_free'd by the
- * caller (it was allocated through g_strdup) */
+ * caller (it was allocated through g_strdup) */
gchar *gnc_numeric_to_string(gnc_numeric n);
-/*@}*/
-/** @name Tests */
-/*@{*/
+/** Convert to string. Uses a static, non-thread-safe buffer.
+ * For internal use only. */
+gchar * gnc_num_dbg_to_string(gnc_numeric n);
+/** @}*/
+
+/** @name Comparisons and Predicates */
+/** @{ */
/** Check for error signal in value. Returns GNC_ERROR_OK (==0) if
- * there is no error, or any error code if there is one
- * (e.g. GNC_ERROR_OVERFLOW) */
-int gnc_numeric_check(gnc_numeric a);
+ * the number appears to be valid, otherwise it returns the
+ * type of error. Error values always have a denominator of zero.
+ */
+GNCNumericErrorCode gnc_numeric_check(gnc_numeric a);
-/** Returns 1 if the given gnc_numeric is 0 (zeros), else returns 0. */
-int gnc_numeric_zero_p(gnc_numeric a);
/** Returns 1 if a>b, -1 if b>a, 0 if a == b */
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b);
-int gnc_numeric_negative_p(gnc_numeric a);
-int gnc_numeric_positive_p(gnc_numeric a);
-/** Equivalence predicate: Returns TRUE (1) if a and b are exactly the
- * same (same numerator and denominator)
+/** Returns 1 if the given gnc_numeric is 0 (zero), else returns 0. */
+gboolean gnc_numeric_zero_p(gnc_numeric a);
+
+/** Returns 1 if a < 0, otherwise returns 0. */
+gboolean gnc_numeric_negative_p(gnc_numeric a);
+
+/** Returns 1 if a > 0, otherwise returns 0. */
+gboolean gnc_numeric_positive_p(gnc_numeric a);
+
+/** Equivalence predicate: Returns TRUE (1) if a and b are
+ * exactly the same (have the same numerator and denominator)
*/
-int gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
+gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
/** Equivalence predicate: Returns TRUE (1) if a and b represent
- * exactly the same number (ratio of numerator to denominator is
- * exactly equal)
+ * the same number. That is, return TRUE if the ratios, when
+ * reduced by eliminating common factors, are identical.
*/
-int gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
+gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
-/** Equivalence predicate: Returns TRUE (1) if after both are
- * converted to DENOM using method HOW, a and b are
- * gnc_numeric_equal().
+/** Equivalence predicate:
+ * Convert both a and b to denom using the
+ * specified DENOM and method HOW, and compare numerators
+ * the results using gnc_numeric_equal.
+ *
+ For example, if a == 7/16 and b == 3/4,
+ gnc_numeric_same(a, b, 2, GNC_HOW_RND_TRUNC) == 1
+ because both 7/16 and 3/4 round to 1/2 under truncation. However,
+ gnc_numeric_same(a, b, 2, GNC_HOW_RND_ROUND) == 0
+ because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds
+ to 2/2.
*/
int gnc_numeric_same(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
-/*@}*/
+/** @}*/
-/** @name Arithmetic operations */
-/*@{*/
+/** @name Arithmetic Operations */
+/** @{*/
+/** Return a+b. */
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
+
+/** Return a-b. */
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
+
+/** Multiply a times b, returning the product. An overflow
+ * may occur if the result of the multiplication can't
+ * be represented as a ratio of 64-bit int's after removing
+ * common factors.
+ */
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
-gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b,
+
+/** Division. Note that division can overflow, in the following
+ * sense: if we write x=a/b and y=c/d then x/y = (a*d)/(b*c)
+ * If, after eliminating all common factors between the numerator
+ * (a*d) and the denominator (b*c), then if either the numerator
+ * and/or the denominator are *still* greater than 2^63, then
+ * the division has overflowed.
+ */
+gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y,
gint64 denom, gint how);
/** Negate the argument */
gnc_numeric gnc_numeric_neg(gnc_numeric a);
+
/** Return the absolute value of the argument */
gnc_numeric gnc_numeric_abs(gnc_numeric a);
/**
- * Shortcut for most common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO,
- * GNC_DENOM_FIXED | GNC_RND_NEVER);
+ * Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO,
+ * GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
*/
-gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b);
+static inline
+gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b) {
+ return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
+}
+
/**
* Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
- * GNC_DENOM_FIXED | GNC_RND_NEVER);
+ * GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
*/
-gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b);
-/*@}*/
-
-/** @name Arithmetic functions with exact error returns */
-/*@{*/
+static inline
+gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b) {
+ return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
+}
+/** @}*/
+
+/** @name Arithmetic Functions with Exact Error Returns */
+/** @{*/
+/** The same as gnc_numeric_add, but uses 'error' for accumulating
+ * conversion roundoff error. */
gnc_numeric gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
+
+/** The same as gnc_numeric_sub, but uses error for accumulating
+ * conversion roundoff error. */
gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
+
+/** The same as gnc_numeric_mul, but uses error for
+ * accumulating conversion roundoff error.
+ */
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
+
+/** The same as gnc_numeric_div, but uses error for
+ * accumulating conversion roundoff error.
+ */
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
-/*@}*/
+/** @}*/
-/** @name Change denominator */
-/*@{*/
-/** change the denominator of a gnc_numeric value */
+/** @name Change Denominator */
+/** @{*/
+/** Change the denominator of a gnc_numeric value to the
+ * specified denominator under standard arguments
+ * 'denom' and 'how'.
+ */
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom,
gint how);
-/** change the denominator of a gnc_numeric value */
+/** Same as gnc_numeric_convert, but return a remainder
+ * value for accumulating conversion error.
+*/
gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
gint how,
gnc_numeric * error);
-/** reduce by GCF elimination */
+/** Return input after reducing it by Greated Common Factor (GCF)
+ * elimination */
gnc_numeric gnc_numeric_reduce(gnc_numeric in);
-/*@}*/
-
+/** @}*/
+/** @name Deprecated, backwards-compatible definitions
+ @{ */
+#define GNC_RND_FLOOR GNC_HOW_RND_FLOOR
+#define GNC_RND_CEIL GNC_HOW_RND_CEIL
+#define GNC_RND_TRUNC GNC_HOW_RND_TRUNC
+#define GNC_RND_PROMOTE GNC_HOW_RND_PROMOTE
+#define GNC_RND_ROUND_HALF_DOWN GNC_HOW_RND_ROUND_HALF_DOWN
+#define GNC_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND_HALF_UP
+#define GNC_RND_ROUND GNC_HOW_RND_ROUND
+#define GNC_RND_NEVER GNC_HOW_RND_NEVER
+
+#define GNC_DENOM_EXACT GNC_HOW_DENOM_EXACT
+#define GNC_DENOM_REDUCE GNC_HOW_DENOM_REDUCE
+#define GNC_DENOM_LCD GNC_HOW_DENOM_LCD
+#define GNC_DENOM_FIXED GNC_HOW_DENOM_FIXED
+#define GNC_DENOM_SIGFIG GNC_HOW_DENOM_SIGFIG
+
+#define GNC_DENOM_SIGFIGS(X) GNC_HOW_DENOM_SIGFIGS(X)
+#define GNC_NUMERIC_GET_SIGFIGS(X) GNC_HOW_GET_SIGFIGS(X)
+/** @}*/
+/** @}*/
#endif
-
-/*@}*/
Index: Scrub3.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Scrub3.c,v
retrieving revision 1.4.4.1
retrieving revision 1.4.4.2
diff -Lsrc/engine/Scrub3.c -Lsrc/engine/Scrub3.c -u -r1.4.4.1 -r1.4.4.2
--- src/engine/Scrub3.c
+++ src/engine/Scrub3.c
@@ -19,10 +19,10 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
\********************************************************************/
-/* @file Scrub3.c
+/** @file Scrub3.c
* @breif Constrain Cap Gains to Track Sources of Gains
* @author Created by Linas Vepstas Sept 2003
- * @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2003,2004 Linas Vepstas <linas at linas.org>
*
* Provides a set of functions and utilities for checking and
* repairing ('scrubbing clean') the usage of Cap Gains
@@ -53,6 +53,36 @@
static short module = MOD_LOT;
/* ================================================================= */
+/** Cap gains are possible only if the lot commodity is not the same
+ * as the transaction currency. We assume here that all splits in
+ * the lot share the same transaction currency, and so we look at
+ * the first split, and see what it's currency is.
+ * This routine returns TRUE if cap gains are possible.
+ */
+
+static inline gboolean
+gains_possible (GNCLot *lot)
+{
+ SplitList *node;
+ Account *acc;
+ Split *split;
+ gboolean comeq;
+
+ acc = gnc_lot_get_account (lot);
+
+ node = gnc_lot_get_split_list (lot);
+ if (!node) return FALSE;
+ split = node->data;
+
+ comeq = gnc_commodity_equiv (acc->commodity, split->parent->common_currency);
+ return (FALSE == comeq);
+}
+
+/* ================================================================= */
+/* XXX What happens if, as a result of scrubbing, the lot is empty?
+ * I don't think this is handled properly. I think that what will
+ * happen is we'll end up with an empty, closed lot ... ?
+ */
gboolean
xaccScrubLot (GNCLot *lot)
@@ -64,7 +94,7 @@
GNCPolicy *pcy;
if (!lot) return FALSE;
- ENTER (" ");
+ ENTER ("(lot=%p) %s", lot, gnc_lot_get_title(lot));
acc = gnc_lot_get_account (lot);
pcy = acc->policy;
@@ -73,6 +103,8 @@
/* If the lot balance is zero, we don't need to rebalance */
lot_baln = gnc_lot_get_balance (lot);
+ PINFO ("lot baln=%s for %s", gnc_num_dbg_to_string (lot_baln),
+ gnc_lot_get_title(lot));
if (! gnc_numeric_zero_p (lot_baln))
{
SplitList *node;
@@ -80,6 +112,7 @@
/* Get the opening balance for this lot */
pcy->PolicyGetLotOpening (pcy, lot, &opening_baln, NULL, NULL);
+ PINFO ("lot opener baln=%s", gnc_num_dbg_to_string (opening_baln));
/* If the lot is fat, give the boot to all the non-opening
* splits, and refill it */
@@ -105,12 +138,21 @@
splits_deleted = xaccScrubMergeLotSubSplits (lot);
}
- /* Now re-compute cap gains, and then double-check that. */
- xaccLotComputeCapGains (lot, NULL);
- xaccLotScrubDoubleBalance (lot);
+ /* Now re-compute cap gains, and then double-check that.
+ * But we only compute cap-gains if gains are possible;
+ * that is if the lot commodity is not the same as the
+ * currency. That is, one can't possibly have gains
+ * selling dollars for dollars. The business modules
+ * use lots with lot commodity == lot currency.
+ */
+ if (gains_possible (lot))
+ {
+ xaccLotComputeCapGains (lot, NULL);
+ xaccLotScrubDoubleBalance (lot);
+ }
xaccAccountCommitEdit(acc);
- LEAVE (" deleted=%d", splits_deleted);
+ LEAVE ("(lot=%s, deleted=%d)", gnc_lot_get_title(lot), splits_deleted);
return splits_deleted;
}
@@ -123,7 +165,7 @@
if (!acc) return;
if (FALSE == xaccAccountHasTrades (acc)) return;
- ENTER ("acc=%s", acc->accountName);
+ ENTER ("(acc=%s)", acc->accountName);
xaccAccountBeginEdit(acc);
xaccAccountAssignLots (acc);
@@ -133,7 +175,7 @@
xaccScrubLot (lot);
}
xaccAccountCommitEdit(acc);
- LEAVE ("acc=%s", acc->accountName);
+ LEAVE ("(acc=%s)", acc->accountName);
}
/* ============================================================== */
Index: qofquery-serialize.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery-serialize.h,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -Lsrc/engine/qofquery-serialize.h -Lsrc/engine/qofquery-serialize.h -u -r1.1.2.1 -r1.1.2.2
--- src/engine/qofquery-serialize.h
+++ src/engine/qofquery-serialize.h
@@ -20,9 +20,10 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
+/** @addtogroup Query
+ @{ */
/** @file qofquery-serialize.h
- @breif Convert QofQuery to XML
+ @brief Convert QofQuery to XML
@author Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org>
*/
@@ -32,10 +33,14 @@
#include <qof/qofquery.h>
#include <libxml/tree.h>
+/** @addtogroup XML Serialize Queries to/from XML */
+/* @{ */
/** 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: qofquery-deserial.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery-deserial.h,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -Lsrc/engine/qofquery-deserial.h -Lsrc/engine/qofquery-deserial.h -u -r1.1.2.1 -r1.1.2.2
--- src/engine/qofquery-deserial.h
+++ src/engine/qofquery-deserial.h
@@ -20,13 +20,10 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
+/** @addtogroup Query
+ @{ */
/** @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.
-
+ @brief Convert Qof-Query XML to QofQuery
@author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
*/
@@ -36,7 +33,15 @@
#include <qof/qofquery.h>
#include <libxml/tree.h>
+/** @addtogroup XML
+ Qof Queries can be converted 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.
+
+ @{ */
/** Given an XML tree, reconstruct and return the equivalent query. */
QofQuery *qof_query_from_xml (xmlNodePtr);
+/* @} */
#endif /* QOF_QUERY_DESERIAL_H */
+/* @} */
Index: FreqSpec.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/FreqSpec.c,v
retrieving revision 1.28.4.5
retrieving revision 1.28.4.6
diff -Lsrc/engine/FreqSpec.c -Lsrc/engine/FreqSpec.c -u -r1.28.4.5 -r1.28.4.6
--- src/engine/FreqSpec.c
+++ src/engine/FreqSpec.c
@@ -1,17 +1,17 @@
/********************************************************************\
- * FreqSpec.c -- Frequency specifier implementation. *
- * Copyright (C) 2001 Joshua Sled <jsled at asynchronous.org> *
- * Copyright (C) 2001 Ben Stanley <bds02 at uow.edu.au> *
- * *
+ * FreqSpec.c -- Frequency specifier implementation. *
+ * Copyright (C) 2001 Joshua Sled <jsled at asynchronous.org> *
+ * Copyright (C) 2001 Ben Stanley <bds02 at uow.edu.au> *
+ * *
* 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. *
- * *
+ * 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. *
+ * 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: *
@@ -88,8 +88,8 @@
#include "gnc-date.h"
#include "gnc-engine-util.h"
#include "gnc-event-p.h"
-#include "messages.h"
#include "gnc-trace.h"
+#include "messages.h"
#include "qofbook.h"
#include "qofbook-p.h"
#include "qofid-p.h"
@@ -181,8 +181,8 @@
g_return_if_fail( fs );
g_return_if_fail (book);
- col = qof_book_get_collection (book, GNC_ID_FREQSPEC);
- qof_entity_init (&fs->entity, GNC_ID_FREQSPEC, col);
+ col = qof_book_get_collection (book, QOF_ID_FREQSPEC);
+ qof_entity_init (&fs->entity, QOF_ID_FREQSPEC, col);
fs->type = INVALID;
fs->uift = UIFREQ_ONCE;
Index: qofclass-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass-p.h,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -Lsrc/engine/qofclass-p.h -Lsrc/engine/qofclass-p.h -u -r1.1 -r1.1.6.1
--- src/engine/qofclass-p.h
+++ src/engine/qofclass-p.h
@@ -20,6 +20,13 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Object_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/** @name Class_Private
+ @{ */
#ifndef QOF_CLASSP_H
#define QOF_CLASSP_H
@@ -31,4 +38,7 @@
QofSortFunc qof_class_get_default_sort (QofIdTypeConst obj_name);
+/* @} */
+/* @} */
+/* @} */
#endif /* QOF_CLASSP_H */
Index: iso-currencies-to-c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/iso-currencies-to-c,v
retrieving revision 1.6.4.2
retrieving revision 1.6.4.3
diff -Lsrc/engine/iso-currencies-to-c -Lsrc/engine/iso-currencies-to-c -u -r1.6.4.2 -r1.6.4.3
--- src/engine/iso-currencies-to-c
+++ src/engine/iso-currencies-to-c
@@ -4,7 +4,12 @@
(use-modules (srfi srfi-2))
(use-modules (ice-9 slib))
-(require 'format)
+;; Test for simple-format
+(if (not (defined? 'simple-format))
+ (begin
+ (require 'format)
+ (export simple-format)
+ (define simple-format format)))
(define *currency-file* (string-append (getenv "srcdir") "/" "iso-4217-currencies.scm"))
(define *c-file-name* "iso-4217-currencies.c")
Index: kvp-util-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp-util-p.h,v
retrieving revision 1.1.4.3
retrieving revision 1.1.4.4
diff -Lsrc/engine/kvp-util-p.h -Lsrc/engine/kvp-util-p.h -u -r1.1.4.3 -r1.1.4.4
--- src/engine/kvp-util-p.h
+++ src/engine/kvp-util-p.h
@@ -1,5 +1,5 @@
/********************************************************************\
- * kvp_util.h -- misc odd-job kvp utils *
+ * kvp-util-p.h -- misc odd-job kvp utils (private file) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -28,13 +28,20 @@
#include "guid.h"
#include "kvp_frame.h"
-/* @file kvp_util.h
- * @breif misc odd-job kvp utils engine-private routines
+/** @addtogroup KVP
+ @{ */
+/** @addtogroup KVP_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/* @file kvp-util-p.h
+ * @brief misc odd-job kvp utils engine-private routines
* @author Copyright (C) 2001, 2003 Linas Vepstas <linas at linas.org> *
* @note PRIVATE FILE
* -- these routines are private to the engine. The should not be used
* outside of the engine.
*/
+/** @name KvpBag Bags of GUID Pointers */
+/* @{ */
/** The gnc_kvp_bag_add() routine is used to maintain a collection
* of pointers in a kvp tree.
@@ -100,4 +107,7 @@
void gnc_kvp_bag_remove_frame (KvpFrame *root, const char *path,
KvpFrame *fr);
+/* @} */
+/* @} */
+/* @} */
#endif /* XACC_KVP_UTIL_P_H */
Index: gnc-lot.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-lot.h,v
retrieving revision 1.8.4.4
retrieving revision 1.8.4.5
diff -Lsrc/engine/gnc-lot.h -Lsrc/engine/gnc-lot.h -u -r1.8.4.4 -r1.8.4.5
--- src/engine/gnc-lot.h
+++ src/engine/gnc-lot.h
@@ -18,10 +18,9 @@
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu at gnu.org *
\********************************************************************/
-
-
-/** @file gnc-lot.h
- *
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup Lot Lots: Core Function for AR/AP, Inventory, Stock Lots, Cap Gains
* One often needs to know that the item 'bought' in one transaction
* is the same one as the item 'sold' in a different transaction.
* Lots are used to make this association. One Lot holds all of the
@@ -34,9 +33,12 @@
* depreciation and stock market investment gains. See the file
* src/doc/lots.txt for implmentation overview.
*
- * HISTORY:
- * Created by Linas Vepstas May 2002
- * Copyright (c) 2002,2003 Linas Vepstas <linas at linas.org>
+ @{ */
+
+/** @file gnc-lot.h
+ *
+ * @author Created by Linas Vepstas May 2002
+ * @author Copyright (c) 2002,2003 Linas Vepstas <linas at linas.org>
*/
#ifndef GNC_LOT_H
@@ -120,3 +122,5 @@
#define LOT_BALANCE "balance"
#endif /* GNC_LOT_H */
+/** @} */
+/** @} */
--- /dev/null
+++ src/engine/qof-be-utils.h
@@ -0,0 +1,168 @@
+/********************************************************************\
+ * qof-be-utils.h: api for data storage backend *
+ * 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 Object
+ @{ */
+/** @addtogroup Backend
+ * @{
+ * @file qof-be-utils.h
+ * @brief QOF Backend Utilities
+ * @author Derek Atkins <derek at ihtfp.com>
+ * Common code used by objects to define begin_edit() and
+ * commit_edit() functions.
+ *
+ */
+
+#ifndef QOF_BE_UTILS_H
+#define QOF_BE_UTILS_H
+
+#include "gnc-engine-util.h"
+#include "qofbackend-p.h"
+#include "qofbook.h"
+
+/** begin_edit helper
+ *
+ * @args:
+ * inst: an instance of QofInstance
+ *
+ * The caller should use this macro first and then perform any other operations.
+ */
+
+#define QOF_BEGIN_EDIT(inst) \
+ QofBackend * be; \
+ if (!(inst)) return; \
+ \
+ (inst)->editlevel++; \
+ if (1 < (inst)->editlevel) return; \
+ \
+ if (0 >= (inst)->editlevel) \
+ { \
+ PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
+ (inst)->editlevel = 1; \
+ } \
+ ENTER ("inst=%p", (inst)); \
+ \
+ /* See if there's a backend. If there is, invoke it. */ \
+ be = qof_book_get_backend ((inst)->book); \
+ if (be && be->begin) { \
+ (be->begin) (be, (inst)); \
+ } else { \
+ /* We tried and failed to start transaction! */ \
+ (inst)->dirty = TRUE; \
+ }
+
+
+/**
+ * commit_edit helpers
+ *
+ * The caller should call PART1 as the first thing, then
+ * perform any local operations prior to calling the backend.
+ * Then call PART2.
+ */
+
+/**
+ * part1 -- deal with the editlevel
+ *
+ * @args:
+ * inst: an instance of QofInstance
+ */
+
+#define QOF_COMMIT_EDIT_PART1(inst) { \
+ if (!(inst)) return; \
+ \
+ (inst)->editlevel--; \
+ if (0 < (inst)->editlevel) return; \
+ \
+ /* The pricedb sufffers from delayed update... */ \
+ /* This may be setting a bad precedent for other types, I fear. */ \
+ /* Other types probably really should handle begin like this. */ \
+ if ((-1 == (inst)->editlevel) && (inst)->dirty) \
+ { \
+ QofBackend * be; \
+ be = qof_book_get_backend ((inst)->book); \
+ if (be && be->begin) { \
+ (be->begin) (be, (inst)); \
+ } \
+ (inst)->editlevel = 0; \
+ } \
+ if (0 > (inst)->editlevel) \
+ { \
+ PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
+ (inst)->editlevel = 0; \
+ } \
+ ENTER ("inst=%p, dirty=%d do-free=%d", \
+ (inst), (inst)->dirty, (inst)->do_free); \
+}
+
+/**
+ * part2 -- deal with the backend
+ *
+ * @args:
+ * inst: an instance of QofInstance
+ * on_error: a function called if there is a backend error.
+ * void (*on_error)(inst, QofBackendError)
+ * on_done: a function called after the commit is complete
+ * but before the instect is freed. Perform any other
+ * operations after the commit.
+ * void (*on_done)(inst)
+ * on_free: a function called if inst->do_free is TRUE.
+ * void (*on_free)(inst)
+ */
+#define QOF_COMMIT_EDIT_PART2(inst,on_error,on_done,on_free) { \
+ QofBackend * be; \
+ \
+ /* See if there's a backend. If there is, invoke it. */ \
+ be = qof_book_get_backend ((inst)->book); \
+ if (be && be->commit) \
+ { \
+ QofBackendError errcode; \
+ \
+ /* clear errors */ \
+ do { \
+ errcode = qof_backend_get_error (be); \
+ } while (ERR_BACKEND_NO_ERR != errcode); \
+ \
+ (be->commit) (be, (inst)); \
+ errcode = qof_backend_get_error (be); \
+ if (ERR_BACKEND_NO_ERR != errcode) \
+ { \
+ /* XXX Should perform a rollback here */ \
+ (inst)->do_free = FALSE; \
+ \
+ /* Push error back onto the stack */ \
+ qof_backend_set_error (be, errcode); \
+ (on_error)((inst), errcode); \
+ } \
+ /* XXX the backend commit code should clear dirty!! */ \
+ (inst)->dirty = FALSE; \
+ } \
+ (on_done)(inst); \
+ \
+ LEAVE ("inst=%p, dirty=%d do-free=%d", \
+ (inst), (inst)->dirty, (inst)->do_free); \
+ if ((inst)->do_free) { \
+ (on_free)(inst); \
+ return; \
+ } \
+}
+
+#endif /* QOF_BE_UTILS_H */
+/** @} */
+/** @} */
Index: qofobject.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofobject.h,v
retrieving revision 1.7.2.1
retrieving revision 1.7.2.2
diff -Lsrc/engine/qofobject.h -Lsrc/engine/qofobject.h -u -r1.7.2.1 -r1.7.2.2
--- src/engine/qofobject.h
+++ src/engine/qofobject.h
@@ -19,12 +19,25 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Objects
+ QOF Objects provide the means for associating
+ a storage backend to a set of QOF Entities. While an entity
+ can be though of as an identified instance of some thing, the
+ QOF Object provides for a way to associate instances with
+ a storage backend. Storage might be file or SQL storage.
+
+ QOF Objects are also used by the query system ....
+
+ XXX todo, we should split out the storage aspects of this
+ thing from the 'foreach' that query depends on. These are
+ kinda unrelated concepts.
+
@{ */
/** @file qofobject.h
- * @breif the Core Object Registration/Lookup Interface
- *
- * @author Copyright (c) 2001,2002, Derek Atkins <warlord at MIT.EDU>
+ * @brief the Core Object Registration/Lookup Interface
+ * @author Copyright (c) 2001,2002 Derek Atkins <warlord at MIT.EDU>
*/
#ifndef QOF_OBJECT_H_
@@ -33,11 +46,11 @@
#include "qofbook.h"
#include "qofid.h"
-/* Defines the version of the core object object registration
+/** Defines the version of the core object object registration
* interface. Only object modules compiled against this version
* of the interface will load properly
*/
-#define QOF_OBJECT_VERSION 1
+#define QOF_OBJECT_VERSION 3
typedef struct _QofObject QofObject;
@@ -48,8 +61,6 @@
gpointer user_data);
/** This is the QofObject Class descriptor
- *
- * XXX Hmm, should we add an object factory to this?
*/
struct _QofObject
{
@@ -57,58 +68,92 @@
QofIdType e_type; /* the Object's QOF_ID */
const char * type_label; /* "Printable" type-label string */
- /* book_begin is called from within the Book routines to create
+ /** Create a new instance of this object type. This routine might be
+ * NULL if the object type doesn't provide a way of creating new
+ * instances.
+ */
+ gpointer (*create)(QofBook *);
+
+ /** book_begin is called from within the Book routines to create
* module-specific hooks in a book whenever a book is created.
- * book_end is called when the book is being closed, to clean
- * up (and free memory).
*/
void (*book_begin)(QofBook *);
+
+ /** book_end is called when the book is being closed, to clean
+ * up (and free memory).
+ */
void (*book_end)(QofBook *);
- /* Determine if there are any dirty items in this book */
+ /** Determine if there are any dirty items in this book */
gboolean (*is_dirty)(QofCollection *);
- /* Mark this object's book clean (for after a load) */
+ /** Mark this object's book clean (for after a load) */
void (*mark_clean)(QofCollection *);
- /* foreach() is used to execute a callback over each object
- * stored in the particular book
+ /** Traverse over all of the items in the collection, calling
+ * the callback on each item. The third argument can be any
+ * arbitrary caller-supplied data, and is passed to the callback.
+ * Although (*foreach) may be NULL, allmost all objects should
+ * provide this routine, as without it, little of interest can
+ * be done.
*/
void (*foreach)(QofCollection *, QofEntityForeachCB, gpointer);
- /* Given a particular object, return a printable string */
- /* Argument should really be QofInstance not gpointer.. */
- const char * (*printable)(gpointer obj);
+ /** Given a particular item of this type, return a printable string.
+ */
+ const char * (*printable)(gpointer instance);
+ /** Given a pair of items of this type, this routine returns value
+ * indicating which item is 'newer'. This routine is used by storage
+ * backends to determine if the local or the remote copy of a
+ * particular item is the latest, 'uptodate' version. Tis routine
+ * should return an integer less than, equal to, or greater than zero
+ * if 'instance_left' is found to be, respecitvely, earlier than, equal
+ * to or later than than 'instance_right'.
+ */
+ int (*version_cmp)(gpointer instance_left, gpointer instance_right);
};
/* -------------------------------------------------------------- */
-/** Initialize the object registration subsystem */
+/** @name Initialize the object registration subsystem */
+/** @{ */
void qof_object_initialize (void);
void qof_object_shutdown (void);
-
-void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data);
-
-void qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
- QofEntityForeachCB cb, gpointer user_data);
-
-const char * qof_object_printable (QofIdTypeConst type_name, gpointer obj);
-
-
-/* REGISTRATION AND REG-LOOKUP FUNCTIONS */
+/** @} */
/** Register new types of object objects */
gboolean qof_object_register (const QofObject *object);
+/** Lookup an object definition */
+const QofObject * qof_object_lookup (QofIdTypeConst type_name);
+
+/** Create an instance of the indicated type, returning a pointer to that
+ * instance. This routine just calls the (*new) callback on the object
+ * definition.
+ */
+gpointer qof_object_new_instance (QofIdTypeConst type_name, QofBook *book);
+
/** Get the printable label for a type. This label is *not*
* translated; you must use _() on it if you want a translated version.
*/
const char * qof_object_get_type_label (QofIdTypeConst type_name);
-/** Lookup a object definition */
-const QofObject * qof_object_lookup (QofIdTypeConst type_name);
+/** @return a Human-readable string name for an instance */
+const char * qof_object_printable (QofIdTypeConst type_name, gpointer instance);
+/** Invoke the callback 'cb' on every object class definition.
+ * The user_data pointer is passed back to the callback.
+ */
+void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data);
+
+/** Invoke the callback 'cb' on every instance ov a particular
+ * object type. It is presumed that the 'book' stores or somehow
+ * identifies a colllection of instances; thus the callback will
+ * be invoked only for those instances stored in the book.
+ */
+void qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
+ QofEntityForeachCB cb, gpointer user_data);
/** Register and lookup backend-specific data for this particular object */
gboolean qof_object_register_backend (QofIdTypeConst type_name,
@@ -124,3 +169,4 @@
#endif /* QOF_OBJECT_H_ */
/** @} */
+/** @} */
Index: qofbook-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbook-p.h,v
retrieving revision 1.4.2.1
retrieving revision 1.4.2.2
diff -Lsrc/engine/qofbook-p.h -Lsrc/engine/qofbook-p.h -u -r1.4.2.1 -r1.4.2.2
--- src/engine/qofbook-p.h
+++ src/engine/qofbook-p.h
@@ -19,7 +19,13 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Object_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/** @name Book_Private
+ @{ */
/*
* HISTORY:
* Created 2001 by Rob Browning
@@ -35,51 +41,55 @@
#include "qofbook.h"
#include "qofid.h"
#include "qofid-p.h"
+#include "qofinstance-p.h"
+/** Book structure */
struct _QofBook
{
- QofEntity entity; /* Unique guid for this book. */
+ QofInstance inst; /**< Unique guid for this book. */
- /* The KvpFrame provides a place for top-level data associated
- * with this book. */
- KvpFrame *kvp_data;
-
- /* The entity table associates the GUIDs of all the objects
+ /** The entity table associates the GUIDs of all the objects
* belonging to this book, with their pointers to the respective
* objects. This allows a lookup of objects based on thier guid.
*/
GHashTable * hash_of_collections;
- /* In order to store arbitrary data, for extensibility, add a table
+ /** In order to store arbitrary data, for extensibility, add a table
* that will be used to hold arbitrary pointers.
*/
GHashTable *data_tables;
- /* state flag: 'y' means 'open for editing',
+ /** Hash table of destroy callbacks for the data table. */
+ GHashTable *data_table_finalizers;
+
+ /** state flag: 'y' means 'open for editing',
* 'n' means 'book is closed'
+ * xxxxx shouldn't this be replaced by the instance editlevel ???
*/
char book_open;
- /* dirty/clean flag. If dirty, then this book has been modified,
- * but has not yet been written out to storage (file/database)
+ /** a flag denoting whether the book is closing down, used to
+ * help the QOF objects shut down cleanly without maintaining
+ * internal consistency.
+ * XXX shouldn't this be replaced by instance->do_free ???
*/
- gboolean dirty;
+ gboolean shutting_down;
- /* version number, used for tracking multiuser updates */
+ /** version number, used for tracking multiuser updates */
gint32 version;
- /* To be technically correct, backends belong to sessions and
+ /** To be technically correct, backends belong to sessions and
* not books. So the pointer below "really shouldn't be here",
* except that it provides a nice convenience, avoiding a lookup
* from the session. Better solutions welcome ... */
QofBackend *backend;
/* -------------------------------------------------------------- */
- /* Backend private expansion data */
- guint32 idata; /* used by the sql backend for kvp management */
+ /** Backend private expansion data */
+ guint32 idata; /**< used by the sql backend for kvp management */
};
-/*
+/**
* These qof_book_set_*() routines are used by backends to
* initialize the pointers in the book structure to
* something that contains actual data. These routines
@@ -91,17 +101,20 @@
void qof_book_set_backend (QofBook *book, QofBackend *be);
-/* The qof_book_mark_saved() routine marks the book as having been
+/** The qof_book_mark_saved() routine marks the book as having been
* saved (to a file, to a database). Used by backends to mark the
* notsaved flag as FALSE just after loading. Do not use otherwise!
*/
void qof_book_mark_saved(QofBook *book);
-/* Register books with the engine */
+/** Register books with the engine */
gboolean qof_book_register (void);
-/* deprecated */
+/** @deprecated */
#define qof_book_set_guid(book,guid) \
qof_entity_set_guid(QOF_ENTITY(book), guid)
+/* @} */
+/* @} */
+/* @} */
#endif /* QOF_BOOK_P_H */
Index: Period.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Period.c,v
retrieving revision 1.27.4.3
retrieving revision 1.27.4.4
diff -Lsrc/engine/Period.c -Lsrc/engine/Period.c -u -r1.27.4.3 -r1.27.4.4
--- src/engine/Period.c
+++ src/engine/Period.c
@@ -546,8 +546,8 @@
/* hack alert -- FIXME -- this should really be a merge, not a
* clobber copy, but I am too lazy to write a kvp merge routine,
* and it is not needed for the current usage. */
- kvp_frame_delete (dest_book->kvp_data);
- dest_book->kvp_data = kvp_frame_copy (src_book->kvp_data);
+ kvp_frame_delete (dest_book->inst.kvp_data);
+ dest_book->inst.kvp_data = kvp_frame_copy (src_book->inst.kvp_data);
/* Next, copy the commodity tables */
src_tbl = gnc_commodity_table_get_table (src_book);
@@ -598,11 +598,11 @@
/* Make note of the sibling books */
now = time(0);
- gnc_kvp_bag_add (src_book->kvp_data, "gemini", now,
- "book_guid", &dest_book->entity.guid,
+ gnc_kvp_bag_add (src_book->inst.kvp_data, "gemini", now,
+ "book_guid", &dest_book->inst.entity.guid,
NULL);
- gnc_kvp_bag_add (dest_book->kvp_data, "gemini", now,
- "book_guid", &src_book->entity.guid,
+ gnc_kvp_bag_add (dest_book->inst.kvp_data, "gemini", now,
+ "book_guid", &src_book->inst.entity.guid,
NULL);
LEAVE (" ");
}
@@ -693,7 +693,7 @@
xaccAccountBeginEdit (twin);
cwd = xaccAccountGetSlots (twin);
kvp_frame_set_guid (cwd, "/book/prev-acct", xaccAccountGetGUID (candidate));
- kvp_frame_set_guid (cwd, "/book/prev-book", &closed_book->entity.guid);
+ kvp_frame_set_guid (cwd, "/book/prev-book", &closed_book->inst.entity.guid);
xaccAccountSetSlots_nc (twin, twin->inst.kvp_data);
@@ -702,7 +702,7 @@
* the next book is. */
xaccAccountBeginEdit (candidate);
cwd = xaccAccountGetSlots (candidate);
- kvp_frame_set_guid (cwd, "/book/next-book", &open_book->entity.guid);
+ kvp_frame_set_guid (cwd, "/book/next-book", &open_book->inst.entity.guid);
kvp_frame_set_guid (cwd, "/book/next-acct", xaccAccountGetGUID (twin));
xaccAccountSetSlots_nc (candidate, candidate->inst.kvp_data);
@@ -760,7 +760,7 @@
/* Add KVP data showing where the balancing
* transaction came from */
cwd = xaccTransGetSlots (trans);
- kvp_frame_set_guid (cwd, "/book/closed-book", &closed_book->entity.guid);
+ kvp_frame_set_guid (cwd, "/book/closed-book", &closed_book->inst.entity.guid);
kvp_frame_set_guid (cwd, "/book/closed-acct", xaccAccountGetGUID(candidate));
xaccTransCommitEdit (trans);
@@ -805,7 +805,7 @@
be = src_book->backend;
if (be && be->begin)
{
- (*be->begin)(be, GNC_ID_PERIOD, dest_book);
+ // (*be->begin)(be, GNC_ID_PERIOD, dest_book);
}
}
@@ -816,7 +816,7 @@
be = src_book->backend;
if (be && be->commit)
{
- (*be->commit)(be, GNC_ID_PERIOD, dest_book);
+ // (*be->commit)(be, GNC_ID_PERIOD, dest_book);
}
}
@@ -870,8 +870,8 @@
/* Now add the various identifying kvp's */
/* cwd == 'current working directory' */
- exist_cwd = existing_book->kvp_data;
- partn_cwd = closing_book->kvp_data;
+ exist_cwd = existing_book->inst.kvp_data;
+ partn_cwd = closing_book->inst.kvp_data;
/* Mark the boundary date between the books */
kvp_frame_set_timespec (exist_cwd, "/book/open-date", calve_date);
@@ -883,8 +883,8 @@
kvp_frame_set_timespec (partn_cwd, "/book/log-date", ts);
/* Set up pointers to each book from the other. */
- kvp_frame_set_guid (partn_cwd, "/book/next-book", &existing_book->entity.guid);
- kvp_frame_set_guid (exist_cwd, "/book/prev-book", &closing_book->entity.guid);
+ kvp_frame_set_guid (partn_cwd, "/book/next-book", &existing_book->inst.entity.guid);
+ kvp_frame_set_guid (exist_cwd, "/book/prev-book", &closing_book->inst.entity.guid);
/* add in transactions to equity accounts that will
* hold the colsing balances */
Index: SchedXaction.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/SchedXaction.h,v
retrieving revision 1.24.4.2
retrieving revision 1.24.4.3
diff -Lsrc/engine/SchedXaction.h -Lsrc/engine/SchedXaction.h -u -r1.24.4.2 -r1.24.4.3
--- src/engine/SchedXaction.h
+++ src/engine/SchedXaction.h
@@ -18,7 +18,13 @@
* *
\********************************************************************/
/**
- * @addtogroup Engine_SchedXaction
+ * @addtogroup Engine
+ * @{ */
+/**
+ * @addtogroup SchedXaction Scheduled/Periodic/Recurring Transactions
+ Scheduled Transactions provides a framework for remembering
+ information about a transactions that are set to occur in the
+ future, either once or periodically.
* @{ */
/**
* @file SchedXaction.h
@@ -224,3 +230,4 @@
#endif /* XACC_SCHEDXACTION_H */
/** @} */
+/** @} */
Index: gnc-trace.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-trace.c,v
retrieving revision 1.2.20.6
retrieving revision 1.2.20.7
diff -Lsrc/engine/gnc-trace.c -Lsrc/engine/gnc-trace.c -u -r1.2.20.6 -r1.2.20.7
--- src/engine/gnc-trace.c
+++ src/engine/gnc-trace.c
@@ -180,6 +180,7 @@
va_end (ap);
fprintf (fout, "\n");
+ fflush (fout);
}
void
@@ -218,6 +219,7 @@
va_end (ap);
fprintf (fout, "\n");
+ fflush (fout);
}
void
@@ -251,6 +253,7 @@
va_end (ap);
fprintf (fout, "\n");
+ fflush (fout);
}
gboolean
Index: gnc-pricedb-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-pricedb-p.h,v
retrieving revision 1.18.4.3
retrieving revision 1.18.4.4
diff -Lsrc/engine/gnc-pricedb-p.h -Lsrc/engine/gnc-pricedb-p.h -u -r1.18.4.3 -r1.18.4.4
--- src/engine/gnc-pricedb-p.h
+++ src/engine/gnc-pricedb-p.h
@@ -59,12 +59,8 @@
struct gnc_price_db_s
{
+ QofInstance inst; /* globally unique object identifier */
GHashTable *commodity_hash;
- QofBook *book; /* book holding this database and all its prices */
-
- /* 'private' object management fields */
- gint32 editlevel; /* nesting level of begin/end edit calls */
- gboolean dirty;
};
/* These structs define the kind of price lookup being done
@@ -98,12 +94,7 @@
} GNCPriceLookupHelper;
#define gnc_price_set_guid(P,G) qof_entity_set_guid(QOF_ENTITY(P),(G))
-
-void gnc_pricedb_set_db(QofBook *book, GNCPriceDB *db);
-void gnc_collection_set_pricedb(QofCollection *col, GNCPriceDB *db);
-
-
-void gnc_pricedb_mark_clean(GNCPriceDB *db);
+#define gnc_pricedb_mark_clean(db) qof_instance_mark_clean(QOF_INSTANCE(db))
void gnc_pricedb_substitute_commodity(GNCPriceDB *db,
gnc_commodity *old_c,
gnc_commodity *new_c);
Index: Group.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Group.c,v
retrieving revision 1.112.4.5
retrieving revision 1.112.4.6
diff -Lsrc/engine/Group.c -Lsrc/engine/Group.c -u -r1.112.4.5 -r1.112.4.6
--- src/engine/Group.c
+++ src/engine/Group.c
@@ -1267,12 +1267,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_GROUP,
type_label: "AccountGroup",
+ create: NULL,
book_begin: group_book_begin,
book_end: group_book_end,
is_dirty: group_is_dirty,
mark_clean: group_mark_clean,
foreach: NULL,
printable: NULL,
+ version_cmp: NULL,
};
gboolean
Index: qofid-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofid-p.h,v
retrieving revision 1.2.6.1
retrieving revision 1.2.6.2
diff -Lsrc/engine/qofid-p.h -Lsrc/engine/qofid-p.h -u -r1.2.6.1 -r1.2.6.2
--- src/engine/qofid-p.h
+++ src/engine/qofid-p.h
@@ -20,6 +20,13 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Object_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/** @name Entity_Private
+ @{ */
#ifndef QOF_ID_P_H
#define QOF_ID_P_H
@@ -42,8 +49,11 @@
*/
void qof_collection_insert_entity (QofCollection *, QofEntity *);
-/* reset value of dirty flag */
+/** reset value of dirty flag */
void qof_collection_mark_clean (QofCollection *);
void qof_collection_mark_dirty (QofCollection *);
+/* @} */
+/* @} */
+/* @} */
#endif /* QOF_ID_P_H */
Index: qofbackend.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend.h,v
retrieving revision 1.3.4.1
retrieving revision 1.3.4.2
diff -Lsrc/engine/qofbackend.h -Lsrc/engine/qofbackend.h -u -r1.3.4.1 -r1.3.4.2
--- src/engine/qofbackend.h
+++ src/engine/qofbackend.h
@@ -18,17 +18,22 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Object
@{ */
-/** @file qofbackend.h
- @brief api for data storage Backend
- *
- The 'backend' is a pseudo-object providing an interface between the
+/** @addtogroup Backend
+ The QOF Backend is a pseudo-object providing an interface between the
engine and a persistant data store (e.g. a server, a database, or
- a file). There are no backend functions that are 'public' to
+ a file). Backends are not meant to be used directly by an
+ application; instead the Session should be used to make a
+ connection with some particular backend.
+ There are no backend functions that are 'public' to
users of the engine. The backend can, however, report errors to
the GUI & other front-end users. This file defines these errors.
- *
+
+ Backends are used to save and restore Entities in a Book.
+ @{ */
+/** @file qofbackend.h
+ @brief API for data storage Backend
@author Copyright (C) 2000-2001 Linas Vepstas <linas at linas.org>
*/
@@ -41,8 +46,8 @@
*/
typedef enum {
ERR_BACKEND_NO_ERR = 0,
- ERR_BACKEND_NO_BACKEND, /**< Backend * pointer was null the err routine
- or no backend handler (ENOSYS) */
+ ERR_BACKEND_NO_HANDLER, /**< no backend handler found for this access method (ENOSYS) */
+ ERR_BACKEND_NO_BACKEND, /**< Backend * pointer was unexpectedly null */
ERR_BACKEND_BAD_URL, /**< Can't parse url */
ERR_BACKEND_NO_SUCH_DB, /**< the named database doesn't exist */
ERR_BACKEND_CANT_CONNECT, /**< bad dbname/login/passwd or network failure */
@@ -91,6 +96,14 @@
ERR_RPC_NOT_ADDED, /**< object not added */
} QofBackendError;
+/**
+ * A structure that declares backend services that can be gotten.
+ * The Provider specifies a URL access method, and specifies the
+ * function to create a backend that can handle that URL access
+ * function.
+ */
+typedef struct QofBackendProvider_s QofBackendProvider;
+
/** \brief Pseudo-object providing an interface between the
* engine and a persistant data store (e.g. a server, a database,
* or a file).
@@ -99,10 +112,11 @@
* engine. The backend can, however, report errors to the GUI & other
* front-end users.
*/
-typedef struct _QofBackend QofBackend;
+typedef struct QofBackend_s QofBackend;
/** \brief DOCUMENT ME! */
typedef void (*QofBePercentageFunc) (const char *message, double percent);
#endif /* QOF_BACKEND_H */
/**@}*/
+/**@}*/
Index: gnc-engine.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine.h,v
retrieving revision 1.16.4.4
retrieving revision 1.16.4.5
diff -Lsrc/engine/gnc-engine.h -Lsrc/engine/gnc-engine.h -u -r1.16.4.4 -r1.16.4.5
--- src/engine/gnc-engine.h
+++ src/engine/gnc-engine.h
@@ -19,7 +19,11 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Engine GnuCash Engine: Core, Non-GUI Accounting Functions
+ The GnuCash Engine provides a set of objects and classes that
+ encapsulate typical financial accounting concepts. The GnuCash
+ GUI is expected to manipulate these objects through the provided
+ engine API.
@{ */
/** @file gnc-engine.h
@brief All type declarations for the whole Gnucash engine
@@ -35,13 +39,13 @@
#include <glib.h>
#include "qofid.h"
-/* IDENTIFIERS *****************************************************/
-/** GUID Identifiers can be used to reference Accounts, Transactions,
+/** @brief IDENTIFIERS
+ * GUID Identifiers can be used to reference Accounts, Transactions,
* Splits and other objects. These Gnucash types are referred to as Gnucash
* entities. GUID Identifiers are globally-unique and permanent, i.e., once
* an entity has been assigned an identifier, it retains that same
* identifier for its lifetime.
- *
+ * -
* Identifiers are 'typed' with strings. The ids used in gnucash are
* defined below. An id with type GNC_ID_NONE does not refer to any
* entity, although that may change as new ids are created. An id with
@@ -76,7 +80,6 @@
/* TYPES **********************************************************/
/** @brief Account in Gnucash.
- *
* This is the typename for an account. The actual structure is
* defined in the private header AccountP.h, but no one outside the
* engine should include that file. Instead, access that data only
@@ -88,7 +91,6 @@
typedef struct account_group_s AccountGroup;
/** @brief Split in Gnucash.
- *
* A "split" is more commonly refered to as a "entry" in a
* "transaction". Each split belongs to one Account and one
* Transaction. The split is one out of several parts a Transaction is
@@ -101,7 +103,6 @@
typedef struct split_s Split;
/** @brief Transaction in Gnucash.
- *
* A Transaction is a piece of business done; the transfer of money
* from one account to one or more other accounts. Each Transaction is
* divided into one or more Splits (usually two).
@@ -113,7 +114,6 @@
typedef struct transaction_s Transaction;
/** @brief An article that is bought and sold.
- *
* A Commodity is the most general term of what an account keeps track
* of. Usually this is a monetary currency, but it can also be a stock
* share or even a precious metal. Every account keeps track of
@@ -136,7 +136,6 @@
typedef struct gnc_commodity_table_s gnc_commodity_table;
/** @breif Identifies that something sold at one time was bought at another.
- *
* A GNCLot provides a way of tracking physical items as they are
* bought and sold in different transactions. By identifying
* the individual, underlying physical objects, it provides the
@@ -148,7 +147,6 @@
typedef struct gnc_lot_struct GNCLot;
/** @breif Price of commodity on a given date.
- *
* A GNCPrice encapsulates price information: the cost of a commodity
* expressed as a currency, on a given date. It also holds info about
* the provenance of the price: where it came from, its general validity.
Index: qofsession-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession-p.h,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -Lsrc/engine/qofsession-p.h -Lsrc/engine/qofsession-p.h -u -r1.2.4.1 -r1.2.4.2
--- src/engine/qofsession-p.h
+++ src/engine/qofsession-p.h
@@ -53,9 +53,6 @@
QofBackendError last_err;
char *error_message;
- char *fullpath;
- char *logpath;
-
/* ---------------------------------------------------- */
/* Pointer to the backend that is actually used to move data
* between the persistant store and the local engine. */
Index: qof.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qof.h,v
retrieving revision 1.2.4.2
retrieving revision 1.2.4.3
diff -Lsrc/engine/qof.h -Lsrc/engine/qof.h -u -r1.2.4.2 -r1.2.4.3
--- src/engine/qof.h
+++ src/engine/qof.h
@@ -21,6 +21,47 @@
#ifndef QOF_H_
#define QOF_H_
+/** @defgroup QOF Query Object Framework */
+/** @{ */
+
+/**
+ @addtogroup Date Date: Date and Time Printing, Parsing and Manipulation
+ @ingroup QOF
+*/
+/**
+ @addtogroup Entity Entity: Types, Identity and Instance Framework
+ @ingroup QOF
+
+*/
+/**
+ @addtogroup KVP KVP: Key-Value Pairs
+ @ingroup QOF
+*/
+/**
+ @addtogroup Math128 Math128: 128-bit Integer Math Library
+ @ingroup QOF
+*/
+/**
+ @addtogroup Numeric Numeric: Rational Number Handling w/ Rounding Error Control
+ @ingroup QOF
+*/
+/**
+ @addtogroup Object Object: Dynamic Object Class Framework
+ @ingroup QOF
+*/
+/**
+ @addtogroup Query Query: Querying for Objects
+ @ingroup QOF
+*/
+/**
+ @addtogroup Trace Trace: Error Reporting and Debugging
+ @ingroup QOF
+*/
+/**
+ @addtogroup Utilities Misc Utilities
+ @ingroup QOF
+*/
+/** @} */
#include "qof/gnc-date.h"
#include "qof/gnc-engine-util.h"
Index: qofbook.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbook.h,v
retrieving revision 1.5.2.3
retrieving revision 1.5.2.4
diff -Lsrc/engine/qofbook.h -Lsrc/engine/qofbook.h -u -r1.5.2.3 -r1.5.2.4
--- src/engine/qofbook.h
+++ src/engine/qofbook.h
@@ -1,4 +1,5 @@
/********************************************************************\
+ * qofbook.h -- Encapsulate all the information about a dataset. *
* 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 *
@@ -17,15 +18,21 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Book
+ A QOF Book is a dataset. It provides a single handle
+ through which all the various collections of entities
+ can be found. In particular, given only the type of
+ the entity, the collection can be found.
+
+ Books also provide the 'natural' place to working with
+ a storage backend, as a book can encapsulate everything
+ held in storage.
@{ */
/** @file qofbook.h
- * @brief dataset access (an "accounting book")
- * Encapsulate all the information about a dataset.
- * See src/docs/books.txt for implementation overview.
+ * @brief Encapsulate all the information about a dataset.
*
- * HISTORY:
- * Created by Linas Vepstas December 1998
* @author Copyright (c) 1998, 1999, 2001, 2003 Linas Vepstas <linas at linas.org>
* @author Copyright (c) 2000 Dave Peticolas
*/
@@ -60,6 +67,8 @@
/** GList of QofBook */
typedef GList QofBookList;
+typedef void (*QofBookFinalCB) (QofBook *, gpointer key, gpointer user_data);
+
/** Register the book object with the QOF object system. */
gboolean qof_book_register (void);
@@ -83,19 +92,33 @@
typedef void (*QofCollectionForeachCB) (QofCollection *, gpointer user_data);
void qof_book_foreach_collection (QofBook *, QofCollectionForeachCB, gpointer);
-/** \return The kvp data for the book */
-KvpFrame * qof_book_get_slots (QofBook *book);
+/** \return The kvp data for the book.
+ * Note that the boom KVP data is persistant, and is stored/retrevied
+ * from the file/database. Thus, the book KVP is the correct place to
+ * store data that needs to be persistant accross sessions (or shared
+ * between multiple users). To store application runtime data, use
+ * qof_book_set_data() isntead.
+ */
+#define qof_book_get_slots(book) qof_instance_get_slots(QOF_INSTANCE(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.
+ * extending QofBook to hold new data types. This is also
+ * the ideal location to store other arbitrary runtime data
+ * that the application may need.
*
- * 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.
+ * The book data differs from the book KVP in that the contents
+ * of the book KVP are persistant (are saved and restored to file
+ * or database), whereas the data pointers exist only at runtime.
*/
void qof_book_set_data (QofBook *book, const char *key, gpointer data);
+/** Same as qof_book_set_data(), except that the callback will be called
+ * when the book is destroyed. The argument to the callback will be
+ * the book followed by the data pointer.
+ */
+void qof_book_set_data_fin (QofBook *book, const char *key, gpointer data, QofBookFinalCB);
+
/** Retreives arbitrary pointers to structs stored by qof_book_set_data. */
gpointer qof_book_get_data (QofBook *book, const char *key);
@@ -104,6 +127,9 @@
void qof_book_set_backend (QofBook *book, QofBackend *);
+/** Is the book shutting down? */
+gboolean qof_book_shutting_down (QofBook *book);
+
/** qof_book_not_saved() will return TRUE if any
* data in the book hasn't been saved to long-term storage.
* (Actually, that's not quite true. The book doesn't know
@@ -128,21 +154,9 @@
*/
gint64 qof_book_get_counter (QofBook *book, const char *counter_name);
-/** Book parameter names */
-/**@{*/
-
-#define QOF_BOOK_KVP "qof-kvp"
-
-/**@}*/
-
-/**
- * @return The releveant QofEntity for the given GUID across all collections
- * in the book, or NULL if one cannot be found.
- **/
-QofEntity* qof_book_get_entity_by_guid( QofBook *book, GUID *entity );
-
/** deprecated */
#define qof_book_get_guid(X) qof_entity_get_guid (QOF_ENTITY(X))
#endif /* QOF_BOOK_H */
/** @} */
+/** @} */
Index: qofsession.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.h,v
retrieving revision 1.2.4.2
retrieving revision 1.2.4.3
diff -Lsrc/engine/qofsession.h -Lsrc/engine/qofsession.h -u -r1.2.4.2 -r1.2.4.3
--- src/engine/qofsession.h
+++ src/engine/qofsession.h
@@ -20,15 +20,10 @@
* *
\********************************************************************/
-/** @addtogroup Engine
- * @{ */
-/** @file qofsession.h
- * @brief Encapsulates a connection to a backednd (persistent store)
- * @author Copyright (c) 1998, 1999, 2001, 2002 Linas Vepstas <linas at linas.org>
- * @author Copyright (c) 2000 Dave Peticolas
+/** @addtogroup Backend
*
- * FUNCTION:
- * Encapsulates a connection to a storage backend. That is, it
+ * The QOF Session
+ * encapsulates a connection to a storage backend. That is, it
* manages the connection to a persistant data store; whereas
* the backend is the thing that performs the actual datastore
* access.
@@ -63,7 +58,7 @@
* level: i.e. does this user even have the authority to connect
* to and open this datastore?
*
- * A breif note about books & sessions:
+ * A brief note about books & sessions:
* A book encapsulates the datasets manipulated by GnuCash. A book
* holds the actual data. By contrast, the session mediates the
* connection between a book (the thing that lives in virtual memory
@@ -80,6 +75,13 @@
* make that assumption, in order to store the different accounting
* periods in a clump so that one can be found, given another.
*
+ * @{
+ */
+
+/** @file qofsession.h
+ * @brief Encapsulates a connection to a backend (persistent store)
+ * @author Copyright (c) 1998, 1999, 2001, 2002 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2000 Dave Peticolas
*/
#ifndef QOF_SESSION_H
@@ -149,19 +151,25 @@
* backends, e.g. network or SQL, this would load only enough data
* to make the book actually usable; it would not cause *all* of the
* data to be loaded.
+ *
+ * XXX the current design tries to accomodate multiple calls to 'load'
+ * for each session, each time wiping out the old books; this seems
+ * wrong to me, and should be restricted to allow only one load per
+ * session.
*/
typedef void (*QofPercentageFunc) (const char *message, double percent);
void qof_session_load (QofSession *session,
QofPercentageFunc percentage_func);
-/* XXX session_export really doesn't belong here */
-gboolean qof_session_export (QofSession *tmp_session,
- QofSession *real_session,
- QofPercentageFunc percentage_func);
-
+/** @name Session Errors
+ @{ */
/** The qof_session_get_error() routine can be used to obtain the reason
* for any failure. Calling this routine returns the current error.
- *
+ */
+QofBackendError qof_session_get_error (QofSession *session);
+const char * qof_session_get_error_message(QofSession *session);
+
+/**
* The qof_session_pop_error() routine can be used to obtain the reason
* for any failure. Calling this routine resets the error value.
*
@@ -171,9 +179,8 @@
*
* See qofbackend.h for a listing of returned errors.
*/
-QofBackendError qof_session_get_error (QofSession *session);
-const char * qof_session_get_error_message(QofSession *session);
QofBackendError qof_session_pop_error (QofSession *session);
+/* @} */
/** The qof_session_add_book() allows additional books to be added to
* a session.
@@ -216,7 +223,10 @@
* more than a write to the file of the current AccountGroup & etc.
* For the SQL backend, this is typically a no-op (since all data
* has already been written out to the database.
- *
+ */
+void qof_session_save (QofSession *session,
+ QofPercentageFunc percentage_func);
+/**
* The qof_session_end() method will release the session lock. For the
* file backend, it will *not* save the account group to a file. Thus,
* this method acts as an "abort" or "rollback" primitive. However,
@@ -224,36 +234,37 @@
* been written out before this, and so this routines wouldn't
* roll-back anything; it would just shut the connection.
*/
-void qof_session_save (QofSession *session,
- QofPercentageFunc percentage_func);
void qof_session_end (QofSession *session);
+/** @name Event Handling
+ @{ */
/** The qof_session_events_pending() method will return TRUE if the backend
* has pending events which must be processed to bring the engine
* up to date with the backend.
- *
- * The qof_session_process_events() method will process any events indicated
+ */
+gboolean qof_session_events_pending (QofSession *session);
+
+/** The qof_session_process_events() method will process any events indicated
* by the qof_session_events_pending() method. It returns TRUE if the
* engine was modified while engine events were suspended.
*/
-gboolean qof_session_events_pending (QofSession *session);
gboolean qof_session_process_events (QofSession *session);
+/* @} */
+
+#ifdef GNUCASH_MAJOR_VERSION
+/** Run the RPC Server
+ * @deprecated will go away */
+void gnc_run_rpc_server (void);
-/** The xaccResolveFilePath() routine is a utility that will accept
- * a fragmentary filename as input, and resolve it into a fully
- * qualified path in the file system, i.e. a path that begins with
- * a leading slash. First, the current working directory is
- * searched for the file. Next, the directory $HOME/.gnucash/data,
- * and finally, a list of other (configurable) paths. If the file
- * is not found, then the path $HOME/.gnucash/data is used. If
- * $HOME is not defined, then the current working directory is
- * used.
+/** XXX session_export really doesn't belong here .
+ * This functino exports the list of accounts to a file. Its a stop-gap
+ * measure until full book-closing is implemented.
*/
-char * xaccResolveFilePath (const char * filefrag);
-char * xaccResolveURL (const char * pathfrag);
+gboolean qof_session_export (QofSession *tmp_session,
+ QofSession *real_session,
+ QofPercentageFunc percentage_func);
-/** Run the RPC Server */
-void gnc_run_rpc_server (void);
+#endif /* GNUCASH_MJOR_VERSION */
/** Register a function to be called just before a session is closed.
*
Index: gw-engine-spec.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gw-engine-spec.scm,v
retrieving revision 1.53.4.5
retrieving revision 1.53.4.6
diff -Lsrc/engine/gw-engine-spec.scm -Lsrc/engine/gw-engine-spec.scm -u -r1.53.4.5 -r1.53.4.6
--- src/engine/gw-engine-spec.scm
+++ src/engine/gw-engine-spec.scm
@@ -21,6 +21,7 @@
ws
(lambda (wrapset client-wrapset)
(list
+ "#include <config.h>\n"
"#include <glib.h>\n"
"#include <guid.h>\n"
"#include <Group.h>\n"
Index: Scrub3.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Scrub3.h,v
retrieving revision 1.4.4.1
retrieving revision 1.4.4.2
diff -Lsrc/engine/Scrub3.h -Lsrc/engine/Scrub3.h -u -r1.4.4.1 -r1.4.4.2
--- src/engine/Scrub3.h
+++ src/engine/Scrub3.h
@@ -21,20 +21,25 @@
/** @addtogroup Engine
@{ */
+/** @addtogroup Scrub
+ @{ */
+
/** @file Scrub3.h
- * @breif Hiogh-Level API for imposing Lot constraints
+ * @brief Hiogh-Level API for imposing Lot constraints
* @author Created by Linas Vepstas Sept 2003
* @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
- *
- * Provides the high-level API for checking and repairing ('scrubbing
- * clean') the usage of Lots and Cap Gains transactions in stock and
- * commodity accounts.
*/
#ifndef XACC_SCRUB3_H
#define XACC_SCRUB3_H
#include "gnc-engine.h"
+/** @name High-Level Lot Constraint
+ * Provides the high-level API for checking and repairing ('scrubbing
+ * clean') the usage of Lots and Cap Gains transactions in stock and
+ * commodity accounts.
+ @{ */
+
/** The xaccScrubLot() routine makes sure that the indicated lot is
* self-consistent and properly balanced, and fixes it if its not.
* This is an important routine to call if the amount of any split
@@ -69,5 +74,7 @@
void xaccGroupScrubLots (AccountGroup *grp);
void xaccAccountTreeScrubLots (Account *acc);
+/** @} */
#endif /* XACC_SCRUB3_H */
/** @} */
+/** @} */
Index: Period.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Period.h,v
retrieving revision 1.9.4.3
retrieving revision 1.9.4.4
diff -Lsrc/engine/Period.h -Lsrc/engine/Period.h -u -r1.9.4.3 -r1.9.4.4
--- src/engine/Period.h
+++ src/engine/Period.h
@@ -20,8 +20,12 @@
\********************************************************************/
/** @addtogroup Engine
@{ */
+/** @addtogroup Period Accounting Periods
+ The architecture of the Accounting Period design is discussed
+ in greater detail in the file "src/doc/books.txt"
+ @{ */
/** @file Period.h
- * @breif Implement accounting periods, as per design in src/doc/books.txt
+ * @brief Implement accounting periods, as per design in src/doc/books.txt
* @author Copyright (c) 2001,2003 Linas Vepstas <linas at linas.org>
*/
@@ -183,3 +187,4 @@
#endif /* XACC_PERIOD_H */
/** @} */
+/** @} */
Index: qofsession.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.c,v
retrieving revision 1.2.4.5
retrieving revision 1.2.4.6
diff -Lsrc/engine/qofsession.c -Lsrc/engine/qofsession.c -u -r1.2.4.5 -r1.2.4.6
--- src/engine/qofsession.c
+++ src/engine/qofsession.c
@@ -28,7 +28,7 @@
*
* HISTORY:
* Created by Linas Vepstas December 1998
- * Copyright (c) 1998-2003 Linas Vepstas <linas at linas.org>
+ * Copyright (c) 1998-2004 Linas Vepstas <linas at linas.org>
* Copyright (c) 2000 Dave Peticolas
*/
@@ -59,18 +59,22 @@
#include "qofsession-p.h"
/* Some gnucash-specific code */
-#ifdef GNUCASH
+#ifdef GNUCASH_MAJOR_VERSION
#include "gnc-module.h"
-#include "TransLog.h"
-#else
-#define xaccLogSetBaseName(x)
-#define xaccLogEnable()
-#define xaccLogDisable()
#endif /* GNUCASH */
static QofSession * current_session = NULL;
static GHookList * session_closed_hooks = NULL;
static short module = MOD_BACKEND;
+static GSList *provider_list = NULL;
+
+/* ====================================================================== */
+
+void
+qof_backend_register_provider (QofBackendProvider *prov)
+{
+ provider_list = g_slist_prepend (provider_list, prov);
+}
/* ====================================================================== */
/* hook routines */
@@ -203,8 +207,6 @@
session->books = g_list_append (NULL, qof_book_new ());
session->book_id = NULL;
- session->fullpath = NULL;
- session->logpath = NULL;
session->backend = NULL;
qof_session_clear_error (session);
@@ -296,7 +298,8 @@
qof_session_get_file_path (QofSession *session)
{
if (!session) return NULL;
- return session->fullpath;
+ if (!session->backend) return NULL;
+ return session->backend->fullpath;
}
const char *
@@ -308,27 +311,20 @@
/* ====================================================================== */
+#ifdef GNUCASH_MAJOR_VERSION
+
static void
qof_session_int_backend_load_error(QofSession *session,
char *message, char *dll_err)
{
PWARN ("%s %s", message, dll_err ? dll_err : "");
- g_free(session->fullpath);
- session->fullpath = NULL;
-
- g_free(session->logpath);
- session->logpath = NULL;
-
g_free(session->book_id);
session->book_id = NULL;
qof_session_push_error (session, ERR_BACKEND_NO_BACKEND, NULL);
}
-
-#ifdef GNUCASH
-
/* Gnucash uses its module system to load a backend; other users
* use traditional dlopen calls.
*/
@@ -344,7 +340,10 @@
/* FIXME: this needs to be smarter with version numbers. */
/* FIXME: this should use dlopen(), instead of guile/scheme,
* to load the modules. Right now, this requires the engine to
- * link to scheme, which is an obvious architecture flaw. */
+ * link to scheme, which is an obvious architecture flaw.
+ * XXX this is fexed below, in the non-gnucash version. Cut
+ * over at some point.
+ */
mod = gnc_module_load(mod_name, 0);
if (mod)
@@ -381,11 +380,68 @@
#else /* GNUCASH */
+/* Specify a library, and a function name. Load the library,
+ * call the function name in the library. */
static void
-qof_session_load_backend(QofSession * session, char * backend_name)
+load_backend_library (const char * libso, const char * loadfn)
{
- ENTER (" ");
- LEAVE (" ");
+ void *dl_hand = dlopen (libso, RTLD_LAZY);
+ if (NULL == dl_hand)
+ {
+ const char * err_str = dlerror();
+ PERR("Can't load %s backend, %s\n", libso, err_str);
+ return;
+ }
+ void (*initfn) (void) = dlsym (dl_hand, loadfn);
+ if (initfn)
+ {
+ (*initfn)();
+ }
+ else
+ {
+ const char * err_str = dlerror();
+ PERR("Can't find %s:%s, %s\n", libso, loadfn, err_str);
+ }
+}
+
+static void
+qof_session_load_backend(QofSession * session, char * access_method)
+{
+ GSList *p;
+ ENTER (" ");
+
+ /* If the provider list is null, try to register the 'well-known'
+ * backends. Right now, there's only one. */
+ if (NULL == provider_list)
+ {
+ load_backend_library ("libqof_backend_dwi.so", "dwiend_provider_init");
+ }
+
+ for (p = provider_list; p; p=p->next)
+ {
+ QofBackendProvider *prov = p->data;
+
+ /* Does this provider handle the desired access method? */
+ if (0 == strcasecmp (access_method, prov->access_method))
+ {
+ if (NULL == prov->backend_new) continue;
+
+ /* Use the providers creation callback */
+ session->backend = (*(prov->backend_new))();
+
+ /* Tell the books about the backend that they'll be using. */
+ GList *node;
+ for (node=session->books; node; node=node->next)
+ {
+ QofBook *book = node->data;
+ qof_book_set_backend (book, session->backend);
+ }
+ return;
+ }
+ }
+
+ qof_session_push_error (session, ERR_BACKEND_NO_HANDLER, NULL);
+ LEAVE (" ");
}
#endif /* GNUCASH */
@@ -426,11 +482,11 @@
session, ignore_lock,
book_id ? book_id : "(null)");
- /* clear the error condition of previous errors */
+ /* Clear the error condition of previous errors */
qof_session_clear_error (session);
- /* check to see if this session is already open */
- if (qof_session_get_url(session))
+ /* Check to see if this session is already open */
+ if (session->book_id)
{
qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL);
LEAVE("push error book is already open ");
@@ -444,74 +500,55 @@
LEAVE("push error missing book_id");
return;
}
- /* Store the sessionid URL */
- session->book_id = g_strdup (book_id);
-
- /* XXX we should probably move this resolve function to the
- * file backend. I think the idea would be to open the backend
- * and then ask it if it can contact it's storage media (disk,
- * network, server, etc.) and abort if it can't. Mal-formed
- * file URL's would be handled the same way!
- */
- /* ResolveURL tries to find the file in the file system. */
- session->fullpath = xaccResolveURL(book_id);
- if (!session->fullpath)
- {
- qof_session_push_error (session, ERR_FILEIO_FILE_NOT_FOUND, NULL);
- LEAVE("push error: can't resolve file path");
- return;
- }
- PINFO ("filepath=%s", session->fullpath ? session->fullpath : "(null)");
- session->logpath = xaccResolveFilePath(session->fullpath);
- PINFO ("logpath=%s", session->logpath ? session->logpath : "(null)");
+ /* Store the session URL */
+ session->book_id = g_strdup (book_id);
/* destroy the old backend */
qof_session_destroy_backend(session);
- /* check to see if this is a type we know how to handle */
- if (!g_strncasecmp(book_id, "file:", 5) ||
- *session->fullpath == '/')
- {
- qof_session_load_backend(session, "file" );
- }
-#if 0
- /* load different backend based on URL. We should probably
- * dynamically load these based on some config file ... */
- else if ((!g_strncasecmp(book_id, "http://", 7)) ||
- (!g_strncasecmp(book_id, "https://", 8)))
+ /* Look for somthing of the form of "file:/", "http://" or
+ * "postgres://". Everything before the colon is the access
+ * method. Load the first backend found for that access method.
+ */
+ char * p = strchr (book_id, ':');
+ if (p)
{
- /* create the backend */
- session->backend = xmlendNew();
+ char * access_method = g_strdup (book_id);
+ p = strchr (access_method, ':');
+ *p = 0;
+ qof_session_load_backend(session, access_method);
+ g_free (access_method);
}
-#endif
- else if (!g_strncasecmp(book_id, "postgres://", 11))
+ else
{
- qof_session_load_backend(session, "postgres");
+ /* If no colon found, assume it must be a file-path */
+ qof_session_load_backend(session, "file");
}
- else if (!g_strncasecmp(book_id, "rpc://", 6))
+
+ /* No backend was found. That's bad. */
+ if (NULL == session->backend)
{
- qof_session_load_backend(session, "rpc");
+ qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
+ LEAVE (" BAD: no backend: sess=%p book-id=%s",
+ session, book_id ? book_id : "(null)");
+ return;
}
/* If there's a begin method, call that. */
- if (session->backend && session->backend->session_begin)
+ if (session->backend->session_begin)
{
int err;
char * msg;
(session->backend->session_begin)(session->backend, session,
- qof_session_get_url(session), ignore_lock,
+ session->book_id, ignore_lock,
create_if_nonexistent);
PINFO("Done running session_begin on backend");
err = qof_backend_get_error(session->backend);
msg = qof_backend_get_message(session->backend);
if (err != ERR_BACKEND_NO_ERR)
{
- g_free(session->fullpath);
- session->fullpath = NULL;
- g_free(session->logpath);
- session->logpath = NULL;
g_free(session->book_id);
session->book_id = NULL;
qof_session_push_error (session, err, msg);
@@ -525,11 +562,6 @@
}
}
- /* No backend was found. That's bad. */
- if (NULL == session->backend)
- {
- qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
- }
LEAVE (" sess=%p book-id=%s",
session, book_id ? book_id : "(null)");
}
@@ -546,10 +578,10 @@
QofBackendError err;
if (!session) return;
- if (!qof_session_get_url(session)) return;
+ if (!session->book_id) return;
- ENTER ("sess=%p book_id=%s", session, qof_session_get_url(session)
- ? qof_session_get_url(session) : "(null)");
+ ENTER ("sess=%p book_id=%s", session, session->book_id
+ ? session->book_id : "(null)");
/* At this point, we should are supposed to have a valid book
@@ -560,8 +592,6 @@
session->books = g_list_append (NULL, newbook);
PINFO ("new book=%p", newbook);
- xaccLogSetBaseName(session->logpath);
-
qof_session_clear_error (session);
/* This code should be sufficient to initialize *any* backend,
@@ -580,7 +610,6 @@
*/
if (be)
{
- xaccLogDisable();
be->percentage = percentage_func;
if (be->load)
@@ -588,7 +617,6 @@
be->load (be, newbook);
qof_session_push_error (session, qof_backend_get_error(be), NULL);
}
- xaccLogEnable();
}
err = qof_session_get_error(session);
@@ -597,27 +625,23 @@
(err != ERR_SQL_DB_TOO_OLD))
{
/* Something broke, put back the old stuff */
- xaccLogDisable();
qof_book_set_backend (newbook, NULL);
qof_book_destroy (newbook);
g_list_free (session->books);
session->books = oldbooks;
LEAVE("error from backend %d", qof_session_get_error(session));
- xaccLogEnable();
return;
}
- xaccLogDisable();
for (node=oldbooks; node; node=node->next)
{
QofBook *ob = node->data;
qof_book_set_backend (ob, NULL);
qof_book_destroy (ob);
}
- xaccLogEnable();
- LEAVE ("sess = %p, book_id=%s", session, qof_session_get_url(session)
- ? qof_session_get_url(session) : "(null)");
+ LEAVE ("sess = %p, book_id=%s", session, session->book_id
+ ? session->book_id : "(null)");
}
/* ====================================================================== */
@@ -625,19 +649,11 @@
gboolean
qof_session_save_may_clobber_data (QofSession *session)
{
- struct stat statbuf;
-
if (!session) return FALSE;
- if (!session->fullpath) return FALSE;
-
- /* FIXME: This should really be sent to the backend. The stat is
- * correct only for the file backend */
-
- /* FIXME: Make sure this doesn't need more sophisticated semantics
- * in the face of special file, devices, pipes, symlinks, etc. */
- if (stat(session->fullpath, &statbuf) == 0) return TRUE;
+ if (!session->backend) return FALSE;
+ if (!session->backend->save_may_clobber_data) return FALSE;
- return FALSE;
+ return (*(session->backend->save_may_clobber_data)) (session->backend);
}
static gboolean
@@ -675,9 +691,7 @@
if (!session) return;
ENTER ("sess=%p book_id=%s",
- session,
- qof_session_get_url(session)
- ? qof_session_get_url(session) : "(null)");
+ session, session->book_id ? session->book_id : "(null)");
/* If there is a backend, and the backend is reachable
* (i.e. we can communicate with it), then synchronize with
@@ -717,7 +731,11 @@
}
/* ====================================================================== */
-/* XXX what does this function do ?? */
+/* XXX This exports the list of accounts to a file. It does not export
+ * any transactions. Its a place-holder until full book-closing is implemented.
+ */
+
+#ifdef GNUCASH_MAJOR_VERSION
gboolean
qof_session_export (QofSession *tmp_session,
@@ -732,8 +750,8 @@
book = qof_session_get_book (real_session);
ENTER ("tmp_session=%p real_session=%p book=%p book_id=%s",
tmp_session, real_session, book,
- qof_session_get_url(tmp_session)
- ? qof_session_get_url(tmp_session) : "(null)");
+ tmp_session -> book_id
+ ? tmp_session->book_id : "(null)");
/* There must be a backend or else. (It should always be the file
* backend too.)
@@ -752,6 +770,7 @@
return TRUE;
}
+#endif /* GNUCASH_MAJOR_VERSION */
/* ====================================================================== */
@@ -760,8 +779,8 @@
{
if (!session) return;
- ENTER ("sess=%p book_id=%s", session, qof_session_get_url(session)
- ? qof_session_get_url(session) : "(null)");
+ ENTER ("sess=%p book_id=%s", session, session->book_id
+ ? session->book_id : "(null)");
/* close down the backend first */
if (session->backend && session->backend->session_end)
@@ -771,17 +790,11 @@
qof_session_clear_error (session);
- g_free (session->fullpath);
- session->fullpath = NULL;
-
- g_free (session->logpath);
- session->logpath = NULL;
-
g_free (session->book_id);
session->book_id = NULL;
- LEAVE ("sess=%p book_id=%s", session, qof_session_get_url(session)
- ? qof_session_get_url(session) : "(null)");
+ LEAVE ("sess=%p book_id=%s", session, session->book_id
+ ? session->book_id : "(null)");
}
void
@@ -790,11 +803,9 @@
GList *node;
if (!session) return;
- ENTER ("sess=%p book_id=%s", session,
- qof_session_get_url(session)
- ? qof_session_get_url(session) : "(null)");
+ ENTER ("sess=%p book_id=%s", session, session->book_id
+ ? session->book_id : "(null)");
- xaccLogDisable();
qof_session_end (session);
/* destroy the backend */
@@ -811,8 +822,6 @@
if (session == current_session)
current_session = NULL;
- xaccLogEnable();
-
g_free (session);
LEAVE ("sess=%p", session);
@@ -874,273 +883,14 @@
}
/* ====================================================================== */
-/*
- * If $HOME/.gnucash/data directory doesn't exist, then create it.
- */
-
-static void
-MakeHomeDir (void)
-{
- int rc;
- struct stat statbuf;
- char *home;
- char *path;
- char *data;
-
- /* Punt. Can't figure out where home is. */
- home = getenv ("HOME");
- if (!home) return;
-
- path = g_strconcat(home, "/.gnucash", NULL);
-
- rc = stat (path, &statbuf);
- if (rc)
- {
- /* assume that the stat failed only because the dir is absent,
- * and not because its read-protected or other error.
- * Go ahead and make it. Don't bother much with checking mkdir
- * for errors; seems pointless. */
- mkdir (path, S_IRWXU); /* perms = S_IRWXU = 0700 */
- }
-
- data = g_strconcat (path, "/data", NULL);
- rc = stat (data, &statbuf);
- if (rc)
- mkdir (data, S_IRWXU);
-
- g_free (path);
- g_free (data);
-}
-
-/* ====================================================================== */
-
-/* XXX hack alert -- we should be yanking this out of some config file */
-static char * searchpaths[] =
-{
- "/usr/share/gnucash/data/",
- "/usr/local/share/gnucash/data/",
- "/usr/share/gnucash/accounts/",
- "/usr/local/share/gnucash/accounts/",
- NULL,
-};
-
-typedef gboolean (*pathGenerator)(char *pathbuf, int which);
-
-static gboolean
-xaccAddEndPath(char *pathbuf, const char *ending, int len)
-{
- if(len + strlen(pathbuf) >= PATH_MAX)
- return FALSE;
-
- strcat (pathbuf, ending);
- return TRUE;
-}
-
-static gboolean
-xaccCwdPathGenerator(char *pathbuf, int which)
-{
- if(which != 0)
- {
- return FALSE;
- }
- else
- {
- /* try to find a file by this name in the cwd ... */
- if (getcwd (pathbuf, PATH_MAX) == NULL)
- return FALSE;
-
- strcat (pathbuf, "/");
- return TRUE;
- }
-}
-
-static gboolean
-xaccDataPathGenerator(char *pathbuf, int which)
-{
- char *path;
-
- if(which != 0)
- {
- return FALSE;
- }
- else
- {
- path = getenv ("HOME");
- if (!path)
- return FALSE;
-
- if (PATH_MAX <= (strlen (path) + 20))
- return FALSE;
-
- strcpy (pathbuf, path);
- strcat (pathbuf, "/.gnucash/data/");
- return TRUE;
- }
-}
-
-static gboolean
-xaccUserPathPathGenerator(char *pathbuf, int which)
-{
- char *path = NULL;
-
- if(searchpaths[which] == NULL)
- {
- return FALSE;
- }
- else
- {
- path = searchpaths[which];
-
- if (PATH_MAX <= strlen(path))
- return FALSE;
-
- strcpy (pathbuf, path);
- return TRUE;
- }
-}
-
-/* ====================================================================== */
-
-char *
-xaccResolveFilePath (const char * filefrag)
-{
- struct stat statbuf;
- char pathbuf[PATH_MAX];
- pathGenerator gens[4];
- char *filefrag_dup;
- int namelen;
- int i;
-
- /* seriously invalid */
- if (!filefrag)
- {
- PERR("filefrag is NULL");
- return NULL;
- }
- ENTER ("filefrag=%s", filefrag);
-
- /* ---------------------------------------------------- */
- /* OK, now we try to find or build an absolute file path */
-
- /* check for an absolute file path */
- if (*filefrag == '/')
- return g_strdup (filefrag);
-
- if (!g_strncasecmp(filefrag, "file:", 5))
- {
- char *ret = g_new(char, strlen(filefrag) - 5 + 1);
- strcpy(ret, filefrag + 5);
- return ret;
- }
-
- /* get conservative on the length so that sprintf(getpid()) works ... */
- /* strlen ("/.LCK") + sprintf (%x%d) */
- namelen = strlen (filefrag) + 25;
-
- gens[0] = xaccCwdPathGenerator;
- gens[1] = xaccDataPathGenerator;
- gens[2] = xaccUserPathPathGenerator;
- gens[3] = NULL;
-
- for (i = 0; gens[i] != NULL; i++)
- {
- int j;
- for(j = 0; gens[i](pathbuf, j) ; j++)
- {
- if(xaccAddEndPath(pathbuf, filefrag, namelen))
- {
- int rc = stat (pathbuf, &statbuf);
- if ((!rc) && (S_ISREG(statbuf.st_mode)))
- {
- return (g_strdup (pathbuf));
- }
- }
- }
- }
- /* OK, we didn't find the file. */
-
- /* make sure that the gnucash home dir exists. */
- MakeHomeDir();
-
- filefrag_dup = g_strdup (filefrag);
-
- /* Replace '/' with ',' for non file backends */
- if (strstr (filefrag, "://"))
- {
- char *p;
-
- p = strchr (filefrag_dup, '/');
- while (p) {
- *p = ',';
- p = strchr (filefrag_dup, '/');
- }
- }
-
- /* Lets try creating a new file in $HOME/.gnucash/data */
- if (xaccDataPathGenerator(pathbuf, 0))
- {
- if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
- {
- g_free (filefrag_dup);
- return (g_strdup (pathbuf));
- }
- }
-
- /* OK, we still didn't find the file */
- /* Lets try creating a new file in the cwd */
- if (xaccCwdPathGenerator(pathbuf, 0))
- {
- if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
- {
- g_free (filefrag_dup);
- return (g_strdup (pathbuf));
- }
- }
-
- g_free (filefrag_dup);
-
- return NULL;
-}
-
-/* ====================================================================== */
-
-char *
-xaccResolveURL (const char * pathfrag)
-{
- /* seriously invalid */
- if (!pathfrag) return NULL;
-
- /* At this stage of checking, URL's are always, by definition,
- * resolved. If there's an error connecting, we'll find out later.
- *
- * FIXME -- we should probably use ghttp_uri_validate
- * to make sure the uri is in good form.
- */
-
- if (!g_strncasecmp (pathfrag, "http://", 7) ||
- !g_strncasecmp (pathfrag, "https://", 8) ||
- !g_strncasecmp (pathfrag, "postgres://", 11) ||
- !g_strncasecmp (pathfrag, "rpc://", 6))
- {
- return g_strdup(pathfrag);
- }
-
- if (!g_strncasecmp (pathfrag, "file:", 5)) {
- return (xaccResolveFilePath (pathfrag));
- }
-
- return (xaccResolveFilePath (pathfrag));
-}
-
-/* ====================================================================== */
+#ifdef GNUCASH_MAJOR_VERSION
/* this should go in a separate binary to create a rpc server */
void
gnc_run_rpc_server (void)
{
-#ifdef GNUCASH
const char * dll_err;
void * dll_handle;
int (*rpc_run)(short);
@@ -1173,7 +923,7 @@
ret = (*rpc_run)(0);
/* XXX How do we force an exit? */
-#endif /* GNUCASH */
}
+#endif /* GNUCASH_MAJOR_VERSION */
/* =================== END OF FILE ====================================== */
Index: qofinstance-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofinstance-p.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -Lsrc/engine/qofinstance-p.h -Lsrc/engine/qofinstance-p.h -u -r1.2 -r1.2.4.1
--- src/engine/qofinstance-p.h
+++ src/engine/qofinstance-p.h
@@ -26,38 +26,56 @@
* Copyright (C) 2003 Linas Vepstas <linas at linas.org>
*/
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Object_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/** @name Instance_Private
+ @{ */
+
#ifndef QOF_INSTANCE_P_H
#define QOF_INSTANCE_P_H
#include "qofinstance.h"
-struct QofInstance_s
-{
-/*
+/**
* UNDER CONSTRUCTION!
* This is mostly scaffolding for now,
* eventually, it may hold more fields, such as refrence counting...
*
*/
- /* Globally unique id identifying this instance */
- QofEntity entity;
+struct QofInstance_s
+{
+ /** Globally unique id identifying this instance */
+ QofEntity entity;
- /* The entity_table in which this instance is stored */
+ /** The entity_table in which this instance is stored */
QofBook * book;
- /* kvp_data is a key-value pair database for storing arbirtary
+ /** kvp_data is a key-value pair database for storing arbirtary
* information associated with this instance.
* See src/engine/kvp_doc.txt for a list and description of the
* important keys. */
KvpFrame *kvp_data;
- /* Keep track of nesting level of begin/end edit calls */
+ /** Timestamp used to track the last modification to this
+ * instance. Typically used to compare two versions of the
+ * same object, to see which is newer. When used with the
+ * SQL backend, this field is reserved for SQL use, to compare
+ * the version in local memory to the remote, server version.
+ */
+ Timespec last_update;
+
+ /** Keep track of nesting level of begin/end edit calls */
int editlevel;
- /* In process of being destroyed */
+ /** In process of being destroyed */
gboolean do_free;
- /* This instance has not been saved yet */
+ /** dirty/clean flag. If dirty, then this instance has been modified,
+ * but has not yet been written out to storage (file/database)
+ */
gboolean dirty;
};
@@ -66,4 +84,14 @@
void qof_instance_set_slots (QofInstance *, KvpFrame *);
+/** Set the last_update time. Reserved for use by the SQL backend;
+ * used for comparing version in local memory to that in remote
+ * server.
+ */
+void qof_instance_set_last_update (QofInstance *inst, Timespec ts);
+
+/* @} */
+/* @} */
+/* @} */
+
#endif /* QOF_INSTANCE_P_H */
Index: Group.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Group.h,v
retrieving revision 1.64.4.3
retrieving revision 1.64.4.4
diff -Lsrc/engine/Group.h -Lsrc/engine/Group.h -u -r1.64.4.3 -r1.64.4.4
--- src/engine/Group.h
+++ src/engine/Group.h
@@ -1,7 +1,5 @@
/********************************************************************\
* Group.h -- chart of accounts (hierarchical tree of accounts) *
- * Copyright (C) 1997 Robin D. Clark *
- * Copyright (C) 1997-2000,2003 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 *
@@ -21,6 +19,18 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup Group Account Heirarchy Tree
+ Accounts are organized into a heirarchical tree. The account
+ group is the parent node that holds accounts.
+ @{ */
+/** @file Group.h
+ @brief Account handling public routines
+ @author Copyright (C) 1997 Robin D. Clark
+ @author Copyright (C) 1997-2000,2003 Linas Vepstas <linas at linas.org>
+*/
+
#ifndef XACC_ACCOUNT_GROUP_H
#define XACC_ACCOUNT_GROUP_H
@@ -34,79 +44,107 @@
/** PROTOTYPES ******************************************************/
-/*
+/** @name Constructors, Destructors */
+/** @{ */
+/**
* The xaccMallocAccountGroup() routine will create a new account group.
* This is an internal-use function, you almost certainly want to
* be using the xaccGetAccountGroup() routine instead.
*/
AccountGroup *xaccMallocAccountGroup (QofBook *book);
-/*
+/**
* The xaccGetAccountGroup() routine will return the top-most
* account group associated with the indicated book.
*/
AccountGroup * xaccGetAccountGroup (QofBook *book);
+
+/**
+ * The xaccCollAccountGroup() routine will return the top-most
+ * account group associated with the indicated collection.
+ */
AccountGroup * xaccCollGetAccountGroup (QofCollection *col);
-/*
- * The xaccAccountDestroy() routine will destroy and free all
+/** The xaccAccountDestroy() routine will destroy and free all
* the data associated with this account group. The group
* must have been opened for editing with
* xaccAccountGroupBeginEdit() first, before the Destroy is called.
*/
void xaccAccountGroupDestroy (AccountGroup *grp);
-
-/* XXX backwards-compat define, remove at later convenience */
+/* @deprecated XXX backwards-compat define, remove at later convenience */
#define gnc_book_get_group xaccGetAccountGroup
+/** Return the book to which this account belongs */
QofBook * xaccGroupGetBook (AccountGroup *group);
+/** DOCUMENT ME! */
+gboolean xaccGroupEqual(AccountGroup *a, AccountGroup *b,
+ gboolean check_guids);
+
+/** @} */
+
+/** @name Editing */
+/** @{ */
+/** Start of begine/commit sequence. All changes to an account
+ * group should be bracketed by calls to begin-edit/commit-edit
+ */
void xaccAccountGroupBeginEdit (AccountGroup *grp);
+
+/** End of begine/commit sequence. All changes to an account
+ * group should be bracketed by calls to begin-edit/commit-edit
+ */
void xaccAccountGroupCommitEdit (AccountGroup *grp);
-/*
+/** The xaccGroupNotSaved() subroutine will return TRUE
+ * if any account in the group or in any subgroup
+ * hasn't been saved.
+ XXX this should be moved to private header file, this is not a public routine!
+ */
+gboolean xaccGroupNotSaved (AccountGroup *grp);
+
+/** The xaccGroupMarkSaved() subroutine will mark
+ * the entire group as having been saved, including
+ * all of the child accounts.
+
+ XXX this should be moved to private header file, this is not a public routine!
+ */
+void xaccGroupMarkSaved (AccountGroup *grp);
+
+/** The xaccGroupMarkNotSaved() subroutine will mark
+ * the given group as not having been saved.
+ XXX this should be moved to private header file, this is not a public routine!
+ */
+void xaccGroupMarkNotSaved (AccountGroup *grp);
+/** @} */
+
+/** @name Concatenation, Merging */
+/** @{ */
+/**
* The xaccGroupConcatGroup() subroutine will move (reparent)
* all accounts from the "src" group to the "dest" group,
* preserving the account heirarchy. It will also take care
* that the moved accounts will have the "dest" group's book
* parent as well.
- *
- * The xaccGroupCopyGroup() subroutine will copy all accounts
+ */
+void xaccGroupConcatGroup (AccountGroup *dest, AccountGroup *src);
+
+/** The xaccGroupCopyGroup() subroutine will copy all accounts
* from the "src" group to the "dest" group, preserving the
* account heirarchy. It will also take care that the moved
* accounts will have the "dest" group's book parent as well.
* This routine will *NOT* copy any splits/transactions.
* It will copy the KVP trees in each account.
- *
- * The xaccGroupMergeAccounts() subroutine will go through a group,
- * merging all accounts that have the same name and description.
- * This function is useful when importing Quicken(TM) files.
*/
-
-void xaccGroupConcatGroup (AccountGroup *dest, AccountGroup *src);
void xaccGroupCopyGroup (AccountGroup *dest, AccountGroup *src);
-void xaccGroupMergeAccounts (AccountGroup *grp);
-/*
- * The xaccGroupNotSaved() subroutine will return TRUE
- * if any account in the group or in any subgroup
- * hasn't been saved.
- *
- * The xaccGroupMarkSaved() subroutine will mark
- * the entire group as having been saved, including
- * all of the child accounts.
- *
- * The xaccGroupMarkNotSaved() subroutine will mark
- * the given group as not having been saved.
+/** The xaccGroupMergeAccounts() subroutine will go through a group,
+ * merging all accounts that have the same name and description.
+ * This function is useful when importing Quicken(TM) files.
*/
+void xaccGroupMergeAccounts (AccountGroup *grp);
-gboolean xaccGroupNotSaved (AccountGroup *grp);
-void xaccGroupMarkSaved (AccountGroup *grp);
-void xaccGroupMarkNotSaved (AccountGroup *grp);
-
-/*
- * The xaccGroupInsertAccount() subroutine will insert the indicated
+/** The xaccGroupInsertAccount() subroutine will insert the indicated
* account into the indicated group. If it already is the child
* of another group, it will be removed there first. If the
* account belongs to a different book than the the group, it
@@ -114,100 +152,118 @@
* entity tables, generating destroy & create events). If the
* account is removed from and inserted into the same group, the
* overall account sort order will be recomputed.
- *
- * The xaccAccountInsertSubAccount() does the same, except that
- * the parent is specified as an account.
*/
-
void xaccGroupInsertAccount (AccountGroup *grp, Account *acc);
+
+/** The xaccAccountInsertSubAccount() does the same, except that
+ * the parent is specified as an account.
+ */
void xaccAccountInsertSubAccount (Account *parent, Account *child);
+/** @} */
-/*
- * The xaccGroupGetNumSubAccounts() subroutine returns the number
+/** @name Counting the Size and Depth of the Account Tree */
+/** @{ */
+/** The xaccGroupGetNumSubAccounts() subroutine returns the number
* of accounts, including subaccounts, in the account group
- *
- * The xaccGroupGetNumAccounts() subroutine returns the number
+ */
+int xaccGroupGetNumSubAccounts (AccountGroup *grp);
+
+/** The xaccGroupGetNumAccounts() subroutine returns the number
* of accounts in the indicated group only (children not counted).
- *
- * The xaccGroupGetDepth() subroutine returns the length of the
+ */
+int xaccGroupGetNumAccounts (AccountGroup *grp);
+
+/** The xaccGroupGetDepth() subroutine returns the length of the
* longest tree branch. Each link between an account and its
* (non-null) children counts as one unit of length.
*/
-
-int xaccGroupGetNumSubAccounts (AccountGroup *grp);
-int xaccGroupGetNumAccounts (AccountGroup *grp);
int xaccGroupGetDepth (AccountGroup *grp);
+/** @} */
+
+/** @name Getting Accounts and Subaccounts */
+/** @{ */
+/** DOCUMENT ME! is this routine deprecated? XXX using index is weird! */
Account * xaccGroupGetAccount (AccountGroup *group, int index);
-/*
- * The xaccGroupGetSubAccounts() subroutine returns an list of the accounts,
+/** The xaccGroupGetSubAccounts() subroutine returns an list of the accounts,
* including subaccounts, in the account group. The returned list
* should be freed with g_list_free() when no longer needed.
- *
- * The xaccGroupGetAccountList() subroutines returns only the immediate
+ */
+AccountList * xaccGroupGetSubAccounts (AccountGroup *grp);
+
+/** The xaccGroupGetAccountList() subroutines returns only the immediate
* children of the account group. The returned list should *not*
* be freed by the caller.
*/
-
-AccountList * xaccGroupGetSubAccounts (AccountGroup *grp);
AccountList * xaccGroupGetAccountList (AccountGroup *grp);
-/*
- * The xaccGetAccountFromName() subroutine fetches the
+/** The xaccGroupGetRoot() subroutine will find the topmost
+ * (root) group to which this group belongs.
+ */
+AccountGroup * xaccGroupGetRoot (AccountGroup *grp);
+
+/** The xaccGetAccountRoot() subroutine will find the topmost
+ * (root) group to which this account belongs.
+ */
+AccountGroup * xaccAccountGetRoot (Account *account);
+
+/** The xaccGroupGetParentAccount() subroutine returns the parent
+ * account of the group, or NULL.
+ */
+Account * xaccGroupGetParentAccount (AccountGroup *group);
+
+/** @} */
+
+/** @name Getting Accounts and Subaccounts by Name */
+/** @{ */
+/** The xaccGetAccountFromName() subroutine fetches the
* account by name from the collection of accounts
* in the indicated AccountGroup group. It returns NULL if the
* account was not found.
- *
- * The xaccGetAccountFromFullName() subroutine works like
+ */
+Account *xaccGetAccountFromName (AccountGroup *group, const char *name);
+
+/** The xaccGetAccountFromFullName() subroutine works like
* xaccGetAccountFromName, but uses fully-qualified names
* using the given separator.
- *
- * The xaccGetPeerAccountFromName() subroutine fetches the
+ */
+Account *xaccGetAccountFromFullName (AccountGroup *group,
+ const char *name,
+ const char separator);
+
+/** The xaccGetPeerAccountFromName() subroutine fetches the
* account by name from the collection of accounts
* in the same AccountGroup anchor group. It returns NULL if the
* account was not found.
- *
- * The xaccGetPeerAccountFromFullName() subroutine works like
+ */
+Account *xaccGetPeerAccountFromName (Account *account, const char *name);
+
+/** The xaccGetPeerAccountFromFullName() subroutine works like
* xaccGetPeerAccountFromName, but uses fully-qualified
* names using the given separator.
*/
-
-Account *xaccGetAccountFromName (AccountGroup *group, const char *name);
-Account *xaccGetAccountFromFullName (AccountGroup *group,
- const char *name,
- const char separator);
-Account *xaccGetPeerAccountFromName (Account *account, const char *name);
Account *xaccGetPeerAccountFromFullName (Account *acc,
const char * name,
const char separator);
-/*
- * The xaccGroupGetRoot() subroutine will find the topmost
- * (root) group to which this group belongs.
- *
- * The xaccGetAccountRoot() subroutine will find the topmost
- * (root) group to which this account belongs.
- */
-AccountGroup * xaccGroupGetRoot (AccountGroup *grp);
-AccountGroup * xaccAccountGetRoot (Account *account);
+/** @} */
-/* The xaccGroupGetParentAccount() subroutine returns the parent
- * account of the group, or NULL.
- */
-Account * xaccGroupGetParentAccount (AccountGroup *group);
+/** @name Traversal, ForEach */
+/** @{ */
-/* The xaccGroupMapAccounts() routine will traverse the account
+typedef gpointer (*AccountCallback)(Account *a, gpointer data);
+
+/** The xaccGroupMapAccounts() routine will traverse the account
group, returning a list of accounts. If the callback
returns null for a given item, it won't show up in
the result list. You should free the returned list when
you are done with it.
*/
-typedef gpointer (*AccountCallback)(Account *a, gpointer data);
AccountList *xaccGroupMapAccounts(AccountGroup *grp,
AccountCallback,
gpointer data);
-/* The xaccGroupForEachAccount() method will traverse the AccountGroup
+/** The xaccGroupForEachAccount() method will traverse the AccountGroup
* tree, calling 'func' on each account. Traversal will stop when
* func returns a non-null value, and the routine wil return with that
* value. If 'deeply' is FALSE, then only the immediate children of
@@ -220,10 +276,9 @@
gpointer data,
gboolean deeply);
-gboolean xaccGroupEqual(AccountGroup *a, AccountGroup *b,
- gboolean check_guids);
+/** @} */
-/*
+/** @name Staged Traversal
* The following functions provide support for "staged traversals"
* over all of the transactions in an account or group. The idea
* is to be able to perform a sequence of traversals ("stages"),
@@ -259,37 +314,38 @@
* can be changed by enlarging "marker" in the transaction struct.
* */
-/* xaccGroupBeginStagedTransactionTraversals() resets the traversal
+/** @{ */
+/** xaccGroupBeginStagedTransactionTraversals() resets the traversal
* marker inside each of all the transactions in the group so that
* a new sequence of staged traversals can begin.
- *
- * xaccSplitsBeginStagedTransactionTraversals() resets the traversal
+ */
+void xaccGroupBeginStagedTransactionTraversals(AccountGroup *grp);
+
+/** xaccSplitsBeginStagedTransactionTraversals() resets the traversal
* marker for each transaction which is a parent of one of the
* splits in the list.
- *
- * xaccAccountBeginStagedTransactionTraversals() resets the traversal
+ */
+void xaccSplitsBeginStagedTransactionTraversals(SplitList *splits);
+
+/** xaccAccountBeginStagedTransactionTraversals() resets the traversal
* marker for each transaction which is a parent of one of the
* splits in the account.
- *
*/
-
-void xaccGroupBeginStagedTransactionTraversals(AccountGroup *grp);
-void xaccSplitsBeginStagedTransactionTraversals(SplitList *splits);
void xaccAccountBeginStagedTransactionTraversals(Account *account);
-/* xaccTransactionTraverse() checks the stage of the given transaction.
+/** xaccTransactionTraverse() checks the stage of the given transaction.
* If the transaction hasn't reached the given stage, the transaction
* is updated to that stage and the function returns TRUE. Otherwise
* no change is made and the function returns FALSE.
- *
- * xaccSplitTransactionTraverse() behaves as above using the parent of
- * the given split.
*/
-
gboolean xaccTransactionTraverse(Transaction *trans, int stage);
+
+/** xaccSplitTransactionTraverse() behaves as above using the parent of
+ * the given split.
+ */
gboolean xaccSplitTransactionTraverse(Split *split, int stage);
-/* xaccGroupStagedTransactionTraversal() calls thunk on each
+/** xaccGroupStagedTransactionTraversal() calls thunk on each
* transaction in the group whose current marker is less than the
* given `stage' and updates each transaction's marker to be `stage'.
* The traversal will stop if thunk() returns a non-zero value.
@@ -306,7 +362,7 @@
TransactionCallback,
void *data);
-/* xaccAccountStagedTransactionTraversal() calls thunk on each
+/** xaccAccountStagedTransactionTraversal() calls thunk on each
* transaction in the account whose current marker is less than the
* given `stage' and updates each transaction's marker to be `stage'.
* The traversal will stop if thunk() returns a non-zero value.
@@ -353,4 +409,8 @@
int xaccGroupForEachTransaction(AccountGroup *g,
TransactionCallback, void *data);
+/** @} */
#endif /* XACC_ACCOUNT_GROUP_H */
+/** @} */
+/** @} */
+
--- /dev/null
+++ src/engine/qofmath128.h
@@ -0,0 +1,85 @@
+/********************************************************************
+ * qofmath128.h -- an 128-bit integer library *
+ * 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 *
+ * *
+ *******************************************************************/
+
+#ifndef QOF_MATH_128_H
+#define QOF_MATH_128_H
+
+#include <glib.h>
+
+/** @addtogroup Math128
+ * Quick-n-dirty 128-bit integer math lib. Things seem to mostly
+ * work, and have been tested, but not comprehensively tested.
+ * @{
+ */
+
+typedef struct {
+ guint64 hi;
+ guint64 lo;
+ short isneg; /**< sign-bit -- T if number is negative */
+ short isbig; /**< sizeflag -- T if number won't fit in signed 64-bit */
+} qofint128;
+
+/** Return true of two numbers are equal */
+inline gboolean equal128 (qofint128 a, qofint128 b);
+
+/** Return returns 1 if a>b, -1 if b>a, 0 if a == b */
+inline int cmp128 (qofint128 a, qofint128 b);
+
+/** Shift right by one bit (i.e. divide by two) */
+inline qofint128 shift128 (qofint128 x);
+
+/** Shift left by one bit (i.e. multiply by two) */
+inline qofint128 shiftleft128 (qofint128 x);
+
+/** Increment by one */
+inline qofint128 inc128 (qofint128 a);
+
+/** Add a pair of 128-bit numbers, returning a 128-bit number */
+inline qofint128 add128 (qofint128 a, qofint128 b);
+
+/** Multiply a pair of signed 64-bit numbers,
+ * returning a signed 128-bit number.
+ */
+inline qofint128 mult128 (gint64 a, gint64 b);
+
+/** Divide a signed 128-bit number by a signed 64-bit,
+ * returning a signed 128-bit number.
+ */
+inline qofint128 div128 (qofint128 n, gint64 d);
+
+/** Return the remainder of a signed 128-bit number modulo
+ * a signed 64-bit. That is, return n%d in 128-bit math.
+ * I beleive that ths algo is overflow-free, but should be
+ * audited some more ...
+ */
+inline gint64 rem128 (qofint128 n, gint64 d);
+
+/** Return the greatest common factor of two 64-bit numbers */
+inline guint64 gcf64(guint64 num, guint64 denom);
+
+/** Return the least common multiple of two 64-bit numbers. */
+inline qofint128 lcm128 (guint64 a, guint64 b);
+
+#endif
+
+/** @} */
Index: policy.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/policy.c,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -Lsrc/engine/policy.c -Lsrc/engine/policy.c -u -r1.2.4.1 -r1.2.4.2
--- src/engine/policy.c
+++ src/engine/policy.c
@@ -22,7 +22,7 @@
/** @file policy.c
* @breif Implement FIFO Accounting Policy.
* @author Created by Linas Vepstas August 2003
- * @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2003,2004 Linas Vepstas <linas at linas.org>
*
* This file implements the FIFO Accounting Policy (and, in the
* future, others as well). The Accounting Polciy determines
@@ -46,37 +46,83 @@
/* static short module = MOD_LOT; */
-/* ============================================================== */
-
-static GNCLot *
-FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
-{
- return xaccAccountFindEarliestOpenLot (split->acc, split->amount);
-}
-
static Split *
-FIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
+DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
{
+ Split *split;
SplitList *node;
+ gnc_commodity *common_currency;
gboolean want_positive;
+ gnc_numeric baln;
+
+ if (!pcy || !lot || !lot->account || !lot->splits) return NULL;
+
+ /* Recomputing the balance re-evaluates the lot closure */
+ baln = gnc_lot_get_balance (lot);
+ if (gnc_lot_is_closed(lot)) return NULL;
+
+ want_positive = gnc_numeric_negative_p (baln);
- want_positive = gnc_numeric_negative_p (gnc_lot_get_balance (lot));
+ /* All splits in lot must share a common transaction currency. */
+ split = lot->splits->data;
+ common_currency = split->parent->common_currency;
- /* Make use of the fact that the splits in a lot are already
- * in date order; so we don't have to search for the earliest. */
- for (node = xaccAccountGetSplitList (lot->account); node; node=node->next)
+ /* Walk over *all* splits in the account, till we find one that
+ * hasn't been assigned to a lot. Return that split.
+ * Make use of the fact that the splits in an account are
+ * already in date order; so we don't have to sort. */
+ node = xaccAccountGetSplitList (lot->account);
+ if (reverse)
+ {
+ node = g_list_last (node);
+ }
+ while (node)
{
+ gboolean is_match;
gboolean is_positive;
- Split *split = node->data;
- if (split->lot) continue;
+ split = node->data;
+ if (split->lot) goto donext;
+
+ /* Allow equiv currencies */
+ is_match = gnc_commodity_equiv (common_currency,
+ split->parent->common_currency);
+ if (FALSE == is_match) goto donext;
+
+ /* Disallow zero-amount splits in general. */
+ if (gnc_numeric_zero_p(split->amount)) goto donext;
is_positive = gnc_numeric_positive_p (split->amount);
if ((want_positive && is_positive) ||
((!want_positive) && (!is_positive))) return split;
+donext:
+ if (reverse)
+ {
+ node=node->prev;
+ }
+ else
+ {
+ node=node->next;
+ }
}
return NULL;
}
+/* ============================================================== */
+
+static GNCLot *
+FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
+{
+ if (!split) return NULL;
+ return xaccAccountFindEarliestOpenLot (split->acc, split->amount,
+ split->parent->common_currency);
+}
+
+static Split *
+FIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
+{
+ return DirectionPolicyGetSplit (pcy, lot, 0);
+}
+
static void
FIFOPolicyGetLotOpening (GNCPolicy *pcy,
GNCLot *lot,
@@ -128,33 +174,15 @@
static GNCLot *
LIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
{
- return xaccAccountFindLatestOpenLot (split->acc, split->amount);
+ if (!split) return NULL;
+ return xaccAccountFindLatestOpenLot (split->acc, split->amount,
+ split->parent->common_currency);
}
static Split *
LIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
{
- SplitList *node;
- gboolean want_positive;
-
- want_positive = gnc_numeric_negative_p (gnc_lot_get_balance (lot));
-
- /* Make use of the fact that the splits in a lot are already
- * in date order; so we don't have to search for the latest,
- * we merely start at the end and go backwards. */
- node = xaccAccountGetSplitList (lot->account);
- node = g_list_last (node);
- for (; node; node=node->prev)
- {
- gboolean is_positive;
- Split *split = node->data;
- if (split->lot) continue;
-
- is_positive = gnc_numeric_positive_p (split->amount);
- if ((want_positive && is_positive) ||
- ((!want_positive) && (!is_positive))) return split;
- }
- return NULL;
+ return DirectionPolicyGetSplit (pcy, lot, 1);
}
/* This routine is actually identical to FIFO... */
Index: guid.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/guid.h,v
retrieving revision 1.15.6.4
retrieving revision 1.15.6.5
diff -Lsrc/engine/guid.h -Lsrc/engine/guid.h -u -r1.15.6.4 -r1.15.6.5
--- src/engine/guid.h
+++ src/engine/guid.h
@@ -24,16 +24,30 @@
#ifndef GUID_H
#define GUID_H
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include <glib.h>
#include <stddef.h>
-/* This file defines an API for using globally unique identifiers. */
+/** @addtogroup Entity
+ @{ */
+/** @addtogroup GUID
+ Globally Unique ID's provide a way to uniquely identify
+ some thing. A GUID is a unique, cryptographically
+ random 128-bit value. The identifier is so random that
+ it is safe to assume that there is no other such item
+ on the planet Earth, and indeed, not even in the Galaxy
+ or beyond.
+
+ QOF GUID's can be used independently of any other subsystem
+ in QOF. In particular, they do not require the use of
+ other parts of the object subsystem.
+
+ @{ */
+/** @file guid.h
+ @brief globally unique ID User API
+ @author Copyright (C) 2000 Dave Peticolas <peticola at cs.ucdavis.edu>
+*/
-/* The type used to store guids */
+/** The type used to store guids */
typedef union _GUID
{
unsigned char data[16];
@@ -43,7 +57,7 @@
} GUID;
-/* number of characters needed to encode a guid as a string
+/** number of characters needed to encode a guid as a string
* not including the null terminator. */
#define GUID_ENCODING_LENGTH 32
@@ -179,4 +193,6 @@
GHashTable *guid_hash_table_new(void);
+/* @} */
+/* @} */
#endif
Index: gnc-engine.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine.c,v
retrieving revision 1.17.4.1
retrieving revision 1.17.4.2
diff -Lsrc/engine/gnc-engine.c -Lsrc/engine/gnc-engine.c -u -r1.17.4.1 -r1.17.4.2
--- src/engine/gnc-engine.c
+++ src/engine/gnc-engine.c
@@ -79,6 +79,8 @@
if (1 == engine_is_initialized) return;
engine_is_initialized = 1;
+ gnc_log_init();
+
/* initialize the string cache */
gnc_engine_get_string_cache();
Index: gnc-commodity.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-commodity.c,v
retrieving revision 1.39.4.9
retrieving revision 1.39.4.10
diff -Lsrc/engine/gnc-commodity.c -Lsrc/engine/gnc-commodity.c -u -r1.39.4.9 -r1.39.4.10
--- src/engine/gnc-commodity.c
+++ src/engine/gnc-commodity.c
@@ -114,12 +114,14 @@
static gnc_quote_source single_quote_sources[] = {
{ FALSE, 0, 0, "AEX", "AEX", "aex" },
+ { FALSE, 0, 0, "AMFI India", "AMFIINDIA", "amfiindia" },
{ FALSE, 0, 0, "ASX", "ASX", "asx" },
{ FALSE, 0, 0, "DWS", "DWS", "dwsfunds" },
{ FALSE, 0, 0, "Fidelity Direct", "FIDELITY_DIRECT", "fidelity_direct" },
{ FALSE, 0, 0, "Motley Fool", "FOOL", "fool" },
{ FALSE, 0, 0, "Fund Library", "FUNDLIBRARY", "fundlibrary" },
{ FALSE, 0, 0, "TD Waterhouse Canada", "TDWATERHOUSE", "tdwaterhouse" },
+ { FALSE, 0, 0, "TD Efunds", "TDEFUNDS", "tdefunds" },
{ FALSE, 0, 0, "TIAA-CREF", "TIAACREF", "tiaacref" },
{ FALSE, 0, 0, "T. Rowe Price", "TRPRICE_DIRECT", "troweprice_direct" },
{ FALSE, 0, 0, "Trustnet", "TRUSTNET", "trustnet" },
@@ -139,6 +141,7 @@
{ FALSE, 0, 0, "Canada Mutual (Fund Library, ...)", "CANADAMUTUAL", "canadamutual" },
{ FALSE, 0, 0, "Dutch (AEX, ...)", "DUTCH", "dutch" },
{ FALSE, 0, 0, "Europe (Yahoo, ...)", "EUROPE", "europe" },
+ { FALSE, 0, 0, "India Mutual (AMFI, ...)", "INDIAMUTUAL", "indiamutual" },
{ FALSE, 0, 0, "Fidelity (Fidelity, ...)", "FIDELITY", "fidelity" },
{ FALSE, 0, 0, "Nasdaq (Yahoo, ...)", "NASDAQ", "nasdaq" },
{ FALSE, 0, 0, "NYSE (Yahoo, ...)", "NYSE", "nyse" },
@@ -1743,12 +1746,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_COMMODITY_TABLE,
type_label: "CommodityTable",
+ create: NULL,
book_begin: commodity_table_book_begin,
book_end: commodity_table_book_end,
is_dirty: NULL,
mark_clean: NULL,
foreach: NULL,
printable: NULL,
+ version_cmp: NULL,
};
gboolean
Index: kvp-util.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp-util.c,v
retrieving revision 1.4.4.3
retrieving revision 1.4.4.4
diff -Lsrc/engine/kvp-util.c -Lsrc/engine/kvp-util.c -u -r1.4.4.3 -r1.4.4.4
--- src/engine/kvp-util.c
+++ src/engine/kvp-util.c
@@ -152,7 +152,7 @@
{
listhead = g_list_remove_link (listhead, node);
g_list_free_1 (node);
- kvp_value_replace_glist_nc (va, listhead);
+ kvp_value_replace_glist_nc (arr, listhead);
kvp_value_replace_frame_nc (va, NULL);
kvp_value_delete (va);
return;
@@ -180,10 +180,10 @@
if (KVP_TYPE_GLIST != valtype) return NULL;
node = kvp_value_get_glist(arr);
- {
- KvpValue *va = node->data;
- return kvp_value_get_frame(va);
- }
+ if (NULL == node) return NULL;
+
+ KvpValue *va = node->data;
+ return kvp_value_get_frame(va);
}
void
Index: FreqSpec.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/FreqSpec.h,v
retrieving revision 1.10.4.3
retrieving revision 1.10.4.4
diff -Lsrc/engine/FreqSpec.h -Lsrc/engine/FreqSpec.h -u -r1.10.4.3 -r1.10.4.4
--- src/engine/FreqSpec.h
+++ src/engine/FreqSpec.h
@@ -17,7 +17,9 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Engine_SchedXaction
+/** @addtogroup QOF
+ @{ */
+/** @addtogroup FreqSpec Specifying Recurring Dates (Periods)
@{ */
/** @file FreqSpec.h
@brief Period / Date Frequency Specification
@@ -32,7 +34,7 @@
#include <glib.h>
-#include "gnc-engine.h"
+#include "qofid.h"
#include "guid.h"
#include "qofbook.h"
@@ -233,3 +235,4 @@
#endif /* XACC_FREQSPEC_H */
/**@}*/
+/**@}*/
--- /dev/null
+++ src/engine/gnc-filepath-utils.h
@@ -0,0 +1,49 @@
+/********************************************************************\
+ * gnc-filepath-utils.h -- file path resolutin utilitie *
+ * *
+ * 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 gnc-filepath-utils.h
+ * @breif file path resolutionutilities
+ * @author Copyright (c) 1998-2004 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2000 Dave Peticolas
+ *
+ * XXX this file does not belong in the gnucash engine; it is here
+ * for the moment only because both the file backend and the app-file
+ * GUI code make use of it. It should be moved away someday.
+ */
+
+#ifndef GNC_FILEPATH_UTILS_H
+#define GNC_FILEPATH_UTILS_H
+
+/** The xaccResolveFilePath() routine is a utility that will accept
+ * a fragmentary filename as input, and resolve it into a fully
+ * qualified path in the file system, i.e. a path that begins with
+ * a leading slash. First, the current working directory is
+ * searched for the file. Next, the directory $HOME/.gnucash/data,
+ * and finally, a list of other (configurable) paths. If the file
+ * is not found, then the path $HOME/.gnucash/data is used. If
+ * $HOME is not defined, then the current working directory is
+ * used.
+ */
+char * xaccResolveFilePath (const char * filefrag);
+char * xaccResolveURL (const char * pathfrag);
+
+#endif /* GNC_FILEPATH_UTILS_H */
Index: qofsql.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsql.h,v
retrieving revision 1.4.2.1
retrieving revision 1.4.2.2
diff -Lsrc/engine/qofsql.h -Lsrc/engine/qofsql.h -u -r1.4.2.1 -r1.4.2.2
--- src/engine/qofsql.h
+++ src/engine/qofsql.h
@@ -20,11 +20,11 @@
* *
\********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Query
@{ */
/**
@file qofsql.h
- @breif QOF client-side SQL parser.
+ @brief QOF client-side SQL parser.
@author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
*/
@@ -36,6 +36,8 @@
#include <qof/qofbook.h>
#include <qof/qofquery.h>
+/** @addtogroup SQL SQL Interface to Query
+ @{ */
typedef struct _QofSqlQuery QofSqlQuery;
/** Create a new SQL-syntax query machine.
@@ -139,5 +141,6 @@
*/
void qof_sql_query_set_kvp (QofSqlQuery *, KvpFrame *);
+/** @} */
#endif /* QOF_SQL_QUERY_H */
/** @} */
Index: qofquery.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery.h,v
retrieving revision 1.5.2.4
retrieving revision 1.5.2.5
diff -Lsrc/engine/qofquery.h -Lsrc/engine/qofquery.h -u -r1.5.2.4 -r1.5.2.5
--- src/engine/qofquery.h
+++ src/engine/qofquery.h
@@ -20,10 +20,62 @@
* *
\********************************************************************/
+/** @addtogroup Query
+
+BASIC QUERY API:
+With this API you can create arbitrary logical
+queries to find sets of arbitrary object. To make simple
+queries (1 term, such as a search for a parameter with one value),
+create the appropriate
+QueryTerm structure and stick it in a Query object using
+xaccInitQuery. The QueryTerm should be malloced but the Query object
+will handle freeing it. To make compound queries, make multiple
+simple queries and combine them using qof_query_merge() and the logical
+operations of your choice.
+
+SQL QUERY API:
+As an alternative to building queries one predicate at a time,
+you can use the SQL query interface. This interface will accept
+a string containing an SQL query, parse it, convert it into the
+core representation, and execute it.
+
+STRUCTURE OF A QUERY: A Query is a logical function of any number of
+QueryTerms. A QueryTerm consists of a C function pointer (the
+Predicate) and a PredicateData structure containing data passed to the
+predicate funtion. The PredicateData structure is a constant
+associated with the Term and is identical for every object that is
+tested.
+
+The terms of the Query may represent any logical function and are
+stored in canonical form, i.e. the function is expressed as a logical
+sum of logical products. So if you have QueryTerms a, b, c, d, e and
+you have the logical function a(b+c) + !(c(d+e)), it gets stored as
+ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation
+of some functions but it's easy to store, easy to manipulate, and it
+doesn't require a complete algebra system to deal with.
+
+The representation is of a GList of GLists of QueryTerms. The
+"backbone" GList q->terms represents the OR-chain, and every item on
+the backbone is a GList of QueryTerms representing an AND-chain
+corresponding to a single product-term in the canonical
+representation. QueryTerms are duplicated when necessary to fill out
+the canonical form, and the same predicate may be evaluated multiple
+times per split for complex queries. This is a place where we could
+probably optimize.
+
+Evaluation of a Query (see qof_query_run()) is optimized as much as
+possible by short-circuited evaluation. The predicates in each
+AND-chain are sorted by predicate type, with Account queries sorted
+first to allow the evaluator to completely eliminate accounts from the
+search if there's no chance of them having splits that match.
+(XXX above no longer applies)
+
+ @{ */
/** @file qofquery.h
- @breif find objects that match a certain expression.
+ @brief find objects that match a certain expression.
@author Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU>
@author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
+
*/
@@ -53,13 +105,17 @@
#define QUERY_DEFAULT_SORT "QofQueryDefaultSort"
/** "Known" Object Parameters -- all objects must support these */
-#define QOF_QUERY_PARAM_BOOK "book"
-#define QOF_QUERY_PARAM_GUID "guid"
+#define QOF_PARAM_BOOK "book"
+#define QOF_PARAM_GUID "guid"
/** "Known" Object Parameters -- some objects might support these */
-#define QOF_QUERY_PARAM_ACTIVE "active"
+#define QOF_PARAM_KVP "kvp"
+#define QOF_PARAM_ACTIVE "active"
+#define QOF_PARAM_VERSION "version"
/* --------------------------------------------------------- */
+/** @name Query Subsystem Initialization and Shudown */
+/* @{ */
/** Subsystem initialization and shutdown. Call init() once
* to initalize the query subsytem; call shutdown() to free
* up any resources associated with the query subsystem.
@@ -68,18 +124,27 @@
void qof_query_init (void);
void qof_query_shutdown (void);
+/* @} */
/* --------------------------------------------------------- */
-/** Basic API Functions */
+/** @name Low-Level API Functions */
+/* @{ */
GSList * qof_query_build_param_list (char const *param, ...);
-/** Create a new query. A Query MUST be set with a 'search-for'
- * type. The results of the query is a list of the indicated
- * search-for type.
+/** Create a new query.
+ * Before running the query, a 'search-for' type must be set
+ * otherwise nothing will be returned. The results of the query
+ * is a list of the indicated search-for type.
+ *
+ * Allocates and initializes a Query structure which must be
+ * freed by the user with qof_query_destroy(). A newly-allocated
+ * QofQuery object matches nothing (qof_query_run() will return NULL).
*/
QofQuery * qof_query_create (void);
QofQuery * qof_query_create_for (QofIdTypeConst obj_type);
+
+/** Frees the resources associate with a Query object. */
void qof_query_destroy (QofQuery *q);
/** Set the object type to be searched for. The results of
@@ -87,9 +152,14 @@
*/
void qof_query_search_for (QofQuery *query, QofIdTypeConst obj_type);
-/** 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).
+/** Set the book to be searched. Books contain/identify collections
+ * of objects; the search will be performed over those books
+ * specified with this function. If no books are set, no results
+ * will be returned (since there is nothing to search over).
+ *
+ * You can search multiple books. To specify multiple books, call
+ * this function multiple times with different arguments.
+ * XXX needed qof_query_clear_books() to reset the list ...
*/
void qof_query_set_book (QofQuery *q, QofBook *book);
@@ -156,15 +226,27 @@
*/
GList * qof_query_last_run (QofQuery *query);
-/** DOCUMENT ME !! */
+/** Remove all query terms from query. query matches nothing
+ * after qof_query_clear().
+ */
void qof_query_clear (QofQuery *query);
-/** DOCUMENT ME !! */
+
+/** Remove query terms of a particular type from q. The "type" of a term
+ * is determined by the type of data that gets passed to the predicate
+ * function.
+ * XXX ??? Huh? remove anything of that predicate type, or just
+ * the particular predicate ?
+ */
void qof_query_purge_terms (QofQuery *q, GSList *param_list);
-/** Return boolean FALSE if there are no terms in the query */
+/** Return boolean FALSE if there are no terms in the query
+ * Can be used as a predicate to see if the query has been
+ * initialized (return value > 0) or is "blank" (return value == 0).
+ */
int qof_query_has_terms (QofQuery *q);
-/** Return the number of terms in thq query. */
+/** Return the number of terms in the canonical form of the query.
+ */
int qof_query_num_terms (QofQuery *q);
/** DOCUMENT ME !! */
@@ -175,17 +257,32 @@
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.
+ * 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. The union
+ * of the results returned by the original and inverted queries
+ * equals the set of all searched objects. These to sets are
+ * disjoint (share no members in common).
+ *
+ * This will return a newly allocated QofQuery object, or NULL
+ * on error. Free it with qof_query_destroy() when no longer needed.
*/
QofQuery * qof_query_invert(QofQuery *q);
-/** Merges two queries together. Both queries must be compatible
- * search-types. If both queries are set, they must search for the
- * same object type. If only one is set, the resulting query will
- * search for the set type. If neither query has the search-type set,
- * the result will be unset as well.
+/** Combine two queries together using the Boolean set (logical)
+ * operator 'op'. For example, if the operator 'op' is set to
+ * QUERY_AND, then the set of results returned by the query will
+ * will be the Boolean set intersection of the results returned
+ * by q1 and q2. Similarly, QUERY_OR maps to set union, etc.
+ *
+ * Both queries must have compatible
+ * search-types. If both queries are set, they must search for the
+ * same object type. If only one is set, the resulting query will
+ * search for the set type. If neither query has the search-type set,
+ * the result will be unset as well.
+ *
+ * This will return a newly allocated QofQuery object, or NULL
+ * on error. Free it with qof_query_destroy() when no longer needed.
*/
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op);
@@ -268,4 +365,6 @@
/** Return the list of books we're using */
GList * qof_query_get_books (QofQuery *q);
+/* @} */
#endif /* QOF_QUERYNEW_H */
+/* @} */
Index: Scrub2.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Scrub2.c,v
retrieving revision 1.15.2.2
retrieving revision 1.15.2.3
diff -Lsrc/engine/Scrub2.c -Lsrc/engine/Scrub2.c -u -r1.15.2.2 -r1.15.2.3
--- src/engine/Scrub2.c
+++ src/engine/Scrub2.c
@@ -55,6 +55,10 @@
static short module = MOD_LOT;
/* ============================================================== */
+/** Loop over all splits, and make sure that every split
+ * belongs to some lot. If a split does not belong to
+ * any lots, poke it into one.
+ */
void
xaccAccountAssignLots (Account *acc)
@@ -66,10 +70,6 @@
ENTER ("acc=%s", acc->accountName);
xaccAccountBeginEdit (acc);
- /* Loop over all splits, and make sure that every split
- * belongs to some lot. If a split does not belong to
- * any lots, poke it into one.
- */
restart_loop:
for (node=acc->splits; node; node=node->next)
{
@@ -77,13 +77,17 @@
/* If already in lot, then no-op */
if (split->lot) continue;
+
+ /* Skip voided transactions */
+ if (gnc_numeric_zero_p (split->amount) &&
+ xaccTransGetVoidStatus(split->parent)) continue;
+
if (xaccSplitAssign (split)) goto restart_loop;
}
xaccAccountCommitEdit (acc);
LEAVE ("acc=%s", acc->accountName);
}
-
/* ============================================================== */
/** The xaccLotFill() routine attempts to assign splits to the
@@ -96,7 +100,6 @@
void
xaccLotFill (GNCLot *lot)
{
- gnc_numeric lot_baln;
Account *acc;
Split *split;
GNCPolicy *pcy;
@@ -105,15 +108,18 @@
acc = lot->account;
pcy = acc->policy;
- ENTER ("acc=%s", acc->accountName);
+ ENTER ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), acc->accountName);
/* If balance already zero, we have nothing to do. */
- lot_baln = gnc_lot_get_balance (lot);
- if (gnc_numeric_zero_p (lot_baln)) return;
+ if (gnc_lot_is_closed (lot)) return;
split = pcy->PolicyGetSplit (pcy, lot);
if (!split) return; /* Handle the common case */
+ /* Reject voided transactions */
+ if (gnc_numeric_zero_p(split->amount) &&
+ xaccTransGetVoidStatus(split->parent)) return;
+
xaccAccountBeginEdit (acc);
/* Loop until we've filled up the lot, (i.e. till the
@@ -126,18 +132,21 @@
if (subsplit == split)
{
PERR ("Accounting Policy gave us a split that "
- "doesn't fit into this lot");
+ "doesn't fit into this lot\n"
+ "lot baln=%s, isclosed=%d, aplit amt=%s",
+ gnc_num_dbg_to_string (gnc_lot_get_balance(lot)),
+ gnc_lot_is_closed (lot),
+ gnc_num_dbg_to_string (split->amount));
break;
}
- lot_baln = gnc_lot_get_balance (lot);
- if (gnc_numeric_zero_p (lot_baln)) break;
+ if (gnc_lot_is_closed (lot)) break;
split = pcy->PolicyGetSplit (pcy, lot);
if (!split) break;
}
xaccAccountCommitEdit (acc);
- LEAVE ("acc=%s", acc->accountName);
+ LEAVE ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), acc->accountName);
}
/* ============================================================== */
@@ -178,17 +187,17 @@
/* This lot has mixed currencies. Can't double-balance.
* Silently punt */
PWARN ("Lot with multiple currencies:\n"
- "\ttrans=%s curr=%s\n", xaccTransGetDescription(trans),
+ "\ttrans=%s curr=%s", xaccTransGetDescription(trans),
gnc_commodity_get_fullname(trans->common_currency));
break;
}
/* Now, total up the values */
value = gnc_numeric_add (value, xaccSplitGetValue (s),
- GNC_DENOM_AUTO, GNC_DENOM_EXACT);
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
PINFO ("Split=%p value=%s Accum Lot value=%s", s,
- gnc_numeric_to_string (s->value),
- gnc_numeric_to_string (value));
+ gnc_num_dbg_to_string (s->value),
+ gnc_num_dbg_to_string (value));
}
@@ -197,10 +206,19 @@
/* Unhandled error condition. Not sure what to do here,
* Since the ComputeCapGains should have gotten it right.
* I suppose there might be small rounding errors, a penny or two,
- * the ideal thing would to figure out why there's a roudning
+ * the ideal thing would to figure out why there's a rounding
* error, and fix that.
*/
- PERR ("Closed lot fails to double-balance !!\n");
+ PERR ("Closed lot fails to double-balance !! lot value=%s",
+ gnc_num_dbg_to_string (value));
+ GList *node;
+ for (node=lot->splits; node; node=node->next)
+ {
+ Split *s = node->data;
+ PERR ("s=%p amt=%s val=%s", s,
+ gnc_num_dbg_to_string(s->amount),
+ gnc_num_dbg_to_string(s->value));
+ }
}
LEAVE ("lot=%s", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
@@ -247,7 +265,7 @@
Split *s = node->data;
Transaction *txn = s->parent;
gnc_numeric dst_amt, dst_val, target_val;
- gnc_numeric delta;
+ gnc_numeric frac, delta;
int scu;
/* Skip the reference split */
@@ -257,10 +275,22 @@
dst_amt = xaccSplitGetAmount (s);
dst_val = xaccSplitGetValue (s);
- target_val = gnc_numeric_mul (dst_amt, src_val,
- GNC_DENOM_AUTO, GNC_DENOM_REDUCE);
- target_val = gnc_numeric_div (target_val, src_amt,
- scu, GNC_DENOM_EXACT);
+ frac = gnc_numeric_div (dst_amt, src_amt,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ target_val = gnc_numeric_mul (frac, src_val,
+ scu, GNC_HOW_DENOM_EXACT|GNC_HOW_RND_ROUND);
+ if (gnc_numeric_check (target_val))
+ {
+ PERR ("Numeric overflow of value\n"
+ "\tAcct=%s txn=%s\n"
+ "\tdst_amt=%s src_val=%s src_amt=%s\n",
+ xaccAccountGetName (s->acc),
+ xaccTransGetDescription(txn),
+ gnc_num_dbg_to_string(dst_amt),
+ gnc_num_dbg_to_string(src_val),
+ gnc_num_dbg_to_string(src_amt));
+ continue;
+ }
/* If the required price changes are 'small', do nothing.
* That is a case that the user will have to deal with
@@ -380,7 +410,7 @@
txn = split->parent;
lot = xaccSplitGetLot (split);
- ENTER (" ");
+ ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
restart:
for (node=txn->splits; node; node=node->next)
{
@@ -396,6 +426,10 @@
rc = TRUE;
goto restart;
}
+ if (gnc_numeric_zero_p (split->amount))
+ {
+ PWARN ("Result of merge has zero amt!");
+ }
LEAVE (" splits merged=%d", rc);
return rc;
}
Index: qofid.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofid.h,v
retrieving revision 1.2.6.3
retrieving revision 1.2.6.4
diff -Lsrc/engine/qofid.h -Lsrc/engine/qofid.h -u -r1.2.6.3 -r1.2.6.4
--- src/engine/qofid.h
+++ src/engine/qofid.h
@@ -23,34 +23,48 @@
#ifndef QOF_ID_H
#define QOF_ID_H
-/** @addtogroup Engine
+/** @addtogroup Entity
@{ */
+/** @addtogroup Entities
+
+ This file defines an API that adds types to the GUID's.
+ GUID's with types can be used to identify and reference
+ typed entities.
+
+ The idea here is that a GUID can be used to uniquely identify
+ some thing. By adding a type, one can then talk about the
+ type of thing identified. By adding a collection, one can
+ then work with a handle to a collection of things of a given
+ type, each uniquely identified by a given ID. QOF Entities
+ can be used independently of any other part of the system.
+ In particular, Entities can be useful even if one is not using
+ the Query ond Object parts of the QOF system.
+
+ Identifiers are globally-unique and permanent, i.e., once
+ an entity has been assigned an identifier, it retains that same
+ identifier for its lifetime.
+ Identifiers can be encoded as hex strings.
+
+ GUID Identifiers are 'typed' with strings. The native ids used
+ by QOF are defined below. An id with type QOF_ID_NONE does not
+ refer to any entity, although that may change (???). An id with
+ type QOF_ID_NULL does not refer to any entity, and will never refer
+ to any entity. An identifier with any other type may refer to an
+ actual entity, but that is not guaranteed (??? Huh?). If an id
+ does refer to an entity, the type of the entity will match the
+ type of the identifier.
+
+ If you have a type name, and you want to have a way of finding
+ a collection that is associated with that type, then you must use
+ Books.
+
+ @{ */
/** @file qofid.h
@brief QOF entity type identification system
@author Copyright (C) 2000 Dave Peticolas <peticola at cs.ucdavis.edu>
@author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
*/
-/** This file defines an API that adds types to the GUID's.
- * GUID's with types can be used to identify and reference
- * typed entities.
- *
- * GUID Identifiers can be used to reference QOF Objects.
- * Identifiers are globally-unique and permanent, i.e., once
- * an entity has been assigned an identifier, it retains that same
- * identifier for its lifetime.
- *
- * Identifiers can be encoded as hex strings.
- *
- * GUID Identifiers are 'typed' with strings. The native ids used
- * by QOF are defined below. An id with type QOF_ID_NONE does not
- * refer to any entity, although that may change (???). An id with
- * type QOF_ID_NULL does not refer to any entity, and will never refer
- * to any entity. An identifier with any other type may refer to an
- * actual entity, but that is not guaranteed (??? Huh?). If an id
- * does refer to an entity, the type of the entity will match the
- * type of the identifier.
- */
#include <string.h>
#include "guid.h"
@@ -59,14 +73,16 @@
typedef const char * QofIdTypeConst;
#define QOF_ID_NONE NULL
-#define QOF_ID_BOOK "Book"
#define QOF_ID_NULL "null"
+
+#define QOF_ID_BOOK "Book"
+#define QOF_ID_FREQSPEC "FreqSpec"
#define QOF_ID_SESSION "Session"
-/* simple,cheesy cast but holds water for now */
+/** simple,cheesy cast but holds water for now */
#define QOF_ENTITY(object) ((QofEntity *)(object))
-/* Inline string comparision; compiler will optimize away most of this */
+/** Inline string comparision; compiler will optimize away most of this */
#define QSTRCMP(da,db) ({ \
int val = 0; \
if ((da) && (db)) { \
@@ -107,17 +123,21 @@
QofCollection * collection;
};
+/** @name QOF Entity Initialization & Shutdown
+ @{ */
/** Initialise the memory associated with an entity */
void qof_entity_init (QofEntity *, QofIdType, QofCollection *);
/** Release the data associated with this entity. Dont actually free
* the memory associated with the instance. */
void qof_entity_release (QofEntity *);
+ /* @} */
-/* Return the GUID of this entity */
+/** Return the GUID of this entity */
const GUID * qof_entity_get_guid (QofEntity *);
-/** collections of entities */
+/** @name Collections of Entities
+ @{ */
QofCollection * qof_collection_new (QofIdType type);
void qof_collection_destroy (QofCollection *col);
@@ -143,10 +163,12 @@
gpointer qof_collection_get_data (QofCollection *col);
void qof_collection_set_data (QofCollection *col, gpointer user_data);
-/* Return value of 'dirty' flag on collection */
+/** Return value of 'dirty' flag on collection */
gboolean qof_collection_is_dirty (QofCollection *col);
+/** @} */
#endif /* QOF_ID_H */
/** @} */
+/** @} */
Index: policy.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/policy.h,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -Lsrc/engine/policy.h -Lsrc/engine/policy.h -u -r1.2.4.1 -r1.2.4.2
--- src/engine/policy.h
+++ src/engine/policy.h
@@ -18,16 +18,20 @@
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu at gnu.org *
\********************************************************************/
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup Policy Accounting Policy (FIFO/LIFO)
+ * This file implements Accounting Policy. The Accounting Policy
+ * determines how Splits are assigned to Lots. The contents
+ * of a Lot determines the Gains on that Lot. The default policy
+ * is the FIFO policy: the first thing bought is also the first
+ * thing sold.
+ @{ */
/** @file policy.h
- * @breif Implement Accounting Policy.
+ * @brief Implement Accounting Policy.
* @author Created by Linas Vepstas August 2003
- * @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
- *
- * This file implements Accounting Policy. The Accounting Policy
- * determines how splits are assigned to lots. The default policy
- * is the FIFO policy: the first thing bought is also the first
- * thing sold.
+ * @author Copyright (c) 2003,2004 Linas Vepstas <linas at linas.org>
*/
#ifndef XACC_POLICY_H
@@ -35,7 +39,27 @@
typedef struct gncpolicy_s GNCPolicy;
+/** First-in, First-out Policy
+ * This policy will create FIFO Lots. FIFO Lots have the following
+ * properties:
+ * -- The lot is started with the earliest posted split that isn't
+ * a part of another lot already.
+ * -- Splits are added to the lot in date order, with earliest splits
+ * added first.
+ * -- All splits in the lot share the same transaction currency as
+ * the split that opened the lot.
+ */
GNCPolicy *xaccGetFIFOPolicy (void);
+
+/** Last-in, First-out Policy
+ * This policy will create LIFO Lots. LIFO Lots have the following
+ * properties:
+ * -- XXX I think the implementation is broken right now.
+ * -- All splits in the lot share the same transaction currency as
+ * the split that opened the lot.
+ */
GNCPolicy *xaccGetLIFOPolicy (void);
#endif /* XACC_POLICY_H */
+/** @} */
+/** @} */
Index: qofbackend.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend.c,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -Lsrc/engine/qofbackend.c -Lsrc/engine/qofbackend.c -u -r1.2.4.1 -r1.2.4.2
--- src/engine/qofbackend.c
+++ src/engine/qofbackend.c
@@ -130,9 +130,12 @@
be->error_msg = NULL;
be->percentage = NULL;
+#ifdef GNUCASH_MAJOR_VERSION
/* XXX remove these */
+ be->fullpath = NULL;
be->price_lookup = NULL;
be->export = NULL;
+#endif
}
/************************* END OF FILE ********************************/
Index: qofquerycore.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquerycore.h,v
retrieving revision 1.5.2.3
retrieving revision 1.5.2.4
diff -Lsrc/engine/qofquerycore.h -Lsrc/engine/qofquerycore.h -u -r1.5.2.3 -r1.5.2.4
--- src/engine/qofquerycore.h
+++ src/engine/qofquerycore.h
@@ -21,8 +21,11 @@
* *
\********************************************************************/
+/** @addtogroup Query
+ @{ */
+
/** @file qofquerycore.h
- @breif API for providing core Query data types
+ @brief API for providing core Query data types
@author Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU>
*/
@@ -36,6 +39,11 @@
#include "kvp_frame.h"
#include "qofclass.h"
+/**
+ * PREDICATE DATA TYPES: All the predicate data types are rolled up into
+ * the union type PredicateData. The "type" field specifies which type
+ * the union is.
+ */
typedef struct _QofQueryPredData QofQueryPredData;
/** Standard Query comparitors, for how to compare objects in a predicate.
@@ -73,7 +81,18 @@
QOF_DATE_MATCH_DAY
} QofDateMatch;
-/* Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED */
+/* Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED
+ *
+ * XXX Should be deprecated, or at least wrapped up as a convnience
+ * function, this is based on the old bill gribble code, which assumed
+ * the amount was always positive, and the then specified a funds-flow
+ * direction (credit, debit, or either).
+ *
+ * The point being that 'match credit' is equivalent to the compound
+ * predicate (amount >= 0) && (amount 'op' value) while the 'match
+ * debit' predicate is equivalent to (amount <= 0) && (abs(amount) 'op' value)
+*/
+
typedef enum {
QOF_NUMERIC_MATCH_DEBIT = 1,
QOF_NUMERIC_MATCH_CREDIT,
@@ -95,17 +114,23 @@
QOF_GUID_MATCH_LIST_ANY,
} QofGuidMatch;
-/** No extended comparisons for QOF_TYPE_INT32, QOF_TYPE_INT64,
- * QOF_TYPE_DOUBLE, QOF_TYPE_BOOLEAN, QOF_TYPE_KVP
+/** A CHAR type is for a RECNCell, Comparisons for QOF_TYPE_CHAR
+ * 'ANY' will match any charagter in the string.
+ *
+ * Match 'ANY' is a convenience/performance-enhanced predicate
+ * for the compound statement (value==char1) || (value==char2) || etc.
+ * Match 'NONE' is equivalent to
+ * (value != char1) && (value != char2) && etc.
*/
-
-/** A CHAR type is for a RECNCell */
-/* Comparisons for QOF_TYPE_CHAR */
typedef enum {
QOF_CHAR_MATCH_ANY = 1,
QOF_CHAR_MATCH_NONE
} QofCharMatch;
+/** No extended comparisons for QOF_TYPE_INT32, QOF_TYPE_INT64,
+ * QOF_TYPE_DOUBLE, QOF_TYPE_BOOLEAN, QOF_TYPE_KVP
+ */
+
/** Head of Predicate Data structures. All PData must start like this. */
struct _QofQueryPredData {
QofType type_name; /* QOF_TYPE_* */
@@ -113,7 +138,8 @@
};
-/** Core Data Type Predicates */
+/** @name Core Data Type Predicates
+ @{ */
QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
const char *str,
QofStringMatch options,
@@ -164,3 +190,5 @@
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.4
retrieving revision 1.8.2.5
diff -Lsrc/engine/qofquerycore.c -Lsrc/engine/qofquerycore.c -u -r1.8.2.4 -r1.8.2.5
--- src/engine/qofquerycore.c
+++ src/engine/qofquerycore.c
@@ -415,13 +415,15 @@
break;
}
+ /* Amounts are considered to be 'equal' if they match to
+ * four decimal places. (epsilon=1/10000) */
if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ) {
gnc_numeric cmp_val = gnc_numeric_create (1, 10000);
compare =
(gnc_numeric_compare (gnc_numeric_abs
(gnc_numeric_sub (gnc_numeric_abs (obj_val),
gnc_numeric_abs (pdata->amount),
- 100000, GNC_RND_ROUND)),
+ 100000, GNC_HOW_RND_ROUND)),
cmp_val) < 0);
} else
compare = gnc_numeric_compare (gnc_numeric_abs (obj_val), pdata->amount);
@@ -504,7 +506,7 @@
gnc_numeric num;
num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
- return g_strdup (gnc_numeric_to_string (num));
+ return gnc_numeric_to_string (num);
}
static char *
@@ -513,7 +515,7 @@
gnc_numeric num;
num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
- return g_strdup (gnc_numeric_to_string (num));
+ return gnc_numeric_to_string (num);
}
/* QOF_TYPE_GUID =================================================== */
Index: qofsql.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsql.c,v
retrieving revision 1.5.2.1
retrieving revision 1.5.2.2
diff -Lsrc/engine/qofsql.c -Lsrc/engine/qofsql.c -u -r1.5.2.1 -r1.5.2.2
--- src/engine/qofsql.c
+++ src/engine/qofsql.c
@@ -22,7 +22,7 @@
/**
@file qofsql.c
- @breif QOF client-side SQL parser.
+ @brief QOF client-side SQL parser.
@author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
*/
Index: gnc-numeric.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-numeric.c,v
retrieving revision 1.26.4.3
retrieving revision 1.26.4.4
diff -Lsrc/engine/gnc-numeric.c -Lsrc/engine/gnc-numeric.c -u -r1.26.4.3 -r1.26.4.4
--- src/engine/gnc-numeric.c
+++ src/engine/gnc-numeric.c
@@ -1,6 +1,7 @@
/********************************************************************
* gnc-numeric.c -- an exact-number library for accounting use *
* Copyright (C) 2000 Bill Gribble *
+ * 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 *
@@ -32,41 +33,130 @@
#include <string.h>
#include "gnc-numeric.h"
-
-/* TODO
- * - use longer intermediate values to make operations
- * 64-bit-overflow-proof
- */
+#include "qofmath128.c"
/* static short module = MOD_ENGINE; */
+/* =============================================================== */
+
#if 0
static const char * _numeric_error_strings[] =
{
"No error",
"Argument is not a valid number",
"Intermediate result overflow",
- "Argument denominators differ in GNC_DENOM_FIXED operation",
- "Remainder part in GNC_RND_NEVER operation"
+ "Argument denominators differ in GNC_HOW_DENOM_FIXED operation",
+ "Remainder part in GNC_HOW_RND_NEVER operation"
};
#endif
-static gint64 gnc_numeric_lcd(gnc_numeric a, gnc_numeric b);
+/* =============================================================== */
+/* This function is small, simple, and used everywhere below,
+ * lets try to inline it.
+ */
+inline GNCNumericErrorCode
+gnc_numeric_check(gnc_numeric in)
+{
+ if(in.denom != 0)
+ {
+ return GNC_ERROR_OK;
+ }
+ else if(in.num)
+ {
+ if ((0 < in.num) || (-4 > in.num))
+ {
+ in.num = (gint64) GNC_ERROR_OVERFLOW;
+ }
+ return (GNCNumericErrorCode) in.num;
+ }
+ else
+ {
+ return GNC_ERROR_ARG;
+ }
+}
+
+/**
+ * Find the least common multiple of the denominators of a and b.
+ */
+
+static inline gint64
+gnc_numeric_lcd(gnc_numeric a, gnc_numeric b)
+{
+ if(gnc_numeric_check(a) || gnc_numeric_check(b))
+ {
+ return GNC_ERROR_ARG;
+ }
+
+ if (b.denom == a.denom) return a.denom;
+
+ /* Special case: smaller divides smoothly into larger */
+ if ((b.denom < a.denom) && ((a.denom % b.denom) == 0))
+ {
+ return a.denom;
+ }
+ if ((a.denom < b.denom) && ((b.denom % a.denom) == 0))
+ {
+ return b.denom;
+ }
+
+ qofint128 lcm = lcm128 (a.denom, b.denom);
+ if (lcm.isbig) return GNC_ERROR_ARG;
+ return lcm.lo;
+}
+
+
+/** Return the ratio n/d reduced so that there are no common factors. */
+static inline gnc_numeric
+reduce128(qofint128 n, gint64 d)
+{
+ gint64 t;
+ gint64 num;
+ gint64 denom;
+ gnc_numeric out;
+
+ t = rem128 (n, d);
+ num = d;
+ denom = t;
+
+ /* The strategy is to use Euclid's algorithm */
+ while (denom > 0)
+ {
+ t = num % denom;
+ num = denom;
+ denom = t;
+ }
+ /* num now holds the GCD (Greatest Common Divisor) */
+
+ qofint128 red = div128 (n, num);
+ if (red.isbig)
+ {
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
+ out.num = red.lo;
+ if (red.isneg) out.num = -out.num;
+ out.denom = d / num;
+ return out;
+}
/********************************************************************
* gnc_numeric_zero_p
********************************************************************/
-int
-gnc_numeric_zero_p(gnc_numeric a) {
- if(gnc_numeric_check(a)) {
+gboolean
+gnc_numeric_zero_p(gnc_numeric a)
+{
+ if(gnc_numeric_check(a))
+ {
return 0;
}
- else {
- if((a.num == 0) && (a.denom != 0)) {
+ else
+ {
+ if((a.num == 0) && (a.denom != 0))
+ {
return 1;
}
- else {
+ else
+ {
return 0;
}
}
@@ -76,16 +166,21 @@
* gnc_numeric_negative_p
********************************************************************/
-int
-gnc_numeric_negative_p(gnc_numeric a) {
- if(gnc_numeric_check(a)) {
+gboolean
+gnc_numeric_negative_p(gnc_numeric a)
+{
+ if(gnc_numeric_check(a))
+ {
return 0;
}
- else {
- if((a.num < 0) && (a.denom != 0)) {
+ else
+ {
+ if((a.num < 0) && (a.denom != 0))
+ {
return 1;
}
- else {
+ else
+ {
return 0;
}
}
@@ -95,46 +190,62 @@
* gnc_numeric_positive_p
********************************************************************/
-int
-gnc_numeric_positive_p(gnc_numeric a) {
- if(gnc_numeric_check(a)) {
+gboolean
+gnc_numeric_positive_p(gnc_numeric a)
+{
+ if(gnc_numeric_check(a))
+ {
return 0;
}
- else {
- if((a.num > 0) && (a.denom != 0)) {
+ else
+ {
+ if((a.num > 0) && (a.denom != 0))
+ {
return 1;
}
- else {
+ else
+ {
return 0;
}
}
}
-
/********************************************************************
* gnc_numeric_compare
* returns 1 if a>b, -1 if b>a, 0 if a == b
********************************************************************/
int
-gnc_numeric_compare(gnc_numeric a, gnc_numeric b) {
- gint64 ab, ba;
+gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
+{
+ gint64 aa, bb;
- if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
+ if(gnc_numeric_check(a) || gnc_numeric_check(b))
+ {
return 0;
}
- ab = a.num * b.denom;
- ba = b.num * a.denom;
- if(ab == ba) {
- return 0;
- }
- else if(ab > ba) {
- return 1;
- }
- else {
+ if (a.denom == b.denom)
+ {
+ if(a.num == b.num) return 0;
+ if(a.num > b.num) return 1;
return -1;
}
+
+ if ((a.denom > 0) && (b.denom > 0))
+ {
+ /* Avoid overflows using 128-bit intermediate math */
+ qofint128 l = mult128 (a.num, b.denom);
+ qofint128 r = mult128 (b.num, a.denom);
+ return cmp128 (l,r);
+ }
+
+ aa = a.num * a.denom;
+ bb = b.num * b.denom;
+
+ if(aa == bb) return 0;
+ if(aa > bb) return 1;
+ return -1;
}
@@ -142,8 +253,9 @@
* gnc_numeric_eq
********************************************************************/
-int
-gnc_numeric_eq(gnc_numeric a, gnc_numeric b) {
+gboolean
+gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
+{
return ((a.num == b.num) && (a.denom == b.denom));
}
@@ -152,13 +264,34 @@
* gnc_numeric_equal
********************************************************************/
-int
-gnc_numeric_equal(gnc_numeric a, gnc_numeric b) {
- if(((a.denom > 0) && (b.denom > 0)) ||
- ((a.denom < 0) && (b.denom < 0))) {
+gboolean
+gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
+{
+ if ((a.denom == b.denom) && (a.denom > 0))
+ {
+ return (a.num == b.num);
+ }
+ if ((a.denom > 0) && (b.denom > 0))
+ {
+ // return (a.num*b.denom == b.num*a.denom);
+ qofint128 l = mult128 (a.num, b.denom);
+ qofint128 r = mult128 (b.num, a.denom);
+ return equal128 (l, r);
+
+#if ALT_WAY_OF_CHECKING_EQUALITY
+ gnc_numeric ra = gnc_numeric_reduce (a);
+ gnc_numeric rb = gnc_numeric_reduce (b);
+ if (ra.denom != rb.denom) return 0;
+ if (ra.num != rb.num) return 0;
+ return 1;
+#endif
+ }
+ if ((a.denom < 0) && (b.denom < 0))
+ {
return ((a.num * b.denom) == (a.denom * b.num));
}
- else {
+ else
+ {
return 0;
}
}
@@ -189,56 +322,83 @@
gnc_numeric
gnc_numeric_add(gnc_numeric a, gnc_numeric b,
- gint64 denom, gint how) {
+ gint64 denom, gint how)
+{
gnc_numeric sum;
- gint64 lcd;
- if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
+ if(gnc_numeric_check(a) || gnc_numeric_check(b))
+ {
return gnc_numeric_error(GNC_ERROR_ARG);
}
if((denom == GNC_DENOM_AUTO) &&
- (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
+ (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
+ {
if(a.denom == b.denom) {
denom = a.denom;
}
else if(b.num == 0) {
denom = a.denom;
+ b.denom = a.denom;
}
else if(a.num == 0) {
denom = b.denom;
+ a.denom = b.denom;
}
else {
return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
}
}
- if(a.denom < 0) {
+ if(a.denom < 0)
+ {
a.num *= a.denom;
a.denom = 1;
}
- if(b.denom < 0) {
+ if(b.denom < 0)
+ {
b.num *= b.denom;
b.denom = 1;
}
- /* get an exact answer.. same denominator is the common case. */
- if(a.denom == b.denom) {
+ /* Get an exact answer.. same denominator is the common case. */
+ if(a.denom == b.denom)
+ {
sum.num = a.num + b.num;
sum.denom = a.denom;
}
- else {
- /* ok, convert to the lcd and compute from there... */
+ else
+ {
+ /* We want to do this:
+ * sum.num = a.num*b.denom + b.num*a.denom;
+ * sum.denom = a.denom*b.denom;
+ * but the multiply could overflow.
+ * Computing the LCD minimizes likelyhood of overflow
+ */
+ gint64 lcd;
lcd = gnc_numeric_lcd(a,b);
- sum.num = a.num*(lcd/a.denom) + b.num*(lcd/b.denom);
+ if (GNC_ERROR_ARG == lcd)
+ {
+ return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+ }
+ qofint128 ca = mult128 (a.num, lcd/a.denom);
+ if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+
+ qofint128 cb = mult128 (b.num, lcd/b.denom);
+ if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+
+ qofint128 cab = add128 (ca, cb);
+ if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+
+ sum.num = cab.lo;
+ if (cab.isneg) sum.num = -sum.num;
sum.denom = lcd;
- // sum.num = a.num*b.denom + b.num*a.denom;
- // sum.denom = a.denom*b.denom;
}
if((denom == GNC_DENOM_AUTO) &&
- ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
+ ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
+ {
denom = gnc_numeric_lcd(a, b);
how = how & GNC_NUMERIC_RND_MASK;
}
@@ -246,92 +406,24 @@
return gnc_numeric_convert(sum, denom, how);
}
-
-/********************************************************************
- * gnc_numeric_add_fixed
- ********************************************************************/
-
-gnc_numeric
-gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b) {
- return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_FIXED | GNC_RND_NEVER);
-}
-
-
/********************************************************************
* gnc_numeric_sub
********************************************************************/
gnc_numeric
gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
- gint64 denom, gint how) {
- gnc_numeric diff;
- gint64 lcd;
-
- if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
+ gint64 denom, gint how)
+{
+ if(gnc_numeric_check(a) || gnc_numeric_check(b))
+ {
return gnc_numeric_error(GNC_ERROR_ARG);
}
- if((denom == GNC_DENOM_AUTO) &&
- (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
- if(a.denom == b.denom) {
- denom = a.denom;
- }
- else if(b.num == 0) {
- denom = a.denom;
- }
- else if(a.num == 0) {
- denom = b.denom;
- }
- else {
- return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
- }
- }
-
- if(a.denom < 0) {
- a.num *= a.denom;
- a.denom = 1;
- }
-
- if(b.denom < 0) {
- b.num *= b.denom;
- b.denom = 1;
- }
-
- /* get an exact answer.. same denominator is the common case. */
- if(a.denom == b.denom) {
- diff.num = a.num - b.num;
- diff.denom = a.denom;
- }
- else {
- /* ok, convert to the lcd and compute from there... */
- lcd = gnc_numeric_lcd(a,b);
- diff.num = a.num*(lcd/a.denom) - b.num*(lcd/b.denom);
- diff.denom = lcd;
- // diff.num = a.num*b.denom - b.num*a.denom;
- // diff.denom = a.denom*b.denom;
- }
-
- if((denom == GNC_DENOM_AUTO) &&
- ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
- denom = gnc_numeric_lcd(a, b);
- how = how & GNC_NUMERIC_RND_MASK;
- }
- return gnc_numeric_convert(diff, denom, how);
+ gnc_numeric nb = b;
+ nb.num = -nb.num;
+ return gnc_numeric_add (a, nb, denom, how);
}
-
-/********************************************************************
- * gnc_numeric_sub_fixed
- ********************************************************************/
-
-gnc_numeric
-gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b) {
- return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_FIXED | GNC_RND_NEVER);
-}
-
-
/********************************************************************
* gnc_numeric_mul
********************************************************************/
@@ -341,13 +433,14 @@
gint64 denom, gint how)
{
gnc_numeric product, result;
+ qofint128 bignume, bigdeno;
if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
return gnc_numeric_error(GNC_ERROR_ARG);
}
if((denom == GNC_DENOM_AUTO) &&
- (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
+ (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) {
if(a.denom == b.denom) {
denom = a.denom;
}
@@ -372,16 +465,56 @@
b.denom = 1;
}
+ bignume = mult128 (a.num, b.num);
+ bigdeno = mult128 (a.denom, b.denom);
product.num = a.num*b.num;
product.denom = a.denom*b.denom;
+
+ /* If it looks to be overflowing, try to reduce the fraction ... */
+ if (bignume.isbig || bigdeno.isbig)
+ {
+ /* If rounding allowed, then shift until there's no
+ * more overflow. The conversion at the end will fix
+ * things up for the final value. Else overflow. */
+ if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER)
+ {
+ if (bigdeno.isbig)
+ {
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
+ product = reduce128 (bignume, product.denom);
+ if (gnc_numeric_check (product))
+ {
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
+ }
+ else
+ {
+ while (bignume.isbig || bigdeno.isbig)
+ {
+ bignume = shift128 (bignume);
+ bigdeno = shift128 (bigdeno);
+ }
+ product.num = bignume.lo;
+ if (bignume.isneg) product.num = -product.num;
+
+ product.denom = bigdeno.lo;
+ if (0 == product.denom)
+ {
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
+ }
+ }
+#if 0 /* currently, product denom won't ever be zero */
if(product.denom < 0) {
product.num = -product.num;
product.denom = -product.denom;
}
+#endif
if((denom == GNC_DENOM_AUTO) &&
- ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD))
+ ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
{
denom = gnc_numeric_lcd(a, b);
how = how & GNC_NUMERIC_RND_MASK;
@@ -398,58 +531,129 @@
gnc_numeric
gnc_numeric_div(gnc_numeric a, gnc_numeric b,
- gint64 denom, gint how) {
+ gint64 denom, gint how)
+{
gnc_numeric quotient;
- gint64 lcd;
- if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
+ if(gnc_numeric_check(a) || gnc_numeric_check(b))
+ {
return gnc_numeric_error(GNC_ERROR_ARG);
}
if((denom == GNC_DENOM_AUTO) &&
- (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
- if(a.denom == b.denom) {
+ (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
+ {
+ if(a.denom == b.denom)
+ {
denom = a.denom;
}
- else if(a.denom == 0) {
+ else if(a.denom == 0)
+ {
denom = b.denom;
}
- else {
+ else
+ {
return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
}
}
- if(a.denom < 0) {
+ if(a.denom < 0)
+ {
a.num *= a.denom;
a.denom = 1;
}
- if(b.denom < 0) {
+ if(b.denom < 0)
+ {
b.num *= b.denom;
b.denom = 1;
}
- if(a.denom == b.denom) {
+ if(a.denom == b.denom)
+ {
quotient.num = a.num;
quotient.denom = b.num;
}
- else {
- /* ok, convert to the lcd and compute from there... */
- lcd = gnc_numeric_lcd(a,b);
- quotient.num = a.num*(lcd/a.denom);
- quotient.denom = b.num*(lcd/b.denom);
- // quotient.num = a.num*b.denom;
- // quotient.denom = a.denom*b.num;
+ else
+ {
+ gint64 sgn = 1;
+ if (0 > a.num)
+ {
+ sgn = -sgn;
+ a.num = -a.num;
+ }
+ if (0 > b.num)
+ {
+ sgn = -sgn;
+ b.num = -b.num;
+ }
+ qofint128 nume = mult128(a.num, b.denom);
+ qofint128 deno = mult128(b.num, a.denom);
+ if ((0 == nume.isbig) && (0 == deno.isbig))
+ {
+ quotient.num = sgn * nume.lo;
+ quotient.denom = deno.lo;
+ }
+ else if (0 == deno.isbig)
+ {
+ quotient = reduce128 (nume, deno.lo);
+ quotient.num *= sgn;
+ }
+ else
+ {
+ /* Try to avoid overflow by removing common factors */
+ gnc_numeric ra = gnc_numeric_reduce (a);
+ gnc_numeric rb = gnc_numeric_reduce (b);
+
+ gint64 gcf_nume = gcf64(ra.num, rb.num);
+ gint64 gcf_deno = gcf64(rb.denom, ra.denom);
+ qofint128 rnume = mult128(ra.num/gcf_nume, rb.denom/gcf_deno);
+ qofint128 rdeno = mult128(rb.num/gcf_nume, ra.denom/gcf_deno);
+
+ if ((0 == rnume.isbig) && (0 == rdeno.isbig))
+ {
+ quotient.num = sgn * rnume.lo;
+ quotient.denom = rdeno.lo;
+ }
+ else if (0 == rdeno.isbig)
+ {
+ quotient = reduce128 (rnume, rdeno.lo);
+ quotient.num *= sgn;
+ }
+ else
+ {
+ /* If rounding allowed, then shift until there's no
+ * more overflow. The conversion at the end will fix
+ * things up for the final value. */
+ if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER)
+ {
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
+ while (rnume.isbig || rdeno.isbig)
+ {
+ rnume = shift128 (rnume);
+ rdeno = shift128 (rdeno);
+ }
+ quotient.num = sgn * rnume.lo;
+ quotient.denom = rdeno.lo;
+ if (0 == quotient.denom)
+ {
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
+ }
+ }
}
- if(quotient.denom < 0) {
+ if(quotient.denom < 0)
+ {
quotient.num = -quotient.num;
quotient.denom = -quotient.denom;
}
if((denom == GNC_DENOM_AUTO) &&
- ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
+ ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
+ {
denom = gnc_numeric_lcd(a, b);
how = how & GNC_NUMERIC_RND_MASK;
}
@@ -476,7 +680,8 @@
********************************************************************/
gnc_numeric
-gnc_numeric_abs(gnc_numeric a) {
+gnc_numeric_abs(gnc_numeric a)
+{
if(gnc_numeric_check(a)) {
return gnc_numeric_error(GNC_ERROR_ARG);
}
@@ -509,17 +714,17 @@
switch(how & GNC_NUMERIC_DENOM_MASK)
{
default:
- case GNC_DENOM_LCD: /* LCD is meaningless with AUTO in here */
- case GNC_DENOM_EXACT:
+ case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */
+ case GNC_HOW_DENOM_EXACT:
return in;
break;
- case GNC_DENOM_REDUCE:
+ case GNC_HOW_DENOM_REDUCE:
/* reduce the input to a relatively-prime fraction */
return gnc_numeric_reduce(in);
break;
- case GNC_DENOM_FIXED:
+ case GNC_HOW_DENOM_FIXED:
if(in.denom != denom) {
return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
}
@@ -528,7 +733,7 @@
}
break;
- case GNC_DENOM_SIGFIG:
+ case GNC_HOW_DENOM_SIGFIG:
ratio = fabs(gnc_numeric_to_double(in));
if(ratio < 10e-20) {
logratio = 0;
@@ -538,7 +743,7 @@
logratio = ((logratio > 0.0) ?
(floor(logratio)+1.0) : (ceil(logratio)));
}
- sigfigs = GNC_NUMERIC_GET_SIGFIGS(how);
+ sigfigs = GNC_HOW_GET_SIGFIGS(how);
if(sigfigs-logratio >= 0) {
denom = (gint64)(pow(10, sigfigs-logratio));
@@ -547,7 +752,7 @@
denom = -((gint64)(pow(10, logratio-sigfigs)));
}
- how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
+ how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
break;
}
@@ -570,6 +775,8 @@
* the reciprocal of its magnitude. */
if(denom < 0)
{
+
+ /* XXX FIXME: use 128-bit math here ... */
denom = - denom;
denom_neg = 1;
temp_a = (in.num < 0) ? -in.num : in.num;
@@ -582,86 +789,140 @@
{
/* Do all the modulo and int division on positive values to make
* things a little clearer. Reduce the fraction denom/in.denom to
- * help with range errors (FIXME : need bigger intermediate rep) */
+ * help with range errors */
temp.num = denom;
temp.denom = in.denom;
temp = gnc_numeric_reduce(temp);
-
- out.num = in.num * temp.num;
- out.num = (out.num < 0) ? -out.num : out.num;
- remainder = out.num % temp.denom;
- out.num = out.num / temp.denom;
+
+ /* Symbolically, do the following:
+ * out.num = in.num * temp.num;
+ * remainder = out.num % temp.denom;
+ * out.num = out.num / temp.denom;
+ * out.denom = denom;
+ */
+ qofint128 nume = mult128 (in.num, temp.num);
+ qofint128 newm = div128 (nume, temp.denom);
+ remainder = rem128 (nume, temp.denom);
+
+ if (newm.isbig)
+ {
+ return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+ }
+
+ out.num = newm.lo;
out.denom = denom;
}
- if(remainder > 0)
+ if (remainder)
{
- switch(how) {
- case GNC_RND_FLOOR:
+ switch(how & GNC_NUMERIC_RND_MASK)
+ {
+ case GNC_HOW_RND_FLOOR:
if(sign < 0) {
out.num = out.num + 1;
}
break;
- case GNC_RND_CEIL:
+ case GNC_HOW_RND_CEIL:
if(sign > 0) {
out.num = out.num + 1;
}
break;
- case GNC_RND_TRUNC:
+ case GNC_HOW_RND_TRUNC:
break;
- case GNC_RND_PROMOTE:
+ case GNC_HOW_RND_PROMOTE:
out.num = out.num + 1;
break;
- case GNC_RND_ROUND_HALF_DOWN:
- if(denom_neg) {
- if((2 * remainder) > in.denom*denom) {
+ case GNC_HOW_RND_ROUND_HALF_DOWN:
+ if(denom_neg)
+ {
+ if((2 * remainder) > in.denom*denom)
+ {
out.num = out.num + 1;
}
}
- else if((2 * remainder) > temp.denom) {
+ else if((2 * remainder) > temp.denom)
+ {
+ out.num = out.num + 1;
+ }
+ /* check that 2*remainder didn't over-flow */
+ else if (((2 * remainder) < remainder) &&
+ (remainder > (temp.denom / 2)))
+ {
out.num = out.num + 1;
}
break;
- case GNC_RND_ROUND_HALF_UP:
- if(denom_neg) {
- if((2 * remainder) >= in.denom*denom) {
+ case GNC_HOW_RND_ROUND_HALF_UP:
+ if(denom_neg)
+ {
+ if((2 * remainder) >= in.denom*denom)
+ {
out.num = out.num + 1;
}
}
- else if((2 * remainder ) >= temp.denom) {
+ else if((2 * remainder ) >= temp.denom)
+ {
+ out.num = out.num + 1;
+ }
+ /* check that 2*remainder didn't over-flow */
+ else if (((2 * remainder) < remainder) &&
+ (remainder >= (temp.denom / 2)))
+ {
out.num = out.num + 1;
}
break;
- case GNC_RND_ROUND:
- if(denom_neg) {
- if((2 * remainder) > in.denom*denom) {
+ case GNC_HOW_RND_ROUND:
+ if(denom_neg)
+ {
+ if((2 * remainder) > in.denom*denom)
+ {
out.num = out.num + 1;
}
- else if((2 * remainder) == in.denom*denom) {
- if(out.num % 2) {
+ else if((2 * remainder) == in.denom*denom)
+ {
+ if(out.num % 2)
+ {
out.num = out.num + 1;
}
}
}
- else {
- if((2 * remainder ) > temp.denom) {
+ else
+ {
+ if((2 * remainder ) > temp.denom)
+ {
+ out.num = out.num + 1;
+ }
+ /* check that 2*remainder didn't over-flow */
+ else if (((2 * remainder) < remainder) &&
+ (remainder > (temp.denom / 2)))
+ {
out.num = out.num + 1;
}
- else if((2 * remainder) == temp.denom) {
- if(out.num % 2) {
+ else if((2 * remainder) == temp.denom)
+ {
+ if(out.num % 2)
+ {
out.num = out.num + 1;
}
}
+ /* check that 2*remainder didn't over-flow */
+ else if (((2 * remainder) < remainder) &&
+ (remainder == (temp.denom / 2)))
+ {
+ if(out.num % 2)
+ {
+ out.num = out.num + 1;
+ }
+ }
}
break;
- case GNC_RND_NEVER:
+ case GNC_HOW_RND_NEVER:
return gnc_numeric_error(GNC_ERROR_REMAINDER);
break;
}
@@ -674,198 +935,46 @@
/********************************************************************
- * gnc_numeric_lcd
- * Find the least common multiple of the denominators of
- * a and b
- ********************************************************************/
-
-gint64
-gnc_numeric_lcd(gnc_numeric a, gnc_numeric b) {
- gint64 current_divisor = 2;
- gint64 max_square;
- gint64 three_count = 0;
- gint64 small_denom;
- gint64 big_denom;
-
- if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
- return GNC_ERROR_ARG;
- }
-
- if(b.denom < a.denom) {
- small_denom = b.denom;
- big_denom = a.denom;
- }
- else {
- small_denom = a.denom;
- big_denom = b.denom;
- }
-
- /* special case: smaller divides smoothly into larger */
- if((big_denom % small_denom) == 0) {
- return big_denom;
- }
-
- max_square = small_denom;
-
- /* the LCM algorithm : factor out the union of the prime factors of the
- * two args and then multiply the remainders together.
- *
- * To do this, we find the successive prime factors of the smaller
- * denominator and eliminate them from both the smaller and larger
- * denominator (so we only count factors on a one-on-one basis),
- * then multiply the original smaller by the remains of the larger.
- *
- * I.e. LCM 100,96875 == 2*2*5*5,31*5*5*5*5 = 2*2,31*5*5
- * answer: multiply 100 by 31*5*5 == 387500
- */
- while(current_divisor * current_divisor <= max_square) {
- if(((small_denom % current_divisor) == 0) &&
- ((big_denom % current_divisor) == 0)) {
- big_denom = big_denom / current_divisor;
- small_denom = small_denom / current_divisor;
- }
- else {
- if(current_divisor == 2) {
- current_divisor++;
- }
- else if(three_count == 3) {
- current_divisor += 4;
- three_count = 1;
- }
- else {
- current_divisor += 2;
- three_count++;
- }
- }
-
- if((current_divisor > small_denom) ||
- (current_divisor > big_denom)) {
- break;
- }
- }
-
- /* max_sqaure is the original small_denom */
- return max_square * big_denom;
-
-}
-
-
-/********************************************************************
- * gnc_numeric_reduce
- * reduce a fraction by GCF elimination. This is NOT done as a
- * part of the arithmetic API unless GNC_DENOM_REDUCE is specified
+ ** reduce a fraction by GCF elimination. This is NOT done as a
+ * part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified
* as the output denominator.
********************************************************************/
-#if 1
gnc_numeric
-gnc_numeric_reduce(gnc_numeric in) {
+gnc_numeric_reduce(gnc_numeric in)
+{
gint64 t;
gint64 num = (in.num < 0) ? (- in.num) : in.num ;
gint64 denom = in.denom;
gnc_numeric out;
- if(gnc_numeric_check(in)) {
+ if(gnc_numeric_check(in))
+ {
return gnc_numeric_error(GNC_ERROR_ARG);
}
- /* the strategy is to use euclid's algorithm */
+ /* The strategy is to use Euclid's algorithm */
while (denom > 0) {
t = num % denom;
num = denom;
denom = t;
}
- /* num = gcd */
+ /* num now holds the GCD (Greatest Common Divisor) */
- /* all calculations are done on positive num, since it's not
+ /* All calculations are done on positive num, since it's not
* well defined what % does for negative values */
out.num = in.num / num;
out.denom = in.denom / num;
return out;
}
-#else
-gnc_numeric
-gnc_numeric_reduce(gnc_numeric in) {
-
- gint64 current_divisor = 2;
- gint64 max_square;
- gint64 num = (in.num < 0) ? (- in.num) : in.num ;
- gint64 denom = in.denom;
- int three_count = 0;
- gnc_numeric out;
-
- if(gnc_numeric_check(in)) {
- return gnc_numeric_error(GNC_ERROR_ARG);
- }
-
- /* the strategy is to eliminate common factors from
- * 2 up to 'max', where max is the smaller of the smaller
- * part of the fraction and the sqrt of the larger part of
- * the fraction. There's also the special case of the
- * smaller of fraction parts being a common factor.
- *
- * we test for 2 and 3 first, and thereafter skip all even numbers
- * and all odd multiples of 3 (that's every third odd number,
- * i.e. 9, 15, 21), thus the three_count stuff. */
-
- /* special case: one side divides evenly by the other */
- if (num == 0) {
- denom = 1;
- }
- else if((num > denom) && (num % denom == 0)) {
- num = num / denom;
- denom = 1;
- }
- else if ((num <= denom) && (denom % num == 0)) {
- denom = denom / num;
- num = 1;
- }
-
- max_square = (num > denom) ? denom : num;
-
- /* normal case: test 2, then 3, 5, 7, 11, etc.
- * (skip multiples of 2 and 3) */
- while(current_divisor * current_divisor <= max_square) {
- if((num % current_divisor == 0) &&
- (denom % current_divisor == 0)) {
- num = num / current_divisor;
- denom = denom / current_divisor;
- }
- else {
- if(current_divisor == 2) {
- current_divisor++;
- }
- else if(three_count == 3) {
- current_divisor += 4;
- three_count = 1;
- }
- else {
- current_divisor += 2;
- three_count++;
- }
- }
-
- if((current_divisor > num) ||
- (current_divisor > denom)) {
- break;
- }
- }
-
- /* all calculations are done on positive num, since it's not
- * well defined what % does for negative values */
- out.num = (in.num < 0) ? (- num) : num;
- out.denom = denom;
- return out;
-}
-#endif
-
/********************************************************************
* double_to_gnc_numeric
********************************************************************/
gnc_numeric
-double_to_gnc_numeric(double in, gint64 denom, gint how) {
+double_to_gnc_numeric(double in, gint64 denom, gint how)
+{
gnc_numeric out;
gint64 int_part=0;
double frac_part;
@@ -873,7 +982,8 @@
double logval;
double sigfigs;
- if((denom == GNC_DENOM_AUTO) && (how & GNC_DENOM_SIGFIG)) {
+ if((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG))
+ {
if(fabs(in) < 10e-20) {
logval = 0;
}
@@ -882,7 +992,7 @@
logval = ((logval > 0.0) ?
(floor(logval)+1.0) : (ceil(logval)));
}
- sigfigs = GNC_NUMERIC_GET_SIGFIGS(how);
+ sigfigs = GNC_HOW_GET_SIGFIGS(how);
if(sigfigs-logval >= 0) {
denom = (gint64)(pow(10, sigfigs-logval));
}
@@ -890,7 +1000,7 @@
denom = -((gint64)(pow(10, logval-sigfigs)));
}
- how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
+ how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
}
int_part = (gint64)(floor(fabs(in)));
@@ -900,24 +1010,24 @@
frac_part = frac_part * (double)denom;
switch(how & GNC_NUMERIC_RND_MASK) {
- case GNC_RND_FLOOR:
+ case GNC_HOW_RND_FLOOR:
frac_int = (gint64)floor(frac_part);
break;
- case GNC_RND_CEIL:
+ case GNC_HOW_RND_CEIL:
frac_int = (gint64)ceil(frac_part);
break;
- case GNC_RND_TRUNC:
+ case GNC_HOW_RND_TRUNC:
frac_int = (gint64)frac_part;
break;
- case GNC_RND_ROUND:
- case GNC_RND_ROUND_HALF_UP:
+ case GNC_HOW_RND_ROUND:
+ case GNC_HOW_RND_ROUND_HALF_UP:
frac_int = (gint64)rint(frac_part);
break;
- case GNC_RND_NEVER:
+ case GNC_HOW_RND_NEVER:
frac_int = (gint64)floor(frac_part);
if(frac_part != (double) frac_int) {
/* signal an error */
@@ -935,86 +1045,44 @@
********************************************************************/
double
-gnc_numeric_to_double(gnc_numeric in) {
- if(in.denom >= 0) {
+gnc_numeric_to_double(gnc_numeric in)
+{
+ if(in.denom >= 0)
+ {
return (double)in.num/(double)in.denom;
}
- else {
+ else
+ {
return (double)(in.num * in.denom);
}
}
-
-/********************************************************************
- * gnc_numeric_create
- ********************************************************************/
-
-gnc_numeric
-gnc_numeric_create(gint64 num, gint64 denom) {
- gnc_numeric out;
- out.num = num;
- out.denom = denom;
- return out;
-}
-
-
/********************************************************************
* gnc_numeric_error
********************************************************************/
gnc_numeric
-gnc_numeric_error(int error_code) {
- if(abs(error_code) < 5) {
- /* PERR("%s", _numeric_error_strings[ - error_code]); */
- }
+gnc_numeric_error(GNCNumericErrorCode error_code)
+{
return gnc_numeric_create(error_code, 0LL);
}
/********************************************************************
- * gnc_numeric_zero
- ********************************************************************/
-
-gnc_numeric
-gnc_numeric_zero(void) {
- return gnc_numeric_create(0LL, 1LL);
-}
-
-
-/********************************************************************
- * gnc_numeric_num
- ********************************************************************/
-
-gint64
-gnc_numeric_num(gnc_numeric a) {
- return a.num;
-}
-
-
-/********************************************************************
- * gnc_numeric_denom
- ********************************************************************/
-
-gint64
-gnc_numeric_denom(gnc_numeric a) {
- return a.denom;
-}
-
-
-/********************************************************************
* gnc_numeric_add_with_error
********************************************************************/
gnc_numeric
gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
- gnc_numeric * error) {
+ gnc_numeric * error)
+{
gnc_numeric sum = gnc_numeric_add(a, b, denom, how);
gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
if(error) {
*error = err;
@@ -1029,13 +1097,13 @@
gnc_numeric
gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
- gnc_numeric * error) {
-
+ gnc_numeric * error)
+{
gnc_numeric diff = gnc_numeric_sub(a, b, denom, how);
gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
if(error) {
*error = err;
}
@@ -1050,13 +1118,13 @@
gnc_numeric
gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
- gnc_numeric * error) {
-
+ gnc_numeric * error)
+{
gnc_numeric prod = gnc_numeric_mul(a, b, denom, how);
gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
if(error) {
*error = err;
}
@@ -1071,38 +1139,26 @@
gnc_numeric
gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
- gnc_numeric * error) {
-
+ gnc_numeric * error)
+{
gnc_numeric quot = gnc_numeric_div(a, b, denom, how);
gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
gnc_numeric err = gnc_numeric_sub(quot, exact,
- GNC_DENOM_AUTO, GNC_DENOM_REDUCE);
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
if(error) {
*error = err;
}
return quot;
}
-int
-gnc_numeric_check(gnc_numeric in) {
- if(in.denom != 0) {
- return GNC_ERROR_OK;
- }
- else if(in.num) {
- return in.num;
- }
- else {
- return GNC_ERROR_ARG;
- }
-}
-
/********************************************************************
* gnc_numeric text IO
********************************************************************/
gchar *
-gnc_numeric_to_string(gnc_numeric n) {
+gnc_numeric_to_string(gnc_numeric n)
+{
gchar *result;
long long int tmpnum = n.num;
long long int tmpdenom = n.denom;
@@ -1112,8 +1168,25 @@
return result;
}
+gchar *
+gnc_num_dbg_to_string(gnc_numeric n)
+{
+ static char buff[1000];
+ static char *p = buff;
+ long long int tmpnum = n.num;
+ long long int tmpdenom = n.denom;
+
+ p+= 100;
+ if (p-buff >= 1000) p = buff;
+
+ sprintf(p, "%lld/%lld", tmpnum, tmpdenom);
+
+ return p;
+}
+
const gchar *
-string_to_gnc_numeric(const gchar* str, gnc_numeric *n) {
+string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
+{
size_t num_read;
long long int tmpnum;
long long int tmpdenom;
@@ -1139,10 +1212,14 @@
return(str + num_read);
}
+/********************************************************************
+ * gnc_numeric misc testing
+ ********************************************************************/
#ifdef _GNC_NUMERIC_TEST
static char *
-gnc_numeric_print(gnc_numeric in) {
+gnc_numeric_print(gnc_numeric in)
+{
char * retval;
if(gnc_numeric_check(in)) {
retval = g_strdup_printf("<ERROR> [%lld / %lld]",
@@ -1158,182 +1235,49 @@
}
int
-main(int argc, char ** argv) {
+main(int argc, char ** argv)
+{
gnc_numeric a = gnc_numeric_create(1, 3);
gnc_numeric b = gnc_numeric_create(1, 4);
gnc_numeric c;
- gnc_numeric d = gnc_numeric_create(1, 2);
gnc_numeric err;
- int i;
- printf("add exact : %s + %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_add(a, b,
- GNC_DENOM_AUTO,
- GNC_DENOM_EXACT)));
-
-
- printf("add least : %s + %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_add(a, b,
- GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE)));
-
- printf("add 100ths (banker's): %s + %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_add(a, b, 100,
- GNC_RND_ROUND)));
-
- c = gnc_numeric_add_with_error(a, b, 100, GNC_RND_ROUND, &err);
+ c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
gnc_numeric_print(err));
- printf("sub exact : %s - %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_EXACT)));
-
- printf("sub least : %s - %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_sub(a, b,
- GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE)));
-
- printf("sub 100ths : %s - %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_sub(a, b, 100,
- GNC_RND_ROUND)));
-
- c = gnc_numeric_sub_with_error(a, b, 100, GNC_RND_FLOOR, &err);
+ c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err);
printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
gnc_numeric_print(err));
- printf("mul exact : %s * %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_EXACT)));
-
- printf("mul least : %s * %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE)));
-
- printf("mul 100ths : %s * %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_mul(a, b, 100,
- GNC_RND_ROUND)));
-
- c = gnc_numeric_mul_with_error(a, b, 100, GNC_RND_ROUND, &err);
+ c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
gnc_numeric_print(err));
- printf("div exact : %s / %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_div(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_EXACT)));
-
- printf("div least : %s / %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_div(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE)));
-
- printf("div 100ths : %s / %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_div(a, b, 100,
- GNC_RND_ROUND)));
-
- c = gnc_numeric_div_with_error(a, b, 100, GNC_RND_ROUND, &err);
+ c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
gnc_numeric_print(err));
- printf("7/16 as float: %e\n",
- gnc_numeric_to_double(gnc_numeric_create(7, 16)));
-
- printf("7/16 as 100ths (floor): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
- 100, GNC_RND_FLOOR)));
- printf("7/16 as 100ths (ceil): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
- 100, GNC_RND_CEIL)));
- printf("7/16 as 100ths (trunc): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
- 100, GNC_RND_TRUNC)));
- printf("7/16 as 100ths (round): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
- 100, GNC_RND_ROUND)));
-
- printf("1511/1000 as 1/100 (round): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1511, 1000),
- 100, GNC_RND_ROUND)));
- printf("1516/1000 as 1/100 (round): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1516, 1000),
- 100, GNC_RND_ROUND)));
- printf("1515/1000 as 1/100 (round): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1515, 1000),
- 100, GNC_RND_ROUND)));
- printf("1525/1000 as 1/100 (round): %s\n",
- gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1525, 1000),
- 100, GNC_RND_ROUND)));
-
- printf("100023234 / 334216654 reduced: %s\n",
- gnc_numeric_print(gnc_numeric_reduce(gnc_numeric_create(10023234LL,
- 334216654LL))));
- printf("2^10*3^10*17^2 / 2^8*3^12 reduced: %s\n",
- gnc_numeric_print
- (gnc_numeric_reduce(gnc_numeric_create(17474724864LL,
- 136048896LL))));
- printf("1024 / 1024^4 reduced: %s\n",
- gnc_numeric_print
- (gnc_numeric_reduce(gnc_numeric_create(1024LL,
- 1099511627776LL))));
- printf("reducing 100,000 times:\n\n");
- for(i = 0; i < 100000; i++) {
- gnc_numeric_reduce(gnc_numeric_create(17474724864LL,
- 136048896LL));
- }
-
- printf("add LCM: %s + %s = %s\n",
- gnc_numeric_print(b), gnc_numeric_print(d),
- gnc_numeric_print(gnc_numeric_add(b, d, GNC_DENOM_AUTO,
- GNC_DENOM_LCD)));
-
- printf("float to 6 sigfigs: %s\n",
- gnc_numeric_print(double_to_gnc_numeric(1.1234567890123,
- GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND)));
- printf("float to 6 sigfigs: %s\n",
- gnc_numeric_print(double_to_gnc_numeric(.011234567890123,
- GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND)));
- printf("float to 6 sigfigs: %s\n",
- gnc_numeric_print(double_to_gnc_numeric(1123.4567890123,
- GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND)));
- printf("float to 6 sigfigs: %s\n",
- gnc_numeric_print(double_to_gnc_numeric(1.1234567890123e-5,
- GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND)));
- printf("add to 4 sigfigs: %s + %s = %s\n",
- gnc_numeric_print(a), gnc_numeric_print(b),
- gnc_numeric_print(gnc_numeric_add(a, b,
- GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(4) |
- GNC_RND_ROUND)));
-
-
+ printf("multiply (EXACT): %s * %s = %s\n",
+ gnc_numeric_print(a), gnc_numeric_print(b),
+ gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT)));
+
+ printf("multiply (REDUCE): %s * %s = %s\n",
+ gnc_numeric_print(a), gnc_numeric_print(b),
+ gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE)));
+
+
return 0;
}
#endif
+
+/* ======================== END OF FILE =================== */
Index: Transaction.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Transaction.h,v
retrieving revision 1.141.4.5
retrieving revision 1.141.4.6
diff -Lsrc/engine/Transaction.h -Lsrc/engine/Transaction.h -u -r1.141.4.5 -r1.141.4.6
--- src/engine/Transaction.h
+++ src/engine/Transaction.h
@@ -19,6 +19,8 @@
\********************************************************************/
/** @addtogroup Engine
@{ */
+/** @addtogroup Transaction Financial Transactions
+ @{ */
/** @file Transaction.h
@brief API for Transactions and Splits (journal entries)
@author Copyright (C) 1997 Robin D. Clark
@@ -874,3 +876,4 @@
#endif /* XACC_TRANSACTION_H */
/** @} */
+/** @} */
Index: qofinstance.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofinstance.h,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -Lsrc/engine/qofinstance.h -Lsrc/engine/qofinstance.h -u -r1.10 -r1.10.2.1
--- src/engine/qofinstance.h
+++ src/engine/qofinstance.h
@@ -19,17 +19,25 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/*
- * Object instance holds many common fields that most
- * gnucash objects use.
+/** @addtogroup Entity
+ @{ */
+/** @addtogroup Instance
+ Qof Instances are a derived type of QofEntity. The Instance
+ adds some common features and functions that most objects
+ will want to use.
+
+ @{ */
+/** @file qofinstance.h
+ * @brief Object instance holds common fields that most gnucash objects use.
*
- * Copyright (C) 2003 Linas Vepstas <linas at linas.org>
+ * @author Copyright (C) 2003,2004 Linas Vepstas <linas at linas.org>
*/
#ifndef QOF_INSTANCE_H
#define QOF_INSTANCE_H
#include "guid.h"
+#include "gnc-date.h"
#include "kvp_frame.h"
#include "qofbook.h"
#include "qofid.h"
@@ -51,13 +59,29 @@
/** Return the book pointer */
QofBook * qof_instance_get_book (QofInstance *);
-/* Return the GUID of this instance */
+/** Return the GUID of this instance */
const GUID * qof_instance_get_guid (QofInstance *);
-/** return the pointer to the kvp_data */
+/** Return the pointer to the kvp_data */
KvpFrame* qof_instance_get_slots (QofInstance *);
-/** return value of is_dirty flag */
+/** Return the last time this instance was modified. If QofInstances
+ * are used with the QofObject storage backends, then the instance
+ * update times are reserved for use by the backend, for managing
+ * multi-user updates. Non-backend code should not set the update
+ * times.
+ */
+Timespec qof_instance_get_last_update (QofInstance *inst);
+
+/** Compare two instances, based on thier last update times.
+ * Returns a negative, zero or positive value, respectively,
+ * if 'left' is earlier, same as or later than 'right'.
+ * Accepts NULL pointers, NULL's are by definition earlier
+ * than any value.
+ */
+int qof_instance_version_cmp (QofInstance *left, QofInstance *right);
+
+/** Return value of is_dirty flag */
gboolean qof_instance_is_dirty (QofInstance *);
/** Pair things up. This routine inserts a kvp value into each instance
@@ -87,4 +111,6 @@
*/
QofInstance * qof_instance_lookup_twin (QofInstance *src, QofBook *book);
+/* @} */
+/* @} */
#endif /* QOF_INSTANCE_H */
Index: qofbook.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbook.c,v
retrieving revision 1.10.2.4
retrieving revision 1.10.2.5
diff -Lsrc/engine/qofbook.c -Lsrc/engine/qofbook.c -u -r1.10.2.4 -r1.10.2.5
--- src/engine/qofbook.c
+++ src/engine/qofbook.c
@@ -60,17 +60,14 @@
static void
qof_book_init (QofBook *book)
{
- QofCollection *col;
if (!book) return;
book->hash_of_collections = g_hash_table_new (g_str_hash, g_str_equal);
- col = qof_book_get_collection (book, QOF_ID_BOOK);
- qof_entity_init (&book->entity, QOF_ID_BOOK, col);
+ qof_instance_init (&book->inst, QOF_ID_BOOK, book);
- book->kvp_data = kvp_frame_new ();
-
book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
+ book->data_table_finalizers = g_hash_table_new (g_str_hash, g_str_equal);
book->book_open = 'y';
book->version = 0;
@@ -87,7 +84,7 @@
qof_book_init(book);
qof_object_book_begin (book);
- gnc_engine_gen_event (&book->entity, GNC_EVENT_CREATE);
+ gnc_engine_gen_event (&book->inst.entity, GNC_EVENT_CREATE);
LEAVE ("book=%p", book);
return book;
}
@@ -100,22 +97,36 @@
return TRUE;
}
+static void
+book_final (gpointer key, gpointer value, gpointer booq)
+{
+ QofBookFinalCB cb = value;
+ QofBook *book = booq;
+
+ gpointer user_data = g_hash_table_lookup (book->data_tables, key);
+ (*cb) (book, key, user_data);
+}
+
void
qof_book_destroy (QofBook *book)
{
if (!book) return;
-
ENTER ("book=%p", book);
- gnc_engine_force_event (&book->entity, GNC_EVENT_DESTROY);
- qof_object_book_end (book);
+ book->shutting_down = TRUE;
+ gnc_engine_force_event (&book->inst.entity, GNC_EVENT_DESTROY);
- kvp_frame_delete (book->kvp_data);
+ /* Call the list of finalizers, let them do thier thing.
+ * Do this before tearing into the rest of the book.
+ */
+ g_hash_table_foreach (book->data_table_finalizers, book_final, book);
- /* FIXME: Make sure the data_table is empty */
+ qof_object_book_end (book);
+
+ g_hash_table_destroy (book->data_table_finalizers);
g_hash_table_destroy (book->data_tables);
- qof_entity_release (&book->entity);
+ qof_instance_release (&book->inst);
g_hash_table_foreach_remove (book->hash_of_collections,
coll_destroy, NULL);
@@ -144,7 +155,7 @@
{
if (!book) return FALSE;
- return(book->dirty || qof_object_is_dirty (book));
+ return(book->inst.dirty || qof_object_is_dirty (book));
}
void
@@ -152,20 +163,13 @@
{
if (!book) return;
- book->dirty = FALSE;
+ book->inst.dirty = FALSE;
qof_object_mark_clean (book);
}
/* ====================================================================== */
/* getters */
-KvpFrame *
-qof_book_get_slots (QofBook *book)
-{
- if (!book) return NULL;
- return book->kvp_data;
-}
-
QofBackend *
qof_book_get_backend (QofBook *book)
{
@@ -173,6 +177,13 @@
return book->backend;
}
+gboolean
+qof_book_shutting_down (QofBook *book)
+{
+ if (!book) return FALSE;
+ return book->shutting_down;
+}
+
/* ====================================================================== */
/* setters */
@@ -187,20 +198,13 @@
void qof_book_kvp_changed (QofBook *book)
{
if (!book) return;
- book->dirty = TRUE;
+ book->inst.dirty = TRUE;
}
/* ====================================================================== */
/* Store arbitrary pointers in the QofBook for data storage extensibility */
/* XXX if data is NULL, we should remove the key from the hash table!
- *
- * XXX We need some design comments: an equivalent storage mechanism
- * would have been to give each item a GUID, store the GUID in a kvp frame,
- * and then do a GUID lookup to get the pointer to the actual object.
- * Of course, doing a kvp lookup followed by a GUID lookup would be
- * a good bit slower, but may be that's OK? In most cases, book data
- * is accessed only infrequently? --linas
*/
void
qof_book_set_data (QofBook *book, const char *key, gpointer data)
@@ -209,6 +213,16 @@
g_hash_table_insert (book->data_tables, (gpointer)key, data);
}
+void
+qof_book_set_data_fin (QofBook *book, const char *key, gpointer data, QofBookFinalCB cb)
+{
+ if (!book || !key) return;
+ g_hash_table_insert (book->data_tables, (gpointer)key, data);
+
+ if (!cb) return;
+ g_hash_table_insert (book->data_table_finalizers, (gpointer)key, cb);
+}
+
gpointer
qof_book_get_data (QofBook *book, const char *key)
{
@@ -223,6 +237,8 @@
{
QofCollection *col;
+ if (!book || !entity_type) return NULL;
+
col = g_hash_table_lookup (book->hash_of_collections, entity_type);
if (col) return col;
@@ -325,8 +341,8 @@
gboolean qof_book_register (void)
{
static QofParam params[] = {
- { QOF_BOOK_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_book_get_slots, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
+ { QOF_PARAM_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
{ NULL },
};
@@ -335,41 +351,4 @@
return TRUE;
}
-typedef struct _BookLookup {
- GUID *guid;
- QofEntity *toRet;
-} BookLookup;
-
-/// QofCollection 'foreach' function to find the QofEntity with the given GUID.
-static
-void
-_entity_by_guid( QofCollection *col, gpointer userData )
-{
- BookLookup *lookup;
-
- lookup = (BookLookup*)userData;
-
- // save some instructions if we've already seen the value.
- if ( lookup->toRet != NULL )
- return;
-
- lookup->toRet = qof_collection_lookup_entity( col, lookup->guid );
-}
-
-QofEntity*
-qof_book_get_entity_by_guid( QofBook *book, GUID *guid )
-{
- BookLookup lookup;
-
- if ( ! (guid && book) )
- return NULL;
-
- lookup.guid = guid;
- lookup.toRet = NULL;
-
- qof_book_foreach_collection( book, _entity_by_guid, &lookup );
-
- return lookup.toRet;
-}
-
/* ========================== END OF FILE =============================== */
Index: gnc-pricedb.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-pricedb.c,v
retrieving revision 1.48.4.4
retrieving revision 1.48.4.5
diff -Lsrc/engine/gnc-pricedb.c -Lsrc/engine/gnc-pricedb.c -u -r1.48.4.4 -r1.48.4.5
--- src/engine/gnc-pricedb.c
+++ src/engine/gnc-pricedb.c
@@ -27,7 +27,6 @@
#include <glib.h>
#include <string.h>
-#include "gnc-be-utils.h"
#include "gnc-engine.h"
#include "gnc-engine-util.h"
#include "gnc-event-p.h"
@@ -37,6 +36,7 @@
#include "kvp-util.h"
#include "qofbackend-p.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofbook-p.h"
#include "qofclass.h"
@@ -154,7 +154,7 @@
void
gnc_price_begin_edit (GNCPrice *p)
{
- GNC_BEGIN_EDIT (&p->inst);
+ QOF_BEGIN_EDIT (&p->inst);
}
static inline void commit_err (QofInstance *inst, QofBackendError errcode)
@@ -167,8 +167,8 @@
void
gnc_price_commit_edit (GNCPrice *p)
{
- GNC_COMMIT_EDIT_PART1 (&p->inst);
- GNC_COMMIT_EDIT_PART2 (&p->inst, commit_err, noop, noop);
+ QOF_COMMIT_EDIT_PART1 (&p->inst);
+ QOF_COMMIT_EDIT_PART2 (&p->inst, commit_err, noop, noop);
}
/* ==================================================================== */
@@ -176,81 +176,14 @@
void
gnc_pricedb_begin_edit (GNCPriceDB *pdb)
{
- QofBackend *be;
-
- if (!pdb) return;
- pdb->editlevel++;
- if (1 < pdb->editlevel) return;
- ENTER ("pdb=%p\n", pdb);
-
- if (0 >= pdb->editlevel)
- {
- PERR ("unbalanced call - resetting (was %d)", pdb->editlevel);
- pdb->editlevel = 1;
- }
-
- /* See if there's a backend. If there is, invoke it. */
- be = xaccPriceDBGetBackend (pdb);
- if (be && be->begin)
- {
- (be->begin) (be, GNC_ID_PRICEDB, pdb);
- }
-
- LEAVE ("pdb=%p\n", pdb);
+ QOF_BEGIN_EDIT (&pdb->inst);
}
void
gnc_pricedb_commit_edit (GNCPriceDB *pdb)
{
- QofBackend *be;
- if (!pdb) return;
-
- pdb->editlevel--;
- if (0 < pdb->editlevel) return;
-
- ENTER ("pdb=%p\n", pdb);
- if (0 > pdb->editlevel)
- {
- PERR ("unbalanced call - resetting (was %d)", pdb->editlevel);
- pdb->editlevel = 0;
- }
-
- /* See if there's a backend. If there is, invoke it. */
- /* We may not be able to find the backend, so make not of that .. */
- be = xaccPriceDBGetBackend (pdb);
- if (be && be->commit)
- {
- QofBackendError errcode;
-
- /* clear errors */
- do {
- errcode = qof_backend_get_error (be);
- } while (ERR_BACKEND_NO_ERR != errcode);
-
- /* if we haven't been able to call begin edit before, call it now */
- if (TRUE == pdb->dirty)
- {
- if (be->begin)
- {
- (be->begin) (be, GNC_ID_PRICEDB, pdb);
- }
- }
-
- (be->commit) (be, GNC_ID_PRICEDB, pdb);
- errcode = qof_backend_get_error (be);
- if (ERR_BACKEND_NO_ERR != errcode)
- {
- /* XXX hack alert FIXME implement price rollback */
- PERR (" backend asked engine to rollback, but this isn't"
- " handled yet. Return code=%d", errcode);
-
- /* push error back onto the stack */
- qof_backend_set_error (be, errcode);
- }
- }
- pdb->dirty = FALSE;
-
- LEAVE ("pdb=%p\n", pdb);
+ QOF_COMMIT_EDIT_PART1 (&pdb->inst);
+ QOF_COMMIT_EDIT_PART2 (&pdb->inst, commit_err, noop, noop);
}
/* ==================================================================== */
@@ -270,7 +203,7 @@
remove_price (p->db, p, TRUE);
gnc_price_begin_edit (p);
p->commodity = c;
- if(p->db) p->db->dirty = TRUE;
+ if(p->db) p->db->inst.dirty = TRUE;
gnc_price_commit_edit (p);
add_price (p->db, p);
gnc_price_unref (p);
@@ -292,7 +225,7 @@
remove_price (p->db, p, TRUE);
gnc_price_begin_edit (p);
p->currency = c;
- if(p->db) p->db->dirty = TRUE;
+ if(p->db) p->db->inst.dirty = TRUE;
gnc_price_commit_edit (p);
add_price (p->db, p);
gnc_price_unref (p);
@@ -312,7 +245,7 @@
remove_price (p->db, p, FALSE);
gnc_price_begin_edit (p);
p->tmspec = t;
- if(p->db) p->db->dirty = TRUE;
+ if(p->db) p->db->inst.dirty = TRUE;
gnc_price_commit_edit (p);
add_price (p->db, p);
gnc_price_unref (p);
@@ -333,7 +266,7 @@
tmp = g_cache_insert(cache, (gpointer) s);
if(p->source) g_cache_remove(cache, p->source);
p->source = tmp;
- if(p->db) p->db->dirty = TRUE;
+ if(p->db) p->db->inst.dirty = TRUE;
gnc_price_commit_edit (p);
}
}
@@ -352,7 +285,7 @@
tmp = g_cache_insert(cache, (gpointer) type);
if(p->type) g_cache_remove(cache, p->type);
p->type = tmp;
- if(p->db) p->db->dirty = TRUE;
+ if(p->db) p->db->inst.dirty = TRUE;
gnc_price_commit_edit (p);
}
}
@@ -365,7 +298,7 @@
{
gnc_price_begin_edit (p);
p->value = value;
- if(p->db) p->db->dirty = TRUE;
+ if(p->db) p->db->inst.dirty = TRUE;
gnc_price_commit_edit (p);
}
}
@@ -623,10 +556,22 @@
g_return_val_if_fail (book, NULL);
+ /* There can only be one pricedb per book. So if one exits already,
+ * then use that. Warn user, they shouldn't be creating two ...
+ */
+ QofCollection *col = qof_book_get_collection (book, GNC_ID_PRICEDB);
+ result = qof_collection_get_data (col);
+ if (result)
+ {
+ PWARN ("A price database already exists for this book!");
+ return result;
+ }
+
result = g_new0(GNCPriceDB, 1);
- result->book = book;
- result->editlevel = 0;
- result->dirty = FALSE;
+ qof_instance_init (&result->inst, GNC_ID_PRICEDB, book);
+
+ qof_collection_set_data (col, result);
+
result->commodity_hash = g_hash_table_new(commodity_hash, commodity_equal);
g_return_val_if_fail (result->commodity_hash, NULL);
return result;
@@ -672,11 +617,16 @@
NULL);
g_hash_table_destroy (db->commodity_hash);
db->commodity_hash = NULL;
- db->book = NULL;
+ qof_instance_release (&db->inst);
g_free(db);
}
/* ==================================================================== */
+/* This is kind of weird, the way its done. Each collection of prices
+ * for a given commodity should get its own guid, be its own entity, etc.
+ * We really shouldn't be using the collection data. But, hey I guess its OK,
+ * yeah?
+ */
GNCPriceDB *
gnc_collection_get_pricedb(QofCollection *col)
@@ -689,50 +639,10 @@
{
QofCollection *col;
if (!book) return NULL;
- col = qof_book_get_collection (book, GNC_ID_PRICE);
+ col = qof_book_get_collection (book, GNC_ID_PRICEDB);
return gnc_collection_get_pricedb (col);
}
-void
-gnc_collection_set_pricedb(QofCollection *col, GNCPriceDB *db)
-{
- GNCPriceDB *old_db;
-
- if(!col) return;
-
- old_db = qof_collection_get_data (col);
- if (db == old_db) return;
-
- qof_collection_set_data (col, db);
- gnc_pricedb_destroy (old_db);
-}
-
-void
-gnc_pricedb_set_db(QofBook *book, GNCPriceDB *db)
-{
- QofCollection *col;
- if(!book) return;
- col = qof_book_get_collection (book, GNC_ID_PRICE);
- gnc_collection_set_pricedb (col, db);
- if (db) db->book = book;
-}
-
-/* ==================================================================== */
-
-gboolean
-gnc_pricedb_dirty(GNCPriceDB *p)
-{
- if(!p) return FALSE;
- return p->dirty;
-}
-
-void
-gnc_pricedb_mark_clean(GNCPriceDB *p)
-{
- if(!p) return;
- p->dirty = FALSE;
-}
-
/* ==================================================================== */
static gboolean
@@ -841,9 +751,7 @@
ENTER ("db=%p, pr=%p dirty=%d do-free=%d",
db, p, p->inst.dirty, p->inst.do_free);
- /* initialize the book pointer for the first time, if needed */
- if (NULL == db->book) db->book = p->inst.book;
- if (db->book != p->inst.book)
+ if (db->inst.book != p->inst.book)
{
PERR ("attempted to mix up prices across different books");
return FALSE;
@@ -876,9 +784,9 @@
LEAVE ("db=%p, pr=%p dirty=%d do-free=%d commodity=%s/%s currency_hash=%p",
db, p, p->inst.dirty, p->inst.do_free,
- gnc_commodity_get_namespace(p->commodity),
- gnc_commodity_get_mnemonic(p->commodity),
- currency_hash);
+ gnc_commodity_get_namespace(p->commodity),
+ gnc_commodity_get_mnemonic(p->commodity),
+ currency_hash);
return TRUE;
}
@@ -898,7 +806,7 @@
if (TRUE == p->inst.dirty)
{
gnc_price_begin_edit(p);
- db->dirty = TRUE;
+ db->inst.dirty = TRUE;
gnc_price_commit_edit(p);
}
@@ -978,7 +886,7 @@
/* invoke the backend to delete this price */
gnc_price_begin_edit (p);
- db->dirty = TRUE;
+ db->inst.dirty = TRUE;
p->inst.do_free = TRUE;
gnc_price_commit_edit (p);
@@ -1047,14 +955,14 @@
ENTER ("db=%p commodity=%p currency=%p", db, commodity, currency);
if(!db || !commodity || !currency) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_LATEST;
pl.prdb = db;
pl.commodity = commodity;
pl.currency = currency;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
@@ -1098,14 +1006,14 @@
ENTER ("db=%p commodity=%p", db, commodity);
if(!db || !commodity) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_LATEST;
pl.prdb = db;
pl.commodity = commodity;
pl.currency = NULL; /* can the backend handle this??? */
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
@@ -1141,14 +1049,14 @@
ENTER ("db=%p commodity=%p currency=%p", db, commodity, currency);
if(!db || !commodity) return FALSE;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book && db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_ALL;
pl.prdb = db;
pl.commodity = commodity;
pl.currency = currency;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
@@ -1186,14 +1094,14 @@
ENTER ("db=%p commodity=%p currency=%p", db, commodity, currency);
if(!db || !commodity) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_ALL;
pl.prdb = db;
pl.commodity = commodity;
pl.currency = currency;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
@@ -1217,9 +1125,9 @@
GList *
gnc_pricedb_lookup_day(GNCPriceDB *db,
- gnc_commodity *c,
- gnc_commodity *currency,
- Timespec t)
+ gnc_commodity *c,
+ gnc_commodity *currency,
+ Timespec t)
{
GList *price_list;
GList *result = NULL;
@@ -1232,7 +1140,7 @@
/* Convert to noon local time. */
t = timespecCanonicalDayTime(t);
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_AT_TIME;
@@ -1240,7 +1148,7 @@
pl.commodity = c;
pl.currency = currency;
pl.date = t;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@@ -1287,8 +1195,8 @@
GList *
gnc_pricedb_lookup_day_any_currency(GNCPriceDB *db,
- gnc_commodity *c,
- Timespec t)
+ gnc_commodity *c,
+ Timespec t)
{
GList *result = NULL;
GHashTable *currency_hash;
@@ -1300,7 +1208,7 @@
/* Convert to noon local time. */
t = timespecCanonicalDayTime(t);
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_AT_TIME;
@@ -1308,7 +1216,7 @@
pl.commodity = c;
pl.currency = NULL; /* can the backend handle this??? */
pl.date = t;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@@ -1341,7 +1249,7 @@
ENTER ("db=%p commodity=%p currency=%p", db, c, currency);
if(!db || !c || !currency) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_AT_TIME;
@@ -1349,7 +1257,7 @@
pl.commodity = c;
pl.currency = currency;
pl.date = t;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@@ -1395,8 +1303,8 @@
GList *
gnc_pricedb_lookup_at_time_any_currency(GNCPriceDB *db,
- gnc_commodity *c,
- Timespec t)
+ gnc_commodity *c,
+ Timespec t)
{
GList *result = NULL;
GHashTable *currency_hash;
@@ -1405,7 +1313,7 @@
ENTER ("db=%p commodity=%p", db, c);
if(!db || !c) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_AT_TIME;
@@ -1413,7 +1321,7 @@
pl.commodity = c;
pl.currency = NULL; /* can the backend handle this??? */
pl.date = t;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@@ -1448,7 +1356,7 @@
ENTER ("db=%p commodity=%p currency=%p", db, c, currency);
if(!db || !c || !currency) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_NEAREST_IN_TIME;
@@ -1456,7 +1364,7 @@
pl.commodity = c;
pl.currency = currency;
pl.date = t;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@@ -1495,9 +1403,9 @@
Timespec abs_next = timespec_abs(&diff_next);
if (timespec_cmp(&abs_current, &abs_next) <= 0) {
- result = current_price;
+ result = current_price;
} else {
- result = next_price;
+ result = next_price;
}
}
}
@@ -1550,9 +1458,9 @@
Timespec abs_next = timespec_abs(&diff_next);
if (timespec_cmp(&abs_current, &abs_next) <= 0) {
- result = current_price;
+ result = current_price;
} else {
- result = next_price;
+ result = next_price;
}
}
}
@@ -1562,8 +1470,8 @@
GList *
gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
- gnc_commodity *c,
- Timespec t)
+ gnc_commodity *c,
+ Timespec t)
{
GList *result = NULL;
GHashTable *currency_hash;
@@ -1572,7 +1480,7 @@
ENTER ("db=%p commodity=%p", db, c);
if(!db || !c) return NULL;
- if (db->book && db->book->backend && db->book->backend->price_lookup)
+ if (db->inst.book->backend && db->inst.book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_NEAREST_IN_TIME;
@@ -1580,7 +1488,7 @@
pl.commodity = c;
pl.currency = NULL; /* can the backend handle this??? */
pl.date = t;
- (db->book->backend->price_lookup) (db->book->backend, &pl);
+ (db->inst.book->backend->price_lookup) (db->inst.book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@@ -1604,9 +1512,9 @@
*/
gnc_numeric
gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb,
- gnc_numeric balance,
- gnc_commodity *balance_currency,
- gnc_commodity *new_currency)
+ gnc_numeric balance,
+ gnc_commodity *balance_currency,
+ gnc_commodity *new_currency)
{
GNCPrice *price, *currency_price;
GList *price_list, *list_helper;
@@ -1621,8 +1529,8 @@
price = gnc_pricedb_lookup_latest (pdb, balance_currency, new_currency);
if (price) {
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
gnc_price_unref (price);
return balance;
}
@@ -1645,33 +1553,33 @@
intermediate_currency = gnc_price_get_currency(price);
currency_price = gnc_pricedb_lookup_latest(pdb, intermediate_currency,
- new_currency);
+ new_currency);
if(currency_price) {
currency_price_value = gnc_price_get_value(currency_price);
gnc_price_unref(currency_price);
} else {
currency_price = gnc_pricedb_lookup_latest(pdb, new_currency,
- intermediate_currency);
+ intermediate_currency);
if (currency_price) {
- /* here we need the reciprocal */
- currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1),
- gnc_price_get_value(currency_price),
- GNC_DENOM_AUTO,
- GNC_DENOM_EXACT | GNC_RND_NEVER);
- gnc_price_unref(currency_price);
+ /* here we need the reciprocal */
+ currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1),
+ gnc_price_get_value(currency_price),
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
+ gnc_price_unref(currency_price);
}
}
list_helper = list_helper->next;
} while((list_helper != NULL) &&
- (!gnc_numeric_zero_p(currency_price_value)));
+ (!gnc_numeric_zero_p(currency_price_value)));
balance = gnc_numeric_mul (balance, currency_price_value,
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
gnc_price_list_destroy(price_list);
return balance;
@@ -1679,10 +1587,10 @@
gnc_numeric
gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
- gnc_numeric balance,
- gnc_commodity *balance_currency,
- gnc_commodity *new_currency,
- Timespec t)
+ gnc_numeric balance,
+ gnc_commodity *balance_currency,
+ gnc_commodity *new_currency,
+ Timespec t)
{
GNCPrice *price, *currency_price;
GList *price_list, *list_helper;
@@ -1697,8 +1605,8 @@
price = gnc_pricedb_lookup_nearest_in_time (pdb, balance_currency, new_currency, t);
if (price) {
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
gnc_price_unref (price);
return balance;
}
@@ -1721,33 +1629,33 @@
intermediate_currency = gnc_price_get_currency(price);
currency_price = gnc_pricedb_lookup_nearest_in_time(pdb, intermediate_currency,
- new_currency, t);
+ new_currency, t);
if(currency_price) {
currency_price_value = gnc_price_get_value(currency_price);
gnc_price_unref(currency_price);
} else {
currency_price = gnc_pricedb_lookup_nearest_in_time(pdb, new_currency,
- intermediate_currency, t);
+ intermediate_currency, t);
if (currency_price) {
- /* here we need the reciprocal */
- currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1),
- gnc_price_get_value(currency_price),
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
- gnc_price_unref(currency_price);
+ /* here we need the reciprocal */
+ currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1),
+ gnc_price_get_value(currency_price),
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
+ gnc_price_unref(currency_price);
}
}
list_helper = list_helper->next;
} while((list_helper != NULL) &&
- (!gnc_numeric_zero_p(currency_price_value)));
+ (!gnc_numeric_zero_p(currency_price_value)));
balance = gnc_numeric_mul (balance, currency_price_value,
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
- gnc_commodity_get_fraction (new_currency),
- GNC_RND_ROUND);
+ gnc_commodity_get_fraction (new_currency),
+ GNC_HOW_RND_ROUND);
gnc_price_list_destroy(price_list);
return balance;
@@ -1844,7 +1752,7 @@
currency_hashes = g_hash_table_key_value_pairs(db->commodity_hash);
currency_hashes = g_slist_sort(currency_hashes,
- compare_kvpairs_by_commodity_key);
+ compare_kvpairs_by_commodity_key);
for(i = currency_hashes; i; i = i->next) {
GHashTableKVPair *kv_pair = (GHashTableKVPair *) i->data;
@@ -2021,28 +1929,18 @@
}
/* ==================================================================== */
-
-QofBackend *
-xaccPriceDBGetBackend (GNCPriceDB *prdb)
-{
- if (!prdb || !prdb->book) return NULL;
- return prdb->book->backend;
-}
-
-/* ==================================================================== */
/* gncObject function implementation and registration */
static void
pricedb_book_begin (QofBook *book)
{
- gnc_pricedb_set_db (book, gnc_pricedb_create(book));
+ gnc_pricedb_create(book);
}
static void
pricedb_book_end (QofBook *book)
{
- /* unhook the prices */
- gnc_pricedb_set_db (book, NULL);
+ /* ????? */
}
static gboolean
@@ -2147,12 +2045,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_PRICE,
type_label: "Price",
+ create: NULL,
book_begin: pricedb_book_begin,
book_end: pricedb_book_end,
is_dirty: pricedb_is_dirty,
mark_clean: pricedb_mark_clean,
foreach: pricedb_foreach,
printable: pricedb_printable,
+ version_cmp: NULL,
};
gboolean
Index: glib-helpers.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/glib-helpers.c,v
retrieving revision 1.3.4.1
retrieving revision 1.3.4.2
diff -Lsrc/engine/glib-helpers.c -Lsrc/engine/glib-helpers.c -u -r1.3.4.1 -r1.3.4.2
--- src/engine/glib-helpers.c
+++ src/engine/glib-helpers.c
@@ -155,7 +155,13 @@
while (!SCM_NULLP (list))
{
- glist = g_list_prepend (glist, gh_scm2newstr(SCM_CAR(list), NULL));
+ /* glist = g_list_prepend (glist, gh_scm2newstr(SCM_CAR(list), NULL)); */
+ char * str = SCM_STRING_CHARS (SCM_CAR(list));
+ if (str)
+ {
+ str = g_strdup (str);
+ glist = g_list_prepend (glist, str);
+ }
list = SCM_CDR (list);
}
Index: cap-gains.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/cap-gains.c,v
retrieving revision 1.13.4.1
retrieving revision 1.13.4.2
diff -Lsrc/engine/cap-gains.c -Lsrc/engine/cap-gains.c -u -r1.13.4.1 -r1.13.4.2
--- src/engine/cap-gains.c
+++ src/engine/cap-gains.c
@@ -22,7 +22,7 @@
/** @file cap-gains.c
* @breif Utilities to Automatically Compute Capital Gains/Losses.
* @author Created by Linas Vepstas August 2003
- * @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2003,2004 Linas Vepstas <linas at linas.org>
*
* This file implements the various routines to automatically
* compute and handle Cap Gains/Losses resulting from trading
@@ -110,6 +110,7 @@
struct find_lot_s
{
GNCLot *lot;
+ gnc_commodity *currency;
Timespec ts;
int (*numeric_pred)(gnc_numeric);
gboolean (*date_pred)(Timespec e, Timespec tr);
@@ -145,6 +146,13 @@
s = gnc_lot_get_earliest_split (lot);
trans = s->parent;
+ if (els->currency &&
+ (FALSE == gnc_commodity_equiv (els->currency,
+ trans->common_currency)))
+ {
+ return NULL;
+ }
+
if (els->date_pred (els->ts, trans->date_posted))
{
els->ts = trans->date_posted;
@@ -156,12 +164,14 @@
static inline GNCLot *
xaccAccountFindOpenLot (Account *acc, gnc_numeric sign,
+ gnc_commodity *currency,
long long guess,
gboolean (*date_pred)(Timespec, Timespec))
{
struct find_lot_s es;
es.lot = NULL;
+ es.currency = currency;
es.ts.tv_sec = guess;
es.ts.tv_nsec = 0;
es.date_pred = date_pred;
@@ -174,24 +184,26 @@
}
GNCLot *
-xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign)
+xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign,
+ gnc_commodity *currency)
{
GNCLot *lot;
ENTER (" sign=%lld/%lld", sign.num, sign.denom);
- lot = xaccAccountFindOpenLot (acc, sign,
+ lot = xaccAccountFindOpenLot (acc, sign, currency,
10000000LL * ((long long) LONG_MAX), earliest_pred);
LEAVE ("found lot=%p %s", lot, gnc_lot_get_title (lot));
return lot;
}
GNCLot *
-xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign)
+xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign,
+ gnc_commodity *currency)
{
GNCLot *lot;
ENTER (" sign=%lld/%lld", sign.num, sign.denom);
- lot = xaccAccountFindOpenLot (acc, sign,
+ lot = xaccAccountFindOpenLot (acc, sign, currency,
-10000000LL * ((long long) LONG_MAX), latest_pred);
LEAVE ("found lot=%p %s", lot, gnc_lot_get_title (lot));
return lot;
@@ -355,6 +367,27 @@
/* If this split already belongs to a lot, we are done. */
if (split->lot) return NULL;
+ /* Anomolous situation; except for voided transactions,
+ * we don't expect to see splits with no amount ..
+ * unless they're gains splits, and we shouldn't see those.
+ */
+ if (gnc_numeric_zero_p (split->amount))
+ {
+ if (xaccTransGetVoidStatus(split->parent)) return NULL;
+
+ PWARN ("split with zero amount; value=%s gflag=%x gsplit=%p",
+ gnc_num_dbg_to_string (split->amount),
+ split->gains,
+ split->gains_split);
+ if (split->gains_split)
+ {
+ PWARN ("gains amt=%s value=%s",
+ gnc_num_dbg_to_string (split->gains_split->amount),
+ gnc_num_dbg_to_string (split->gains_split->value));
+ }
+ return NULL;
+ }
+
/* If the lot is closed, we can't add anything to it */
baln = gnc_lot_get_balance (lot);
if (gnc_lot_is_closed (lot)) return split;
@@ -366,22 +399,37 @@
acc = split->acc;
xaccAccountBeginEdit (acc);
gnc_lot_add_split (lot, split);
- PINFO ("simple added split to lot, new lot baln=%s",
- gnc_numeric_to_string (gnc_lot_get_balance(lot)));
+ PINFO ("added split to empty lot, new lot baln=%s (%s)",
+ gnc_num_dbg_to_string (gnc_lot_get_balance(lot)),
+ gnc_lot_get_title (lot));
xaccAccountCommitEdit (acc);
return NULL;
}
/* If the sign of the split is the same as the sign of the lot,
- * we won't add it, because that would make the lot bigger, not
- * smaller. Our only function here is to make lot balances smaller.
+ * add the split, but complain about it ... none of the currently
+ * implemented accounting policies should be giving us splits
+ * that make lots larger. One a lot is open, the FIFO/LIFO
+ * policies should be working only to make the lot smaller.
+ * We can remove teh warning emssage come the day we have
+ * fancier policies.
*/
baln_is_positive = gnc_numeric_positive_p (baln);
amt_is_positive = gnc_numeric_positive_p (split->amount);
if ((baln_is_positive && amt_is_positive) ||
((!baln_is_positive) && (!amt_is_positive)))
{
- return split;
+ PWARN ("accounting policy gave us split that enlarges the lot!\n"
+ "old lot baln=%s split amt=%s lot=%s",
+ gnc_num_dbg_to_string (gnc_lot_get_balance(lot)),
+ gnc_num_dbg_to_string (split->amount),
+ gnc_lot_get_title (lot));
+
+ acc = split->acc;
+ xaccAccountBeginEdit (acc);
+ gnc_lot_add_split (lot, split);
+ xaccAccountCommitEdit (acc);
+ return NULL;
}
/* If adding the split would make the lot balance change sign,
@@ -391,7 +439,9 @@
cmp = gnc_numeric_compare (gnc_numeric_abs(split->amount),
gnc_numeric_abs(baln));
- PINFO ("found open lot with baln=%s", gnc_numeric_to_string (baln));
+ PINFO ("found open lot with baln=%s (%s)", gnc_num_dbg_to_string (baln),
+ gnc_lot_get_title (lot));
+
/* cmp == -1 if amt < baln, ==0 if amt==baln */
if (0 >= cmp)
{
@@ -399,7 +449,7 @@
xaccAccountBeginEdit (acc);
gnc_lot_add_split (lot, split);
PINFO ("simple added split to lot, new lot baln=%s",
- gnc_numeric_to_string (gnc_lot_get_balance(lot)));
+ gnc_num_dbg_to_string (gnc_lot_get_balance(lot)));
xaccAccountCommitEdit (acc);
return NULL;
}
@@ -411,7 +461,7 @@
Split * new_split;
gnc_numeric amt_a, amt_b, amt_tot;
gnc_numeric val_a, val_b, val_tot;
- gnc_numeric tmp;
+ gnc_numeric frac;
Transaction *trans;
Timespec ts;
@@ -424,26 +474,43 @@
amt_a = gnc_numeric_neg (baln);
amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
- PINFO ("++++++++++++++ splitting split into amt = %s + %s",
- gnc_numeric_to_string(amt_a),
- gnc_numeric_to_string(amt_b) );
+ PINFO ("++++++++++++++ splitting split=%p into amt = %s + %s",
+ split,
+ gnc_num_dbg_to_string(amt_a),
+ gnc_num_dbg_to_string(amt_b) );
/* Compute the value so that it holds in the same proportion:
* i.e. so that (amt_a / amt_tot) = (val_a / val_tot)
*/
val_tot = split->value;
- val_a = gnc_numeric_mul (amt_a, val_tot,
- GNC_DENOM_AUTO, GNC_DENOM_REDUCE);
- tmp = gnc_numeric_div (val_a, amt_tot,
- gnc_numeric_denom(val_tot), GNC_DENOM_EXACT);
+ frac = gnc_numeric_div (amt_a, amt_tot,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ val_a = gnc_numeric_mul (frac, val_tot,
+ gnc_numeric_denom(val_tot),
+ GNC_HOW_RND_ROUND| GNC_HOW_DENOM_EXACT);
- val_a = tmp;
val_b = gnc_numeric_sub_fixed (val_tot, val_a);
+ if (gnc_numeric_check(val_a))
+ {
+ PERR("Numeric overflow\n"
+ "Acct=%s Txn=%s\n"
+ "\tval_tot=%s amt_a=%s amt_tot=%s\n",
+ xaccAccountGetName(acc),
+ xaccTransGetDescription(trans),
+ gnc_num_dbg_to_string(val_tot),
+ gnc_num_dbg_to_string(amt_a),
+ gnc_num_dbg_to_string(amt_tot));
+ }
+
+ if (gnc_numeric_zero_p(val_a) || gnc_numeric_zero_p(val_b))
+ {
+ PERR ("Failed to split into two!");
+ }
PINFO ("split value is = %s = %s + %s",
- gnc_numeric_to_string(val_tot),
- gnc_numeric_to_string(val_a),
- gnc_numeric_to_string(val_b) );
+ gnc_num_dbg_to_string(val_tot),
+ gnc_num_dbg_to_string(val_a),
+ gnc_num_dbg_to_string(val_b) );
xaccSplitSetAmount (split, amt_a);
xaccSplitSetValue (split, val_a);
@@ -526,7 +593,7 @@
if (!split) return FALSE;
- ENTER ("split=%p", split);
+ ENTER ("(split=%p)", split);
/* If this split already belongs to a lot, we are done. */
if (split->lot) return FALSE;
@@ -539,22 +606,22 @@
* block is written in the form of a while loop, since we
* may have to bust a split across several lots.
*/
- while (split)
- {
- PINFO ("have split amount=%s", gnc_numeric_to_string (split->amount));
+ while (split)
+ {
+ PINFO ("have split amount=%s", gnc_num_dbg_to_string (split->amount));
split->gains |= GAINS_STATUS_VDIRTY;
lot = pcy->PolicyGetLot (pcy, split);
if (!lot)
{
lot = MakeDefaultLot (acc);
- PINFO ("start new lot");
+ PINFO ("start new lot (%s)", gnc_lot_get_title(lot));
}
split = xaccSplitAssignToLot (split, lot);
if (split) splits_split_up = TRUE;
}
xaccAccountCommitEdit (acc);
- LEAVE ("split_up=%d", splits_split_up);
+ LEAVE (" split_up=%d", splits_split_up);
return splits_split_up;
}
@@ -591,6 +658,7 @@
gnc_commodity *currency = NULL;
gnc_numeric zero = gnc_numeric_zero();
gnc_numeric value = zero;
+ gnc_numeric frac;
gnc_numeric opening_amount, opening_value;
gnc_commodity *opening_currency;
@@ -600,7 +668,7 @@
pcy = lot->account->policy;
currency = split->parent->common_currency;
- ENTER ("split=%p gains=%p status=0x%x lot=%s", split,
+ ENTER ("(split=%p gains=%p status=0x%x lot=%s)", split,
split->gains_split, split->gains,
kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
@@ -626,11 +694,13 @@
xaccTransCommitEdit (trans);
}
#endif
+ LEAVE ("Lot opening split, returning.");
return;
}
if (GAINS_STATUS_GAINS & split->gains)
{
+ PINFO ("split is a gains recording split, switch over");
/* If this is the split that records the gains, then work with
* the split that generates the gains.
*/
@@ -676,7 +746,11 @@
* nothing to do. Just return. */
if ((FALSE == (split->gains & GAINS_STATUS_A_VDIRTY)) &&
(split->gains_split) &&
- (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY))) return;
+ (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
+ {
+ LEAVE ("split not dirty, returning");
+ return;
+ }
/* Yow! If amount is zero, there's nothing to do! Amount-zero splits
* may exist if users attempted to manually record gains. */
@@ -697,6 +771,7 @@
* I don't know how to compute cap gains for that. This is not
* an error. Just punt, silently.
*/
+ LEAVE ("Can't compute gains, mismatched commodities!");
return;
}
@@ -708,7 +783,18 @@
if (0 > gnc_numeric_compare (gnc_numeric_abs(opening_amount),
gnc_numeric_abs(split->amount)))
{
- PERR ("Malformed Lot! (too thin!)\n");
+ GList *n;
+ for (n=lot->splits; n; n=n->next)
+ {
+ Split *s = n->data;
+ PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
+ }
+ PERR ("Malformed Lot \"%s\"! (too thin!) "
+ "opening amt=%s split amt=%s baln=%s",
+ gnc_lot_get_title (lot),
+ gnc_num_dbg_to_string (opening_amount),
+ gnc_num_dbg_to_string (split->amount),
+ gnc_num_dbg_to_string (gnc_lot_get_balance(lot)));
return;
}
if ( (gnc_numeric_negative_p(opening_amount) ||
@@ -716,7 +802,18 @@
(gnc_numeric_positive_p(opening_amount) ||
gnc_numeric_negative_p(split->amount)))
{
- PERR ("Malformed Lot! (too fat!)\n");
+ GList *n;
+ for (n=lot->splits; n; n=n->next)
+ {
+ Split *s = n->data;
+ PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
+ }
+ PERR ("Malformed Lot \"%s\"! (too fat!) "
+ "opening amt=%s split amt=%s baln=%s",
+ gnc_lot_get_title (lot),
+ gnc_num_dbg_to_string (opening_amount),
+ gnc_num_dbg_to_string (split->amount),
+ gnc_num_dbg_to_string (gnc_lot_get_balance(lot)));
return;
}
@@ -727,19 +824,34 @@
* cost_basis = purchase_price * current_amount
* cap_gain = current_value - cost_basis
*/
- value = gnc_numeric_mul (opening_value, split->amount,
- GNC_DENOM_AUTO, GNC_RND_NEVER);
- value = gnc_numeric_div (value, opening_amount,
- gnc_numeric_denom(opening_value), GNC_DENOM_EXACT);
-
+ frac = gnc_numeric_div (split->amount, opening_amount,
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_REDUCE);
+ value = gnc_numeric_mul (frac, opening_value,
+ gnc_numeric_denom(opening_value),
+ GNC_HOW_DENOM_EXACT|GNC_HOW_RND_ROUND);
value = gnc_numeric_sub (value, split->value,
- GNC_DENOM_AUTO, GNC_DENOM_LCD);
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
PINFO ("Open amt=%s val=%s; split amt=%s val=%s; gains=%s\n",
- gnc_numeric_to_string (opening_amount),
- gnc_numeric_to_string (opening_value),
- gnc_numeric_to_string (split->amount),
- gnc_numeric_to_string (split->value),
- gnc_numeric_to_string (value));
+ gnc_num_dbg_to_string (opening_amount),
+ gnc_num_dbg_to_string (opening_value),
+ gnc_num_dbg_to_string (split->amount),
+ gnc_num_dbg_to_string (split->value),
+ gnc_num_dbg_to_string (value));
+ if (gnc_numeric_check (value))
+ {
+ PERR ("Numeric overflow during gains calculation\n"
+ "Acct=%s Txn=%s\n"
+ "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
+ xaccAccountGetName(split->acc),
+ xaccTransGetDescription(split->parent),
+ gnc_num_dbg_to_string (opening_amount),
+ gnc_num_dbg_to_string (opening_value),
+ gnc_num_dbg_to_string (split->amount),
+ gnc_num_dbg_to_string (split->value),
+ gnc_num_dbg_to_string (value));
+ return;
+ }
/* Are the cap gains zero? If not, add a balancing transaction.
* As per design doc lots.txt: the transaction has two splits,
@@ -843,7 +955,7 @@
xaccTransCommitEdit (trans);
}
- LEAVE ("lot=%s", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
+ LEAVE ("(lot=%s)", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
}
/* ============================================================== */
@@ -852,6 +964,7 @@
xaccSplitGetCapGains(Split * split)
{
if (!split) return gnc_numeric_zero();
+ ENTER("(split=%p)", split);
if (GAINS_STATUS_UNKNOWN == split->gains) xaccSplitDetermineGainStatus(split);
if ((split->gains & GAINS_STATUS_A_VDIRTY) ||
@@ -869,6 +982,7 @@
split = split->gains_split;
}
+ LEAVE("(split=%p)", split);
if (!split) return gnc_numeric_zero();
return split->value;
@@ -887,6 +1001,7 @@
* then the cap gains are changed. To capture this, we need
* to mark all splits dirty if the opening splits are dirty. */
+ ENTER("(lot=%p)", lot);
pcy = lot->account->policy;
for (node=lot->splits; node; node=node->next)
{
@@ -916,6 +1031,7 @@
Split *s = node->data;
xaccSplitComputeCapGains (s, gain_acc);
}
+ LEAVE("(lot=%p)", lot);
}
/* ============================================================== */
@@ -979,6 +1095,7 @@
{
SplitList *node;
+ ENTER("(trans=%p)", trans);
/* Lock down posted date, its to be synced to the posted date
* for the source of the cap gains. */
xaccScrubGainsDate(trans);
@@ -1013,6 +1130,7 @@
xaccSplitComputeCapGains (split, gain_acc);
}
}
+ LEAVE("(trans=%p)", trans);
}
/* =========================== END OF FILE ======================= */
--- /dev/null
+++ src/engine/gnc-filepath-utils.c
@@ -0,0 +1,309 @@
+/********************************************************************\
+ * gnc-filepath-utils.c -- file path resolutin utilitie *
+ * *
+ * 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 gnc-filepath-utils.c
+ * @breif file path resolutionutilities
+ * @author Copyright (c) 1998-2004 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2000 Dave Peticolas
+ *
+ * XXX this file does not belong in the gnucash engine; it is here
+ * for the moment only because both the file backend and the app-file
+ * GUI code make use of it.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "gnc-filepath-utils.h"
+#include "gnc-trace.h"
+
+static short module = MOD_BACKEND;
+
+
+/* ====================================================================== */
+/*
+ * If $HOME/.gnucash/data directory doesn't exist, then create it.
+ */
+
+static void
+MakeHomeDir (void)
+{
+ int rc;
+ struct stat statbuf;
+ char *home;
+ char *path;
+ char *data;
+
+ /* Punt. Can't figure out where home is. */
+ home = getenv ("HOME");
+ if (!home) return;
+
+ path = g_strconcat(home, "/.gnucash", NULL);
+
+ rc = stat (path, &statbuf);
+ if (rc)
+ {
+ /* assume that the stat failed only because the dir is absent,
+ * and not because its read-protected or other error.
+ * Go ahead and make it. Don't bother much with checking mkdir
+ * for errors; seems pointless. */
+ mkdir (path, S_IRWXU); /* perms = S_IRWXU = 0700 */
+ }
+
+ data = g_strconcat (path, "/data", NULL);
+ rc = stat (data, &statbuf);
+ if (rc)
+ mkdir (data, S_IRWXU);
+
+ g_free (path);
+ g_free (data);
+}
+
+/* ====================================================================== */
+
+/* XXX hack alert -- we should be yanking this out of some config file */
+static char * searchpaths[] =
+{
+ "/usr/share/gnucash/data/",
+ "/usr/local/share/gnucash/data/",
+ "/usr/share/gnucash/accounts/",
+ "/usr/local/share/gnucash/accounts/",
+ NULL,
+};
+
+typedef gboolean (*pathGenerator)(char *pathbuf, int which);
+
+static gboolean
+xaccAddEndPath(char *pathbuf, const char *ending, int len)
+{
+ if(len + strlen(pathbuf) >= PATH_MAX)
+ return FALSE;
+
+ strcat (pathbuf, ending);
+ return TRUE;
+}
+
+static gboolean
+xaccCwdPathGenerator(char *pathbuf, int which)
+{
+ if(which != 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ /* try to find a file by this name in the cwd ... */
+ if (getcwd (pathbuf, PATH_MAX) == NULL)
+ return FALSE;
+
+ strcat (pathbuf, "/");
+ return TRUE;
+ }
+}
+
+static gboolean
+xaccDataPathGenerator(char *pathbuf, int which)
+{
+ char *path;
+
+ if(which != 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ path = getenv ("HOME");
+ if (!path)
+ return FALSE;
+
+ if (PATH_MAX <= (strlen (path) + 20))
+ return FALSE;
+
+ strcpy (pathbuf, path);
+ strcat (pathbuf, "/.gnucash/data/");
+ return TRUE;
+ }
+}
+
+static gboolean
+xaccUserPathPathGenerator(char *pathbuf, int which)
+{
+ char *path = NULL;
+
+ if(searchpaths[which] == NULL)
+ {
+ return FALSE;
+ }
+ else
+ {
+ path = searchpaths[which];
+
+ if (PATH_MAX <= strlen(path))
+ return FALSE;
+
+ strcpy (pathbuf, path);
+ return TRUE;
+ }
+}
+
+/* ====================================================================== */
+
+char *
+xaccResolveFilePath (const char * filefrag)
+{
+ struct stat statbuf;
+ char pathbuf[PATH_MAX];
+ pathGenerator gens[4];
+ char *filefrag_dup;
+ int namelen;
+ int i;
+
+ /* seriously invalid */
+ if (!filefrag)
+ {
+ PERR("filefrag is NULL");
+ return NULL;
+ }
+
+ ENTER ("filefrag=%s", filefrag);
+
+ /* ---------------------------------------------------- */
+ /* OK, now we try to find or build an absolute file path */
+
+ /* check for an absolute file path */
+ if (*filefrag == '/')
+ return g_strdup (filefrag);
+
+ if (!g_strncasecmp(filefrag, "file:", 5))
+ {
+ char *ret = g_new(char, strlen(filefrag) - 5 + 1);
+ strcpy(ret, filefrag + 5);
+ return ret;
+ }
+
+ /* get conservative on the length so that sprintf(getpid()) works ... */
+ /* strlen ("/.LCK") + sprintf (%x%d) */
+ namelen = strlen (filefrag) + 25;
+
+ gens[0] = xaccCwdPathGenerator;
+ gens[1] = xaccDataPathGenerator;
+ gens[2] = xaccUserPathPathGenerator;
+ gens[3] = NULL;
+
+ for (i = 0; gens[i] != NULL; i++)
+ {
+ int j;
+ for(j = 0; gens[i](pathbuf, j) ; j++)
+ {
+ if(xaccAddEndPath(pathbuf, filefrag, namelen))
+ {
+ int rc = stat (pathbuf, &statbuf);
+ if ((!rc) && (S_ISREG(statbuf.st_mode)))
+ {
+ return (g_strdup (pathbuf));
+ }
+ }
+ }
+ }
+ /* OK, we didn't find the file. */
+
+ /* make sure that the gnucash home dir exists. */
+ MakeHomeDir();
+
+ filefrag_dup = g_strdup (filefrag);
+
+ /* Replace '/' with ',' for non file backends */
+ if (strstr (filefrag, "://"))
+ {
+ char *p;
+
+ p = strchr (filefrag_dup, '/');
+ while (p) {
+ *p = ',';
+ p = strchr (filefrag_dup, '/');
+ }
+ }
+
+ /* Lets try creating a new file in $HOME/.gnucash/data */
+ if (xaccDataPathGenerator(pathbuf, 0))
+ {
+ if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
+ {
+ g_free (filefrag_dup);
+ return (g_strdup (pathbuf));
+ }
+ }
+
+ /* OK, we still didn't find the file */
+ /* Lets try creating a new file in the cwd */
+ if (xaccCwdPathGenerator(pathbuf, 0))
+ {
+ if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
+ {
+ g_free (filefrag_dup);
+ return (g_strdup (pathbuf));
+ }
+ }
+
+ g_free (filefrag_dup);
+
+ return NULL;
+}
+
+/* ====================================================================== */
+
+char *
+xaccResolveURL (const char * pathfrag)
+{
+ /* seriously invalid */
+ if (!pathfrag) return NULL;
+
+ /* At this stage of checking, URL's are always, by definition,
+ * resolved. If there's an error connecting, we'll find out later.
+ *
+ * FIXME -- we should probably use ghttp_uri_validate
+ * to make sure the uri is in good form.
+ */
+
+ if (!g_strncasecmp (pathfrag, "http://", 7) ||
+ !g_strncasecmp (pathfrag, "https://", 8) ||
+ !g_strncasecmp (pathfrag, "postgres://", 11) ||
+ !g_strncasecmp (pathfrag, "rpc://", 6))
+ {
+ return g_strdup(pathfrag);
+ }
+
+ if (!g_strncasecmp (pathfrag, "file:", 5)) {
+ return (xaccResolveFilePath (pathfrag));
+ }
+
+ return (xaccResolveFilePath (pathfrag));
+}
+
+/* =============================== END OF FILE ========================== */
Index: qofbackend-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend-p.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -Lsrc/engine/qofbackend-p.h -Lsrc/engine/qofbackend-p.h -u -r1.2 -r1.2.4.1
--- src/engine/qofbackend-p.h
+++ src/engine/qofbackend-p.h
@@ -1,8 +1,6 @@
/********************************************************************\
* qofbackend-p.h -- private api for data storage backend *
* *
- * Copyright (c) 2000, 2001 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 *
@@ -21,21 +19,24 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-
-/*
- * FILE:
- * qofbackend-p.h
- *
- * FUNCTION:
- * Pseudo-object defining how the engine can interact with different
- * back-ends (which may be SQL databases, or network interfaces to
- * remote GnuCash servers. In theory, file-io should be a type of
- * backend).
- *
- * The callbacks will be called at the appropriate times during
- * a book session to allow the backend to store the data as needed.
- *
- */
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Object_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/** @name Backend_Private
+ Pseudo-object defining how the engine can interact with different
+ back-ends (which may be SQL databases, or network interfaces to
+ remote GnuCash servers. In theory, file-io should be a type of
+ backend).
+
+ The callbacks will be called at the appropriate times during
+ a book session to allow the backend to store the data as needed.
+
+ @file qofbackend-p.h
+ @brief private api for data storage backend
+ @author Copyright (c) 2000,2001,2004 Linas Vepstas <linas at linas.org>
+@{ */
#ifndef QOF_BACKEND_P_H
#define QOF_BACKEND_P_H
@@ -44,10 +45,11 @@
#include "qofbackend.h"
#include "qofbook.h"
+#include "qofinstance.h"
#include "qofquery.h"
#include "qofsession.h"
-/*
+/**
* The session_begin() routine gives the backend a second initialization
* opportunity. It is suggested that the backend check that
* the URL is syntactically correct, and that it is actually
@@ -223,7 +225,24 @@
*
*/
-struct _QofBackend
+struct QofBackendProvider_s
+{
+ /** Some arbitrary name given for this particular backend provider */
+ const char * provider_name;
+
+ /** The access method that this provider provides, for example,
+ * http:// or postgres:// or rpc://, but without the :// at the end
+ */
+ const char * access_method;
+
+ /** Return a new, initialized backend backend. */
+ QofBackend * (*backend_new) (void);
+
+ /** Free this structure, unregister this backend handler. */
+ void (*provider_free) (QofBackendProvider *);
+};
+
+struct QofBackend_s
{
void (*session_begin) (QofBackend *be,
QofSession *session,
@@ -235,9 +254,9 @@
void (*load) (QofBackend *, QofBook *);
- void (*begin) (QofBackend *, QofIdTypeConst, gpointer);
- void (*commit) (QofBackend *, QofIdTypeConst, gpointer);
- void (*rollback) (QofBackend *, QofIdTypeConst, gpointer);
+ void (*begin) (QofBackend *, QofInstance *);
+ void (*commit) (QofBackend *, QofInstance *);
+ void (*rollback) (QofBackend *, QofInstance *);
gpointer (*compile_query) (QofBackend *, QofQuery *);
void (*free_query) (QofBackend *, gpointer);
@@ -247,15 +266,25 @@
gint64 (*counter) (QofBackend *, const char *counter_name);
- gboolean (*events_pending) (QofBackend *be);
- gboolean (*process_events) (QofBackend *be);
+ gboolean (*events_pending) (QofBackend *);
+ gboolean (*process_events) (QofBackend *);
QofBePercentageFunc percentage;
+ /** Document Me !!! what is this supposed to do ?? */
+ gboolean (*save_may_clobber_data) (QofBackend *);
+
QofBackendError last_err;
char * error_msg;
- /* XXX price_lookup should be removed during the redesign
+ /** XXX the file backend resolves the if to a fully-qualified file
+ * path. This holds the filepath and communicates it to the GUI.
+ * This is temprary scaffolding and should be removed. Deprecated.
+ */
+ char * fullpath;
+
+#ifdef GNUCASH_MAJOR_VERSION
+ /** XXX price_lookup should be removed during the redesign
* of the SQL backend... prices can now be queried using
* the generic query mechanism.
*
@@ -265,32 +294,46 @@
*/
void (*price_lookup) (QofBackend *, gpointer);
- /* XXX Export should really _NOT_ be here, but is left here for now.
+ /** XXX Export should really _NOT_ be here, but is left here for now.
* I'm not sure where this should be going to. It should be
- * removed ASAP.
+ * removed ASAP. This is a temporary hack-around until period-closing
+ * is fully implemented.
*/
void (*export) (QofBackend *, QofBook *);
+#endif
+
};
-/*
- * The qof_backend_set_error() routine pushes an error code onto the error
- * stack. (FIXME: the stack is 1 deep in current implementation).
- *
- * The qof_backend_get_error() routine pops an error code off the error
- * stack.
- *
- * The qof_backend_set_message() assigns a string to the backend error
- * message.
- *
- * The qof_backend_get_message() pops the error message string from
- * the Backend. This string should be freed with g_free().
+/** Let the sytem know about a new provider of backends. This function
+ * is typically called by the provider library at library load time.
+ * This function allows the backend library to tell the QOF infrastructure
+ * that it can handle URL's of a certain type. Note that a single
+ * backend library may register more than one provider, if it is
+ * capable of handling more than one URL access method.
*/
+void qof_backend_register_provider (QofBackendProvider *);
+/** The qof_backend_set_error() routine pushes an error code onto the error
+ * stack. (FIXME: the stack is 1 deep in current implementation).
+ */
void qof_backend_set_error (QofBackend *be, QofBackendError err);
+
+/** The qof_backend_get_error() routine pops an error code off the error stack.
+ */
QofBackendError qof_backend_get_error (QofBackend *be);
+
+/** The qof_backend_set_message() assigns a string to the backend error message.
+ */
void qof_backend_set_message(QofBackend *be, const char *format, ...);
+
+/** The qof_backend_get_message() pops the error message string from
+ * the Backend. This string should be freed with g_free().
+ */
char * qof_backend_get_message(QofBackend *be);
void qof_backend_init(QofBackend *be);
+/* @} */
+/* @} */
+/* @} */
#endif /* QOF_BACKEND_P_H */
Index: qofgobj.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofgobj.h,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -Lsrc/engine/qofgobj.h -Lsrc/engine/qofgobj.h -u -r1.1.2.1 -r1.1.2.2
--- src/engine/qofgobj.h
+++ src/engine/qofgobj.h
@@ -23,20 +23,24 @@
#ifndef QOF_GOBJ_H
#define QOF_GOBJ_H
-/** @addtogroup Engine
+/** @addtogroup Object
@{ */
+/** @addtogroup GObject GLib GObjects
+ 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, as a QOF Object Class. This allows
+ the QOF Query routines to be used to search over collections
+ of GObjects.
+
+ XXX Only GObject properties are searchable, data and other
+ hanging off the GObject is not. Fix this. This needs fixing.
+
+@{ */
/** @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>
@@ -79,4 +83,5 @@
#endif /* QOF_GOBJ_H */
/** @} */
+/** @} */
Index: GNCId.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/GNCId.h,v
retrieving revision 1.22.4.2
retrieving revision 1.22.4.3
diff -Lsrc/engine/GNCId.h -Lsrc/engine/GNCId.h -u -r1.22.4.2 -r1.22.4.3
--- src/engine/GNCId.h
+++ src/engine/GNCId.h
@@ -1,13 +1,6 @@
#include "qofid.h"
-/* Return the type of an identifier.
- * Equivalent function prototype:
- * QofIdType xaccGUIDType (const GUID * guid, QofBook *book);
- */
-
-#define xaccGUIDType(obj,book) (QOF_ENTITY(obj)->e_type)
-
/* Equivalent function prototype:
* void xaccGUIDNew (GUID *guid, QofBook *book)
*/
@@ -15,7 +8,6 @@
qof_entity_guid_new (qof_book_get_entity_table (book), (guid))
-
#define xaccGUIDNULL guid_null
#define xaccGUIDMalloc guid_malloc
#define xaccGUIDFree guid_free
Index: gnc-lot.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-lot.c,v
retrieving revision 1.14.4.3
retrieving revision 1.14.4.4
diff -Lsrc/engine/gnc-lot.c -Lsrc/engine/gnc-lot.c -u -r1.14.4.3 -r1.14.4.4
--- src/engine/gnc-lot.c
+++ src/engine/gnc-lot.c
@@ -361,8 +361,8 @@
void gnc_lot_register (void)
{
static const QofParam params[] = {
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)gnc_lot_get_book, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)gnc_lot_get_book, NULL },
{ LOT_IS_CLOSED, QOF_TYPE_BOOLEAN, (QofAccessFunc)gnc_lot_is_closed, NULL },
{ LOT_BALANCE, QOF_TYPE_NUMERIC, (QofAccessFunc)gnc_lot_get_balance, NULL },
{ NULL },
Index: kvp_frame.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp_frame.c,v
retrieving revision 1.30.4.4
retrieving revision 1.30.4.5
diff -Lsrc/engine/kvp_frame.c -Lsrc/engine/kvp_frame.c -u -r1.30.4.4 -r1.30.4.5
--- src/engine/kvp_frame.c
+++ src/engine/kvp_frame.c
@@ -147,11 +147,9 @@
kvp_frame_copy_worker(gpointer key, gpointer value, gpointer user_data)
{
KvpFrame * dest = (KvpFrame *)user_data;
- g_hash_table_freeze(dest->hash);
g_hash_table_insert(dest->hash,
(gpointer)g_cache_insert(gnc_engine_get_string_cache(), key),
(gpointer)kvp_value_copy(value));
- g_hash_table_thaw(dest->hash);
}
KvpFrame *
@@ -186,8 +184,6 @@
if (!frame || !slot) return NULL;
if (!init_frame_body_if_needed(frame)) return NULL; /* Error ... */
- g_hash_table_freeze(frame->hash);
-
key_exists = g_hash_table_lookup_extended(frame->hash, slot,
& orig_key, & orig_value);
if(key_exists)
@@ -208,8 +204,6 @@
new_value);
}
- g_hash_table_thaw(frame->hash);
-
return (KvpValue *) orig_value;
}
Index: qofid.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofid.c,v
retrieving revision 1.3.2.3
retrieving revision 1.3.2.4
diff -Lsrc/engine/qofid.c -Lsrc/engine/qofid.c -u -r1.3.2.3 -r1.3.2.4
--- src/engine/qofid.c
+++ src/engine/qofid.c
@@ -182,6 +182,7 @@
static void
qof_collection_remove_entity (QofEntity *ent)
{
+ if (!ent) return;
QofCollection *col = ent->collection;
if (!col) return;
g_hash_table_remove (col->hash_of_entities, &ent->guid);
@@ -191,6 +192,7 @@
void
qof_collection_insert_entity (QofCollection *col, QofEntity *ent)
{
+ if (!col || !ent) return;
if (guid_equal(&ent->guid, guid_null())) return;
g_return_if_fail (col->e_type == ent->e_type);
qof_collection_remove_entity (ent);
Index: SX-book.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/SX-book.c,v
retrieving revision 1.7.4.1
retrieving revision 1.7.4.2
diff -Lsrc/engine/SX-book.c -Lsrc/engine/SX-book.c -u -r1.7.4.1 -r1.7.4.2
--- src/engine/SX-book.c
+++ src/engine/SX-book.c
@@ -269,12 +269,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_SXTT,
type_label: "Scheduled Transaction Templates",
+ create: NULL,
book_begin: sxtt_book_begin,
book_end: sxtt_book_end,
is_dirty: book_sxlist_notsaved,
mark_clean: book_sxns_mark_saved,
foreach: NULL,
printable: NULL,
+ version_cmp: NULL,
};
gboolean
Index: gnc-date.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-date.h,v
retrieving revision 1.6.2.3
retrieving revision 1.6.2.4
diff -Lsrc/engine/gnc-date.h -Lsrc/engine/gnc-date.h -u -r1.6.2.3 -r1.6.2.4
--- src/engine/gnc-date.h
+++ src/engine/gnc-date.h
@@ -17,19 +17,9 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
\********************************************************************/
/** @addtogroup Date
- @{ */
-/** @file gnc-date.h
- @brief Date and Time handling routines
- *
Utility functions to handle date and time (adjusting, getting
the current date, printing the date and time, etc.)
- \warning HACK ALERT -- the scan and print routines should probably be moved
- to somewhere else. The engine really isn't involved with things
- like printing formats. This is needed mostly by the GUI and so on.
- If a file-io backend needs date handling, it should do it itself,
- instead of depending on the routines here.
-
Overall, this file is quite a mess. Note, however, that other
applications, besides just GnuCash, use this file. In particular,
GnoTime (gttr.sourcefore.net) uses this file, and this file is
@@ -50,10 +40,21 @@
that is not Universal Time. Break these rules, and you will
rue the day...
+ \warning HACK ALERT -- the scan and print routines should probably be moved
+ to somewhere else. The engine really isn't involved with things
+ like printing formats. This is needed mostly by the GUI and so on.
+ If a file-io backend needs date handling, it should do it itself,
+ instead of depending on the routines here.
+
@author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
@author Copyright (C) 1998-2001,2003 Linas Vepstas <linas at linas.org>
*/
+/* @{
+ @file gnc-date.h
+ @brief Date and Time handling routines
+*/
+
#ifndef GNC_DATE_H
#define GNC_DATE_H
Index: gnc-session-scm.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-session-scm.c,v
retrieving revision 1.3.4.1
retrieving revision 1.3.4.2
diff -Lsrc/engine/gnc-session-scm.c -Lsrc/engine/gnc-session-scm.c -u -r1.3.4.1 -r1.3.4.2
--- src/engine/gnc-session-scm.c
+++ src/engine/gnc-session-scm.c
@@ -84,10 +84,10 @@
gnc_session_scm_set_callback (SCM percentage_cb)
{
if (gnc_session_scm_gui_cb != SCM_BOOL_F)
- scm_unprotect_object(gnc_session_scm_gui_cb);
+ scm_gc_unprotect_object(gnc_session_scm_gui_cb);
gnc_session_scm_gui_cb = percentage_cb;
if (gnc_session_scm_gui_cb != SCM_BOOL_F)
- scm_protect_object(gnc_session_scm_gui_cb);
+ scm_gc_protect_object(gnc_session_scm_gui_cb);
}
--- src/engine/gnc-be-utils.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/********************************************************************\
- * gnc-be-utils.h: api for data storage backend *
- * 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 *
- * *
-\********************************************************************/
-/*
- * gnc-be-utils.h -- QOF Backend Utilities
- * common code used by objects to define begin_edit() and
- * commit_edit() functions.
- *
- * Written by: Derek Atkins <derek at ihtfp.com>
- *
- */
-
-#ifndef GNC_BE_UTILS_H
-#define GNC_BE_UTILS_H
-
-#include "gnc-engine-util.h"
-#include "qofbackend-p.h"
-#include "qofbook.h"
-
-/* begin_edit helper
- *
- * @args:
- * inst: an instance of QofInstance
- *
- * The caller should use this macro first and then perform any other operations.
- */
-
-#define GNC_BEGIN_EDIT(inst) \
- QofBackend * be; \
- if (!(inst)) return; \
- \
- (inst)->editlevel++; \
- if (1 < (inst)->editlevel) return; \
- \
- if (0 >= (inst)->editlevel) \
- { \
- PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
- (inst)->editlevel = 1; \
- } \
- ENTER ("inst=%p", (inst)); \
- \
- /* See if there's a backend. If there is, invoke it. */ \
- be = qof_book_get_backend ((inst)->book); \
- if (be && be->begin) { \
- (be->begin) (be, (inst)->entity.e_type, (inst)); \
- } else { \
- /* We tried and failed to start transaction! */ \
- (inst)->dirty = TRUE; \
- }
-
-
-/*
- * commit_edit helpers
- *
- * The caller should call PART1 as the first thing, then
- * perform any local operations prior to calling the backend.
- * Then call PART2.
- */
-
-/*
- * part1 -- deal with the editlevel
- *
- * @args:
- * inst: an instance of QofInstance
- */
-
-#define GNC_COMMIT_EDIT_PART1(inst) { \
- if (!(inst)) return; \
- \
- (inst)->editlevel--; \
- if (0 < (inst)->editlevel) return; \
- \
- /* The pricedb sufffers from delayed update... */ \
- /* This may be setting a bad precedent for other types, I fear. */ \
- /* Other types probably really should handle begin like this. */ \
- if ((-1 == (inst)->editlevel) && (inst)->dirty) \
- { \
- QofBackend * be; \
- be = qof_book_get_backend ((inst)->book); \
- if (be && be->begin) { \
- (be->begin) (be, (inst)->entity.e_type, (inst)); \
- } \
- (inst)->editlevel = 0; \
- } \
- if (0 > (inst)->editlevel) \
- { \
- PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
- (inst)->editlevel = 0; \
- } \
- ENTER ("inst=%p, dirty=%d do-free=%d", \
- (inst), (inst)->dirty, (inst)->do_free); \
-}
-
-/*
- * part2 -- deal with the backend
- *
- * @args:
- * inst: an instance of QofInstance
- * on_error: a function called if there is a backend error.
- * void (*on_error)(inst, QofBackendError)
- * on_done: a function called after the commit is complete
- * but before the instect is freed. Perform any other
- * operations after the commit.
- * void (*on_done)(inst)
- * on_free: a function called if inst->do_free is TRUE.
- * void (*on_free)(inst)
- */
-#define GNC_COMMIT_EDIT_PART2(inst,on_error,on_done,on_free) { \
- QofBackend * be; \
- \
- /* See if there's a backend. If there is, invoke it. */ \
- be = qof_book_get_backend ((inst)->book); \
- if (be && be->commit) \
- { \
- QofBackendError errcode; \
- \
- /* clear errors */ \
- do { \
- errcode = qof_backend_get_error (be); \
- } while (ERR_BACKEND_NO_ERR != errcode); \
- \
- (be->commit) (be, (inst)->entity.e_type, (inst)); \
- errcode = qof_backend_get_error (be); \
- if (ERR_BACKEND_NO_ERR != errcode) \
- { \
- /* XXX Should perform a rollback here */ \
- (inst)->do_free = FALSE; \
- \
- /* Push error back onto the stack */ \
- qof_backend_set_error (be, errcode); \
- (on_error)((inst), errcode); \
- } \
- /* XXX the backend commit code should clear dirty!! */ \
- (inst)->dirty = FALSE; \
- } \
- (on_done)(inst); \
- \
- LEAVE ("inst=%p, dirty=%d do-free=%d", \
- (inst), (inst)->dirty, (inst)->do_free); \
- if ((inst)->do_free) { \
- (on_free)(inst); \
- return; \
- } \
-}
-
-
-#endif /* GNC_BE_UTILS_H */
Index: qofobject.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofobject.c,v
retrieving revision 1.6.4.3
retrieving revision 1.6.4.4
diff -Lsrc/engine/qofobject.c -Lsrc/engine/qofobject.c -u -r1.6.4.3 -r1.6.4.4
--- src/engine/qofobject.c
+++ src/engine/qofobject.c
@@ -41,6 +41,22 @@
static GList *book_list = NULL;
static GHashTable *backend_data = NULL;
+gpointer
+qof_object_new_instance (QofIdTypeConst type_name, QofBook *book)
+{
+ const QofObject *obj;
+
+ if (!type_name) return NULL;
+
+ obj = qof_object_lookup (type_name);
+ if (!obj) return NULL;
+
+ if (obj->create)
+ return (obj->create (book));
+
+ return NULL;
+}
+
void qof_object_book_begin (QofBook *book)
{
GList *l;
@@ -333,3 +349,5 @@
g_hash_table_foreach (ht, foreach_backend, &cb_data);
}
+
+/* ========================= END OF FILE =================== */
Index: Scrub.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Scrub.c,v
retrieving revision 1.43.4.3
retrieving revision 1.43.4.4
diff -Lsrc/engine/Scrub.c -Lsrc/engine/Scrub.c -u -r1.43.4.3 -r1.43.4.4
--- src/engine/Scrub.c
+++ src/engine/Scrub.c
@@ -144,9 +144,19 @@
if (split->acc)
{
TransScrubOrphansFast (trans, xaccAccountGetRoot(split->acc));
- break;
+ return;
}
}
+
+ /* If we got to here, then *none* of the splits belonged to an
+ * account. Not a happy situation. We should dig an account
+ * out of the book the transaction belongs to.
+ * XXX we should probably *always* to this, instead of the above loop!
+ */
+ PINFO ("Free Floating Transaction!");
+ QofBook *book = xaccTransGetBook (trans);
+ AccountGroup *root = xaccGetAccountGroup (book);
+ TransScrubOrphansFast (trans, root);
}
/* ================================================================ */
@@ -250,7 +260,7 @@
value = xaccSplitGetValue (split);
if (gnc_numeric_same (xaccSplitGetAmount (split),
- value, scu, GNC_RND_ROUND))
+ value, scu, GNC_HOW_RND_ROUND))
{
return;
}
@@ -262,9 +272,9 @@
PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
" old amount %s %s, new amount %s",
trans->description, split->memo,
- gnc_numeric_to_string (xaccSplitGetAmount(split)),
+ gnc_num_dbg_to_string (xaccSplitGetAmount(split)),
gnc_commodity_get_mnemonic (currency),
- gnc_numeric_to_string (xaccSplitGetValue(split)));
+ gnc_num_dbg_to_string (xaccSplitGetValue(split)));
xaccTransBeginEdit (trans);
xaccSplitSetAmount (split, value);
@@ -344,7 +354,27 @@
if (!root)
{
Split *s = slist->data;
+ if (NULL == s->acc)
+ {
+ /* This should never occur, since xaccTransScrubSplits()
+ * above should have fixed things up. */
+ PERR ("Split is not assigned to any account");
+ }
root = xaccAccountGetRoot (s->acc);
+ if (NULL == root)
+ {
+ /* This should never occur, accounts are always
+ * in an account group */
+ PERR ("Can't find root account");
+ QofBook *book = xaccTransGetBook (trans);
+ root = xaccGetAccountGroup (book);
+ }
+ if (NULL == root)
+ {
+ /* This can't occur, things should be in books */
+ PERR ("Bad data corruption, no root account in book");
+ return;
+ }
}
account = xaccScrubUtilityGetOrMakeAccount (root,
trans->common_currency, _("Imbalance"));
@@ -398,7 +428,7 @@
* of the denominators might already be reduced. */
new_value = gnc_numeric_sub (old_value, imbalance,
gnc_commodity_get_fraction(currency),
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
xaccSplitSetValue (balance_split, new_value);
@@ -608,9 +638,9 @@
PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
" old amount %s %s, new amount %s",
trans->description, sp->memo,
- gnc_numeric_to_string (xaccSplitGetAmount(sp)),
+ gnc_num_dbg_to_string (xaccSplitGetAmount(sp)),
gnc_commodity_get_mnemonic (currency),
- gnc_numeric_to_string (xaccSplitGetValue(sp)));
+ gnc_num_dbg_to_string (xaccSplitGetValue(sp)));
xaccTransBeginEdit (trans);
xaccSplitSetAmount (sp, xaccSplitGetValue(sp));
xaccTransCommitEdit (trans);
@@ -619,9 +649,9 @@
{
PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
xaccSplitGetMemo (sp),
- gnc_numeric_to_string (amount),
+ gnc_num_dbg_to_string (amount),
gnc_commodity_get_mnemonic (currency),
- gnc_numeric_to_string (value),
+ gnc_num_dbg_to_string (value),
gnc_commodity_get_mnemonic (acc_currency));
}*/
}
--- /dev/null
+++ src/engine/qofmath128.c
@@ -0,0 +1,400 @@
+/********************************************************************
+ * qofmath128.c -- an 128-bit integer library *
+ * 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 *
+ * *
+ *******************************************************************/
+
+#define _GNU_SOURCE
+
+#include "config.h"
+#include "qofmath128.h"
+
+#include <glib.h>
+
+/* =============================================================== */
+/*
+ * Quick-n-dirty 128-bit integer math lib. Things seem to mostly
+ * work, and have been tested, but not comprehensively tested.
+ */
+
+#define HIBIT (0x8000000000000000ULL)
+
+/** Multiply a pair of signed 64-bit numbers,
+ * returning a signed 128-bit number.
+ */
+inline qofint128
+mult128 (gint64 a, gint64 b)
+{
+ qofint128 prod;
+
+ prod.isneg = 0;
+ if (0>a)
+ {
+ prod.isneg = !prod.isneg;
+ a = -a;
+ }
+
+ if (0>b)
+ {
+ prod.isneg = !prod.isneg;
+ b = -b;
+ }
+
+ guint64 a1 = a >> 32;
+ guint64 a0 = a - (a1<<32);
+
+ guint64 b1 = b >> 32;
+ guint64 b0 = b - (b1<<32);
+
+ guint64 d = a0*b0;
+ guint64 d1 = d >> 32;
+ guint64 d0 = d - (d1<<32);
+
+ guint64 e = a0*b1;
+ guint64 e1 = e >> 32;
+ guint64 e0 = e - (e1<<32);
+
+ guint64 f = a1*b0;
+ guint64 f1 = f >> 32;
+ guint64 f0 = f - (f1<<32);
+
+ guint64 g = a1*b1;
+ guint64 g1 = g >> 32;
+ guint64 g0 = g - (g1<<32);
+
+ guint64 sum = d1+e0+f0;
+ guint64 carry = 0;
+ /* Can't say 1<<32 cause cpp will goof it up; 1ULL<<32 might work */
+ guint64 roll = 1<<30;
+ roll <<= 2;
+
+ guint64 pmax = roll-1;
+ while (pmax < sum)
+ {
+ sum -= roll;
+ carry ++;
+ }
+
+ prod.lo = d0 + (sum<<32);
+ prod.hi = carry + e1 + f1 + g0 + (g1<<32);
+ // prod.isbig = (prod.hi || (sum >> 31));
+ prod.isbig = prod.hi || (prod.lo >> 63);
+
+ return prod;
+}
+
+/** Shift right by one bit (i.e. divide by two) */
+inline qofint128
+shift128 (qofint128 x)
+{
+ guint64 sbit = x.hi & 0x1;
+ x.hi >>= 1;
+ x.lo >>= 1;
+ x.isbig = 0;
+ if (sbit)
+ {
+ x.lo |= HIBIT;
+ x.isbig = 1;
+ return x;
+ }
+ if (x.hi)
+ {
+ x.isbig = 1;
+ }
+ return x;
+}
+
+/** Shift leftt by one bit (i.e. multiply by two) */
+inline qofint128
+shiftleft128 (qofint128 x)
+{
+ guint64 sbit = x.lo & HIBIT;
+ x.hi <<= 1;
+ x.lo <<= 1;
+ x.isbig = 0;
+ if (sbit)
+ {
+ x.hi |= 1;
+ x.isbig = 1;
+ return x;
+ }
+ if (x.hi)
+ {
+ x.isbig = 1;
+ }
+ return x;
+}
+
+/** increment a 128-bit number by one */
+inline qofint128
+inc128 (qofint128 a)
+{
+ if (0 == a.isneg)
+ {
+ a.lo ++;
+ if (0 == a.lo)
+ {
+ a.hi ++;
+ }
+ }
+ else
+ {
+ if (0 == a.lo)
+ {
+ a.hi --;
+ }
+ a.lo --;
+ }
+
+ a.isbig = (a.hi != 0) || (a.lo >> 63);
+ return a;
+}
+
+/** Divide a signed 128-bit number by a signed 64-bit,
+ * returning a signed 128-bit number.
+ */
+inline qofint128
+div128 (qofint128 n, gint64 d)
+{
+ qofint128 quotient;
+ guint64 remainder = 0;
+
+ quotient = n;
+ if (0 > d)
+ {
+ d = -d;
+ quotient.isneg = !quotient.isneg;
+ }
+
+ /* Use grade-school long division algorithm */
+ int i;
+ for (i=0; i<128; i++)
+ {
+ guint64 sbit = HIBIT & quotient.hi;
+ remainder <<= 1;
+ if (sbit) remainder |= 1;
+ quotient = shiftleft128 (quotient);
+ if (remainder >= d)
+ {
+ remainder -= d;
+ quotient.lo |= 1;
+ }
+ }
+
+ /* compute the carry situation */
+ quotient.isbig = (quotient.hi || (quotient.lo >> 63));
+
+ return quotient;
+}
+
+/** Return the remainder of a signed 128-bit number modulo
+ * a signed 64-bit. That is, return n%d in 128-bit math.
+ * I beleive that ths algo is overflow-free, but should be
+ * audited some more ...
+ */
+inline gint64
+rem128 (qofint128 n, gint64 d)
+{
+ qofint128 quotient = div128 (n,d);
+
+ qofint128 mu = mult128 (quotient.lo, d);
+
+ gint64 nn = 0x7fffffffffffffffULL & n.lo;
+ gint64 rr = 0x7fffffffffffffffULL & mu.lo;
+ return nn - rr;
+}
+
+/** Return true of two numbers are equal */
+inline gboolean
+equal128 (qofint128 a, qofint128 b)
+{
+ if (a.lo != b.lo) return 0;
+ if (a.hi != b.hi) return 0;
+ if (a.isneg != b.isneg) return 0;
+ return 1;
+}
+
+/** Return returns 1 if a>b, -1 if b>a, 0 if a == b */
+inline int
+cmp128 (qofint128 a, qofint128 b)
+{
+ if ((0 == a.isneg) && b.isneg) return 1;
+ if (a.isneg && (0 == b.isneg)) return -1;
+ if (0 == a.isneg)
+ {
+ if (a.hi > b.hi) return 1;
+ if (a.hi < b.hi) return -1;
+ if (a.lo > b.lo) return 1;
+ if (a.lo < b.lo) return -1;
+ return 0;
+ }
+
+ if (a.hi > b.hi) return -1;
+ if (a.hi < b.hi) return 1;
+ if (a.lo > b.lo) return -1;
+ if (a.lo < b.lo) return 1;
+ return 0;
+}
+
+/** Return the greatest common factor of two 64-bit numbers */
+inline guint64
+gcf64(guint64 num, guint64 denom)
+{
+ guint64 t;
+
+ t = num % denom;
+ num = denom;
+ denom = t;
+
+ /* The strategy is to use Euclid's algorithm */
+ while (0 != denom)
+ {
+ t = num % denom;
+ num = denom;
+ denom = t;
+ }
+ /* num now holds the GCD (Greatest Common Divisor) */
+ return num;
+}
+
+/** Return the least common multiple of two 64-bit numbers. */
+inline qofint128
+lcm128 (guint64 a, guint64 b)
+{
+ guint64 gcf = gcf64 (a,b);
+ b /= gcf;
+ return mult128 (a,b);
+}
+
+/** Add a pair of 128-bit numbers, returning a 128-bit number */
+inline qofint128
+add128 (qofint128 a, qofint128 b)
+{
+ qofint128 sum;
+ if (a.isneg == b.isneg)
+ {
+ sum.isneg = a.isneg;
+ sum.hi = a.hi + b.hi;
+ sum.lo = a.lo + b.lo;
+ if ((sum.lo < a.lo) || (sum.lo < b.lo))
+ {
+ sum.hi ++;
+ }
+ sum.isbig = sum.hi || (sum.lo >> 63);
+ return sum;
+ }
+ if ((b.hi > a.hi) ||
+ ((b.hi == a.hi) && (b.lo > a.lo)))
+ {
+ qofint128 tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ sum.isneg = a.isneg;
+ sum.hi = a.hi - b.hi;
+ sum.lo = a.lo - b.lo;
+
+ if (sum.lo > a.lo)
+ {
+ sum.hi --;
+ }
+
+ sum.isbig = sum.hi || (sum.lo >> 63);
+ return sum;
+}
+
+
+#ifdef TEST_128_BIT_MULT
+static void pr (gint64 a, gint64 b)
+{
+ qofint128 prod = mult128 (a,b);
+ printf ("%lld * %lld = %lld %llu (0x%llx %llx) %hd\n",
+ a, b, prod.hi, prod.lo, prod.hi, prod.lo, prod.isbig);
+}
+
+static void prd (gint64 a, gint64 b, gint64 c)
+{
+ qofint128 prod = mult128 (a,b);
+ qofint128 quot = div128 (prod, c);
+ gint64 rem = rem128 (prod, c);
+ printf ("%lld * %lld / %lld = %lld %llu + %lld (0x%llx %llx) %hd\n",
+ a, b, c, quot.hi, quot.lo, rem, quot.hi, quot.lo, quot.isbig);
+}
+
+int main ()
+{
+ pr (2,2);
+
+ gint64 x = 1<<30;
+ x <<= 2;
+
+ pr (x,x);
+ pr (x+1,x);
+ pr (x+1,x+1);
+
+ pr (x,-x);
+ pr (-x,-x);
+ pr (x-1,x);
+ pr (x-1,x-1);
+ pr (x-2,x-2);
+
+ x <<= 1;
+ pr (x,x);
+ pr (x,-x);
+
+ pr (1000000, 10000000000000);
+
+ prd (x,x,2);
+ prd (x,x,3);
+ prd (x,x,4);
+ prd (x,x,5);
+ prd (x,x,6);
+
+ x <<= 29;
+ prd (3,x,3);
+ prd (6,x,3);
+ prd (99,x,3);
+ prd (100,x,5);
+ prd (540,x,5);
+ prd (777,x,7);
+ prd (1111,x,11);
+
+ /* Really test division */
+ qofint128 n;
+ n.hi = 0xdd91;
+ n.lo = 0x6c5abefbb9e13480ULL;
+
+ gint64 d = 0x2ae79964d3ae1d04ULL;
+
+ int i;
+ for (i=0; i<20; i++) {
+
+ qofint128 quot = div128 (n, d);
+ printf ("%d result = %llx %llx\n", i, quot.hi, quot.lo);
+ d >>=1;
+ n = shift128 (n);
+ }
+ return 0;
+}
+
+#endif /* TEST_128_BIT_MULT */
+
+/* ======================== END OF FILE =================== */
Index: gnc-trace.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-trace.h,v
retrieving revision 1.3.4.5
retrieving revision 1.3.4.6
diff -Lsrc/engine/gnc-trace.h -Lsrc/engine/gnc-trace.h -u -r1.3.4.5 -r1.3.4.6
--- src/engine/gnc-trace.h
+++ src/engine/gnc-trace.h
@@ -22,7 +22,11 @@
* Author: Linas Vepstas (linas at linas.org) *
\********************************************************************/
-/** @file gnc-trace.h @brief GnuCash error loging and tracing facility */
+/** @addtogroup Trace
+ @{ */
+
+/** @file gnc-trace.h
+ * @brief GnuCash error loging and tracing facility */
#ifndef GNC_TRACE_H
#define GNC_TRACE_H
@@ -130,11 +134,13 @@
* handle.
*/
+/** Log an fatal error */
#define FATAL(format, args...) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
"Fatal Error: %s(): " format, FUNK , ## args); \
}
+/** Log an serious error */
#define PERR(format, args...) { \
if (gnc_should_log (module, GNC_LOG_ERROR)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
@@ -142,6 +148,7 @@
} \
}
+/** Log an warning */
#define PWARN(format, args...) { \
if (gnc_should_log (module, GNC_LOG_WARNING)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
@@ -149,6 +156,7 @@
} \
}
+/** Print an informational note */
#define PINFO(format, args...) { \
if (gnc_should_log (module, GNC_LOG_INFO)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
@@ -156,6 +164,7 @@
} \
}
+/** Print an debugging message */
#define DEBUG(format, args...) { \
if (gnc_should_log (module, GNC_LOG_DEBUG)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
@@ -163,6 +172,7 @@
} \
}
+/** Print an function entry debugging message */
#define ENTER(format, args...) { \
if (gnc_should_log (module, GNC_LOG_DEBUG)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
@@ -170,6 +180,7 @@
} \
}
+/** Print an function exit debugging message */
#define LEAVE(format, args...) { \
if (gnc_should_log (module, GNC_LOG_DEBUG)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
@@ -177,6 +188,7 @@
} \
}
+/** Print an function trace debugging message */
#define TRACE(format, args...) { \
if (gnc_should_log (module, GNC_LOG_TRACE)) { \
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
@@ -187,7 +199,7 @@
#define DEBUGCMD(x) { if (gnc_should_log (module, GNC_LOG_DEBUG)) { (x); }}
/* -------------------------------------------------------- */
-/* Infrastructure to make timing measurements for critical peices
+/** Infrastructure to make timing measurements for critical peices
* of code. Used for only for performance tuning & debugging.
*/
@@ -206,18 +218,21 @@
const char *function_name,
const char *format, ...);
+/** start a particular timer */
#define START_CLOCK(clockno,format, args...) { \
if (gnc_should_log (module, GNC_LOG_INFO)) \
gnc_start_clock (clockno, module, GNC_LOG_INFO, \
__FUNCTION__, format , ## args); \
}
+/** report elapsed time since last report on a particular timer */
#define REPORT_CLOCK(clockno,format, args...) { \
if (gnc_should_log (module, GNC_LOG_INFO)) \
gnc_report_clock (clockno, module, GNC_LOG_INFO, \
__FUNCTION__, format , ## args); \
}
+/** report total elapsed time since timer started */
#define REPORT_CLOCK_TOTAL(clockno,format, args...) { \
if (gnc_should_log (module, GNC_LOG_INFO)) \
gnc_report_clock_total (clockno, module, GNC_LOG_INFO, \
@@ -225,3 +240,4 @@
}
#endif /* GNC_TRACE_H */
+/* @} */
Index: cap-gains.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/cap-gains.h,v
retrieving revision 1.4.4.1
retrieving revision 1.4.4.2
diff -Lsrc/engine/cap-gains.h -Lsrc/engine/cap-gains.h -u -r1.4.4.1 -r1.4.4.2
--- src/engine/cap-gains.h
+++ src/engine/cap-gains.h
@@ -21,11 +21,8 @@
/** @addtogroup Engine
* @{ */
-/** @file cap-gains.h
- * @breif Utilities to Automatically Compute Capital Gains/Losses.
- * @author Created by Linas Vepstas August 2003
- * @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
- *
+
+/** @addtogroup CapGains Cap Gains
* This file implements the various routines to automatically
* compute and handle Cap Gains/Losses resulting from trading
* activities. Some of these routines might have broader
@@ -38,6 +35,12 @@
* This code does not currently handle tax distinctions, e.g
* the different tax treatment that short-term and long-term
* cap gains have.
+ * @{ */
+
+/** @file cap-gains.h
+ * @brief Utilities to Automatically Compute Capital Gains/Losses.
+ * @author Created by Linas Vepstas August 2003
+ * @author Copyright (c) 2003,2004 Linas Vepstas <linas at linas.org>
*/
#ifndef XACC_CAP_GAINS_H
@@ -78,9 +81,15 @@
* The sign comparison helps identify a lot that can be
* added to: usually, one wants to add splits to a lot so
* that the balance only decreases.
+ * If 'currency' is non-null, then this attempts to find
+ * a lot whose opening transaction has the same currency.
*/
-GNCLot * xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign);
-GNCLot * xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign);
+GNCLot * xaccAccountFindEarliestOpenLot (Account *acc,
+ gnc_numeric sign,
+ gnc_commodity *currency);
+GNCLot * xaccAccountFindLatestOpenLot (Account *acc,
+ gnc_numeric sign,
+ gnc_commodity *currency);
/** The xaccAccountGetDefaultGainAccount() routine will return
* the account to which realized gains/losses may be posted.
@@ -187,5 +196,6 @@
#endif /* XACC_CAP_GAINS_H */
/** @} */
+/** @} */
/* =========================== END OF FILE ======================= */
Index: qofinstance.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofinstance.c,v
retrieving revision 1.10.2.2
retrieving revision 1.10.2.3
diff -Lsrc/engine/qofinstance.c -Lsrc/engine/qofinstance.c -u -r1.10.2.2 -r1.10.2.3
--- src/engine/qofinstance.c
+++ src/engine/qofinstance.c
@@ -44,40 +44,42 @@
void
qof_instance_init (QofInstance *inst, QofIdType type, QofBook *book)
{
- QofCollection *col;
+ QofCollection *col;
- inst->book = book;
+ inst->book = book;
inst->kvp_data = kvp_frame_new();
+ inst->last_update.tv_sec = 0;
+ inst->last_update.tv_nsec = -1;
inst->editlevel = 0;
inst->do_free = FALSE;
inst->dirty = FALSE;
- col = qof_book_get_collection (book, type);
+ col = qof_book_get_collection (book, type);
qof_entity_init (&inst->entity, type, col);
}
void
qof_instance_release (QofInstance *inst)
{
- kvp_frame_delete (inst->kvp_data);
+ kvp_frame_delete (inst->kvp_data);
inst->editlevel = 0;
inst->do_free = FALSE;
- inst->dirty = FALSE;
+ inst->dirty = FALSE;
qof_entity_release (&inst->entity);
}
const GUID *
qof_instance_get_guid (QofInstance *inst)
{
- if (!inst) return NULL;
- return &inst->entity.guid;
+ if (!inst) return NULL;
+ return &inst->entity.guid;
}
QofBook *
qof_instance_get_book (QofInstance *inst)
{
- if (!inst) return NULL;
- return inst->book;
+ if (!inst) return NULL;
+ return inst->book;
}
KvpFrame*
@@ -87,11 +89,35 @@
return inst->kvp_data;
}
+Timespec
+qof_instance_get_last_update (QofInstance *inst)
+{
+ if (!inst)
+ {
+ Timespec ts = {0,-1};
+ return ts;
+ }
+ return inst->last_update;
+}
+
+int
+qof_instance_version_cmp (QofInstance *left, QofInstance *right)
+{
+ if (!left && !right) return 0;
+ if (!left) return -1;
+ if (!right) return +1;
+ if (left->last_update.tv_sec < right->last_update.tv_sec) return -1;
+ if (left->last_update.tv_sec > right->last_update.tv_sec) return +1;
+ if (left->last_update.tv_nsec < right->last_update.tv_nsec) return -1;
+ if (left->last_update.tv_nsec > right->last_update.tv_nsec) return +1;
+ return 0;
+}
+
gboolean
qof_instance_is_dirty (QofInstance *inst)
{
- if (!inst) return FALSE;
- return inst->dirty;
+ if (!inst) return FALSE;
+ return inst->dirty;
}
/* ========================================================== */
@@ -112,11 +138,18 @@
{
kvp_frame_delete(inst->kvp_data);
}
-
+
inst->dirty = TRUE;
inst->kvp_data = frm;
}
+void
+qof_instance_set_last_update (QofInstance *inst, Timespec ts)
+{
+ if (!inst) return;
+ inst->last_update = ts;
+}
+
/* ========================================================== */
void
@@ -132,11 +165,11 @@
/* Make a note of where the copy came from */
gnc_kvp_bag_add (to->kvp_data, "gemini", now,
"inst_guid", &from->entity.guid,
- "book_guid", &from->book->entity.guid,
+ "book_guid", &from->book->inst.entity.guid,
NULL);
gnc_kvp_bag_add (from->kvp_data, "gemini", now,
"inst_guid", &to->entity.guid,
- "book_guid", &to->book->entity.guid,
+ "book_guid", &to->book->inst.entity.guid,
NULL);
to->dirty = TRUE;
@@ -146,23 +179,23 @@
qof_instance_lookup_twin (QofInstance *src, QofBook *target_book)
{
QofCollection *col;
- KvpFrame *fr;
- GUID * twin_guid;
- QofInstance * twin;
-
- if (!src || !target_book) return NULL;
- ENTER (" ");
-
- fr = gnc_kvp_bag_find_by_guid (src->kvp_data, "gemini",
- "book_guid", &target_book->entity.guid);
-
- twin_guid = kvp_frame_get_guid (fr, "inst_guid");
+ KvpFrame *fr;
+ GUID * twin_guid;
+ QofInstance * twin;
+
+ if (!src || !target_book) return NULL;
+ ENTER (" ");
+
+ fr = gnc_kvp_bag_find_by_guid (src->kvp_data, "gemini",
+ "book_guid", &target_book->inst.entity.guid);
+
+ twin_guid = kvp_frame_get_guid (fr, "inst_guid");
col = qof_book_get_collection (target_book, src->entity.e_type);
- twin = (QofInstance *) qof_collection_lookup_entity (col, twin_guid);
+ twin = (QofInstance *) qof_collection_lookup_entity (col, twin_guid);
- LEAVE (" found twin=%p", twin);
- return twin;
+ LEAVE (" found twin=%p", twin);
+ return twin;
}
/* ========================== END OF FILE ======================= */
Index: TransLog.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/TransLog.h,v
retrieving revision 1.9.6.1
retrieving revision 1.9.6.2
diff -Lsrc/engine/TransLog.h -Lsrc/engine/TransLog.h -u -r1.9.6.1 -r1.9.6.2
--- src/engine/TransLog.h
+++ src/engine/TransLog.h
@@ -20,13 +20,23 @@
/** @addtogroup Engine
@{ */
+/** @addtogroup TransLog Transaction Logging
+ The transaction logging mechanism provides a very simple,
+ low-level logging of user input to a file. The goal of
+ the transaction logger is to provide mechanism of last resort
+ for recovering lost user data in the event of a crash.
+
+ Ideally, the storage backends should provide a robust journaling,
+ logging and crash-recovery mechanism. But just in case they
+ don't, or it didn't work, this mechanism provides a "Plan B"
+ by providing a low-tech, fool-proof, simple logging system
+ that can be used to recover user input.
+ There are some simple command-line tools that will read a log
+ and replay it.
+
+ @{ */
/** @file TransLog.h
@brief API for the transaction logger
-*
- * The logfiles are useful for tracing, journalling, error recovery.
- * Note that the current support for journalling is at best
- * embryonic, at worst, is dangerous by setting the wrong expectations.
- *
@author Copyright (C) 1998 Linas Vepstas
*/
@@ -69,4 +79,5 @@
#endif /* XACC_TRANS_LOG_H */
/** @} */
+/** @} */
Index: qofobject-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofobject-p.h,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -Lsrc/engine/qofobject-p.h -Lsrc/engine/qofobject-p.h -u -r1.4 -r1.4.2.1
--- src/engine/qofobject-p.h
+++ src/engine/qofobject-p.h
@@ -18,11 +18,15 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Object_Private
+ Private interfaces, not meant to be used by applications.
+ @{ */
+/** @name Objects_Private
@{ */
/** @file qofobject-p.h
- * @breif the Core Object Registration/Lookup Private Interface
- *
+ * @brief the Core Object Registration/Lookup Private Interface
* @author Copyright (c) 2001,2002, Derek Atkins <warlord at MIT.EDU>
*/
@@ -32,7 +36,7 @@
#include "qofbook.h"
#include "qofobject.h"
-/* To be called from within the book */
+/** To be called from within the book */
void qof_object_book_begin (QofBook *book);
void qof_object_book_end (QofBook *book);
@@ -41,3 +45,5 @@
#endif /* QOF_OBJECT_P_H_ */
/** @} */
+/** @} */
+/** @} */
Index: Query.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Query.c,v
retrieving revision 1.118.4.3
retrieving revision 1.118.4.4
diff -Lsrc/engine/Query.c -Lsrc/engine/Query.c -u -r1.118.4.3 -r1.118.4.4
--- src/engine/Query.c
+++ src/engine/Query.c
@@ -266,7 +266,7 @@
switch (how) {
case QOF_GUID_MATCH_ANY:
case QOF_GUID_MATCH_NONE:
- param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_QUERY_PARAM_GUID, NULL);
+ param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_PARAM_GUID, NULL);
break;
case QOF_GUID_MATCH_ALL:
param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_SPLITLIST,
@@ -524,11 +524,11 @@
return;
if (!safe_strcmp (id_type, GNC_ID_SPLIT))
- param_list = qof_query_build_param_list (QOF_QUERY_PARAM_GUID, NULL);
+ param_list = qof_query_build_param_list (QOF_PARAM_GUID, NULL);
else if (!safe_strcmp (id_type, GNC_ID_TRANS))
- param_list = qof_query_build_param_list (SPLIT_TRANS, QOF_QUERY_PARAM_GUID, NULL);
+ param_list = qof_query_build_param_list (SPLIT_TRANS, QOF_PARAM_GUID, NULL);
else if (!safe_strcmp (id_type, GNC_ID_ACCOUNT))
- param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_QUERY_PARAM_GUID, NULL);
+ param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_PARAM_GUID, NULL);
else
PERR ("Invalid match type: %s", id_type);
Index: Scrub.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Scrub.h,v
retrieving revision 1.17.4.1
retrieving revision 1.17.4.2
diff -Lsrc/engine/Scrub.h -Lsrc/engine/Scrub.h -u -r1.17.4.1 -r1.17.4.2
--- src/engine/Scrub.h
+++ src/engine/Scrub.h
@@ -20,18 +20,31 @@
* *
\********************************************************************/
+/** @addtogroup Engine
+ @{ */
+/** @addtogroup Scrub
+ Data scrubbing, repairing and forward migration routines.
+ These routines check and repair data, making sure that it
+ is in a format that the current version of the GnuCash
+ Engine likes. These routines serve both to provide backwards
+ compatibility with older versions of GnuCash, and to fix
+ or at least paper over possible current problems.
+
+ It is typically expected that the scrub routines are run
+ over newly imported data, as well as during data file input.
+
+ In some cases, it is entirely appropriate to invoke these
+ routines from the GUI, to validate that the user input
+ through the GUI is in a format that the system likes.
+ This includes things like balancing individual transactions,
+ or assigning splits to lots, so that capital gains can be
+ computed.
+ @{ */
+
/** @file Scrub.h
- *
- * Provides a set of functions and utilities for checking and
- * repairing (formerly called 'scrubbing clean') single-entry accounts
- * so that they can be promoted into self-consistent, clean
- * double-entry accounts. Basically and additionally, this file
- * collects all functions that turn old (deprecated) data structures
- * into the current new data model.
- *
- * HISTORY:
- * Created by Linas Vepstas December 1998
- * Copyright (c) 1998-2000, 2003 Linas Vepstas <linas at linas.org>
+ * @brief convert single-entry accounts to clean double-entry
+ * @author Created by Linas Vepstas December 1998
+ * @author Copyright (c) 1998-2000, 2003 Linas Vepstas <linas at linas.org>
*/
#ifndef XACC_SCRUB_H
@@ -40,27 +53,41 @@
#include "Group.h"
#include "gnc-engine.h"
-/** The ScrubOrphans() methods search for transacations that contain
- * splits that do not have a parent account. These "orphaned splits"
- * are placed into an "orphan account" which the user will have to
- * go into and clean up. Kind of like the unix "Lost+Found" directory
- * for orphaned inodes.
- *
- * The xaccTransScrubOrphans() method scrubs only the splits in the
+/** @name Double-Entry Scrubbing
+ Convert single-entry accounts to clean double-entry
+
+ Provides a set of functions and utilities for checking and
+ repairing (formerly called 'scrubbing clean') single-entry accounts
+ so that they can be promoted into self-consistent, clean
+ double-entry accounts. Basically and additionally, this file
+ collects all functions that turn old (deprecated) data structures
+ into the current new data model.
+
+ The ScrubOrphans() methods search for transacations that contain
+ splits that do not have a parent account. These "orphaned splits"
+ are placed into an "orphan account" which the user will have to
+ go into and clean up. Kind of like the unix "Lost+Found" directory
+ for orphaned inodes.
+ @{ */
+
+/** The xaccTransScrubOrphans() method scrubs only the splits in the
* given transaction.
- *
- * The xaccAccountScrubOrphans() method performs this scrub only for the
- * indicated account, and not for any of its children.
- *
- * The xaccAccountTreeScrubOrphans() method performs this scrub for the
- * indicated account and its children.
- *
- * The xaccGroupScrubOrphans() method performs this scrub for the
- * child accounts of this group.
*/
void xaccTransScrubOrphans (Transaction *trans);
+
+/** The xaccAccountScrubOrphans() method performs this scrub only for the
+ * indicated account, and not for any of its children.
+ */
void xaccAccountScrubOrphans (Account *acc);
+
+/** The xaccAccountTreeScrubOrphans() method performs this scrub for the
+ * indicated account and its children.
+ */
void xaccAccountTreeScrubOrphans (Account *acc);
+
+/** The xaccGroupScrubOrphans() method performs this scrub for the
+ * child accounts of this group.
+ */
void xaccGroupScrubOrphans (AccountGroup *grp);
/** The xaccSplitScrub method ensures that if this split has the same
@@ -121,3 +148,6 @@
void xaccGroupScrubQuoteSources (AccountGroup *group, gnc_commodity_table *table);
#endif /* XACC_SCRUB_H */
+/** @} */
+/** @} */
+/** @} */
Index: kvp-scm.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp-scm.c,v
retrieving revision 1.11.4.1
retrieving revision 1.11.4.2
diff -Lsrc/engine/kvp-scm.c -Lsrc/engine/kvp-scm.c -u -r1.11.4.1 -r1.11.4.2
--- src/engine/kvp-scm.c
+++ src/engine/kvp-scm.c
@@ -49,9 +49,9 @@
{
char *newstr;
KvpValue *ret;
- newstr = gh_scm2newstr(val, NULL);
+ /* newstr = gh_scm2newstr(val, NULL); */
+ newstr = SCM_STRING_CHARS (val);
ret = kvp_value_new_string(newstr);
- free(newstr);
return ret;
}
else if(gw_wcp_p(val) &&
Index: gnc-engine-util.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine-util.h,v
retrieving revision 1.32.4.4
retrieving revision 1.32.4.5
diff -Lsrc/engine/gnc-engine-util.h -Lsrc/engine/gnc-engine-util.h -u -r1.32.4.4 -r1.32.4.5
--- src/engine/gnc-engine-util.h
+++ src/engine/gnc-engine-util.h
@@ -19,7 +19,7 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
\********************************************************************/
-/** @addtogroup Engine
+/** @addtogroup Utilities
@{ */
/** @file gnc-engine-util.h
@brief GnuCash engine utility functions
@@ -130,7 +130,7 @@
* cached the strings are just plain C strings.
*/
-/* get the gnc_string_cache. Create it if it doesn't exist already */
+/** Get the gnc_string_cache. Create it if it doesn't exist already */
GCache* gnc_engine_get_string_cache(void);
void gnc_engine_string_cache_destroy (void);
Index: gnc-commodity.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-commodity.h,v
retrieving revision 1.20.4.4
retrieving revision 1.20.4.5
diff -Lsrc/engine/gnc-commodity.h -Lsrc/engine/gnc-commodity.h -u -r1.20.4.4 -r1.20.4.5
--- src/engine/gnc-commodity.h
+++ src/engine/gnc-commodity.h
@@ -22,15 +22,22 @@
/** @addtogroup Engine
@{ */
+/** @addtogroup Commodity Commodities
+ A commodity is something of value that is easily tradeable or
+ sellable; for example, currencies, stocks, bonds, grain,
+ copper, and oil are all commodities. This file provides
+ an API for defining a commodities, and for working with
+ collections of commodities. All GnuCash financial transactions
+ must identify the commodity that is being traded.
+
+ @warning The system used here does not follow the object
+ handling and identification system (GUID's, Entities, etc.)
+ that the other parts of GnuCash use. The API really should be
+ ported over. This would allow us to get rid of the
+ commodity table reoutines defined below.
+
+ @{ */
/** @file gnc-commodity.h
- *
- * This file contains the functions to manipulate two different
- * objects. These are an object of type gnc_commodity, and an object
- * of type gnc_commodity_table. The gnc_commodity object corresponds
- * one-to-one with some type of tradable commodity; a currency, a
- * stock, a mutual fund, etc. The gnc_commodity_table object is a
- * database containing objects of type gnc_commodity.
- *
* @brief Commodity handling public routines
* @author Copyright (C) 2000 Bill Gribble
* @author Copyright (C) 2001 Linas Vepstas <linas at linas.org>
@@ -837,3 +844,4 @@
#endif /* GNC_COMMODITY_H */
/** @} */
+/** @} */
Index: qofgobj.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofgobj.c,v
retrieving revision 1.2.2.1
retrieving revision 1.2.2.2
diff -Lsrc/engine/qofgobj.c -Lsrc/engine/qofgobj.c -u -r1.2.2.1 -r1.2.2.2
--- src/engine/qofgobj.c
+++ src/engine/qofgobj.c
@@ -296,12 +296,14 @@
/* 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->create = NULL;
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;
+ class_def->version_cmp = NULL;
qof_object_register (class_def);
}
Index: qofclass.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.c,v
retrieving revision 1.1.6.1
retrieving revision 1.1.6.2
diff -Lsrc/engine/qofclass.c -Lsrc/engine/qofclass.c -u -r1.1.6.1 -r1.1.6.2
--- src/engine/qofclass.c
+++ src/engine/qofclass.c
@@ -33,7 +33,7 @@
static short module = MOD_QUERY;
-static GHashTable *paramTable = NULL;
+static GHashTable *classTable = NULL;
static GHashTable *sortTable = NULL;
static gboolean initialized = FALSE;
@@ -61,13 +61,13 @@
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
}
- ht = g_hash_table_lookup (paramTable, obj_name);
+ ht = g_hash_table_lookup (classTable, 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);
+ g_hash_table_insert (classTable, (char *)obj_name, ht);
}
/* At least right now, we allow dummy, paramterless objects,
@@ -89,7 +89,7 @@
if (initialized) return;
initialized = TRUE;
- paramTable = g_hash_table_new (g_str_hash, g_str_equal);
+ classTable = g_hash_table_new (g_str_hash, g_str_equal);
sortTable = g_hash_table_new (g_str_hash, g_str_equal);
}
@@ -99,8 +99,8 @@
if (!initialized) return;
initialized = FALSE;
- g_hash_table_foreach_remove (paramTable, clear_table, NULL);
- g_hash_table_destroy (paramTable);
+ g_hash_table_foreach_remove (classTable, clear_table, NULL);
+ g_hash_table_destroy (classTable);
g_hash_table_destroy (sortTable);
}
@@ -109,7 +109,7 @@
{
if (!obj_name) return FALSE;
- if (g_hash_table_lookup (paramTable, obj_name)) return TRUE;
+ if (g_hash_table_lookup (classTable, obj_name)) return TRUE;
return FALSE;
}
@@ -123,7 +123,7 @@
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
- ht = g_hash_table_lookup (paramTable, obj_name);
+ ht = g_hash_table_lookup (classTable, obj_name);
if (!ht)
{
PERR ("no object of type %s", obj_name);
@@ -186,4 +186,68 @@
return g_hash_table_lookup (sortTable, obj_name);
}
+/* ================================================================ */
+
+struct class_iterate {
+ QofClassForeachCB fcn;
+ gpointer data;
+};
+
+static void
+class_foreach_cb (gpointer key, gpointer item, gpointer arg)
+{
+ struct class_iterate *iter = arg;
+ QofIdTypeConst id = key;
+
+ iter->fcn (id, iter->data);
+}
+
+void
+qof_class_foreach (QofClassForeachCB cb, gpointer user_data)
+{
+ struct class_iterate iter;
+
+ if (!cb) return;
+ if (!classTable) return;
+
+ iter.fcn = cb;
+ iter.data = user_data;
+
+ g_hash_table_foreach (classTable, class_foreach_cb, &iter);
+}
+
+/* ================================================================ */
+
+struct parm_iterate {
+ QofParamForeachCB fcn;
+ gpointer data;
+};
+
+static void
+param_foreach_cb (gpointer key, gpointer item, gpointer arg)
+{
+ struct parm_iterate *iter = arg;
+ QofParam *parm = item;
+
+ iter->fcn (parm, iter->data);
+}
+
+void
+qof_class_param_foreach (QofIdTypeConst obj_name,
+ QofParamForeachCB cb, gpointer user_data)
+{
+ struct parm_iterate iter;
+ GHashTable *param_ht;
+
+ if (!obj_name || !cb) return;
+ if (!classTable) return;
+ param_ht = g_hash_table_lookup (classTable, obj_name);
+ if (!param_ht) return;
+
+ iter.fcn = cb;
+ iter.data = user_data;
+
+ g_hash_table_foreach (param_ht, param_foreach_cb, &iter);
+}
+
/* ============================= END OF FILE ======================== */
Index: Account.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Account.h,v
retrieving revision 1.110.4.5
retrieving revision 1.110.4.6
diff -Lsrc/engine/Account.h -Lsrc/engine/Account.h -u -r1.110.4.5 -r1.110.4.6
--- src/engine/Account.h
+++ src/engine/Account.h
@@ -19,6 +19,8 @@
\********************************************************************/
/** @addtogroup Engine
@{ */
+/** @addtogroup Account
+ @{ */
/** @file Account.h
@brief Account handling public routines
@author Copyright (C) 1997 Robin D. Clark
@@ -163,7 +165,7 @@
/** @name Account lookup and GUID routines */
/** @{ */
-/** deprecated */
+/** @deprecated */
#define xaccAccountGetBook(X) qof_instance_get_book(QOF_INSTANCE(X))
#define xaccAccountGetGUID(X) qof_entity_get_guid(QOF_ENTITY(X))
#define xaccAccountReturnGUID(X) (X ? *(qof_entity_get_guid(QOF_ENTITY(X))) : *(guid_null()))
@@ -250,7 +252,7 @@
void xaccAccountSetAutoInterestXfer (Account *account, gboolean value);
/** @} */
-/* @name Account Commodity setters/getters
+/** @name Account Commodity setters/getters
* Accounts are used to store an amount of 'something', that 'something'
* is called the 'commodity'. An account can only hold one kind of
* commodity. The following are used to get and set the commodity,
@@ -283,13 +285,13 @@
/** Set the account's commodity */
void xaccAccountSetCommodity (Account *account, gnc_commodity *comm);
-/* deprecated do not use */
+/** @deprecated do not use */
#define DxaccAccountSetSecurity xaccAccountSetCommodity
/** Get the account's commodity */
gnc_commodity * xaccAccountGetCommodity (Account *account);
-/* deprecated do not use */
+/** @deprecated do not use */
#define DxaccAccountGetSecurity xaccAccountGetCommodity
/** Return the SCU for the account. If a non-standard SCU has been
@@ -308,7 +310,7 @@
*/
void xaccAccountSetCommoditySCU (Account *account, int frac);
-/* deprecated -- do not use for future development */
+/** @deprecated -- do not use for future development */
#define xaccAccountSetCommoditySCUandFlag xaccAccountSetCommoditySCU
/** Set the flag indicating that this account uses a non-standard SCU. */
@@ -674,7 +676,7 @@
/*@}*/
-/** @name Account deprecated routines. */
+/** @name Deprecated Routines. */
/** @{ */
/** @deprecated The current API associates only one thing with an
@@ -728,3 +730,4 @@
#endif /* XACC_ACCOUNT_H */
/** @} */
+/** @} */
Index: kvp_frame.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp_frame.h,v
retrieving revision 1.22.4.6
retrieving revision 1.22.4.7
diff -Lsrc/engine/kvp_frame.h -Lsrc/engine/kvp_frame.h -u -r1.22.4.6 -r1.22.4.7
--- src/engine/kvp_frame.h
+++ src/engine/kvp_frame.h
@@ -18,24 +18,9 @@
* Boston, MA 02111-1307, USA gnu at gnu.org *
* *
\********************************************************************/
-/** @addtogroup Engine
- @{ */
-/** @file kvp_frame.h
- @brief A key-value frame system
- @author Copyright (C) 2000 Bill Gribble
- @author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
-*/
-
-#ifndef KVP_FRAME_H
-#define KVP_FRAME_H
+/** @addtogroup KVP
-#include <glib.h>
-
-#include "gnc-date.h"
-#include "gnc-numeric.h"
-#include "guid.h"
-
-/** a KvpFrame is a set of associations between character strings
+ * A KvpFrame is a set of associations between character strings
* (keys) and KvpValue structures. A KvpValue is a union with
* possible types enumerated in the KvpValueType enum, and includes,
* among other things, ints, doubles, strings, guid's, lists, time
@@ -61,10 +46,27 @@
* a key such as 'some/key' or 'some/./other/../key' because you
* may get unexpected results.
*
- * In almost all cases, you want to be using the kvp_frame_set_gint64()
- * routine or one of its brothers. Most of the other routines provide
- * only low-level access.
- */
+ * To set a value into a frame, you will want to use one of the
+ * kvp_frame_set_xxx() routines. Most of the other routines provide
+ * only low-level access that you probably shouldn't use.
+
+@{ */
+/** @file kvp_frame.h
+ @brief A key-value frame system
+ @author Copyright (C) 2000 Bill Gribble
+ @author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
+*/
+
+#ifndef KVP_FRAME_H
+#define KVP_FRAME_H
+
+#include <glib.h>
+
+#include "gnc-date.h"
+#include "gnc-numeric.h"
+#include "guid.h"
+
+/** Opaque frame structure */
typedef struct _KvpFrame KvpFrame;
/** A KvpValue is a union with possible types enumerated in the
Index: Transaction.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Transaction.c,v
retrieving revision 1.261.4.5
retrieving revision 1.261.4.6
diff -Lsrc/engine/Transaction.c -Lsrc/engine/Transaction.c -u -r1.261.4.5 -r1.261.4.6
--- src/engine/Transaction.c
+++ src/engine/Transaction.c
@@ -38,7 +38,6 @@
#include "TransactionP.h"
#include "TransLog.h"
#include "cap-gains.h"
-#include "gnc-be-utils.h"
#include "gnc-commodity.h"
#include "gnc-date.h"
#include "gnc-engine-util.h"
@@ -50,6 +49,7 @@
#include "messages.h"
#include "qofbackend-p.h"
+#include "qof-be-utils.h"
#include "qofbook.h"
#include "qofbook-p.h"
#include "qofclass.h"
@@ -674,13 +674,12 @@
check_open (s->parent);
s->amount = double_to_gnc_numeric(amt, get_commodity_denom(s),
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
s->value = double_to_gnc_numeric(price * amt, get_currency_denom(s),
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
SET_GAINS_A_VDIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
void
@@ -691,13 +690,12 @@
ENTER (" ");
check_open (s->parent);
- s->amount = gnc_numeric_convert(amt, get_commodity_denom(s), GNC_RND_ROUND);
+ s->amount = gnc_numeric_convert(amt, get_commodity_denom(s), GNC_HOW_RND_ROUND);
s->value = gnc_numeric_mul(s->amount, price,
- get_currency_denom(s), GNC_RND_ROUND);
+ get_currency_denom(s), GNC_HOW_RND_ROUND);
SET_GAINS_A_VDIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
void
@@ -709,11 +707,10 @@
s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
price, get_currency_denom(s),
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
SET_GAINS_VDIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
void
@@ -722,7 +719,7 @@
gnc_numeric old_price, old_amt;
int commodity_denom = get_commodity_denom(s);
gnc_numeric amt = double_to_gnc_numeric(damt, commodity_denom,
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
if (!s) return;
ENTER (" ");
check_open (s->parent);
@@ -732,20 +729,19 @@
{
old_price = gnc_numeric_div(xaccSplitGetValue (s),
old_amt, GNC_DENOM_AUTO,
- GNC_DENOM_REDUCE);
+ GNC_HOW_DENOM_REDUCE);
}
else {
old_price = gnc_numeric_create(1, 1);
}
s->amount = gnc_numeric_convert(amt, commodity_denom,
- GNC_RND_NEVER);
+ GNC_HOW_RND_NEVER);
s->value = gnc_numeric_mul(s->amount, old_price,
- get_currency_denom(s), GNC_RND_ROUND);
+ get_currency_denom(s), GNC_HOW_RND_ROUND);
SET_GAINS_A_VDIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
@@ -757,11 +753,10 @@
s->amount.num, s->amount.denom, amt.num, amt.denom);
check_open (s->parent);
- s->amount = gnc_numeric_convert(amt, get_commodity_denom(s), GNC_RND_ROUND);
+ s->amount = gnc_numeric_convert(amt, get_commodity_denom(s), GNC_HOW_RND_ROUND);
SET_GAINS_ADIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
@@ -773,11 +768,10 @@
s->value.num, s->value.denom, amt.num, amt.denom);
check_open (s->parent);
- s->value = gnc_numeric_convert(amt, get_currency_denom(s), GNC_RND_ROUND);
+ s->value = gnc_numeric_convert(amt, get_currency_denom(s), GNC_HOW_RND_ROUND);
SET_GAINS_VDIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
/********************************************************************\
@@ -1250,15 +1244,15 @@
if(gnc_commodity_equiv(commodity, base_currency)) {
s->amount = gnc_numeric_convert(value,
get_commodity_denom(s),
- GNC_RND_NEVER);
+ GNC_HOW_RND_NEVER);
}
s->value = gnc_numeric_convert(value,
get_currency_denom(s),
- GNC_RND_NEVER);
+ GNC_HOW_RND_NEVER);
}
else if (gnc_commodity_equiv(commodity, base_currency)) {
s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
- GNC_RND_NEVER);
+ GNC_HOW_RND_NEVER);
}
else {
PERR ("inappropriate base currency %s "
@@ -1271,7 +1265,6 @@
SET_GAINS_A_VDIRTY(s);
mark_split (s);
- /* gen_event (s); No! only in TransCommit() ! */
}
gnc_numeric
@@ -1356,12 +1349,12 @@
if (gnc_commodity_equiv(currency, base_currency))
{
value = gnc_numeric_add(value, xaccSplitGetValue(s),
- GNC_DENOM_AUTO, GNC_DENOM_LCD);
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
else if (gnc_commodity_equiv(commodity, base_currency))
{
value = gnc_numeric_add(value, xaccSplitGetAmount(s),
- GNC_DENOM_AUTO, GNC_DENOM_LCD);
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
else {
PERR ("inconsistent currencies\n"
@@ -1377,7 +1370,7 @@
* doesn't mean the denominators are the same! */
value = gnc_numeric_convert (value,
gnc_commodity_get_fraction (base_currency),
- GNC_RND_ROUND);
+ GNC_HOW_RND_ROUND);
LEAVE (" total=%lld/%lld", value.num, value.denom);
return value;
@@ -1409,7 +1402,7 @@
Account *a = xaccSplitGetAccount (s);
if (a == account)
total = gnc_numeric_add (total, xaccSplitGetValue (s),
- GNC_DENOM_AUTO, GNC_DENOM_LCD);
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
return total;
}
@@ -1446,13 +1439,12 @@
{
Split *s = splits->data;
s->value = gnc_numeric_convert(xaccSplitGetValue(s),
- fraction, GNC_RND_ROUND);
+ fraction, GNC_HOW_RND_ROUND);
SET_GAINS_VDIRTY(s);
}
}
mark_trans (trans);
- /* gen_event_trans (trans); No! only in TransCommit() ! */
}
/********************************************************************\
@@ -1461,7 +1453,10 @@
void
xaccTransBeginEdit (Transaction *trans)
{
- GNC_BEGIN_EDIT(&trans->inst)
+ QOF_BEGIN_EDIT(&trans->inst)
+
+ if (qof_book_shutting_down(trans->inst.book))
+ return;
xaccOpenLog ();
xaccTransWriteLog (trans, 'B');
@@ -1481,7 +1476,8 @@
if (!trans) return;
check_open (trans);
- if (xaccTransGetReadOnly (trans)) return;
+ if (xaccTransGetReadOnly (trans) &&
+ !qof_book_shutting_down(trans->inst.book)) return;
trans->inst.do_free = TRUE;
}
@@ -1509,13 +1505,17 @@
do_destroy (Transaction *trans)
{
SplitList *node;
+ gboolean shutting_down;
/* If there are capital-gains transactions associated with this,
* they need to be destroyed too. */
destroy_gains (trans);
+ shutting_down = qof_book_shutting_down(trans->inst.book);
+
/* Make a log in the journal before destruction. */
- xaccTransWriteLog (trans, 'D');
+ if (! shutting_down)
+ xaccTransWriteLog (trans, 'D');
gnc_engine_gen_event (&trans->inst.entity, GNC_EVENT_DESTROY);
@@ -1525,7 +1525,8 @@
mark_split (split);
xaccAccountRemoveSplit (split->acc, split);
- xaccAccountRecomputeBalance (split->acc);
+ if (!shutting_down)
+ xaccAccountRecomputeBalance (split->acc);
gen_event (split);
xaccFreeSplit (split);
@@ -1551,7 +1552,7 @@
xaccTransCommitEdit (Transaction *trans)
{
QofBackend *be;
- GNC_COMMIT_EDIT_PART1 (&trans->inst);
+ QOF_COMMIT_EDIT_PART1 (&trans->inst);
/* We increment this for the duration of the call
* so other functions don't result in a recursive
@@ -1591,7 +1592,7 @@
if (!trans->splits) trans->inst.do_free = TRUE;
/* XXX the code below is almost identical to
- * GNC_COMMIT_EDIT_PART1 (&trans->inst);
+ * QOF_COMMIT_EDIT_PART1 (&trans->inst);
* except for the rollback bits */
/* See if there's a backend. If there is, invoke it. */
be = qof_book_get_backend (trans->inst.book);
@@ -1604,7 +1605,7 @@
errcode = qof_backend_get_error (be);
} while (ERR_BACKEND_NO_ERR != errcode);
- (be->commit) (be, GNC_ID_TRANS, trans);
+ (be->commit) (be, &(trans->inst));
errcode = qof_backend_get_error (be);
if (ERR_BACKEND_NO_ERR != errcode)
@@ -1673,7 +1674,7 @@
int i;
ENTER ("trans addr=%p\n", trans);
- GNC_COMMIT_EDIT_PART1(&trans->inst);
+ QOF_COMMIT_EDIT_PART1(&trans->inst);
/* We increment this for the duration of the call
* so other functions don't result in a recursive
@@ -1843,7 +1844,7 @@
errcode = qof_backend_get_error (be);
} while (ERR_BACKEND_NO_ERR != errcode);
- (be->rollback) (be, GNC_ID_TRANS, trans);
+ (be->rollback) (be, &(trans->inst));
errcode = qof_backend_get_error (be);
if (ERR_BACKEND_MOD_DESTROY == errcode)
@@ -1952,7 +1953,15 @@
/* Note: split is removed from lot when its removed from accoount */
xaccAccountRemoveSplit (acc, split);
- xaccAccountRecomputeBalance (acc);
+
+ /* If we're shutting down then destroy the transaction, too, and
+ * don't recompute the balance.
+ */
+ if (qof_book_shutting_down (split->parent->inst.book))
+ xaccTransDestroy (trans);
+ else
+ xaccAccountRecomputeBalance (acc);
+
gen_event (split);
xaccFreeSplit (split);
@@ -1989,7 +1998,7 @@
gnc_numeric new_value;
new_value = gnc_numeric_convert(xaccSplitGetValue(split),
- fraction, GNC_RND_ROUND);
+ fraction, GNC_HOW_RND_ROUND);
if (gnc_numeric_check (new_value) == GNC_ERROR_OK)
split->value = new_value;
SET_GAINS_VDIRTY(split);
@@ -2325,7 +2334,6 @@
*dadate = val;
mark_trans(trans);
- /* gen_event_trans (trans); No! only in TransCommit() ! */
/* Because the date has changed, we need to make sure that each of
* the splits is properly ordered in each of their accounts. We
@@ -2661,7 +2669,6 @@
tmp = g_cache_insert(gnc_engine_get_string_cache(), (gpointer) memo);
g_cache_remove(gnc_engine_get_string_cache(), split->memo);
split->memo = tmp;
- /* gen_event (split); No! only in TransCommit() ! */
}
void
@@ -2674,7 +2681,6 @@
tmp = g_cache_insert(gnc_engine_get_string_cache(), (gpointer) actn);
g_cache_remove(gnc_engine_get_string_cache(), split->action);
split->action = tmp;
- /* gen_event (split); No! only in TransCommit() ! */
}
void
@@ -2703,7 +2709,6 @@
split->reconciled = recn;
mark_split (split);
xaccAccountRecomputeBalance (account);
- /* gen_event (split); No! only in TransCommit() ! */
}
}
@@ -2715,7 +2720,6 @@
split->date_reconciled.tv_sec = secs;
split->date_reconciled.tv_nsec = 0;
- /* gen_event (split); No! only in TransCommit() ! */
}
void
@@ -2725,7 +2729,6 @@
check_open (split->parent);
split->date_reconciled = *ts;
- /* gen_event (split); No! only in TransCommit() ! */
}
void
@@ -2802,7 +2805,7 @@
gnc_numeric
xaccSplitGetSharePrice (const Split * split)
{
- gnc_numeric amt, val;
+ gnc_numeric amt, val, price;
if(!split)
{
return gnc_numeric_create(1, 1);
@@ -2823,10 +2826,22 @@
}
return gnc_numeric_create(0, 1);
}
- return gnc_numeric_div(val, amt,
+ price = gnc_numeric_div(val, amt,
GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(PRICE_SIGFIGS) |
- GNC_RND_ROUND);
+ GNC_HOW_DENOM_SIGFIGS(PRICE_SIGFIGS) |
+ GNC_HOW_RND_ROUND);
+
+ /* During random checks we can get some very weird prices. Let's
+ * handle some overflow and other error conditions by returning
+ * zero. But still print an error to let us know it happened.
+ */
+ if (gnc_numeric_check(price)) {
+ PERR("Computing Shares Price Failed (%d): [ %lld / %lld ] / [ %lld / %lld ]",
+ gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
+ return gnc_numeric_create(0,1);
+ }
+
+ return price;
}
/********************************************************************\
@@ -2861,7 +2876,6 @@
kvp_frame_set_str(s->kvp_data, "split-type", "stock-split");
SET_GAINS_VDIRTY(s);
mark_split(s);
- /* gen_event (s); No! only in TransCommit() ! */
}
@@ -3187,12 +3201,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_SPLIT,
type_label: "Split",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: NULL,
mark_clean: NULL,
foreach: qof_collection_foreach,
- printable: (const char* (*)(gpointer)) xaccSplitGetMemo
+ printable: (const char* (*)(gpointer)) xaccSplitGetMemo,
+ version_cmp: NULL,
};
static gpointer
@@ -3258,8 +3274,8 @@
{ SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
{ SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
{ SPLIT_KVP, QOF_TYPE_KVP, (QofAccessFunc)xaccSplitGetSlots, NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
{ NULL },
};
@@ -3281,12 +3297,14 @@
interface_version: QOF_OBJECT_VERSION,
e_type: GNC_ID_TRANS,
type_label: "Transaction",
+ create: NULL,
book_begin: NULL,
book_end: NULL,
is_dirty: NULL,
mark_clean: NULL,
foreach: qof_collection_foreach,
- printable: (const char* (*)(gpointer)) xaccTransGetDescription
+ printable: (const char* (*)(gpointer)) xaccTransGetDescription,
+ version_cmp: (int (*)(gpointer,gpointer)) qof_instance_version_cmp,
};
static gboolean
@@ -3314,8 +3332,8 @@
{ TRANS_VOID_TIME, QOF_TYPE_DATE, (QofAccessFunc)xaccTransGetVoidTime,NULL },
{ TRANS_SPLITLIST, GNC_ID_SPLIT, (QofAccessFunc)xaccTransGetSplitList,NULL },
{ TRANS_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots,NULL },
- { QOF_QUERY_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book,NULL },
- { QOF_QUERY_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid,NULL },
+ { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book,NULL },
+ { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid,NULL },
{ NULL },
};
Index: SX-book.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/SX-book.h,v
retrieving revision 1.4.16.1
retrieving revision 1.4.16.2
diff -Lsrc/engine/SX-book.h -Lsrc/engine/SX-book.h -u -r1.4.16.1 -r1.4.16.2
--- src/engine/SX-book.h
+++ src/engine/SX-book.h
@@ -20,7 +20,10 @@
\********************************************************************/
/**
- * @addtogroup Engine_SchedXaction
+ * @addtogroup Engine
+ * @{ */
+/**
+ * @addtogroup SchedXaction
* @{ */
/**
* @file SX-book.h
@@ -57,3 +60,4 @@
#endif /* GNC_SX_BOOK_H */
/** @} */
+/** @} */
Index: Scrub2.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Scrub2.h,v
retrieving revision 1.8.20.2
retrieving revision 1.8.20.3
diff -Lsrc/engine/Scrub2.h -Lsrc/engine/Scrub2.h -u -r1.8.20.2 -r1.8.20.3
--- src/engine/Scrub2.h
+++ src/engine/Scrub2.h
@@ -21,11 +21,20 @@
/** @addtogroup Engine
@{ */
+/** @addtogroup Scrub Data Validation
+ @{ */
/** @file Scrub2.h
- * @breif Utilities to Convert Stock Accounts to use Lots
+ * @brief Utilities to Convert Stock Accounts to use Lots
* @author Created by Linas Vepstas March 2003
* @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
- *
+ */
+
+#ifndef XACC_SCRUB2_H
+#define XACC_SCRUB2_H
+
+#include "gnc-engine.h"
+
+/** @name Lot Management Routines
* Provides the low-level API for checking and repairing ('scrubbing
* clean') the usage of Lots and lot balances in stock and commodity
* accounts. Broken lots are repaired using a first-in, first-out
@@ -35,12 +44,7 @@
* only one particular task needed to clean up a Lot. To clean up a
* Lot as a whole, you almost certainly want to use one of the
* high-level API routines from the Scrub3.h file.
- */
-
-#ifndef XACC_SCRUB2_H
-#define XACC_SCRUB2_H
-
-#include "gnc-engine.h"
+ @{ */
/** The xaccAccountAssignLots() routine will walk over all of
* the splits in an account, and make sure that each belongs
@@ -121,3 +125,5 @@
#endif /* XACC_SCRUB2_H */
/** @} */
+/** @} */
+/** @} */
Index: qofclass.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.h,v
retrieving revision 1.1.6.1
retrieving revision 1.1.6.2
diff -Lsrc/engine/qofclass.h -Lsrc/engine/qofclass.h -u -r1.1.6.1 -r1.1.6.2
--- src/engine/qofclass.h
+++ src/engine/qofclass.h
@@ -20,17 +20,44 @@
* *
\********************************************************************/
-/** @file qofclass.h
- @brief API for registering paramters on objects
- @author Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU>
- @author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
+/** @addtogroup Object
+ @{ */
+/** @addtogroup Class
This file defines a class messaging system reminiscent of
traditional OO-style setter and getter interfaces to object
properties. A C-language object can declare a collection
of setters and getters on itself that can then be used
to perform run-time (as opposed to compile-time) bindings
to the object.
+
+ To put it differently, a QOF class is a set of parameter
+ getters and setters that are associated with an object type.
+ Given a pointer to some thing, the setters and getters can
+ be used to get and set values out of that thing. Note
+ that the pointer to "some thing" need not be a pointer
+ to a QOF Entity or Instance (although QOF classes are
+ more interesting when used with Entities/Instances).
+ What "some thing" is defined entirely by the programmer
+ declaring a new QOF Class.
+
+ Because a QOF Class associates getters and setters with
+ a type, one can then ask, at run time, what paramters
+ are associated with a given type, even if those paramters
+ were not known at compile time. Thus, a QOF Class is
+ sort-of like a DynAny implementation. QOF classes can
+ be used to provide "object introspection", i.e. asking
+ object to describe itself.
+
+ The QOF Query subsystem depends on QOF classes having been
+ declared; the Query uses the getters to get values associated
+ with particular instances.
+@{ */
+
+/** @file qofclass.h
+ @brief API for registering paramters on objects
+ @author Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU>
+ @author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
*/
#ifndef QOF_CLASS_H
@@ -42,16 +69,16 @@
* Note that QofIdTypes may also be used. */
#define QOF_TYPE_STRING "string"
-#define QOF_TYPE_DATE "date"
+#define QOF_TYPE_DATE "date"
#define QOF_TYPE_NUMERIC "numeric"
#define QOF_TYPE_DEBCRED "debcred"
-#define QOF_TYPE_GUID "guid"
-#define QOF_TYPE_INT32 "gint32"
-#define QOF_TYPE_INT64 "gint64"
+#define QOF_TYPE_GUID "guid"
+#define QOF_TYPE_INT32 "gint32"
+#define QOF_TYPE_INT64 "gint64"
#define QOF_TYPE_DOUBLE "double"
#define QOF_TYPE_BOOLEAN "boolean"
-#define QOF_TYPE_KVP "kvp"
-#define QOF_TYPE_CHAR "character"
+#define QOF_TYPE_KVP "kvp"
+#define QOF_TYPE_CHAR "character"
/** Type of Paramters (String, Date, Numeric, GUID, etc.) */
typedef const char * QofType;
@@ -89,9 +116,9 @@
* 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).
+ * -- param_userdata is a place where the object author can place any
+ * desired object-author-defined data (and thus can be used by the
+ * author-defined setter/getter).
*
* Either the getter or the setter may be NULL.
*
@@ -115,24 +142,26 @@
* In particular, it registers the set of setters and getters for
* controlling the object. The getters are typically used by the
* query subsystem to query type specific data. Note that there
- * is no particular reqquirement for there to be a setter for every
- * getter or even v.v. nor is there any requeirement for these to
- * map 'cleanly' or orthogonaly to the actual object design.
+ * is no particular requirement for there to be a setter for every
+ * getter or even vice-versa, nor is there any requeirement for these
+ * to map 'cleanly' or orthogonaly to the underlying object. The
+ * parameters are really just a set of value setting and getting
+ * routines.
*
* The "params" argument must be a NULL-terminated array of QofParam.
* It may be NULL if there are no parameters to be registered.
*/
void qof_class_register (QofIdTypeConst obj_name,
- QofSortFunc default_sort_fcn,
- const QofParam *params);
+ QofSortFunc default_sort_fcn,
+ const QofParam *params);
/** An example:
*
- * #define MY_OBJ_MEMO "memo"
- * #define MY_OBJ_VALUE "value"
- * #define MY_OBJ_DATE "date"
- * #define MY_OBJ_ACCOUNT "account"
- * #define MY_OBJ_TRANS "trans"
+ * #define MY_OBJ_MEMO "memo"
+ * #define MY_OBJ_VALUE "value"
+ * #define MY_OBJ_DATE "date"
+ * #define MY_OBJ_ACCOUNT "account"
+ * #define MY_OBJ_TRANS "trans"
*
* static QofParam myParams[] = {
* { MY_OBJ_MEMO, QOF_TYPE_STRING, myMemoGetter, NULL },
@@ -152,19 +181,38 @@
/** Return the core datatype of the specified object's parameter */
QofType qof_class_get_parameter_type (QofIdTypeConst obj_name,
- const char *param_name);
+ const char *param_name);
/** Return the registered Parameter Definition for the requested parameter */
const QofParam * qof_class_get_parameter (QofIdTypeConst obj_name,
- const char *parameter);
+ const char *parameter);
/** Return the object's parameter getter function */
QofAccessFunc qof_class_get_parameter_getter (QofIdTypeConst obj_name,
- const char *parameter);
+ const char *parameter);
/** Return the object's parameter setter function */
QofSetterFunc qof_class_get_parameter_setter (QofIdTypeConst obj_name,
- const char *parameter);
+ const char *parameter);
+
+/** Type definition for the class callback function. */
+typedef void (*QofClassForeachCB) (QofIdTypeConst, gpointer);
+
+/** Call the callback once for each object class that is registered
+ * with the system. The 'user_data' is passed back to the callback.
+ */
+void qof_class_foreach (QofClassForeachCB, gpointer user_data);
+
+/** Type definition for the paramter callback function. */
+typedef void (*QofParamForeachCB) (QofParam *, gpointer user_data);
+
+/** Call the callback once for each parameter on the indicated
+ * object class. The 'user_data' is passed back to the callback.
+ */
+void qof_class_param_foreach (QofIdTypeConst obj_name,
+ QofParamForeachCB, gpointer user_data);
#endif /* QOF_CLASS_H */
+/* @} */
+/* @} */
Index: engine-helpers.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/engine-helpers.c,v
retrieving revision 1.24.4.3
retrieving revision 1.24.4.4
diff -Lsrc/engine/engine-helpers.c -Lsrc/engine/engine-helpers.c -u -r1.24.4.3 -r1.24.4.4
--- src/engine/engine-helpers.c
+++ src/engine/engine-helpers.c
@@ -131,30 +131,44 @@
}
GUID
-gnc_scm2guid(SCM guid_scm) {
- char string[GUID_ENCODING_LENGTH + 1];
+gnc_scm2guid(SCM guid_scm)
+{
GUID guid;
+ char * str;
- gh_get_substr(guid_scm, string, 0, GUID_ENCODING_LENGTH);
- string[GUID_ENCODING_LENGTH] = '\0';
-
- string_to_guid(string, &guid);
+ /* char string[GUID_ENCODING_LENGTH + 1]; */
+ /* gh_get_substr(guid_scm, string, 0, GUID_ENCODING_LENGTH); */
+ /* string[GUID_ENCODING_LENGTH] = '\0'; */
+ if (GUID_ENCODING_LENGTH != SCM_STRING_LENGTH (guid_scm))
+ {
+ return *guid_null();
+ }
+ str = SCM_STRING_CHARS (guid_scm);
+ string_to_guid(str, &guid);
return guid;
}
int
-gnc_guid_p(SCM guid_scm) {
- char string[GUID_ENCODING_LENGTH + 1];
+gnc_guid_p(SCM guid_scm)
+{
GUID guid;
+ char * str;
if (!SCM_STRINGP(guid_scm))
return FALSE;
- gh_get_substr(guid_scm, string, 0, GUID_ENCODING_LENGTH);
- string[GUID_ENCODING_LENGTH] = '\0';
+ /* char string[GUID_ENCODING_LENGTH + 1]; */
+ /* gh_get_substr(guid_scm, string, 0, GUID_ENCODING_LENGTH); */
+ /* string[GUID_ENCODING_LENGTH] = '\0'; */
+
+ if (GUID_ENCODING_LENGTH != SCM_STRING_LENGTH (guid_scm))
+ {
+ return FALSE;
+ }
+ str = SCM_STRING_CHARS (guid_scm);
- return string_to_guid(string, &guid);
+ return string_to_guid(str, &guid);
}
@@ -315,7 +329,8 @@
gnc_scm2acct_match_how (SCM how_scm)
{
QofGuidMatch res;
- char *how = gh_symbol2newstr (how_scm, NULL);
+ /* char *how = gh_symbol2newstr (how_scm, NULL); */
+ char *how = SCM_SYMBOL_CHARS (how_scm);
if (!safe_strcmp (how, "acct-match-all"))
res = QOF_GUID_MATCH_ALL;
@@ -327,8 +342,6 @@
PINFO ("invalid account match: %s", how);
res = QOF_GUID_MATCH_NULL;
}
-
- if (how) free (how);
return res;
}
@@ -336,7 +349,8 @@
gnc_scm2amt_match_how (SCM how_scm)
{
QofQueryCompare res;
- char *how = gh_symbol2newstr (how_scm, NULL);
+ /* char *how = gh_symbol2newstr (how_scm, NULL); */
+ char *how = SCM_SYMBOL_CHARS (how_scm);
if (!safe_strcmp (how, "amt-match-atleast"))
res = QOF_COMPARE_GTE;
@@ -349,7 +363,6 @@
res = QOF_COMPARE_EQUAL;
}
- if (how) free (how);
return res;
}
@@ -357,7 +370,8 @@
gnc_scm2kvp_match_how (SCM how_scm)
{
QofQueryCompare res;
- char *how = gh_symbol2newstr (how_scm, NULL);
+ /* char *how = gh_symbol2newstr (how_scm, NULL); */
+ char *how = SCM_SYMBOL_CHARS (how_scm);
if (!safe_strcmp (how, "kvp-match-lt"))
res = QOF_COMPARE_LT;
@@ -373,8 +387,6 @@
PINFO ("invalid kvp match: %s", how);
res = QOF_COMPARE_EQUAL;
}
-
- if (how) free (how);
return res;
}
@@ -422,15 +434,14 @@
if (!SCM_NULLP (SCM_CDR (how_scm)))
return FALSE;
- how = gh_symbol2newstr (SCM_CAR (how_scm), NULL);
+ /* how = gh_symbol2newstr (SCM_CAR (how_scm), NULL); */
+ how = SCM_SYMBOL_CHARS (SCM_CAR(how_scm));
if (!safe_strcmp (how, "balance-match-balanced"))
*resp = TRUE;
else
*resp = FALSE;
- if (how) free (how);
-
return TRUE;
}
@@ -443,7 +454,8 @@
if (!SCM_LISTP (where_scm))
return NULL;
- where = gh_symbol2newstr (SCM_CAR (where_scm), NULL);
+ /* where = gh_symbol2newstr (SCM_CAR (where_scm), NULL); */
+ where = SCM_SYMBOL_CHARS (SCM_CAR(where_scm));
if (!safe_strcmp (where, "kvp-match-split"))
res = GNC_ID_SPLIT;
@@ -455,8 +467,6 @@
PINFO ("Unknown kvp-match-where: %s", where);
res = NULL;
}
-
- if (where) free (where);
return res;
}
@@ -516,7 +526,7 @@
gnc_query_numeric2scm (gnc_numeric val)
{
return scm_cons (gnc_gint64_to_scm (val.num),
- gnc_gint64_to_scm (val.denom));
+ gnc_gint64_to_scm (val.denom));
}
static gboolean
@@ -535,7 +545,7 @@
denom = SCM_CDR (pair);
return gnc_numeric_create (gnc_scm_to_gint64 (num),
- gnc_scm_to_gint64 (denom));
+ gnc_scm_to_gint64 (denom));
}
static SCM
@@ -571,9 +581,9 @@
if (!SCM_STRINGP (key_scm))
break;
- tmp = gh_scm2newstr (key_scm, NULL);
+ /* tmp = gh_scm2newstr (key_scm, NULL); */
+ tmp = SCM_STRING_CHARS (key_scm);
key = g_strdup (tmp);
- if (tmp) free (tmp);
path = g_slist_prepend (path, key);
@@ -744,9 +754,9 @@
break;
case KVP_TYPE_STRING: {
- char *str = gh_scm2newstr (val_scm, NULL);
+ /* char *str = gh_scm2newstr (val_scm, NULL); */
+ char * str = SCM_STRING_CHARS (val_scm);
value = kvp_value_new_string (str);
- if (str) free (str);
break;
}
@@ -770,7 +780,7 @@
gnc_numeric n;
if (!gnc_query_numeric_p (val_scm))
- return NULL;
+ return NULL;
n = gnc_query_scm2numeric (val_scm);
@@ -844,20 +854,15 @@
if (!SCM_STRINGP (key_scm))
continue;
- key = gh_scm2newstr (key_scm, NULL);
+ /* key = gh_scm2newstr (key_scm, NULL); */
+ key = SCM_STRING_CHARS (key_scm);
if (!key)
continue;
value = gnc_scm2KvpValue (val_scm);
- if (!value)
- {
- free (key);
- continue;
- }
+ if (!value) continue;
kvp_frame_set_slot_nc (frame, key, value);
-
- free (key);
}
return frame;
@@ -870,7 +875,7 @@
QofQueryPredData *pd = NULL;
qt_scm = scm_cons (gnc_query_path2scm (qof_query_term_get_param_path (qt)),
- qt_scm);
+ qt_scm);
qt_scm = scm_cons (SCM_BOOL (qof_query_term_is_inverted (qt)), qt_scm);
pd = qof_query_term_get_pred_data (qt);
@@ -971,7 +976,8 @@
qt_scm = SCM_CDR (qt_scm);
if (!SCM_SYMBOLP (scm))
break;
- type = gh_symbol2newstr (scm, NULL);
+ /* type = gh_symbol2newstr (scm, NULL); */
+ type = SCM_SYMBOL_CHARS (scm);
/* QofCompareFunc */
scm = SCM_CAR (qt_scm);
@@ -982,47 +988,47 @@
/* Now compute the predicate */
- if (!safe_strcmp (type, QOF_TYPE_STRING)) {
+ if (!safe_strcmp (type, QOF_TYPE_STRING))
+ {
QofStringMatch options;
gboolean is_regex;
char *matchstring;
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
- if (SCM_NULLP (scm))
- break;
+ if (SCM_NULLP (scm)) break;
options = gnc_query_scm2string (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
- if (!SCM_BOOLP (scm))
- break;
+ if (!SCM_BOOLP (scm)) break;
is_regex = SCM_NFALSEP (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
- if (!SCM_STRINGP (scm))
- break;
- matchstring = gh_scm2newstr (scm, NULL);
+ if (!SCM_STRINGP (scm)) break;
- pd = qof_query_string_predicate (compare_how, matchstring,
- options, is_regex);
- free (matchstring);
+ /* matchstring = gh_scm2newstr (scm, NULL); */
+ matchstring = SCM_STRING_CHARS (scm);
- } else if (!safe_strcmp (type, QOF_TYPE_DATE)) {
+ pd = qof_query_string_predicate (compare_how, matchstring,
+ options, is_regex);
+ }
+ else if (!safe_strcmp (type, QOF_TYPE_DATE))
+ {
QofDateMatch options;
Timespec date;
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm))
- break;
+ break;
options = gnc_query_scm2date (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm))
- break;
+ break;
date = gnc_timepair2timespec (scm);
pd = qof_query_date_predicate (compare_how, options, date);
@@ -1034,13 +1040,13 @@
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm))
- break;
+ break;
options = gnc_query_scm2numericop (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (!gnc_query_numeric_p (scm))
- break;
+ break;
val = gnc_query_scm2numeric (scm);
pd = qof_query_numeric_predicate (compare_how, options, val);
@@ -1052,13 +1058,13 @@
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm))
- break;
+ break;
options = gnc_query_scm2guid (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (!SCM_LISTP (scm))
- break;
+ break;
guids = gnc_scm2guid_glist (scm);
pd = qof_query_guid_predicate (options, guids);
@@ -1071,7 +1077,7 @@
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm))
- break;
+ break;
val = gnc_scm_to_gint64 (scm);
pd = qof_query_int64_predicate (compare_how, val);
@@ -1082,7 +1088,7 @@
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (!SCM_NUMBERP (scm))
- break;
+ break;
val = scm_num2dbl (scm, __FUNCTION__);
pd = qof_query_double_predicate (compare_how, val);
@@ -1093,7 +1099,7 @@
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (!SCM_BOOLP (scm))
- break;
+ break;
val = SCM_NFALSEP (scm);
pd = qof_query_boolean_predicate (compare_how, val);
@@ -1105,33 +1111,34 @@
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm))
- break;
+ break;
options = gnc_query_scm2char (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (!SCM_STRINGP (scm))
- break;
- char_list = gh_scm2newstr (scm, NULL);
+ break;
+ /* char_list = gh_scm2newstr (scm, NULL); */
+ char_list = SCM_STRING_CHARS (scm);
pd = qof_query_char_predicate (options, char_list);
- free (char_list);
-
- } else if (!safe_strcmp (type, QOF_TYPE_KVP)) {
+ }
+ else if (!safe_strcmp (type, QOF_TYPE_KVP))
+ {
GSList *kvp_path;
KvpValue *value;
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (!SCM_LISTP (scm))
- break;
+ break;
kvp_path = gnc_query_scm2path (scm);
scm = SCM_CAR (qt_scm);
qt_scm = SCM_CDR (qt_scm);
if (SCM_NULLP (scm)) {
- gnc_query_path_free (kvp_path);
- break;
+ gnc_query_path_free (kvp_path);
+ break;
}
value = gnc_scm2KvpValue (scm);
@@ -1158,9 +1165,6 @@
gnc_query_path_free (path);
}
- if (type)
- free (type);
-
return q;
}
@@ -1184,7 +1188,8 @@
/* pd_type */
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
- pd_type = gh_symbol2newstr (scm, NULL);
+ /* pd_type = gh_symbol2newstr (scm, NULL); */
+ pd_type = SCM_SYMBOL_CHARS (scm);
/* pr_type */
if (SCM_NULLP (query_term_scm)) {
@@ -1193,7 +1198,8 @@
}
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
- pr_type = gh_symbol2newstr (scm, NULL);
+ /* pr_type = gh_symbol2newstr (scm, NULL); */
+ pr_type = SCM_SYMBOL_CHARS (scm);
/* sense */
if (SCM_NULLP (query_term_scm)) {
@@ -1214,8 +1220,8 @@
/* use_start */
if (SCM_NULLP (query_term_scm)) {
- PINFO ("null use_start");
- break;
+ PINFO ("null use_start");
+ break;
}
scm = SCM_CAR (query_term_scm);
@@ -1224,7 +1230,7 @@
/* start */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1232,7 +1238,7 @@
/* use_end */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1240,7 +1246,7 @@
/* end */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1250,7 +1256,9 @@
ok = TRUE;
- } else if (!safe_strcmp (pd_type, "pd-amount")) {
+ }
+ else if (!safe_strcmp (pd_type, "pd-amount"))
+ {
QofQueryCompare how;
QofNumericMatch amt_sgn;
double amount;
@@ -1258,51 +1266,54 @@
/* how */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
how = gnc_scm2amt_match_how (scm);
/* amt_sgn */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
amt_sgn = gnc_query_scm2numericop (scm);
/* amount */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
amount = scm_num2dbl (scm, __FUNCTION__);
- val = double_to_gnc_numeric (amount, GNC_DENOM_AUTO, GNC_RND_ROUND);
+ val = double_to_gnc_numeric (amount, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND);
if (!safe_strcmp (pr_type, "pr-price")) {
- xaccQueryAddSharePriceMatch (q, val, how, QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddSharePriceMatch (q, val, how, QOF_QUERY_OR);
+ ok = TRUE;
} else if (!safe_strcmp (pr_type, "pr-shares")) {
- xaccQueryAddSharesMatch (q, val, how, QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddSharesMatch (q, val, how, QOF_QUERY_OR);
+ ok = TRUE;
} else if (!safe_strcmp (pr_type, "pr-value")) {
- xaccQueryAddValueMatch (q, val, amt_sgn, how, QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddValueMatch (q, val, amt_sgn, how, QOF_QUERY_OR);
+ ok = TRUE;
} else {
- PINFO ("unknown amount predicate: %s", pr_type);
+ PINFO ("unknown amount predicate: %s", pr_type);
}
- } else if (!safe_strcmp (pd_type, "pd-account")) {
+ }
+ else if (!safe_strcmp (pd_type, "pd-account"))
+ {
QofGuidMatch how;
GList *account_guids;
/* how */
if (SCM_NULLP (query_term_scm)) {
- PINFO ("pd-account: null how");
- break;
+ PINFO ("pd-account: null how");
+ break;
}
scm = SCM_CAR (query_term_scm);
@@ -1311,8 +1322,8 @@
/* account guids */
if (SCM_NULLP (query_term_scm)) {
- PINFO ("pd-account: null guids");
- break;
+ PINFO ("pd-account: null guids");
+ break;
}
scm = SCM_CAR (query_term_scm);
@@ -1333,7 +1344,7 @@
/* case_sens */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1341,7 +1352,7 @@
/* use_regexp */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1349,34 +1360,35 @@
/* matchstring */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
- matchstring = gh_scm2newstr (scm, NULL);
+ /* matchstring = gh_scm2newstr (scm, NULL); */
+ matchstring = SCM_STRING_CHARS (scm);
if (!safe_strcmp (pr_type, "pr-action")) {
- xaccQueryAddActionMatch (q, matchstring, case_sens, use_regexp,
- QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddActionMatch (q, matchstring, case_sens, use_regexp,
+ QOF_QUERY_OR);
+ ok = TRUE;
} else if (!safe_strcmp (pr_type, "pr-desc")) {
- xaccQueryAddDescriptionMatch (q, matchstring, case_sens,
- use_regexp, QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddDescriptionMatch (q, matchstring, case_sens,
+ use_regexp, QOF_QUERY_OR);
+ ok = TRUE;
} else if (!safe_strcmp (pr_type, "pr-memo")) {
- xaccQueryAddMemoMatch (q, matchstring, case_sens, use_regexp,
- QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddMemoMatch (q, matchstring, case_sens, use_regexp,
+ QOF_QUERY_OR);
+ ok = TRUE;
} else if (!safe_strcmp (pr_type, "pr-num")) {
- xaccQueryAddNumberMatch (q, matchstring, case_sens, use_regexp,
- QOF_QUERY_OR);
- ok = TRUE;
+ xaccQueryAddNumberMatch (q, matchstring, case_sens, use_regexp,
+ QOF_QUERY_OR);
+ ok = TRUE;
} else {
- PINFO ("Unknown string predicate: %s", pr_type);
+ PINFO ("Unknown string predicate: %s", pr_type);
}
} else if (!safe_strcmp (pd_type, "pd-cleared")) {
@@ -1384,7 +1396,7 @@
/* how */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1398,12 +1410,12 @@
/* how */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
if (gnc_scm2balance_match_how (scm, &how) == FALSE)
- break;
+ break;
xaccQueryAddBalanceMatch (q, how, QOF_QUERY_OR);
ok = TRUE;
@@ -1415,7 +1427,7 @@
/* guid */
if (SCM_NULLP (query_term_scm))
- break;
+ break;
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
@@ -1424,9 +1436,9 @@
/* id type */
scm = SCM_CAR (query_term_scm);
query_term_scm = SCM_CDR (query_term_scm);
- tmp = gh_scm2newstr (scm, NULL);
+ /* tmp = gh_scm2newstr (scm, NULL); */
+ tmp = SCM_STRING_CHARS (scm);
id_type = g_strdup (tmp);
- if (tmp) free (tmp);
xaccQueryAddGUIDMatch (q, &guid, id_type, QOF_QUERY_OR);
ok = TRUE;
@@ -1477,12 +1489,6 @@
} while (FALSE);
- if (pd_type)
- free (pd_type);
-
- if (pr_type)
- free (pr_type);
-
if (ok)
{
Query *out_q;
@@ -1762,17 +1768,17 @@
path = g_slist_prepend (path, QUERY_DEFAULT_SORT);
} else if (!safe_strcmp (symbol, "by-date") ||
- !safe_strcmp (symbol, "by-date-rounded")) {
+ !safe_strcmp (symbol, "by-date-rounded")) {
path = g_slist_prepend (path, TRANS_DATE_POSTED);
path = g_slist_prepend (path, SPLIT_TRANS);
} else if (!safe_strcmp (symbol, "by-date-entered") ||
- !safe_strcmp (symbol, "by-date-entered-rounded")) {
+ !safe_strcmp (symbol, "by-date-entered-rounded")) {
path = g_slist_prepend (path, TRANS_DATE_ENTERED);
path = g_slist_prepend (path, SPLIT_TRANS);
} else if (!safe_strcmp (symbol, "by-date-reconciled") ||
- !safe_strcmp (symbol, "by-date-reconciled-rounded")) {
+ !safe_strcmp (symbol, "by-date-reconciled-rounded")) {
path = g_slist_prepend (path, SPLIT_DATE_RECONCILED);
} else if (!safe_strcmp (symbol, "by-num")) {
@@ -1809,8 +1815,6 @@
PERR ("Unknown sort-type, %s", symbol);
}
- free (symbol);
-
return path;
}
@@ -1852,7 +1856,8 @@
break;
}
- symbol = gh_symbol2newstr (sym_scm, NULL);
+ /* symbol = gh_symbol2newstr (sym_scm, NULL); */
+ symbol = SCM_SYMBOL_CHARS (sym_scm);
if (!symbol) {
PERR ("No string found");
ok = FALSE;
@@ -1865,41 +1870,40 @@
q = gnc_scm2query_or_terms (value, gnc_QUERY_v1);
if (!q) {
- PINFO ("invalid terms");
+ PINFO ("invalid terms");
ok = FALSE;
- free (symbol);
break;
}
} else if (safe_strcmp ("primary-sort", symbol) == 0) {
if (!SCM_SYMBOLP (value)) {
- PINFO ("Invalid primary sort");
+ PINFO ("Invalid primary sort");
ok = FALSE;
- free (symbol);
break;
}
- primary_sort = gh_symbol2newstr (value, NULL);
+ /* primary_sort = gh_symbol2newstr (value, NULL); */
+ primary_sort = SCM_SYMBOL_CHARS (value);
} else if (safe_strcmp ("secondary-sort", symbol) == 0) {
if (!SCM_SYMBOLP (value)) {
- PINFO ("Invalid secondary sort");
+ PINFO ("Invalid secondary sort");
ok = FALSE;
- free (symbol);
break;
}
- secondary_sort = gh_symbol2newstr (value, NULL);
+ /* secondary_sort = gh_symbol2newstr (value, NULL); */
+ secondary_sort = SCM_SYMBOL_CHARS (value);
} else if (safe_strcmp ("tertiary-sort", symbol) == 0) {
if (!SCM_SYMBOLP (value)) {
- PINFO ("Invalid tertiary sort");
+ PINFO ("Invalid tertiary sort");
ok = FALSE;
- free (symbol);
break;
}
- tertiary_sort = gh_symbol2newstr (value, NULL);
+ /* tertiary_sort = gh_symbol2newstr (value, NULL); */
+ tertiary_sort = SCM_SYMBOL_CHARS (value);
} else if (safe_strcmp ("primary-increasing", symbol) == 0) {
primary_increasing = SCM_NFALSEP (value);
@@ -1912,9 +1916,8 @@
} else if (safe_strcmp ("max-splits", symbol) == 0) {
if (!SCM_NUMBERP (value)) {
- PERR ("invalid max-splits");
+ PERR ("invalid max-splits");
ok = FALSE;
- free (symbol);
break;
}
@@ -1923,11 +1926,8 @@
} else {
PERR ("Unknown symbol: %s", symbol);
ok = FALSE;
- free (symbol);
break;
}
-
- free (symbol);
}
if (ok) {
@@ -1938,21 +1938,12 @@
qof_query_set_sort_order (q, s1, s2, s3);
qof_query_set_sort_increasing (q, primary_increasing, secondary_increasing,
- tertiary_increasing);
+ tertiary_increasing);
xaccQuerySetMaxSplits (q, max_splits);
return q;
}
- if (primary_sort)
- free (primary_sort);
-
- if (secondary_sort)
- free (secondary_sort);
-
- if (tertiary_sort)
- free (tertiary_sort);
-
xaccFreeQuery (q);
return NULL;
}
@@ -1993,7 +1984,8 @@
break;
}
- symbol = gh_symbol2newstr (sym_scm, NULL);
+ /* symbol = gh_symbol2newstr (sym_scm, NULL); */
+ symbol = SCM_SYMBOL_CHARS (sym_scm);
if (!symbol) {
ok = FALSE;
break;
@@ -2006,43 +1998,38 @@
q = gnc_scm2query_or_terms (value, gnc_QUERY_v2);
if (!q) {
ok = FALSE;
- free (symbol);
break;
}
} else if (!safe_strcmp ("search-for", symbol)) {
if (!SCM_SYMBOLP (value)) {
- ok = FALSE;
- free (symbol);
- break;
+ ok = FALSE;
+ break;
}
- search_for = gh_symbol2newstr (value, NULL);
+ /* search_for = gh_symbol2newstr (value, NULL); */
+ search_for = SCM_SYMBOL_CHARS (value);
} else if (safe_strcmp ("primary-sort", symbol) == 0) {
if (! gnc_query_scm2sort (value, &sp1, &so1, &si1)) {
ok = FALSE;
- free (symbol);
break;
}
} else if (!safe_strcmp ("secondary-sort", symbol)) {
if (! gnc_query_scm2sort (value, &sp2, &so2, &si2)) {
ok = FALSE;
- free (symbol);
break;
}
} else if (!safe_strcmp ("tertiary-sort", symbol)) {
if (! gnc_query_scm2sort (value, &sp3, &so3, &si3)) {
ok = FALSE;
- free (symbol);
break;
}
} else if (!safe_strcmp ("max-results", symbol)) {
if (!SCM_NUMBERP (value)) {
ok = FALSE;
- free (symbol);
break;
}
@@ -2050,11 +2037,8 @@
} else {
ok = FALSE;
- free (symbol);
break;
}
-
- free (symbol);
}
--scm_block_gc;
@@ -2097,14 +2081,14 @@
}
/* Ok, the LHS is the version and the RHS is the actual query list */
- type = gh_symbol2newstr (q_type, NULL);
+ /* type = gh_symbol2newstr (q_type, NULL); */
+ type = SCM_SYMBOL_CHARS (q_type);
if (!type)
return NULL;
if (!safe_strcmp (type, "query-v2"))
q = gnc_scm2query_v2 (SCM_CDR (query_scm));
- free (type);
return q;
}
@@ -2119,7 +2103,7 @@
if(trans_type == SCM_BOOL_F) {
trans_type = scm_c_eval_string("<gnc:Transaction*>");
/* don't really need this - types are bound globally anyway. */
- if(trans_type != SCM_BOOL_F) scm_protect_object(trans_type);
+ if(trans_type != SCM_BOOL_F) scm_gc_protect_object(trans_type);
}
scm_trans = gw_wcp_assimilate_ptr(t, trans_type);
@@ -2144,7 +2128,7 @@
SCM thunk)
{
return xaccAccountStagedTransactionTraversal(a, new_marker,
- gnc_scm_traversal_adapter,
+ gnc_scm_traversal_adapter,
&thunk);
}
@@ -2187,7 +2171,7 @@
SCM bits;
unsigned long c_bits;
long long c_result = 0;
- int i;
+ int i;
/* This doesn't work -- atm (bit-extract 4000 0 32) proves it */
/*
@@ -2196,7 +2180,7 @@
if (bits00to15_mask == SCM_BOOL_F) {
bits00to15_mask = scm_ulong2num(0xFFFF);
- scm_protect_object (bits00to15_mask);
+ scm_gc_protect_object (bits00to15_mask);
}
/*
@@ -2248,8 +2232,8 @@
tmp <<= 32;
minval = gnc_gint64_to_scm(tmp);
- scm_protect_object(maxval);
- scm_protect_object(minval);
+ scm_gc_protect_object(maxval);
+ scm_gc_protect_object(minval);
initialized = 1;
}
@@ -2285,7 +2269,7 @@
}
return scm_call_2(maker, gnc_gint64_to_scm(gnc_numeric_num(arg)),
- gnc_gint64_to_scm(gnc_numeric_denom(arg)));
+ gnc_gint64_to_scm(gnc_numeric_denom(arg)));
}
int
@@ -2318,7 +2302,7 @@
if(commodity_type == SCM_UNDEFINED) {
commodity_type = scm_c_eval_string("<gnc:commodity*>");
/* don't really need this - types are bound globally anyway. */
- if(commodity_type != SCM_UNDEFINED) scm_protect_object(commodity_type);
+ if(commodity_type != SCM_UNDEFINED) scm_gc_protect_object(commodity_type);
}
if(!gw_wcp_is_of_type_p(commodity_type, scm)) {
@@ -2342,7 +2326,7 @@
if(commodity_type == SCM_UNDEFINED) {
commodity_type = scm_c_eval_string("<gnc:commodity*>");
/* don't really need this - types are bound globally anyway. */
- if(commodity_type != SCM_UNDEFINED) scm_protect_object(commodity_type);
+ if(commodity_type != SCM_UNDEFINED) scm_gc_protect_object(commodity_type);
}
return gw_wcp_assimilate_ptr((void *) commodity, commodity_type);
@@ -2365,7 +2349,7 @@
/* don't really need this - types are bound globally anyway. */
if (book_type != SCM_UNDEFINED)
- scm_protect_object (book_type);
+ scm_gc_protect_object (book_type);
}
return gw_wcp_assimilate_ptr ((void *) book, book_type);
@@ -2388,7 +2372,7 @@
/* don't really need this - types are bound globally anyway. */
if (session_type != SCM_UNDEFINED)
- scm_protect_object (session_type);
+ scm_gc_protect_object (session_type);
}
return gw_wcp_assimilate_ptr ((void *) session, session_type);
Index: xlate.pl
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/xlate.pl,v
retrieving revision 1.11.2.1
retrieving revision 1.11.2.2
diff -Lsrc/engine/xlate.pl -Lsrc/engine/xlate.pl -u -r1.11.2.1 -r1.11.2.2
--- src/engine/xlate.pl
+++ src/engine/xlate.pl
@@ -110,9 +110,9 @@
s/QUERY_NAND/QOF_QUERY_NAND/g;
s/QUERY_NOR/QOF_QUERY_NOR/g;
s/QUERY_XOR/QOF_QUERY_XOR/g;
- s/QUERY_PARAM_BOOK/QOF_QUERY_PARAM_BOOK/g;
- s/QUERY_PARAM_GUID/QOF_QUERY_PARAM_GUID/g;
- s/QUERY_PARAM_ACTIVE/QOF_QUERY_PARAM_ACTIVE/g;
+ s/QUERY_PARAM_BOOK/QOF_PARAM_BOOK/g;
+ s/QUERY_PARAM_GUID/QOF_PARAM_GUID/g;
+ s/QUERY_PARAM_ACTIVE/QOF_PARAM_ACTIVE/g;
s/QUERYCORE_INT64/QOF_QUERYCORE_INT64/g;
s/QUERYCORE_STRING/QOF_QUERYCORE_STRING/g;
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Makefile.am,v
retrieving revision 1.94.2.5
retrieving revision 1.94.2.6
diff -Lsrc/engine/Makefile.am -Lsrc/engine/Makefile.am -u -r1.94.2.5 -r1.94.2.6
--- src/engine/Makefile.am
+++ src/engine/Makefile.am
@@ -30,6 +30,7 @@
gnc-engine-util.c \
gnc-engine.c \
gnc-event.c \
+ gnc-filepath-utils.c \
gnc-lot.c \
gnc-numeric.c \
gnc-pricedb.c \
@@ -77,13 +78,13 @@
engine-helpers.h \
glib-helpers.h \
gnc-associate-account.h \
- gnc-be-utils.h \
gnc-book.h \
gnc-commodity.h \
gnc-date.h \
gnc-engine-util.h \
gnc-engine.h \
gnc-event.h \
+ gnc-filepath-utils.h \
gnc-numeric.h \
gnc-pricedb.h \
gnc-session.h \
@@ -98,10 +99,13 @@
policy.h \
qof.h \
qofbackend.h \
+ qof-be-utils.h \
qofbook.h \
qofclass.h \
qofid.h \
qofinstance.h \
+ qofmath128.c \
+ qofmath128.h \
qofobject.h \
qofquery.h \
qofquerycore.h \
Index: QueryNew.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/QueryNew.h,v
retrieving revision 1.15.4.1
retrieving revision 1.15.4.2
diff -Lsrc/engine/QueryNew.h -Lsrc/engine/QueryNew.h -u -r1.15.4.1 -r1.15.4.2
--- src/engine/QueryNew.h
+++ src/engine/QueryNew.h
@@ -6,9 +6,9 @@
#define QUERY_NAND QOF_QUERY_NAND
#define QUERY_NOR QOF_QUERY_NOR
#define QUERY_XOR QOF_QUERY_XOR
- #define QUERY_PARAM_BOOK QOF_QUERY_PARAM_BOOK
- #define QUERY_PARAM_GUID QOF_QUERY_PARAM_GUID
- #define QUERY_PARAM_ACTIVE QOF_QUERY_PARAM_ACTIVE
+ #define QUERY_PARAM_BOOK QOF_PARAM_BOOK
+ #define QUERY_PARAM_GUID QOF_PARAM_GUID
+ #define QUERY_PARAM_ACTIVE QOF_PARAM_ACTIVE
#define querynew_s _QofQuery
#define QueryNew QofQuery
Index: test-lots.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-lots.c,v
retrieving revision 1.3.4.1
retrieving revision 1.3.4.2
diff -Lsrc/engine/test/test-lots.c -Lsrc/engine/test/test-lots.c -u -r1.3.4.1 -r1.3.4.2
--- src/engine/test/test-lots.c
+++ src/engine/test/test-lots.c
@@ -1,7 +1,8 @@
-/* Test file created by Linas Vepstas <linas at linas.org>
- * Minimal test to see if automatic lot scrubbing works.
- * April 2003
+/**
+ * @file test-lots.c
+ * @brief Minimal test to see if automatic lot scrubbing works.
+ * @author Copyright (C) 2003 Linas Vepstas <linas at linas.org>
* License: GPL
*/
@@ -31,7 +32,7 @@
* without crashing. We don't check to see if data is good. */
sess = get_random_session ();
book = qof_session_get_book (sess);
- do_test ((NULL != book), "book not created");
+ do_test ((NULL != book), "create random data");
add_random_transactions_to_book (book, 720);
@@ -42,18 +43,32 @@
/* In the second test, we create an account with unrealized gains,
* and see if that gets fixed correctly, with the correct balances,
* and etc.
- * XXX not inplemented
+ * XXX not implemented
*/
success ("automatic lot scrubbing lightly tested and seem to work");
+ qof_session_destroy (sess);
+
}
static void
main_helper (void *closure, int argc, char **argv)
{
+ int i;
+
+ /* Any tests that cause an error or warning to be printed
+ * automatically fail! */
g_log_set_always_fatal( G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING );
- do_test((NULL!=gnc_module_load("gnucash/engine", 0)), "couldn't load engine");
- run_test ();
+ set_success_print (TRUE);
+
+ do_test((NULL!=gnc_module_load("gnucash/engine", 0)), "load engine");
+
+ /* set the rng to a known starting point */
+ srand(0);
+
+ /* Iterate the test a number of times */
+ for (i=0; i< 20; i++)
+ run_test ();
print_test_results();
exit(get_rv());
Index: .cvsignore
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/.cvsignore,v
retrieving revision 1.13.4.3
retrieving revision 1.13.4.4
diff -Lsrc/engine/test/.cvsignore -Lsrc/engine/test/.cvsignore -u -r1.13.4.3 -r1.13.4.4
--- src/engine/test/.cvsignore
+++ src/engine/test/.cvsignore
@@ -11,6 +11,7 @@
test-group-vs-book
test-link
test-lots
+test-numeric
test-object
test-period
test-print-queries
Index: test-resolve-file-path.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-resolve-file-path.c,v
retrieving revision 1.3.6.1
retrieving revision 1.3.6.2
diff -Lsrc/engine/test/test-resolve-file-path.c -Lsrc/engine/test/test-resolve-file-path.c -u -r1.3.6.1 -r1.3.6.2
--- src/engine/test/test-resolve-file-path.c
+++ src/engine/test/test-resolve-file-path.c
@@ -5,6 +5,7 @@
#include "test-stuff.h"
#include "gnc-engine-util.h"
+#include "gnc-filepath-utils.h"
#include "qofsession.h"
struct test_strings_struct
--- /dev/null
+++ src/engine/test/test-numeric.c
@@ -0,0 +1,738 @@
+
+/* Test file created by Linas Vepstas <linas at linas.org>
+ * Review operation of the gnc-numeric tools by verifying results
+ * of vairous operations.
+ *
+ * June 2004
+ * License: GPL
+ */
+
+#include <ctype.h>
+#include <glib.h>
+
+#include "gnc-module.h"
+#include "test-stuff.h"
+#include "test-engine-stuff.h"
+#include "gnc-numeric.h"
+
+#define NREPS 2000
+
+static char *
+gnc_numeric_print(gnc_numeric in)
+{
+ char * retval;
+ if(gnc_numeric_check(in))
+ {
+ retval = g_strdup_printf("<ERROR> [%lld / %lld]",
+ (long long int) in.num,
+ (long long int) in.denom);
+ }
+ else
+ {
+ retval = g_strdup_printf("[%lld / %lld]",
+ (long long int) in.num,
+ (long long int) in.denom);
+ }
+ return retval;
+}
+
+/* ======================================================= */
+
+static void
+check_unary_op (gboolean (*eqtest) (gnc_numeric, gnc_numeric),
+ gnc_numeric expected,
+ gnc_numeric actual,
+ gnc_numeric input,
+ const char * errmsg)
+{
+ char *e = gnc_numeric_print (expected);
+ char *r = gnc_numeric_print (actual);
+ char *a = gnc_numeric_print (input);
+ char *str = g_strdup_printf (errmsg, e,r, a);
+
+ do_test (eqtest(expected, actual), str);
+
+ g_free (a);
+ g_free (r);
+ g_free (e);
+ g_free (str);
+}
+
+/* ======================================================= */
+
+static void
+check_binary_op (gnc_numeric expected,
+ gnc_numeric actual,
+ gnc_numeric input_a,
+ gnc_numeric input_b,
+ const char * errmsg)
+{
+ char *e = gnc_numeric_print (expected);
+ char *r = gnc_numeric_print (actual);
+ char *a = gnc_numeric_print (input_a);
+ char *b = gnc_numeric_print (input_b);
+ char *str = g_strdup_printf (errmsg, e,r,a,b);
+
+ do_test (gnc_numeric_eq(expected, actual), str);
+
+ g_free (a);
+ g_free (b);
+ g_free (r);
+ g_free (e);
+ g_free (str);
+}
+
+/* ======================================================= */
+
+static gboolean
+gnc_numeric_unequal (gnc_numeric a, gnc_numeric b)
+{
+ return (0 == gnc_numeric_equal (a,b));
+}
+
+/* ======================================================= */
+
+/* Make sure that the equivalence operator we use for
+ * later tests actually works */
+static void
+check_eq_operator (void)
+{
+ gnc_numeric a = gnc_numeric_create (42, 58);
+ gnc_numeric b = gnc_numeric_create (42, 58);
+ gnc_numeric c = gnc_numeric_create (40, 58);
+
+ /* Check strict equivalence and non-equivalence */
+ do_test (gnc_numeric_eq(a, a), "expected self-equivalence");
+ do_test (gnc_numeric_eq(a, b), "expected equivalence");
+ do_test (0 == gnc_numeric_eq(a, c), "expected inequivalence");
+}
+
+/* ======================================================= */
+
+static void
+check_reduce (void)
+{
+ /* Check common factor elimination (needed for equality checks) */
+ gnc_numeric one = gnc_numeric_create (1,1);
+ gnc_numeric rone = gnc_numeric_create (1000000,1000000);
+ rone = gnc_numeric_reduce (rone);
+ do_test (gnc_numeric_eq(one, rone), "reduce to one");
+
+ gnc_numeric four = gnc_numeric_create (4,1);
+ gnc_numeric rfour = gnc_numeric_create (480,120);
+ rfour = gnc_numeric_reduce (rfour);
+ do_test (gnc_numeric_eq(four, rfour), "reduce to four");
+
+ gnc_numeric val = gnc_numeric_create(10023234LL, 334216654LL);
+ gnc_numeric rval = gnc_numeric_reduce (val);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (5011617,167108327),
+ rval,
+ val, "expected %s = %s = reduce(%s)");
+
+ val = gnc_numeric_create(17474724864LL,136048896LL);
+ rval = gnc_numeric_reduce (val);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (4*17*17,9),
+ rval,
+ val, "expected %s = %s = reduce(%s)");
+
+ val = gnc_numeric_create(1024LL,1099511627776LL);
+ rval = gnc_numeric_reduce (val);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (1,1024*1024*1024),
+ rval,
+ val, "expected %s = %s = reduce(%s)");
+}
+
+/* ======================================================= */
+
+static void
+check_equality_operator (void)
+{
+ /* Check equality operator for some large numer/denom values */
+ gint64 numer = 1<<30;
+ numer <<= 30; /* we don't trust cpp to compute 1<<60 correctly */
+ gint64 deno = 1<<30;
+ deno <<= 20;
+ gnc_numeric rbig = gnc_numeric_create (numer, deno);
+
+ gnc_numeric big = gnc_numeric_create (1<<10,1);
+ do_test (gnc_numeric_equal(big, rbig), "equal to billion");
+
+ big = gnc_numeric_create (1<<20,1<<10);
+ do_test (gnc_numeric_equal(big, rbig), "equal to 1<<20/1<<10");
+
+ big = gnc_numeric_create (1<<30,1<<20);
+ do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30/1<<20");
+
+ numer = 1<<30;
+ numer <<= 30; /* we don't trust cpp to compute 1<<60 correctly */
+ deno = 1<<30;
+ rbig = gnc_numeric_create (numer, deno);
+
+ big = gnc_numeric_create (1<<30,1);
+ do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30");
+
+ numer = 1<<30;
+ numer <<= 10;
+ big = gnc_numeric_create (numer, 1<<10);
+ do_test (gnc_numeric_equal(big, rbig), "equal to 1<<40/1<<10");
+
+ numer <<= 10;
+ big = gnc_numeric_create (numer, 1<<20);
+ do_test (gnc_numeric_equal(big, rbig), "equal to 1<<50/1<<20");
+
+ int i;
+ /* We assume RAND_MAX is less that 1<<32 */
+ for (i=0; i<NREPS; i++)
+ {
+ gint64 deno = rand() / 2;
+ gint64 mult = rand() / 2;
+ gint64 numer = rand() / 2;
+
+ gnc_numeric val = gnc_numeric_create (numer, deno);
+ gnc_numeric mval = gnc_numeric_create (numer*mult, deno*mult);
+
+ /* The reduced version should be equivalent */
+ gnc_numeric bval = gnc_numeric_reduce (val);
+ gnc_numeric rval = gnc_numeric_reduce (mval);
+ check_unary_op (gnc_numeric_eq,
+ bval, rval, mval, "expected %s = %s = reduce(%s)");
+
+ /* The unreduced versions should be equal */
+ check_unary_op (gnc_numeric_equal,
+ val, mval, mval, "expected %s = %s");
+
+ /* Certain modulo's should be very cleary un-equal; this
+ * helps stop funky modulo-64 aliasing in compares that
+ * might creep in. */
+ mval.denom >>= 1;
+ mval.num >>= 1;
+ int m=0;
+ gint64 f = mval.denom;
+ while (f%2 == 0)
+ {
+ f >>= 1;
+ m++;
+ }
+ if (1 < m)
+ {
+ gint64 nn = 1 << (32-m);
+ nn <<= 32;
+ nn += mval.num;
+ val = gnc_numeric_create (2*nn, 2*mval.denom);
+ check_unary_op (gnc_numeric_unequal,
+ val, mval, mval, "expected unequality %s != %s");
+
+ }
+ }
+}
+
+/* ======================================================= */
+
+static void
+check_rounding (void)
+{
+ gnc_numeric val;
+
+ val = gnc_numeric_create(7, 16);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (43,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_FLOOR),
+ val, "expected %s = %s = (%s as 100th's floor)");
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (44,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_CEIL),
+ val, "expected %s = %s = (%s as 100th's ceiling)");
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (43,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_TRUNC),
+ val, "expected %s = %s = (%s as 100th's trunc)");
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (44,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+
+ val = gnc_numeric_create(1511, 1000);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (151,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+
+ val = gnc_numeric_create(1516, 1000);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (152,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+
+ /* Half-values always get rounded to nearest even number */
+ val = gnc_numeric_create(1515, 1000);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (152,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+
+ val = gnc_numeric_create(1525, 1000);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (152,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+
+ val = gnc_numeric_create(1535, 1000);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (154,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+
+ val = gnc_numeric_create(1545, 1000);
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (154,100),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
+ val, "expected %s = %s = (%s as 100th's round)");
+}
+
+/* ======================================================= */
+
+static void
+check_double (void)
+{
+ gnc_numeric val = gnc_numeric_create (0,1);
+
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (112346,100000),
+ double_to_gnc_numeric(1.1234567890123,
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
+ val, "expected %s = %s double 6 figs");
+
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (112346,10000000),
+ double_to_gnc_numeric(0.011234567890123,
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
+ val, "expected %s = %s double 6 figs");
+
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (112346,100),
+ double_to_gnc_numeric(1123.4567890123,
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
+ val, "expected %s = %s double 6 figs");
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (112346,10000000000LL),
+ double_to_gnc_numeric(1.1234567890123e-5,
+ GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
+ val, "expected %s = %s double 6 figs");
+
+ double flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
+ do_test ((0.4375 == flo), "float pt conversion");
+}
+
+/* ======================================================= */
+
+static void
+check_neg (void)
+{
+ gnc_numeric a = gnc_numeric_create(2, 6);
+ gnc_numeric b = gnc_numeric_create(1, 4);
+ gnc_numeric c = gnc_numeric_neg (a);
+ gnc_numeric d = gnc_numeric_neg (b);
+
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (-2,6), c,
+ a, "expected %s = %s = -(%s)");
+
+ check_unary_op (gnc_numeric_eq,
+ gnc_numeric_create (-1,4), d,
+ b, "expected %s = %s = -(%s)");
+
+}
+
+/* ======================================================= */
+
+static void
+check_add_subtract (void)
+{
+ gnc_numeric a = gnc_numeric_create(2, 6);
+ gnc_numeric b = gnc_numeric_create(1, 4);
+
+ /* Well, actually 14/24 would be acceptable/better in this case */
+ check_binary_op (gnc_numeric_create(7,12),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s + %s for add exact");
+
+ check_binary_op (gnc_numeric_create(58,100),
+ gnc_numeric_add(a, b, 100, GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
+
+ check_binary_op (gnc_numeric_create(5833,10000),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(4) |
+ GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s + %s for add 4 sig figs");
+
+ check_binary_op (gnc_numeric_create(583333,1000000),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s + %s for add 6 sig figs");
+
+ check_binary_op (gnc_numeric_create(1,12),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s - %s for sub exact");
+
+ /* We should try something trickier for reduce & lcd */
+ check_binary_op (gnc_numeric_create(1,12),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
+ a, b, "expected %s got %s = %s - %s for sub reduce");
+
+ check_binary_op (gnc_numeric_create(1,12),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
+ a, b, "expected %s got %s = %s - %s for sub reduce");
+
+ check_binary_op (gnc_numeric_create(8,100),
+ gnc_numeric_sub(a, b, 100, GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
+
+ /* ------------------------------------------------------------ */
+ /* This test has failed before */
+ gnc_numeric c = gnc_numeric_neg (a);
+ gnc_numeric d = gnc_numeric_neg (b);
+ gnc_numeric z = gnc_numeric_zero();
+ check_binary_op (c, gnc_numeric_add_fixed(z,c),
+ z, c, "expected %s got %s = %s + %s for add fixed");
+
+ check_binary_op (d, gnc_numeric_add_fixed(z,d),
+ z, d, "expected %s got %s = %s + %s for add fixed");
+
+ /* ------------------------------------------------------------ */
+ /* Same as above, but with signs reviersed */
+ a = c;
+ b = d;
+ /* Well, actually 14/24 would be acceptable/better in this case */
+ check_binary_op (gnc_numeric_create(-7,12),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s + %s for add exact");
+
+ check_binary_op (gnc_numeric_create(-58,100),
+ gnc_numeric_add(a, b, 100, GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
+
+ check_binary_op (gnc_numeric_create(-5833,10000),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(4) |
+ GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s + %s for add 4 sig figs");
+
+ check_binary_op (gnc_numeric_create(-583333,1000000),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s + %s for add 6 sig figs");
+
+ check_binary_op (gnc_numeric_create(-1,12),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s - %s for sub exact");
+
+ /* We should try something trickier for reduce & lcd */
+ check_binary_op (gnc_numeric_create(-1,12),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
+ a, b, "expected %s got %s = %s - %s for sub reduce");
+
+ check_binary_op (gnc_numeric_create(-1,12),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
+ a, b, "expected %s got %s = %s - %s for sub reduce");
+
+ check_binary_op (gnc_numeric_create(-8,100),
+ gnc_numeric_sub(a, b, 100, GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
+
+ /* ------------------------------------------------------------ */
+#if CHECK_ERRORS_TOO
+ gnc_numeric c;
+ c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
+ printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
+ gnc_numeric_print(a), gnc_numeric_print(b),
+ gnc_numeric_print(c),
+ gnc_numeric_print(err));
+
+ c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err);
+ printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
+ gnc_numeric_print(a), gnc_numeric_print(b),
+ gnc_numeric_print(c),
+ gnc_numeric_print(err));
+
+#endif
+
+ /* ------------------------------------------------------------ */
+ /* Add and subtract some random numbers */
+ int i;
+ for (i=0; i<NREPS; i++)
+ {
+ gnc_numeric e;
+ gint64 deno = rand() +1;
+ gint64 na = get_random_gint64();
+ gint64 nb = get_random_gint64();
+ gint64 ne;
+
+ /* avoid overflow; */
+ na /=2;
+ nb /=2;
+
+ a = gnc_numeric_create(na, deno);
+ b = gnc_numeric_create(nb, deno);
+
+ /* Add */
+ ne = na+nb;
+ e = gnc_numeric_create(ne, deno);
+ check_binary_op (e,
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s + %s for exact addition");
+
+ /* Subtract */
+ ne = na-nb;
+ e = gnc_numeric_create(ne, deno);
+ check_binary_op (e,
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s - %s for exact subtraction");
+ }
+}
+
+/* ======================================================= */
+
+static void
+check_mult_div (void)
+{
+ gnc_numeric c, d;
+ gnc_numeric a = gnc_numeric_create(2, 6);
+ gnc_numeric b = gnc_numeric_create(1, 4);
+
+ check_binary_op (gnc_numeric_create(2,24),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s * %s for mult exact");
+
+ check_binary_op (gnc_numeric_create(1,12),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
+ a, b, "expected %s got %s = %s * %s for mult reduce");
+
+ check_binary_op (gnc_numeric_create(8,100),
+ gnc_numeric_mul(a, b, 100, GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s * %s for mult 100th's");
+
+ check_binary_op (gnc_numeric_create(8,6),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s / %s for div exact");
+
+ check_binary_op (gnc_numeric_create(4,3),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
+ a, b, "expected %s got %s = %s / %s for div reduce");
+
+ check_binary_op (gnc_numeric_create(133,100),
+ gnc_numeric_div(a, b, 100, GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s * %s for div 100th's");
+
+#if CHECK_ERRORS_TOO
+ gnc_numeric c;
+ c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
+ printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
+ gnc_numeric_print(a), gnc_numeric_print(b),
+ gnc_numeric_print(c),
+ gnc_numeric_print(err));
+
+ c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
+ printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
+ gnc_numeric_print(a), gnc_numeric_print(b),
+ gnc_numeric_print(c),
+ gnc_numeric_print(err));
+
+#endif
+
+ /* Check for math with 2^63 < num*num < 2^64 which previously failed
+ * see http://bugzilla.gnome.org/show_bug.cgi?id=144980
+ */
+ gint64 v = 1000000;
+ a = gnc_numeric_create(1*v, v);
+ b = gnc_numeric_create(10000000*v, v);
+
+ check_binary_op (b,
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
+ a, b, "expected %s got %s = %s * %s for multiply");
+
+ /* Multiply some random numbers. This test presumes that
+ * RAND_MAX is approx 2^32
+ */
+ int i;
+ for (i=0; i<NREPS; i++)
+ {
+ gint64 deno = 1;
+ gint64 na = rand();
+ gint64 nb = rand();
+ gint64 ne;
+
+ /* avoid overflow; */
+ na /= 2;
+ nb /= 2;
+ ne = na*nb;
+
+ a = gnc_numeric_create(na, deno);
+ b = gnc_numeric_create(nb, deno);
+
+ check_binary_op (gnc_numeric_create(ne,1),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s * %s for mult exact");
+
+ /* Force 128-bit math to come into play */
+ int j;
+ for (j=1; j<31; j++)
+ {
+ a = gnc_numeric_create(na << j, 1<<j);
+ b = gnc_numeric_create(nb << j, 1<<j);
+ check_binary_op (gnc_numeric_create(ne, 1),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
+ a, b, "expected %s got %s = %s * %s for mult reduce");
+ }
+
+ /* Do some hokey random 128-bit division too */
+ b = gnc_numeric_create(deno, nb);
+
+ check_binary_op (gnc_numeric_create(ne,1),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s / %s for div exact");
+
+ /* avoid overflow; */
+ na /= 2;
+ nb /= 2;
+ ne = na*nb;
+ for (j=1; j<16; j++)
+ {
+ a = gnc_numeric_create(na << j, 1<<j);
+ b = gnc_numeric_create(1<<j, nb << j);
+ check_binary_op (gnc_numeric_create(ne, 1),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
+ a, b, "expected %s got %s = %s / %s for div reduce");
+ }
+ }
+
+ a = gnc_numeric_create(782592055622866ULL,89025);
+ b = gnc_numeric_create(2222554708930978ULL,85568);
+ /* Dividing the above pair overflows, in that after
+ * the division the denominator won't fit into a
+ * 64-bit quantity. This can be seen from
+ * the factorization int primes:
+ * 782592055622866 = 2 * 2283317 * 171371749
+ * (yes, thats a seven and a nine digit prime)
+ * 2222554708930978 = 2 * 1111277354465489
+ * (yes, that's a sixteen-digit prime number)
+ * 89025 = 3*5*5*1187
+ * 85568= 64*7*191
+ * If the rounding method is exact/no-round, then
+ * an overflow error should be signalled; else the
+ * divide routine should shift down the results till
+ * the overflow is eliminated.
+ *
+ */
+ check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_RND_NEVER | GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s / %s for div exact");
+
+ check_binary_op (gnc_numeric_create(338441, 1000000),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s / %s for div round");
+
+ /* The below is a 'typical' value calculation:
+ * value_frac = value_tot * amt_frace / amt_tot
+ * and has some typical potential-overflow values.
+ * 82718 = 2 * 59 * 701
+ * 47497125586 = 2 * 1489 * 15949337
+ * 69100955 = 5 * 7 * 11 * 179483
+ * 32005637020 = 4 * 5 * 7 * 43 * 71 * 103 * 727
+ */
+ a = gnc_numeric_create (-47497125586LL, 82718);
+ b = gnc_numeric_create (-69100955LL, 55739);
+ c = gnc_numeric_mul (a,b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+ d = gnc_numeric_create (-32005637020LL, 55739);
+
+ check_binary_op (gnc_numeric_create(-102547458LL, 82718),
+ gnc_numeric_div(c, d, 82718,
+ GNC_HOW_DENOM_EXACT),
+ c, d, "expected %s got %s = %s / %s for div round");
+
+ /* If we specify GNC_HOW_RND_NEVER, then we shoukld get an error,
+ * since the exact result won't fit into a 64-bit quantity. */
+ check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER),
+ gnc_numeric_div(c, d, 82718,
+ GNC_HOW_DENOM_EXACT|GNC_HOW_RND_NEVER),
+ c, d, "expected %s got %s = %s / %s for div round");
+
+ /* A simple irreducible ratio, involving negative numbers */
+ gnc_numeric amt_a = gnc_numeric_create (-6005287905LL, 40595);
+ gnc_numeric amt_tot = gnc_numeric_create (-8744187958LL, 40595);
+ gnc_numeric frac = gnc_numeric_div (amt_a, amt_tot,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+
+ check_binary_op (gnc_numeric_create(6005287905LL, 8744187958LL),
+ frac, amt_a, amt_tot,
+ "expected %s got %s = %s / %s for div reduce");
+
+ /* Another overflow-prone condition */
+ gnc_numeric val_tot = gnc_numeric_create (-4280656418LL, 19873);
+ gnc_numeric val_a = gnc_numeric_mul (frac, val_tot,
+ gnc_numeric_denom(val_tot),
+ GNC_HOW_RND_ROUND| GNC_HOW_DENOM_EXACT);
+ check_binary_op (gnc_numeric_create(-2939846940LL, 19873),
+ val_a, val_tot, frac,
+ "expected %s got %s = %s * %s for mult round");
+
+ frac = gnc_numeric_create (396226789777979LL, 328758834367851752LL);
+ val_tot = gnc_numeric_create (467013515494988LL, 100);
+ val_a = gnc_numeric_mul (frac, val_tot,
+ gnc_numeric_denom(val_tot),
+ GNC_HOW_RND_ROUND| GNC_HOW_DENOM_EXACT);
+ check_binary_op (gnc_numeric_create(562854125307LL, 100),
+ val_a, val_tot, frac,
+ "expected %s got %s = %s * %s for mult round");
+}
+
+/* ======================================================= */
+
+static void
+run_test (void)
+{
+ check_eq_operator ();
+ check_reduce ();
+ check_equality_operator ();
+ check_rounding();
+ check_double();
+ check_neg();
+ check_add_subtract();
+ check_mult_div ();
+}
+
+static void
+main_helper (void *closure, int argc, char **argv)
+{
+ g_log_set_always_fatal( G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING );
+ do_test((NULL!=gnc_module_load("gnucash/engine", 0)), "couldn't load engine");
+
+ run_test ();
+
+ print_test_results();
+ exit(get_rv());
+}
+
+int
+main (int argc, char **argv)
+{
+ scm_boot_guile(argc, argv, main_helper, NULL);
+ return 0;
+}
+
+/* ======================== END OF FILE ====================== */
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/Makefile.am,v
retrieving revision 1.29.4.3
retrieving revision 1.29.4.4
diff -Lsrc/engine/test/Makefile.am -Lsrc/engine/test/Makefile.am -u -r1.29.4.3 -r1.29.4.4
--- src/engine/test/Makefile.am
+++ src/engine/test/Makefile.am
@@ -25,6 +25,7 @@
test-link \
test-load-engine \
test-guid \
+ test-numeric \
test-date \
test-object \
test-commodities \
@@ -63,6 +64,7 @@
test-group-vs-book \
test-load-engine \
test-lots \
+ test-numeric \
test-object \
test-period \
test-query \
Index: test-split-vs-account.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-split-vs-account.c,v
retrieving revision 1.8.4.1
retrieving revision 1.8.4.2
diff -Lsrc/engine/test/test-split-vs-account.c -Lsrc/engine/test/test-split-vs-account.c -u -r1.8.4.1 -r1.8.4.2
--- src/engine/test/test-split-vs-account.c
+++ src/engine/test/test-split-vs-account.c
@@ -19,7 +19,6 @@
Account *act1;
Account *act2;
Split *spl;
- gnc_numeric num;
QofSession *session;
QofBook *book;
@@ -40,16 +39,13 @@
return;
}
- num = get_random_gnc_numeric();
- spl = get_random_split(book, num);
+ spl = get_random_split(book, act1);
if(!spl)
{
failure("spl not created");
return;
}
- xaccAccountInsertSplit(act1, spl);
-
if(act1 != xaccSplitGetAccount(spl))
{
failure("xaccAccountInsertSplit is broken");
Index: test-object.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-object.c,v
retrieving revision 1.3.4.2
retrieving revision 1.3.4.3
diff -Lsrc/engine/test/test-object.c -Lsrc/engine/test/test-object.c -u -r1.3.4.2 -r1.3.4.3
--- src/engine/test/test-object.c
+++ src/engine/test/test-object.c
@@ -22,15 +22,17 @@
static void test_foreach (QofBook *, const char *);
static QofObject bus_obj = {
- QOF_OBJECT_VERSION,
- TEST_MODULE_NAME,
- TEST_MODULE_DESC,
- NULL, /* create */
- NULL, /* destroy */
- NULL, /* is dirty */
- NULL, /* mark_clean */
- obj_foreach,
- printable,
+ interface_version: QOF_OBJECT_VERSION,
+ e_type: TEST_MODULE_NAME,
+ type_label: TEST_MODULE_DESC,
+ create: NULL,
+ book_begin: NULL,
+ book_end: NULL,
+ is_dirty: NULL,
+ mark_clean: NULL,
+ foreach: obj_foreach,
+ printable: printable,
+ version_cmp: NULL,
};
static void
Index: test-query.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-query.c,v
retrieving revision 1.6.4.2
retrieving revision 1.6.4.3
diff -Lsrc/engine/test/test-query.c -Lsrc/engine/test/test-query.c -u -r1.6.4.2 -r1.6.4.3
--- src/engine/test/test-query.c
+++ src/engine/test/test-query.c
@@ -66,13 +66,20 @@
static void
main_helper (void *closure, int argc, char **argv)
{
+ int i;
+
gnc_module_load("gnucash/engine", 0);
g_log_set_always_fatal( G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING );
xaccLogDisable ();
- run_test ();
+ /* Always start from the same random seed so we fail consistently */
+ srand(0);
+
+ /* Loop the test. */
+ for (i=0; i < 10; i++)
+ run_test ();
success("queries seem to work");
Index: test-transaction-reversal.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-transaction-reversal.c,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -Lsrc/engine/test/test-transaction-reversal.c -Lsrc/engine/test/test-transaction-reversal.c -u -r1.3 -r1.3.4.1
--- src/engine/test/test-transaction-reversal.c
+++ src/engine/test/test-transaction-reversal.c
@@ -20,7 +20,6 @@
static void
transaction_set_splits_to_accounts(Transaction *tr, Account *a1, Account *a2)
{
-
Split *split;
split = xaccTransGetSplit(tr, 0);
@@ -72,21 +71,24 @@
failure("xaccTransClone failed.");
xaccTransReverse(new_trans);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++)
+ {
old = xaccSplitGetAmount(xaccTransGetSplit(transaction, i));
new = xaccSplitGetAmount(xaccTransGetSplit(new_trans, i));
result = gnc_numeric_add(old, new, GNC_DENOM_AUTO, GNC_DENOM_FIXED);
- if (gnc_numeric_eq(old, gnc_numeric_neg(new))) {
- msg = g_strdup_printf("Amount of split %d wrong after reversal", i);
- failure(msg);
+ if (gnc_numeric_eq(old, gnc_numeric_neg(new)))
+ {
+ msg = g_strdup_printf("Amount of split %d wrong after reversal", i);
+ failure(msg);
}
old = xaccSplitGetValue(xaccTransGetSplit(transaction, i));
new = xaccSplitGetValue(xaccTransGetSplit(new_trans, i));
result = gnc_numeric_add(old, new, GNC_DENOM_AUTO, GNC_DENOM_FIXED);
- if (gnc_numeric_eq(old, gnc_numeric_neg(new))) {
- msg = g_strdup_printf("Value of split %d wrong after reversal", i);
- failure(msg);
+ if (gnc_numeric_eq(old, gnc_numeric_neg(new)))
+ {
+ msg = g_strdup_printf("Value of split %d wrong after reversal", i);
+ failure(msg);
}
}
Index: report-html.txt
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/doc/report-html.txt,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -Lsrc/report/report-system/doc/report-html.txt -Lsrc/report/report-system/doc/report-html.txt -u -r1.1 -r1.1.6.1
--- src/report/report-system/doc/report-html.txt
+++ src/report/report-system/doc/report-html.txt
@@ -202,7 +202,7 @@
- the HTML tag to render (specified by 'tag). Note that this
may be different from the tag used to look up the style (the
- one passed to html-markup).
+ one passed to html-markup). (See NB below.)
- Any attributes to be used inside the start tag (listed
individually as 'attribute (list name value))
- The font face to use in the body ('font-face)
@@ -259,6 +259,7 @@
;; object is rendered.
(gnc:html-text-set-style! txt
"bigred" 'tag "" 'font-color "ff0000" 'font-size 7)
+ ;; ^^ NB: "bigred" is the tag. 'tag "" is the info in the style table.
(gnc:html-document-add-object! doc txt)
(gnc:html-document-render doc))
Index: test-engine-stuff.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test-core/test-engine-stuff.c,v
retrieving revision 1.52.4.6
retrieving revision 1.52.4.7
diff -Lsrc/engine/test-core/test-engine-stuff.c -Lsrc/engine/test-core/test-engine-stuff.c -u -r1.52.4.6 -r1.52.4.7
--- src/engine/test-core/test-engine-stuff.c
+++ src/engine/test-core/test-engine-stuff.c
@@ -1,3 +1,12 @@
+/**
+ * @file test-engine-stuff.c
+ * @brief tools to set up random, but finanically consistent books.
+ * Create transactions with random values, random accounts, random
+ * account heirarchies, etc.
+ *
+ * Created by Linux Developers Group, 2001
+ * Updates Linas Vepstas July 2004
+ */
#include "config.h"
#include <sys/types.h>
@@ -30,10 +39,12 @@
static gint max_group_depth = 4;
static gint max_group_accounts = 10;
+static gint max_total_accounts = 1000;
+static gint total_num_accounts = 0;
static kvp_value* get_random_kvp_value_depth (int type, gint depth);
static gpointer get_random_list_element (GList *list);
-static void add_random_splits(QofBook *book, Transaction *trn);
+static void add_random_splits(QofBook *book, Transaction *trn, GList *account_list);
gboolean gnc_engine_debug_random = FALSE;
@@ -140,10 +151,38 @@
return ret;
}
+#define RAND_IN_RANGE(X) (((X)*((gint64) (rand()+1)))/RAND_MAX)
+
gnc_numeric
get_random_gnc_numeric(void)
{
- return gnc_numeric_create(get_random_gint64(), rand());
+ gint64 numer;
+ gint64 deno;
+
+ if (RAND_MAX/8 > rand())
+ {
+ /* Random number between 1 and 6000 */
+ deno = RAND_IN_RANGE(6000ULL);
+ }
+ else
+ {
+ gint64 norm = RAND_IN_RANGE (10ULL);
+
+ /* multiple of 10, between 1 and 10 000 million */
+ deno = 1;
+ while (norm)
+ {
+ deno *= 10;
+ norm --;
+ }
+ }
+
+ /* Arbitrary random numbers can cause pointless overflow
+ * during calculations. Limit dynamic range in hopes
+ * of avoiding overflow. */
+ numer = get_random_gint64()/100000;
+ if (0 == numer) numer = 1;
+ return gnc_numeric_create(numer, deno);
}
const char *types[] =
@@ -541,13 +580,15 @@
return;
num_accounts = get_random_int_in_range (1, 10);
-
while (num_accounts-- > 0)
{
Account *sub = get_random_account (book);
xaccAccountInsertSubAccount (account, sub);
+ total_num_accounts ++;
+ if (total_num_accounts > max_total_accounts) return;
+
account_add_subaccounts (book, sub, depth - 1);
}
}
@@ -583,6 +624,7 @@
g_return_if_fail (book);
g_return_if_fail (group);
+ total_num_accounts = 0;
depth = get_random_int_in_range (1, max_group_depth);
make_random_group_depth (book, group, depth);
@@ -637,7 +679,7 @@
xaccSplitDestroy (split);
} while (split);
- add_random_splits (book, trans);
+ add_random_splits (book, trans, accounts);
/* fall through */
@@ -897,10 +939,10 @@
static char possible_chars[] = { NREC, CREC, YREC, FREC };
Split*
-get_random_split(QofBook *book, gnc_numeric num)
+get_random_split(QofBook *book, Account *acct)
{
Split *ret;
- gnc_numeric oneVal;
+ gnc_numeric num;
ret = xaccMallocSplit(book);
@@ -911,12 +953,11 @@
xaccSplitSetDateReconciledTS(ret, get_random_timespec());
- xaccSplitSetValue(ret, num);
+ /* Split must be in an account before we can set an amount */
+ xaccAccountInsertSplit (acct, ret);
+ num = get_random_gnc_numeric ();
xaccSplitSetAmount(ret, num);
- oneVal = gnc_numeric_create(1,1);
- xaccSplitSetSharePrice(ret, oneVal);
-
xaccSplitSetSlots_nc(ret, get_random_kvp_frame());
return ret;
@@ -962,12 +1003,26 @@
}
static void
-add_random_splits(QofBook *book, Transaction *trn)
+add_random_splits(QofBook *book, Transaction *trn, GList *account_list)
{
+ Account *account;
+ Split *s;
+
+ /* Set up two splits whose values really are opposites. */
+ gnc_commodity *com = xaccTransGetCurrency (trn);
+ int scu = gnc_commodity_get_fraction(com);
gnc_numeric num = get_random_gnc_numeric();
+ num = gnc_numeric_convert (num, scu, GNC_HOW_RND_ROUND);
- xaccTransAppendSplit(trn, get_random_split(book, num));
- xaccTransAppendSplit(trn, get_random_split(book, gnc_numeric_neg(num)));
+ account = get_random_list_element (account_list);
+ s = get_random_split(book, account);
+ xaccTransAppendSplit(trn, s);
+ xaccSplitSetValue(s, num);
+
+ account = get_random_list_element (account_list);
+ s = get_random_split(book, account);
+ xaccTransAppendSplit(trn, s);
+ xaccSplitSetValue(s, gnc_numeric_neg(num));
}
static void
@@ -984,10 +1039,16 @@
Transaction *
get_random_transaction_with_currency(QofBook *book,
- gnc_commodity *currency)
+ gnc_commodity *currency,
+ GList *account_list)
{
Transaction* ret;
+ if (!account_list)
+ {
+ account_list = xaccGroupGetSubAccounts (gnc_book_get_group (book));
+ }
+
ret = xaccMallocTransaction(book);
xaccTransBeginEdit(ret);
@@ -1002,7 +1063,7 @@
xaccTransSetSlots_nc(ret, get_random_kvp_frame());
- add_random_splits(book, ret);
+ add_random_splits(book, ret, account_list);
if (get_random_int_in_range (1, 10) == 1)
{
@@ -1018,7 +1079,7 @@
Transaction*
get_random_transaction (QofBook *book)
{
- return get_random_transaction_with_currency (book, NULL);
+ return get_random_transaction_with_currency (book, NULL, NULL);
}
void
@@ -1129,7 +1190,10 @@
name = get_random_string();
xcode = get_random_string();
- ran_int = get_random_int_in_range(1, 100000);
+
+ /* SCU == smallest currency unit -- the value of the denominator */
+#define MAX_SCU 6000
+ ran_int = get_random_int_in_range(1, MAX_SCU);
ret = gnc_commodity_new (book, name, space, mn, xcode, ran_int);
@@ -1580,23 +1644,9 @@
{
gnc_commodity *com;
Transaction *trans;
- Account *account;
- Split *split;
com = get_random_commodity_from_table (table);
- trans = get_random_transaction_with_currency (book, com);
-
- xaccTransBeginEdit (trans);
-
- split = xaccTransGetSplit (trans, 0);
- account = get_random_list_element (accounts);
- xaccAccountInsertSplit (account, split);
-
- split = xaccTransGetSplit (trans, 1);
- account = get_random_list_element (accounts);
- xaccAccountInsertSplit (account, split);
-
- xaccTransCommitEdit (trans);
+ trans = get_random_transaction_with_currency (book, com, accounts);
}
g_list_free (accounts);
}
Index: test-engine-stuff.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test-core/test-engine-stuff.h,v
retrieving revision 1.22.4.1
retrieving revision 1.22.4.2
diff -Lsrc/engine/test-core/test-engine-stuff.h -Lsrc/engine/test-core/test-engine-stuff.h -u -r1.22.4.1 -r1.22.4.2
--- src/engine/test-core/test-engine-stuff.h
+++ src/engine/test-core/test-engine-stuff.h
@@ -1,4 +1,5 @@
-/* This file declares testing functions for the engine.
+/** @file test-engine-stuff.h
+ * $brief This file declares testing functions for the engine.
*/
#ifndef TEST_ENGINE_STUFF_H
@@ -46,10 +47,11 @@
GNCPriceDB * get_random_pricedb(QofBook *book);
AccountGroup * get_random_group(QofBook * book);
Account* get_random_account(QofBook * book);
-Split* get_random_split(QofBook *book, gnc_numeric num);
+Split* get_random_split(QofBook *book, Account *account);
Transaction* get_random_transaction(QofBook *book);
Transaction* get_random_transaction_with_currency(QofBook *book,
- gnc_commodity *currency);
+ gnc_commodity *currency,
+ GList *account_list);
gnc_commodity* get_random_commodity(QofBook *book);
const char *get_random_commodity_namespace(void);
Index: gnc-module.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnc-module/gnc-module.scm,v
retrieving revision 1.4.4.1
retrieving revision 1.4.4.2
diff -Lsrc/gnc-module/gnc-module.scm -Lsrc/gnc-module/gnc-module.scm -u -r1.4.4.1 -r1.4.4.2
--- src/gnc-module/gnc-module.scm
+++ src/gnc-module/gnc-module.scm
@@ -11,12 +11,18 @@
(export gnc:module-system-init)
+(if (not (defined? 're-export))
+ (begin
+ (defmacro re-export names
+ `(eval export names))
+ (export re-export)))
+
;; symbols from gw-gnc-module
-(export gnc:module-system-refresh)
-(export gnc:module-load)
-(export gnc:module-load-optional)
-(export gnc:module-unload)
-(export gnc:module-lookup)
+(re-export gnc:module-system-refresh)
+(re-export gnc:module-load)
+(re-export gnc:module-load-optional)
+(re-export gnc:module-unload)
+(re-export gnc:module-lookup)
(define (gnc:module-system-init)
(let ((lib (if (or (string=? (version) "1.3")
Index: druid-stock-split.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/druid-stock-split.c,v
retrieving revision 1.34.4.9
retrieving revision 1.34.4.10
diff -Lsrc/gnome/druid-stock-split.c -Lsrc/gnome/druid-stock-split.c -u -r1.34.4.9 -r1.34.4.10
--- src/gnome/druid-stock-split.c
+++ src/gnome/druid-stock-split.c
@@ -56,7 +56,7 @@
/* account page data */
GtkWidget * account_list;
- GUID account;
+ Account * acct;
/* info page data */
GtkWidget * date_edit;
@@ -198,7 +198,7 @@
if (account == NULL)
return;
- info->account = *xaccAccountGetGUID (account);
+ info->acct = account;
}
static void
@@ -207,7 +207,7 @@
GNCPrintAmountInfo print_info;
Account *account;
- account = xaccAccountLookup (&info->account, gnc_get_current_book ());
+ account = info->acct;
g_return_if_fail (account != NULL);
@@ -229,11 +229,8 @@
gpointer user_data)
{
StockSplitInfo *info = user_data;
- Account *account;
-
- account = xaccAccountLookup (&info->account, gnc_get_current_book ());
- g_return_val_if_fail (account != NULL, TRUE);
+ g_return_val_if_fail (info->acct != NULL, TRUE);
refresh_details_page (info);
@@ -398,7 +395,7 @@
Split *split;
time_t date;
- account = xaccAccountLookup (&info->account, gnc_get_current_book ());
+ account = info->acct;
g_return_if_fail (account != NULL);
amount = gnc_amount_edit_get_amount
@@ -665,24 +662,18 @@
{
StockSplitInfo *info = user_data;
Account *old_account;
- Account *new_account;
- GNCIdType id_type;
GtkWidget *page;
GladeXML *xml;
- old_account = xaccAccountLookup (&info->account, gnc_get_current_book ());
- id_type = xaccGUIDType (old_account, gnc_get_current_book ());
+ old_account = info->acct;
- if (fill_account_list (info, old_account) == 0)
+ if (fill_account_list (info, info->acct) == 0)
{
gnc_close_gui_component_by_data (DRUID_STOCK_SPLIT_CM_CLASS, info);
return;
}
- new_account = xaccAccountLookup (&info->account, gnc_get_current_book ());
-
- if (!safe_strcmp (id_type, GNC_ID_NULL) || old_account == new_account)
- return;
+ if (NULL == info->acct || old_account == info->acct) return;
xml = glade_get_widget_tree (info->window);
page = glade_xml_get_widget (xml, "account_page");
@@ -714,7 +705,7 @@
info = g_new0 (StockSplitInfo, 1);
- info->account = *xaccGUIDNULL ();
+ info->acct = NULL;
gnc_stock_split_druid_create (info);
Index: dialog-print-check.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/dialog-print-check.c,v
retrieving revision 1.13.4.5
retrieving revision 1.13.4.6
diff -Lsrc/gnome/dialog-print-check.c -Lsrc/gnome/dialog-print-check.c -u -r1.13.4.5 -r1.13.4.6
--- src/gnome/dialog-print-check.c
+++ src/gnome/dialog-print-check.c
@@ -181,7 +181,7 @@
int sel_option;
double multip = 72.0;
- char * formats[] = { "quicken", "deluxe", "custom" };
+ char * formats[] = { "quicken", "deluxe", "wallet", "custom" };
char * positions[] = { "top", "middle", "bottom", "custom" };
sel_option = gnc_option_menu_get_active(pcd->format_picker);
Index: top-level.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/top-level.c,v
retrieving revision 1.140.4.12
retrieving revision 1.140.4.13
diff -Lsrc/gnome/top-level.c -Lsrc/gnome/top-level.c -u -r1.140.4.12 -r1.140.4.13
--- src/gnome/top-level.c
+++ src/gnome/top-level.c
@@ -138,6 +138,35 @@
gnc_gnome_help (HF_CUSTOM, HL_GLOBPREFS);
}
+static void
+gnc_commodity_help_cb (void)
+{
+ gnc_gnome_help (HF_USAGE, HL_COMMODITY);
+}
+
+/* ============================================================== */
+/* HTML Hadler for reports. */
+
+#define IF_TYPE(URL_TYPE_STR,ENTITY_TYPE) \
+ if (strncmp (URL_TYPE_STR, location, strlen (URL_TYPE_STR)) == 0) \
+ { \
+ GUID guid; \
+ QofCollection *col; \
+ QofEntity *entity; \
+ if (!string_to_guid (location + strlen(URL_TYPE_STR), &guid)) \
+ { \
+ result->error_message = g_strdup_printf (_("Bad URL: %s"), location); \
+ return FALSE; \
+ } \
+ col = qof_book_get_collection (book, ENTITY_TYPE); \
+ entity = qof_collection_lookup_entity (col, &guid); \
+ if (NULL == entity) \
+ { \
+ result->error_message = g_strdup_printf (_("Entity Not Found: %s"), location); \
+ return FALSE; \
+ } \
+
+
static gboolean
gnc_html_register_url_cb (const char *location, const char *label,
gboolean new_window, GNCURLResult *result)
@@ -145,9 +174,10 @@
GncPluginPage *page = NULL;
GNCSplitReg * gsr = NULL;
Split * split = NULL;
- Account * account;
+ Account * account = NULL;
Transaction * trans;
GList * node;
+ QofBook * book = gnc_get_current_book();
g_return_val_if_fail (location != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
@@ -160,150 +190,82 @@
account = xaccGetAccountFromFullName (gnc_get_current_group (),
location + 8,
gnc_get_account_separator ());
- page = gnc_plugin_page_register_new (account, FALSE);
- gnc_main_window_open_page (NULL, page);
}
- /* href="gnc-register:guid=12345678901234567890123456789012" */
- else if (strncmp ("guid=", location, 5) == 0)
- {
- GUID guid;
- QofEntity *qofEnt;
- if (!string_to_guid (location + 5, &guid))
- {
- result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
- return FALSE;
- }
+ /* href="gnc-register:guid=12345678901234567890123456789012" */
+ else IF_TYPE ("acct-guid=", GNC_ID_ACCOUNT)
+ account = GNC_ACCOUNT(entity);
+ }
- qofEnt = qof_book_get_entity_by_guid( gnc_get_current_book(), &guid );
- if ( (qofEnt == NULL)
- || (qofEnt->e_type == GNC_ID_NONE)
- || !safe_strcmp( qofEnt->e_type, GNC_ID_NULL ))
- {
- result->error_message = g_strdup_printf (_("No such entity: %s"),
- location);
- return FALSE;
- }
+ else IF_TYPE ("trans-guid=", GNC_ID_TRANS)
+ trans = (Transaction *) entity;
- else if (!safe_strcmp (qofEnt->e_type, GNC_ID_ACCOUNT))
+ for (node = xaccTransGetSplitList (trans); node; node = node->next)
{
- account = xaccAccountLookup (&guid, gnc_get_current_book ());
- page = gnc_plugin_page_register_new (account, FALSE);
- gnc_main_window_open_page (NULL, page);
+ split = node->data;
+ account = xaccSplitGetAccount(split);
+ if (account) break;
}
- else if (!safe_strcmp (qofEnt->e_type, GNC_ID_TRANS))
- {
- trans = xaccTransLookup (&guid, gnc_get_current_book ());
- split = NULL;
- for (node = xaccTransGetSplitList (trans); node; node = node->next)
- {
- split = node->data;
- if (xaccSplitGetAccount (split))
- break;
- }
-
- if (!split)
- {
- result->error_message =
- g_strdup_printf (_("Transaction with no Accounts: %s"), location);
- return FALSE;
- }
-
- account = xaccSplitGetAccount(split);
- page = gnc_plugin_page_register_new (account, FALSE);
- gnc_main_window_open_page (NULL, page);
- }
- else if (!safe_strcmp (qofEnt->e_type, GNC_ID_SPLIT))
+ if (!account)
{
- split = xaccSplitLookup (&guid, gnc_get_current_book ());
- if (!split)
- {
- result->error_message = g_strdup_printf (_("No such split: %s"),
- location);
- return FALSE;
- }
-
- account = xaccSplitGetAccount(split);
- page = gnc_plugin_page_register_new (account, FALSE);
- gnc_main_window_open_page (NULL, page);
- }
- else
- {
- result->error_message =
- g_strdup_printf (_("Unsupported entity type: %s"), location);
- return FALSE;
- }
-
- if (page && split) {
- gsr = gnc_plugin_page_register_get_gsr(page);
- gnc_split_reg_jump_to_split( gsr, split );
+ result->error_message =
+ g_strdup_printf (_("Transaction with no Accounts: %s"), location);
+ return FALSE;
}
}
+ else IF_TYPE ("split-guid=", GNC_ID_SPLIT)
+ split = (Split *) entity;
+ account = xaccSplitGetAccount(split);
+ }
else
{
- result->error_message = g_strdup_printf (_("Badly formed URL %s"),
- location);
+ result->error_message =
+ g_strdup_printf (_("Unsupported entity type: %s"), location);
return FALSE;
}
+ page = gnc_plugin_page_register_new (account, FALSE);
+ gnc_main_window_open_page (NULL, page);
+ if (split) {
+ gsr = gnc_plugin_page_register_get_gsr(page);
+ gnc_split_reg_jump_to_split( gsr, split );
+ }
+
return TRUE;
}
+/* ============================================================== */
+
static gboolean
gnc_html_price_url_cb (const char *location, const char *label,
- gboolean new_window, GNCURLResult *result)
+ gboolean new_window, GNCURLResult *result)
{
+ QofBook * book = gnc_get_current_book();
g_return_val_if_fail (location != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
result->load_to_stream = FALSE;
/* href="gnc-register:guid=12345678901234567890123456789012" */
- if (strncmp ("guid=", location, 5) == 0)
- {
- GUID guid;
- QofEntity *qofEnt;
-
- if (!string_to_guid (location + 5, &guid))
- {
- result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
- return FALSE;
- }
-
- qofEnt = qof_book_get_entity_by_guid( gnc_get_current_book(),
- &guid );
-
- if ( qofEnt == NULL
- || qofEnt->e_type == GNC_ID_NONE
- || safe_strcmp (qofEnt->e_type, GNC_ID_PRICE))
- {
- result->error_message =
- g_strdup_printf (_("Unsupported entity type: %s"), location);
- return FALSE;
- }
- if (!gnc_price_edit_by_guid (NULL, &guid)) {
- result->error_message = g_strdup_printf(_("No such entity: %s"),
- location);
- return FALSE;
- }
+ IF_TYPE ("price-guid=", GNC_ID_PRICE)
+ if (!gnc_price_edit_by_guid (NULL, &guid))
+ {
+ result->error_message = g_strdup_printf (_("No such price: %s"),
+ location);
+ return FALSE;
+ }
}
else
{
result->error_message = g_strdup_printf (_("Badly formed URL %s"),
- location);
+ location);
return FALSE;
}
return TRUE;
}
-static void
-gnc_commodity_help_cb (void)
-{
- gnc_gnome_help (HF_USAGE, HL_COMMODITY);
-}
-
/* ============================================================== */
SCM
@@ -516,8 +478,7 @@
}
static int
-gnc_x_error (Display *display,
- XErrorEvent *error)
+gnc_x_error (Display *display, XErrorEvent *error)
{
if (error->error_code)
{
@@ -873,7 +834,7 @@
{
gnc_file_be_set_retention_days
(gnc_lookup_number_option("General",
- "Days to retain log files", 0));
+ "Days to retain log files", 0));
}
/* gnc_configure_file_be_retention_days_cb
Index: dialog-progress.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/dialog-progress.c,v
retrieving revision 1.4.6.1
retrieving revision 1.4.6.2
diff -Lsrc/gnome/dialog-progress.c -Lsrc/gnome/dialog-progress.c -u -r1.4.6.1 -r1.4.6.2
--- src/gnome/dialog-progress.c
+++ src/gnome/dialog-progress.c
@@ -148,7 +148,7 @@
/* Make sure the callbacks aren't invoked */
progress->cancel_func = NULL;
if (progress->cancel_scm_func != SCM_UNDEFINED)
- scm_unprotect_object (progress->cancel_scm_func);
+ scm_gc_unprotect_object (progress->cancel_scm_func);
progress->cancel_scm_func = SCM_UNDEFINED;
g_free(progress);
@@ -309,12 +309,12 @@
return;
if (progress->cancel_scm_func != SCM_UNDEFINED)
- scm_unprotect_object (progress->cancel_scm_func);
+ scm_gc_unprotect_object (progress->cancel_scm_func);
if (SCM_PROCEDUREP(cancel_scm_func))
{
progress->cancel_scm_func = cancel_scm_func;
- scm_protect_object (cancel_scm_func);
+ scm_gc_protect_object (cancel_scm_func);
gtk_widget_show (progress->cancel_button);
}
else
@@ -378,7 +378,7 @@
/* Make sure the callbacks aren't invoked */
progress->cancel_func = NULL;
if (progress->cancel_scm_func != SCM_UNDEFINED)
- scm_unprotect_object (progress->cancel_scm_func);
+ scm_gc_unprotect_object (progress->cancel_scm_func);
progress->cancel_scm_func = SCM_UNDEFINED;
if (!progress->finished)
Index: gnc-general-search.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-search/gnc-general-search.c,v
retrieving revision 1.1.4.7
retrieving revision 1.1.4.8
diff -Lsrc/gnome-search/gnc-general-search.c -Lsrc/gnome-search/gnc-general-search.c -u -r1.1.4.7 -r1.1.4.8
--- src/gnome-search/gnc-general-search.c
+++ src/gnome-search/gnc-general-search.c
@@ -301,7 +301,7 @@
g_return_val_if_fail (type && label && search_cb, NULL);
- get_guid = qof_class_get_parameter (type, QOF_QUERY_PARAM_GUID);
+ get_guid = qof_class_get_parameter (type, QOF_PARAM_GUID);
g_return_val_if_fail (get_guid, NULL);
gsl = g_object_new (gnc_general_search_get_type (), NULL);
Index: dialog-search.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-search/dialog-search.c,v
retrieving revision 1.35.4.14
retrieving revision 1.35.4.15
diff -Lsrc/gnome-search/dialog-search.c -Lsrc/gnome-search/dialog-search.c -u -r1.35.4.14 -r1.35.4.15
--- src/gnome-search/dialog-search.c
+++ src/gnome-search/dialog-search.c
@@ -918,8 +918,7 @@
sw->free_cb = free_cb;
/* Grab the get_guid function */
- sw->get_guid = qof_class_get_parameter (sw->search_for,
- QOF_QUERY_PARAM_GUID);
+ sw->get_guid = qof_class_get_parameter (sw->search_for, QOF_PARAM_GUID);
if (start_query)
sw->start_q = gncQueryCopy (start_query);
sw->q = show_start_query;
Index: print.glade
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/glade/print.glade,v
retrieving revision 1.6.4.5
retrieving revision 1.6.4.6
diff -Lsrc/gnome/glade/print.glade -Lsrc/gnome/glade/print.glade -u -r1.6.4.5 -r1.6.4.6
--- src/gnome/glade/print.glade
+++ src/gnome/glade/print.glade
@@ -245,6 +245,15 @@
</child>
<child>
+ <widget class="GtkMenuItem" id="buyand2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Quicken(tm) Wallet Checks w/ side stub
+</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkMenuItem" id="convertwidget3">
<property name="visible">True</property>
<property name="label" translatable="yes">Custom</property>
--- /dev/null
+++ src/gnome-utils/account-quickfill.c
@@ -0,0 +1,173 @@
+/********************************************************************\
+ * account-quickfill.h -- Create an account-name quick-fill *
+ * 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 *
+ * *
+\********************************************************************/
+
+#include "config.h"
+#include "account-quickfill.h"
+#include "gnc-engine-util.h"
+#include "gnc-event.h"
+#include "gnc-trace.h"
+#include "gnc-ui-util.h"
+
+/* This static indicates the debugging module that this .o belongs to. */
+static short module = MOD_REGISTER;
+
+/* ===================================================================== */
+/* In order to speed up register starts for registers htat have a huge
+ * number of accounts in them (where 'huge' is >500) we build a quickfill
+ * cache of account names. This cache is needed because some users on
+ * some machines experience register open times in the tens of seconds
+ * type timescales. Building the quickfill list accounts for almost
+ * all of that cpu time (about 90% of the xfer_cell build time for 600
+ * accounts).
+ */
+
+typedef struct {
+ QuickFill *qf;
+ QofBook *book;
+ gint listener;
+ AccountBoolCB dont_add_cb;
+ gpointer dont_add_data;
+} QFB;
+
+static void
+shared_quickfill_destroy (QofBook *book, gpointer key, gpointer user_data)
+{
+ QFB *qfb = user_data;
+ gnc_quickfill_destroy (qfb->qf);
+ gnc_engine_unregister_event_handler (qfb->listener);
+ g_free (qfb);
+}
+
+/* Since we are maintaining a 'global' quickfill list, we need to
+ * update it whenever the user creates a new account. So listen
+ * for account modification events, and add new accounts.
+ */
+static void
+listen_for_account_events (GUID *guid, QofIdType type,
+ GNCEngineEventType event_type,
+ gpointer user_data)
+{
+ QFB *qfb = user_data;
+ QuickFill *qf = qfb->qf;
+ QuickFill *match;
+ char * name;
+ const char *match_str;
+ QofCollection *col;
+ Account *account;
+
+ if (! (event_type & GNC_EVENT_MODIFY)) return;
+ if (QSTRCMP (type, GNC_ID_ACCOUNT)) return;
+
+ col = qof_book_get_collection (qfb->book, GNC_ID_ACCOUNT);
+ account = GNC_ACCOUNT (qof_collection_lookup_entity (col, guid));
+
+ /* Not every new account is eligable for the menu */
+ if (qfb->dont_add_cb)
+ {
+ gboolean skip = (qfb->dont_add_cb) (account, qfb->dont_add_data);
+ if (skip) return;
+ }
+
+ name = xaccAccountGetFullName (account, gnc_get_account_separator ());
+ if (NULL == name) return;
+
+ match = gnc_quickfill_get_string_match (qf, name);
+ if (!match) goto add_string;
+ match_str = gnc_quickfill_string (match);
+ if (!match_str) goto add_string;
+ if (safe_strcmp (match_str, name)) goto add_string;
+
+ PINFO ("got match for %s", name);
+ goto done;
+
+add_string:
+ PINFO ("insert new account %s into qf=%p\n", name, qf);
+ gnc_quickfill_insert (qf, name, QUICKFILL_ALPHA);
+done:
+ g_free(name);
+}
+
+/* Splat the account name into the shared quickfill object */
+static gpointer
+load_shared_qf_cb (Account *account, gpointer data)
+{
+ QFB *qfb = data;
+ char *name;
+
+ if (qfb->dont_add_cb)
+ {
+ gboolean skip = (qfb->dont_add_cb) (account, qfb->dont_add_data);
+ if (skip) return NULL;
+ }
+
+ name = xaccAccountGetFullName (account, gnc_get_account_separator ());
+ if (NULL == name) return NULL;
+ gnc_quickfill_insert (qfb->qf, name, QUICKFILL_ALPHA);
+ g_free(name);
+
+ return NULL;
+}
+
+/* Build the quickfill list out of account names.
+ * Essentially same loop as in gnc_load_xfer_cell() above.
+ */
+static QuickFill *
+build_shared_quickfill (QofBook *book, AccountGroup *group, const char * key,
+ AccountBoolCB cb, gpointer data)
+{
+ QFB *qfb;
+
+ qfb = g_new0(QFB, 1);
+ qfb->qf = gnc_quickfill_new ();
+ qfb->book = book;
+ qfb->listener = 0;
+ qfb->dont_add_cb = cb;
+ qfb->dont_add_data = data;
+
+ xaccGroupForEachAccount (group, load_shared_qf_cb, qfb, TRUE);
+
+ qfb->listener =
+ gnc_engine_register_event_handler (listen_for_account_events, qfb);
+
+ qof_book_set_data_fin (book, key, qfb, shared_quickfill_destroy);
+
+ return qfb->qf;
+}
+
+QuickFill *
+gnc_get_shared_account_name_quickfill (AccountGroup *group,
+ const char * key,
+ AccountBoolCB cb, gpointer cb_data)
+{
+ QFB *qfb;
+ QofBook *book;
+
+ book = xaccGroupGetBook (group);
+ qfb = qof_book_get_data (book, key);
+
+ if (qfb) return qfb->qf;
+
+ return build_shared_quickfill (book, group, key, cb, cb_data);
+}
+
+/* ====================== END OF FILE ================================== */
Index: gnc-menu-extensions.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/gnc-menu-extensions.c,v
retrieving revision 1.9.4.3
retrieving revision 1.9.4.4
diff -Lsrc/gnome-utils/gnc-menu-extensions.c -Lsrc/gnome-utils/gnc-menu-extensions.c -u -r1.9.4.3 -r1.9.4.4
--- src/gnome-utils/gnc-menu-extensions.c
+++ src/gnome-utils/gnc-menu-extensions.c
@@ -210,11 +210,12 @@
path = SCM_CDR(path);
if (SCM_STRINGP(item))
- strings[i] = gh_scm2newstr(item, NULL);
+ {
+ /* strings[i] = gh_scm2newstr(item, NULL); */
+ strings[i] = SCM_STRING_CHARS (item);
+ }
else
{
- while (i > 0)
- free(strings[--i]);
g_free(strings);
PERR("not a string");
@@ -237,9 +238,6 @@
*fullpath = g_strjoinv("/", strings);
}
- i = 0;
- while (strings[i] != NULL)
- free(strings[i++]);
g_free(strings);
}
@@ -372,7 +370,7 @@
ext_info->info[1].type = GNOME_APP_UI_ENDOFINFO;
*/
- scm_protect_object(extension);
+ scm_gc_protect_object(extension);
/* need to append so we can run them in order */
extension_list = g_slist_append(extension_list, ext_info);
@@ -387,7 +385,7 @@
ExtensionInfo *ext_info = extension_info;
if (ext_info->extension)
- scm_unprotect_object(ext_info->extension);
+ scm_gc_unprotect_object(ext_info->extension);
g_free(ext_info->extra_info);
g_free(ext_info->path);
Index: QuickFill.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/QuickFill.h,v
retrieving revision 1.1.4.1
retrieving revision 1.1.4.2
diff -Lsrc/gnome-utils/QuickFill.h -Lsrc/gnome-utils/QuickFill.h -u -r1.1.4.1 -r1.1.4.2
--- src/gnome-utils/QuickFill.h
+++ src/gnome-utils/QuickFill.h
@@ -1,8 +1,5 @@
/********************************************************************\
* QuickFill.h -- the quickfill tree data structure *
- * Copyright (C) 1997 Robin D. Clark *
- * Copyright (C) 1998 Linas Vepstas *
- * Copyright (C) 2000 Dave Peticolas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -31,6 +28,28 @@
#include <gdk/gdk.h>
#include <glib.h>
+/** @addtogroup QuickFill
+ QuickFill is meant to be used by the GUI to auto-complete
+ (e.g. tab-complete) typed user input.
+ Quickfill is implemented as a heirarchical tree
+ of partial matching strings. The root of the tree contains
+ all of the strings that user input should be matched to.
+ Then, given a short string segment, quickfill will return
+ a subtree containing only those strings that start with desired
+ substring. As additional letters are added to the substring,
+ Quickfill will thus narrow down to the unique matching string
+ (or to nothing if no match).
+
+ QuickFill works with national-language i18n'ed/l10n'ed multi-byte
+ and wide-char strings, as well as plain-old C-locale strings.
+ @{
+
+ @file QuickFill.h
+ @breif Quickfill is used to auto-complete typed user entries.
+ @author Copyright (C) 1997 Robin D. Clark
+ @author Copyright (C) 1998,2004 Linas Vepstas <linas at linas.org>
+ @author Copyright (C) 2000 Dave Peticolas
+ */
typedef enum
{
@@ -41,24 +60,64 @@
typedef struct _QuickFill QuickFill;
-/** PROTOTYPES ******************************************************/
+/* PROTOTYPES ******************************************************/
QuickFill * gnc_quickfill_new (void);
void gnc_quickfill_destroy (QuickFill *qf);
+/** For the given node 'qf', return the best-guess matching string.
+ */
const char * gnc_quickfill_string (QuickFill *qf);
+/** Return the subnode of the tree whose strings all hold 'wc' as
+ * the next letter. That is, if 'qf' holds all strings starting
+ * with the letter 'a', and we ask for the letter 'b', then this
+ * routine will return the node holding all strings that start
+ * with "ab".
+ *
+ * The best-guess matching string can be retreived with
+ * gnc_quickfill_string().
+ */
QuickFill * gnc_quickfill_get_char_match (QuickFill *qf, gunichar c);
+/** Return a subnode in the tree whose strings all match the
+ * string 'str' as the next substring. Thus, for example, if
+ * the argument 'qf' holds strings that start with "abc", and
+ * this routine is called with "def", then the returned node
+ * will hold strings that start with "abcdef".
+ *
+ * The best-guess matching string can be retreived with
+ * gnc_quickfill_string().
+ *
+ * To convert a plain C-locale char * string to GdkWChar *,
+ * use the gnc_mbstowcs() routine.
+ */
QuickFill * gnc_quickfill_get_string_match (QuickFill *qf,
const char *str);
+/** Same as gnc_quickfill_get_string_match(), except that the
+ * string length is explicilty specified.
+ */
QuickFill * gnc_quickfill_get_string_len_match (QuickFill *qf,
const char *str, int len);
+/** Walk a 'unique' part of the quickfill tree. This routine is
+ * typically used to assist in the tab-completion of strings.
+ * If the inital portion of the string is unique, but some later
+ * portion is not, this routine will advance to the first non-unique
+ * part of the string. If len is non-NULL, then *len will be set
+ * to the length of the unique portion of the string.
+ *
+ * Thus, for example, if the root node contains the strings
+ * "The Book" and "The Movie", then the returned len will be 4,
+ * and the returned node will distinguish "Book" and "Movie".
+ * Thus, for example, gnc_quickfill_get_char_match(.., 'B') on
+ * the result will identify "The Book".
+ */
QuickFill * gnc_quickfill_get_unique_len_match (QuickFill *qf, int *len);
-void gnc_quickfill_insert (QuickFill *qf, const char *text,
+/** Add the string "text" to the collection of searchable strings. */
+void gnc_quickfill_insert (QuickFill *root, const char *text,
QuickFillSort sort_code);
#endif /* QUICKFILL_H */
Index: argv-list-converters.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/argv-list-converters.c,v
retrieving revision 1.1.4.1
retrieving revision 1.1.4.2
diff -Lsrc/gnome-utils/argv-list-converters.c -Lsrc/gnome-utils/argv-list-converters.c -u -r1.1.4.1 -r1.1.4.2
--- src/gnome-utils/argv-list-converters.c
+++ src/gnome-utils/argv-list-converters.c
@@ -61,10 +61,9 @@
next = SCM_CDR(next);
if(SCM_STRINGP(scm_string))
{
- char *onestr = gh_scm2newstr(scm_string, 0);
+ /* char *onestr = gh_scm2newstr(scm_string, 0); */
+ char *onestr = SCM_STRING_CHARS(scm_string);
ret[loc] = g_strdup (onestr);
- if (onestr)
- free (onestr);
}
else
{
--- /dev/null
+++ src/gnome-utils/account-quickfill.h
@@ -0,0 +1,75 @@
+/********************************************************************\
+ * account-quickfill.h -- Create an account-name quick-fill *
+ * *
+ * 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 Account_Quickfill Quickfill Account Names
+ For systems with a large number of accounts (>500), the creation
+ of the account name quickfill can take a significant amount of
+ time (tens of seconds in bad cases). This routine will build
+ a cache of account names that can be shared by all registers,
+ thus dramatically improving the performance of opening a new
+ register.
+ @{
+
+ @file account-quickfill.h
+ @brief Create an account-name quick-fill
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
+*/
+
+#ifndef QUICKFILL_ACCOUNT_H
+#define QUICKFILL_ACCOUNT_H
+
+#include <glib.h>
+
+#include "Account.h"
+#include "Group.h"
+#include "QuickFill.h"
+
+typedef gboolean (*AccountBoolCB) (Account *, gpointer);
+
+/** Create/fetch a quickfill of account names.
+ *
+ * The quickfill is created out of all of the subaccounts
+ * the the account group, filtered by the 'skip_cb' callback.
+ * If 'skip_cb' is not NULL, and if it returns TRUE when passed
+ * a particular account, then that account won't be included in
+ * the quickfill. The 'cb_data' is passed to the callback.
+ *
+ * The quickfill is created only once; it is then stored with
+ * the QofBook that is the parent of the AccountGroup. It is
+ * automatically destroyed when the QofBook is destroyed.
+ *
+ * Multiple, distinct quickfills, for different uses, are allowed.
+ * Each is identified with the 'key'. Be sure to use distinct,
+ * unique keys that don't conflict with other users of QofBook.
+ *
+ * This code listens to account creation events, and automatically
+ * adds new accounts to the quickfill list (assuming skip_cb allows
+ * it). This code does not currently listen to account-destroy
+ * events.
+ */
+QuickFill * gnc_get_shared_account_name_quickfill (AccountGroup *group,
+ const char * key,
+ AccountBoolCB skip_cb,
+ gpointer cb_data);
+
+#endif
+
+/** @} */
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/Makefile.am,v
retrieving revision 1.48.2.21
retrieving revision 1.48.2.22
diff -Lsrc/gnome-utils/Makefile.am -Lsrc/gnome-utils/Makefile.am -u -r1.48.2.21 -r1.48.2.22
--- src/gnome-utils/Makefile.am
+++ src/gnome-utils/Makefile.am
@@ -27,6 +27,7 @@
libgncmod_gnome_utils_la_SOURCES = \
QuickFill.c \
+ account-quickfill.c \
cursors.c \
argv-list-converters.c \
dialog-account.c \
@@ -80,6 +81,7 @@
gncincludedir = ${GNC_INCLUDE_DIR}
gncinclude_HEADERS = \
QuickFill.h \
+ account-quickfill.h \
dialog-account.h \
dialog-commodity.h \
dialog-options.h \
Index: dialog-options.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/dialog-options.c,v
retrieving revision 1.22.2.16
retrieving revision 1.22.2.17
diff -Lsrc/gnome-utils/dialog-options.c -Lsrc/gnome-utils/dialog-options.c -u -r1.22.2.16 -r1.22.2.17
--- src/gnome-utils/dialog-options.c
+++ src/gnome-utils/dialog-options.c
@@ -2019,9 +2019,9 @@
{
if (SCM_STRINGP(value))
{
- char *string = gh_scm2newstr(value, NULL);
+ /* char *string = gh_scm2newstr(value, NULL); */
+ char *string = SCM_STRING_CHARS(value);
gtk_entry_set_text(GTK_ENTRY(widget), string);
- free(string);
return FALSE;
}
else
@@ -2041,7 +2041,8 @@
if (SCM_STRINGP(value))
{
- char *string = gh_scm2newstr(value, NULL);
+ /* char *string = gh_scm2newstr(value, NULL); */
+ char *string = SCM_STRING_CHARS(value);
gtk_text_buffer_set_text (buffer, string, strlen (string));
free(string);
return FALSE;
@@ -2308,14 +2309,13 @@
{
if (SCM_STRINGP(value))
{
- char *string = gh_scm2newstr(value, NULL);
+ /* char *string = gh_scm2newstr(value, NULL); */
+ char *string = SCM_STRING_CHARS(value);
if ((string != NULL) && (*string != '\0'))
{
GnomeFontPicker *picker = GNOME_FONT_PICKER(widget);
gnome_font_picker_set_font_name(picker, string);
}
- if(string)
- free(string);
return FALSE;
}
else
@@ -2329,7 +2329,8 @@
ENTER("option %p(%s)", option, gnc_option_name(option));
if (SCM_STRINGP(value))
{
- char * string = gh_scm2newstr(value, NULL);
+ /* char * string = gh_scm2newstr(value, NULL); */
+ char *string = SCM_STRING_CHARS(value);
if (string && *string)
{
@@ -2338,8 +2339,6 @@
entry = GTK_ENTRY(gnome_pixmap_entry_gtk_entry(GNOME_PIXMAP_ENTRY(widget)));
gtk_entry_set_text(entry, string);
}
- if(string)
- free(string);
LEAVE("FALSE");
return FALSE;
}
@@ -2770,11 +2769,11 @@
if (cbdata->close_cb != SCM_BOOL_F) {
scm_call_0 (cbdata->close_cb);
- scm_unprotect_object (cbdata->close_cb);
+ scm_gc_unprotect_object (cbdata->close_cb);
}
if (cbdata->apply_cb != SCM_BOOL_F)
- scm_unprotect_object (cbdata->apply_cb);
+ scm_gc_unprotect_object (cbdata->apply_cb);
g_free (cbdata);
}
@@ -2793,10 +2792,10 @@
cbdata->close_cb = close_cb;
if (apply_cb != SCM_BOOL_F)
- scm_protect_object (cbdata->apply_cb);
+ scm_gc_protect_object (cbdata->apply_cb);
if (close_cb != SCM_BOOL_F)
- scm_protect_object (cbdata->close_cb);
+ scm_gc_protect_object (cbdata->close_cb);
gnc_options_dialog_set_apply_cb (win, scm_apply_cb, cbdata);
gnc_options_dialog_set_close_cb (win, scm_close_cb, cbdata);
Index: gnc-query-list.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/gnc-query-list.c,v
retrieving revision 1.8.2.5
retrieving revision 1.8.2.6
diff -Lsrc/gnome-utils/gnc-query-list.c -Lsrc/gnome-utils/gnc-query-list.c -u -r1.8.2.5 -r1.8.2.6
--- src/gnome-utils/gnc-query-list.c
+++ src/gnome-utils/gnc-query-list.c
@@ -126,8 +126,7 @@
/* cache the function to get the guid of this query type */
list->priv->get_guid =
- qof_class_get_parameter (qof_query_get_search_for(query),
- QOF_QUERY_PARAM_GUID);
+ qof_class_get_parameter (qof_query_get_search_for(query), QOF_PARAM_GUID);
/* Initialize the CList */
gnc_query_list_init_clist(list);
Index: QuickFill.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/QuickFill.c,v
retrieving revision 1.1.4.1
retrieving revision 1.1.4.2
diff -Lsrc/gnome-utils/QuickFill.c -Lsrc/gnome-utils/QuickFill.c -u -r1.1.4.1 -r1.1.4.2
--- src/gnome-utils/QuickFill.c
+++ src/gnome-utils/QuickFill.c
@@ -55,6 +55,7 @@
/********************************************************************\
\********************************************************************/
+
static guint
quickfill_hash (gconstpointer key)
{
@@ -72,6 +73,7 @@
/********************************************************************\
\********************************************************************/
+
QuickFill *
gnc_quickfill_new (void)
{
@@ -99,6 +101,7 @@
/********************************************************************\
\********************************************************************/
+
static void
destroy_helper (gpointer key, gpointer value, gpointer data)
{
@@ -125,6 +128,7 @@
/********************************************************************\
\********************************************************************/
+
const char *
gnc_quickfill_string (QuickFill *qf)
{
@@ -136,21 +140,29 @@
/********************************************************************\
\********************************************************************/
+
QuickFill *
gnc_quickfill_get_char_match (QuickFill *qf, gunichar uc)
{
guint key = g_unichar_toupper (uc);
- if (qf == NULL)
- return NULL;
+ if (NULL == qf) return NULL;
DEBUG ("xaccGetQuickFill(): index = %u\n", key);
+#if DEBUG_ME
+ GdkWChar s[2];
+ s[0] = wc;
+ s[1] = 0;
+ char * r= gnc_wcstombs (s);
+ PINFO ("ascii char=%s (%d)\n", r, (int) r[0]);
+#endif
return g_hash_table_lookup (qf->matches, GUINT_TO_POINTER (key));
}
/********************************************************************\
\********************************************************************/
+
QuickFill *
gnc_quickfill_get_string_len_match (QuickFill *qf,
const char *str, int len)
@@ -158,8 +170,8 @@
const char *c;
gunichar uc;
- if (str == NULL)
- return NULL;
+ if (NULL == qf) return NULL;
+ if (NULL == str) return NULL;
c = str;
while (*c && (len > 0))
@@ -179,17 +191,19 @@
/********************************************************************\
\********************************************************************/
+
QuickFill *
gnc_quickfill_get_string_match (QuickFill *qf, const char *str)
{
- if (str == NULL)
- return NULL;
+ if (NULL == qf) return NULL;
+ if (NULL == str) return NULL;
return gnc_quickfill_get_string_len_match (qf, str, g_utf8_strlen (str, -1));
}
/********************************************************************\
\********************************************************************/
+
static void
unique_len_helper (gpointer key, gpointer value, gpointer data)
{
@@ -214,7 +228,9 @@
count = g_hash_table_size (qf->matches);
if (count != 1)
+ {
return qf;
+ }
g_hash_table_foreach (qf->matches, unique_len_helper, &qf);
@@ -225,13 +241,15 @@
/********************************************************************\
\********************************************************************/
+
void
gnc_quickfill_insert (QuickFill *qf, const char *text, QuickFillSort sort)
{
gchar *normalized_str;
- if ((qf == NULL) || (text == NULL))
- return;
+ if (NULL == qf) return;
+ if (NULL == text) return;
+
normalized_str = g_utf8_normalize (text, -1, G_NORMALIZE_DEFAULT);
quickfill_insert_recursive (qf, normalized_str, 0, sort);
@@ -240,6 +258,7 @@
/********************************************************************\
\********************************************************************/
+
static void
quickfill_insert_recursive (QuickFill *qf, const char *text, int depth,
QuickFillSort sort)
Index: import-match-map.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/import-export/import-match-map.c,v
retrieving revision 1.4.4.2
retrieving revision 1.4.4.3
diff -Lsrc/import-export/import-match-map.c -Lsrc/import-export/import-match-map.c -u -r1.4.4.2 -r1.4.4.3
--- src/import-export/import-match-map.c
+++ src/import-export/import-match-map.c
@@ -480,6 +480,13 @@
for(current_token = g_list_first(tokens); current_token;
current_token = current_token->next)
{
+ /* Jump to next iteration if the pointer is not valid or if the
+ string is empty. In HBCI import we almost always get an empty
+ string, which doesn't work in the kvp loopkup later. So we
+ skip this case here. */
+ if (!current_token->data || (*((char*)current_token->data) == '\0'))
+ continue;
+
/* start off with no tokens for this account */
token_count = 0;
Index: combocell.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/register-core/combocell.h,v
retrieving revision 1.4
retrieving revision 1.4.6.1
diff -Lsrc/register/register-core/combocell.h -Lsrc/register/register-core/combocell.h -u -r1.4 -r1.4.6.1
--- src/register/register-core/combocell.h
+++ src/register/register-core/combocell.h
@@ -20,28 +20,19 @@
* *
\********************************************************************/
-/*
- * FILE:
- * combocell.h
- *
- * FUNCTION:
- * The ComboCell object implements a cell handler with a
- * "combination-box" pull-down menu in it.
+/**
+ * @file combocell.h
+ * @breif The ComboCell object implements a cell handler with a
+ * "combination-box" pull-down menu in it.
*
* On output, the currently selected menu item is displayed.
* On input, the user can select from a list in the pull-down menu,
* or use the keyboard to slect a menu entry by typing the first
* few menu characters.
*
- * METHODS:
- * The xaccAddComboCellMenuItem() method can be used to add a menu
- * item to the list.
- *
- *
- * HISTORY:
- * Created Jan 1998 Linas Vepstas
- * Copyright (c) 1998 Linas Vepstas
- * Copyright (c) 2000 Dave Peticolas
+ * @author Created Jan 1998 Linas Vepstas
+ * @author Copyright (c) 1998 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2000 Dave Peticolas
*/
#ifndef COMBO_CELL_H
@@ -50,7 +41,7 @@
#include <glib.h>
#include "basiccell.h"
-
+#include "QuickFill.h"
typedef struct
{
@@ -64,27 +55,40 @@
void gnc_combo_cell_set_value (ComboCell *cell, const char *value);
void gnc_combo_cell_clear_menu (ComboCell *cell);
+
+/** Add a menu item to the list. */
void gnc_combo_cell_add_menu_item (ComboCell *cell, char * menustr);
-/* Determines whether the cell will accept strings not in the
+/** Determines whether the cell will accept strings not in the
* menu. Defaults to strict, i.e., only menu items are accepted. */
void gnc_combo_cell_set_strict (ComboCell *cell, gboolean strict);
-/* Sets a character used for special completion processing. */
+/** Sets a character used for special completion processing. */
void gnc_combo_cell_set_complete_char (ComboCell *cell,
char complete_char);
-/* Add a string to a list of strings which, if the cell has that value,
+/** Add a string to a list of strings which, if the cell has that value,
* will cause the cell to be uneditable on 'enter'. */
void gnc_combo_cell_add_ignore_string (ComboCell *cell,
const char *ignore_string);
-/* Determines whether the popup list autosizes itself or uses
+/** Determines whether the popup list autosizes itself or uses
* all available space. FALSE by default. */
void gnc_combo_cell_set_autosize (ComboCell *cell, gboolean autosize);
-/* Determines whether combocells are automatically raised upon typing.
+/** Determines whether combocells are automatically raised upon typing.
* Defaults to false. This is a 'class' method. */
void gnc_combo_cell_set_autopop (gboolean auto_pop_combos);
+/** Tell the combocell to use a shared QuickFill object. Using this routine
+ * can dramatically improve performance when creating combocells with a
+ * large number of entries. For example, users with thousands of accounts
+ * are complaining about 10-second register startup times, of which 98%
+ * of the cpu is spent building the multi-thousand entry quickfill.
+ * When a shared quickfill is specified, the combo-cell will not add to
+ * nor delete the quickfill; it is the users resonsibility to manage the
+ * quickfill object. The combocell will *not* make a copy of teh quickfill.
+ */
+void gnc_combo_cell_use_quickfill_cache (ComboCell *cell, QuickFill *shared_qf);
+
#endif
Index: combocell-gnome.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/register/register-gnome/combocell-gnome.c,v
retrieving revision 1.11.4.7
retrieving revision 1.11.4.8
diff -Lsrc/register/register-gnome/combocell-gnome.c -Lsrc/register/register-gnome/combocell-gnome.c -u -r1.11.4.7 -r1.11.4.8
--- src/register/register-gnome/combocell-gnome.c
+++ src/register/register-gnome/combocell-gnome.c
@@ -63,6 +63,8 @@
gboolean autosize;
QuickFill *qf;
+ gboolean use_quickfill_cache; /* If TRUE, we don't own the qf */
+
gboolean in_list_select;
gboolean strict;
@@ -127,6 +129,8 @@
cell->cell.gui_private = box;
box->qf = gnc_quickfill_new ();
+ box->use_quickfill_cache = FALSE;
+
box->in_list_select = FALSE;
box->strict = TRUE;
@@ -298,8 +302,12 @@
g_list_free (box->menustrings);
box->menustrings = NULL;
- gnc_quickfill_destroy (box->qf);
- box->qf = NULL;
+ /* Don't destroy the qf if its not ours to destroy */
+ if (FALSE == box->use_quickfill_cache)
+ {
+ gnc_quickfill_destroy (box->qf);
+ box->qf = NULL;
+ }
for (node = box->ignore_strings; node; node = node->next)
{
@@ -336,8 +344,12 @@
g_list_free (box->menustrings);
box->menustrings = NULL;
- gnc_quickfill_destroy (box->qf);
- box->qf = gnc_quickfill_new ();
+ /* Don't destroy the qf if its not ours to destroy */
+ if (FALSE == box->use_quickfill_cache)
+ {
+ gnc_quickfill_destroy (box->qf);
+ box->qf = gnc_quickfill_new ();
+ }
if (box->item_list != NULL)
{
@@ -352,6 +364,24 @@
box->list_sorted = TRUE;
}
+void
+gnc_combo_cell_use_quickfill_cache (ComboCell * cell, QuickFill *shared_qf)
+{
+ PopBox *box;
+
+ if (cell == NULL) return;
+
+ box = cell->cell.gui_private;
+ if (NULL == box) return;
+
+ if (FALSE == box->use_quickfill_cache)
+ {
+ box->use_quickfill_cache = TRUE;
+ gnc_quickfill_destroy (box->qf);
+ }
+ box->qf = shared_qf;
+}
+
static void
gnc_append_string_to_list (gpointer _string, gpointer _item_list)
{
@@ -401,7 +431,7 @@
{
block_list_signals (cell);
- gnc_item_list_append (box->item_list, menustr);
+ gnc_item_list_append (box->item_list, menustr);
if (cell->cell.value &&
(strcmp (menustr, cell->cell.value) == 0))
gnc_item_list_select (box->item_list, menustr);
@@ -411,7 +441,12 @@
else
box->list_in_sync = FALSE;
- gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA);
+ /* If we're going to be using a pre-fab quickfill,
+ * then don't fill it in here */
+ if (FALSE == box->use_quickfill_cache)
+ {
+ gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA);
+ }
box->list_sorted = FALSE;
}
Index: taxtxf.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/locale-specific/us/taxtxf.scm,v
retrieving revision 1.16
retrieving revision 1.16.4.1
diff -Lsrc/report/locale-specific/us/taxtxf.scm -Lsrc/report/locale-specific/us/taxtxf.scm -u -r1.16 -r1.16.4.1
--- src/report/locale-specific/us/taxtxf.scm
+++ src/report/locale-specific/us/taxtxf.scm
@@ -289,13 +289,27 @@
;; Only formats 1,3 implemented now! Others are treated as 1.
(format (gnc:get-txf-format code (eq? type 'income)))
(payer-src (gnc:account-get-txf-payer-source account))
- (account-name (if (eq? payer-src 'parent)
- (gnc:account-get-name
- (gnc:group-get-parent
- (gnc:account-get-parent account)))
- (gnc:account-get-name account)))
+ (account-name (let* ((named-acct
+ (if (eq? payer-src 'parent)
+ (gnc:group-get-parent
+ (gnc:account-get-parent account))
+ account))
+ (name (gnc:account-get-name named-acct)))
+ (if name
+ name
+ (begin
+ (display
+ (string-append
+ "Failed to get name for account: "
+ (gnc:account-get-guid named-acct)
+ (if (not (eq? account named-acct))
+ (string-append
+ " which is the parent of "
+ (gnc:account-get-guid account)))
+ "\n"))
+ "<NONE> -- See the Terminal Output"))))
(action (if (eq? type 'income)
- (case (string->symbol code)
+ (case code
((N286 N488) "ReinvD")
(else "Income"))
"Expense"))
Index: dialog-column-view.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-gnome/dialog-column-view.c,v
retrieving revision 1.3.4.3
retrieving revision 1.3.4.4
diff -Lsrc/report/report-gnome/dialog-column-view.c -Lsrc/report/report-gnome/dialog-column-view.c -u -r1.3.4.3 -r1.3.4.4
--- src/report/report-gnome/dialog-column-view.c
+++ src/report/report-gnome/dialog-column-view.c
@@ -81,8 +81,8 @@
static void
gnc_column_view_edit_destroy(gnc_column_view_edit * view) {
gnc_options_dialog_destroy(view->optwin);
- scm_unprotect_object(view->options);
- scm_unprotect_object(view->view);
+ scm_gc_unprotect_object(view->options);
+ scm_gc_unprotect_object(view->view);
gnc_option_db_destroy(view->odb);
g_free(view);
}
@@ -113,9 +113,9 @@
selection = SCM_UNDEFINED;
}
- scm_unprotect_object(view->available_list);
+ scm_gc_unprotect_object(view->available_list);
view->available_list = names;
- scm_protect_object(view->available_list);
+ scm_gc_protect_object(view->available_list);
gtk_clist_freeze(view->available);
gtk_clist_clear(view->available);
@@ -144,9 +144,9 @@
selection = SCM_UNDEFINED;
}
- scm_unprotect_object(view->contents_list);
+ scm_gc_unprotect_object(view->contents_list);
view->contents_list = contents;
- scm_protect_object(view->contents_list);
+ scm_gc_protect_object(view->contents_list);
gtk_clist_freeze(view->contents);
gtk_clist_clear(view->contents);
@@ -273,10 +273,10 @@
editor,
gtk_label_new(_("Contents")));
- scm_protect_object(r->options);
- scm_protect_object(r->view);
- scm_protect_object(r->available_list);
- scm_protect_object(r->contents_list);
+ scm_gc_protect_object(r->options);
+ scm_gc_protect_object(r->view);
+ scm_gc_protect_object(r->available_list);
+ scm_gc_protect_object(r->contents_list);
g_signal_connect(G_OBJECT(r->available), "select_row",
G_CALLBACK (gnc_column_view_select_avail_cb), (gpointer)r);
@@ -344,9 +344,9 @@
r->contents_selected = oldlength;
}
- scm_unprotect_object(r->contents_list);
+ scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
- scm_protect_object(r->contents_list);
+ scm_gc_protect_object(r->contents_list);
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
@@ -380,9 +380,9 @@
r->contents_selected --;
}
- scm_unprotect_object(r->contents_list);
+ scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
- scm_protect_object(r->contents_list);
+ scm_gc_protect_object(r->contents_list);
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
@@ -413,9 +413,9 @@
newlist = scm_cons(temp, scm_cons(SCM_CAR(oldlist), newlist));
newlist = scm_append(scm_listify(scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
- scm_unprotect_object(r->contents_list);
+ scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
- scm_protect_object(r->contents_list);
+ scm_gc_protect_object(r->contents_list);
r->contents_selected = r->contents_selected - 1;
@@ -448,9 +448,9 @@
newlist = scm_cons(temp, scm_cons(SCM_CAR(oldlist), newlist));
newlist = scm_append(scm_listify(scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
- scm_unprotect_object(r->contents_list);
+ scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
- scm_protect_object(r->contents_list);
+ scm_gc_protect_object(r->contents_list);
r->contents_selected = r->contents_selected + 1;
@@ -501,11 +501,11 @@
scm_int2num(gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(rowspin))),
SCM_BOOL_F);
- scm_unprotect_object(r->contents_list);
+ scm_gc_unprotect_object(r->contents_list);
r->contents_list = scm_list_set_x(r->contents_list,
scm_int2num(r->contents_selected),
current);
- scm_protect_object(r->contents_list);
+ scm_gc_protect_object(r->contents_list);
gnc_options_dialog_changed (r->optwin);
update_display_lists(r);
}
Index: window-report.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-gnome/window-report.c,v
retrieving revision 1.15.4.9
retrieving revision 1.15.4.10
diff -Lsrc/report/report-gnome/window-report.c -Lsrc/report/report-gnome/window-report.c -u -r1.15.4.9 -r1.15.4.10
--- src/report/report-gnome/window-report.c
+++ src/report/report-gnome/window-report.c
@@ -564,6 +564,20 @@
return TRUE;
}
+static int
+gnc_report_window_save_cb(GtkWidget * w, gpointer data)
+{
+ gnc_report_window * report = data;
+ SCM save_func = gh_eval_str("gnc:report-save-to-savefile");
+
+ if(report->cur_report != SCM_BOOL_F)
+ {
+ gh_call1(save_func, report->cur_report);
+ }
+
+ return TRUE;
+}
+
/* We got a draw event. See if we need to reload the report */
static void
gnc_report_window_draw_cb(GtkWidget *unused, GdkRectangle *unused1, gpointer data)
@@ -697,9 +711,9 @@
}
if(win->initial_report == SCM_BOOL_F) {
- scm_unprotect_object(win->initial_report);
+ scm_gc_unprotect_object(win->initial_report);
win->initial_report = inst_report;
- scm_protect_object(win->initial_report);
+ scm_gc_protect_object(win->initial_report);
scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
@@ -719,9 +733,9 @@
}
if(win->cur_report != SCM_BOOL_F)
- scm_unprotect_object(win->cur_report);
+ scm_gc_unprotect_object(win->cur_report);
win->cur_report = inst_report;
- scm_protect_object(win->cur_report);
+ scm_gc_protect_object(win->cur_report);
win->cur_odb = gnc_option_db_new(scm_call_1(get_options, inst_report));
win->option_change_cb_id =
@@ -821,9 +835,9 @@
report->edited_reports = SCM_EOL;
report->name_change_cb_id = SCM_BOOL_F;
- scm_protect_object(report->cur_report);
- scm_protect_object(report->initial_report);
- scm_protect_object(report->edited_reports);
+ scm_gc_protect_object(report->cur_report);
+ scm_gc_protect_object(report->initial_report);
+ scm_gc_protect_object(report->edited_reports);
gnc_html_history_set_node_destroy_cb(gnc_html_get_history(report->html),
gnc_report_window_history_destroy_cb,
@@ -931,6 +945,15 @@
GNOME_STOCK_PIXMAP_PRINT,
0, 0, NULL
},
+ { GNOME_APP_UI_ITEM,
+ _("Save report"),
+ _("Save the current report for later use in ~/.gnucash/saved-reports-1.8 so that they are accessible as menu entries in the report menu. Will go into effect at the next startup of gnucash."),
+ gnc_report_window_save_cb, win,
+ NULL,
+ GNOME_APP_PIXMAP_STOCK,
+ GNOME_STOCK_PIXMAP_SAVE,
+ 0, 0, NULL
+ },
GNOMEUIINFO_END
};
@@ -987,8 +1010,8 @@
win->container = NULL;
win->html = NULL;
- scm_unprotect_object(win->cur_report);
- scm_unprotect_object(win->edited_reports);
+ scm_gc_unprotect_object(win->cur_report);
+ scm_gc_unprotect_object(win->edited_reports);
g_free(win);
}
@@ -1087,7 +1110,7 @@
scm_call_2(set_editor, win->cur_report, SCM_BOOL_F);
gnc_option_db_destroy(win->db);
- scm_unprotect_object(win->scm_options);
+ scm_gc_unprotect_object(win->scm_options);
gnc_options_dialog_destroy(win->win);
g_free(win);
}
@@ -1126,8 +1149,8 @@
free(title);
}
- scm_protect_object(prm->scm_options);
- scm_protect_object(prm->cur_report);
+ scm_gc_protect_object(prm->scm_options);
+ scm_gc_protect_object(prm->cur_report);
gnc_build_options_dialog_contents(prm->win, prm->db);
gnc_option_db_clean(prm->db);
@@ -1149,18 +1172,18 @@
gnc_report_window_remove_edited_report(gnc_report_window * win, SCM report)
{
SCM new_edited = scm_delete(win->edited_reports, report);
- scm_unprotect_object(win->edited_reports);
+ scm_gc_unprotect_object(win->edited_reports);
win->edited_reports = new_edited;
- scm_protect_object(win->edited_reports);
+ scm_gc_protect_object(win->edited_reports);
}
void
gnc_report_window_add_edited_report(gnc_report_window * win, SCM report)
{
SCM new_edited = scm_cons(report, win->edited_reports);
- scm_unprotect_object(win->edited_reports);
+ scm_gc_unprotect_object(win->edited_reports);
win->edited_reports = new_edited;
- scm_protect_object(win->edited_reports);
+ scm_gc_protect_object(win->edited_reports);
}
void
Index: dialog-style-sheet.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-gnome/dialog-style-sheet.c,v
retrieving revision 1.3.4.7
retrieving revision 1.3.4.8
diff -Lsrc/report/report-gnome/dialog-style-sheet.c -Lsrc/report/report-gnome/dialog-style-sheet.c -u -r1.3.4.7 -r1.3.4.8
--- src/report/report-gnome/dialog-style-sheet.c
+++ src/report/report-gnome/dialog-style-sheet.c
@@ -114,7 +114,7 @@
ssinfo->row_ref = row_ref;
g_free(title);
- scm_protect_object(ssinfo->stylesheet);
+ scm_gc_protect_object(ssinfo->stylesheet);
g_object_ref(gnc_options_dialog_widget(ssinfo->odialog));
gnc_build_options_dialog_contents(ssinfo->odialog,
Index: report-gnome.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-gnome/report-gnome.scm,v
retrieving revision 1.9.4.3
retrieving revision 1.9.4.4
diff -Lsrc/report/report-gnome/report-gnome.scm -Lsrc/report/report-gnome/report-gnome.scm -u -r1.9.4.3 -r1.9.4.4
--- src/report/report-gnome/report-gnome.scm
+++ src/report/report-gnome/report-gnome.scm
@@ -96,17 +96,21 @@
(define menu (gnc:make-menu gnc:menuname-reports
(list gnc:window-name-main)))
(define menu-namer (gnc:new-menu-namer))
- (define tax-menu (gnc:make-menu gnc:menuname-taxes
- (list gnc:window-name-main gnc:menuname-reports)))
- (define income-expense-menu
- (gnc:make-menu gnc:menuname-income-expense
- (list gnc:window-name-main gnc:menuname-reports)))
(define asset-liability-menu
(gnc:make-menu gnc:menuname-asset-liability
(list gnc:window-name-main gnc:menuname-reports)))
+ (define income-expense-menu
+ (gnc:make-menu gnc:menuname-income-expense
+ (list gnc:window-name-main gnc:menuname-reports)))
(define utility-menu
(gnc:make-menu gnc:menuname-utility
(list gnc:window-name-main gnc:menuname-reports)))
+ (define custom-menu
+ (gnc:make-menu gnc:menuname-custom
+ (list gnc:window-name-main gnc:menuname-reports)))
+ (define tax-menu
+ (gnc:make-menu gnc:menuname-taxes
+ (list gnc:window-name-main gnc:menuname-reports)))
(gnc:warn "report-menu-setup")
(gnc:add-extension menu)
@@ -115,6 +119,7 @@
(gnc:add-extension income-expense-menu)
(gnc:add-extension asset-liability-menu)
(gnc:add-extension utility-menu)
+ (gnc:add-extension custom-menu)
;; run report-hook danglers
(gnc:hook-run-danglers gnc:*report-hook*)
Index: report-system.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/report-system.scm,v
retrieving revision 1.20.4.1
retrieving revision 1.20.4.2
diff -Lsrc/report/report-system/report-system.scm -Lsrc/report/report-system/report-system.scm -u -r1.20.4.1 -r1.20.4.2
--- src/report/report-system/report-system.scm
+++ src/report/report-system/report-system.scm
@@ -48,7 +48,7 @@
(export gnc:case-exchange-time-fn)
(export gnc:sum-collector-commodity)
(export gnc:sum-collector-stocks)
-
+(export gnc:commodity-collector-contains-commodity?)
;; options-utilities.scm
@@ -84,7 +84,8 @@
(export gnc:html-acct-table-cell)
(export gnc:html-acct-table-row-helper! )
(export gnc:html-acct-table-comm-row-helper!)
-(export gnc:html-build-acct-table )
+(export gnc:html-build-acct-table)
+(export gnc:first-html-build-acct-table)
(export gnc:html-make-exchangerates)
(export gnc:html-make-no-account-warning)
(export gnc:html-make-empty-data-warning)
@@ -95,6 +96,7 @@
(export gnc:menuname-income-expense )
(export gnc:menuname-taxes)
(export gnc:menuname-utility)
+(export gnc:menuname-custom)
(export gnc:pagename-general)
(export gnc:pagename-accounts)
(export gnc:pagename-display)
@@ -105,6 +107,7 @@
(export *gnc:_reports_*)
(export gnc:report-template-new-options/name)
(export gnc:report-template-menu-name/name)
+(export gnc:report-template-renderer/name)
(export gnc:report-template-new-options)
(export gnc:report-template-version)
(export gnc:report-template-name)
@@ -146,6 +149,8 @@
(export gnc:find-report)
(export gnc:find-report-template)
(export gnc:report-generate-restore-forms)
+(export gnc:report-generate-saved-forms)
+(export gnc:report-save-to-savefile)
(export gnc:report-render-html)
(export gnc:report-run)
(export gnc:report-templates-for-each)
@@ -399,6 +404,43 @@
(export gnc:html-style-sheet-find)
(export gnc:html-style-sheet-remove)
+;; html-acct-table.scm
+
+(export gnc:colspans-are-working-right)
+(export <html-acct-table>)
+(export gnc:html-acct-table?)
+(export gnc:_make-html-acct-table_)
+(export gnc:make-html-acct-table)
+(export gnc:make-html-acct-table/env)
+(export gnc:make-html-acct-table/env/accts)
+(export gnc:_html-acct-table-matrix_)
+(export gnc:_html-acct-table-set-matrix!_)
+(export gnc:_html-acct-table-env_)
+(export gnc:_html-acct-table-set-env!_)
+(export gnc:html-acct-table-add-accounts!)
+(export gnc:html-acct-table-num-rows)
+(export gnc:html-acct-table-num-cols)
+(export gnc:html-acct-table-get-row)
+(export gnc:html-acct-table-get-cell)
+(export gnc:html-acct-table-set-cell!)
+(export gnc:html-acct-table-get-row-env)
+(export gnc:html-acct-table-set-row-env!)
+(export gnc:html-acct-table-append-row)
+(export gnc:html-acct-table-prepend-row!)
+(export gnc:html-acct-table-append-col)
+(export gnc:html-acct-table-prepend-col!)
+(export gnc:html-acct-table-remove-last-row!)
+(export gnc:html-acct-table-render)
+(export gnc:account-code-less-p)
+(export gnc:account-name-less-p)
+(export gnc:account-path-less-p)
+(export gnc:identity)
+(export gnc:html-table-add-labeled-amount-line!)
+(export gnc:html-table-add-account-balances)
+(export gnc:second-html-build-acct-table)
+(export gnc:commodity-table)
+(export gnc:uniform-commodity?)
+
;; html-table.scm
(export <html-table>)
@@ -463,9 +505,11 @@
(export gnc:html-table-append-row!)
(export gnc:html-table-remove-last-row!)
(export gnc:html-table-prepend-row!)
+(export gnc:html-table-get-cell)
(export gnc:html-table-set-cell!)
(export gnc:html-table-append-column!)
(export gnc:html-table-prepend-column!)
+(export gnc:html-table-merge)
(export gnc:html-table-render)
;; html-text.scm
@@ -528,6 +572,7 @@
(export gnc:make-value-collector)
(export gnc:make-numeric-collector)
(export gnc:make-commodity-collector)
+(export gnc:commodity-collector-commodity-count)
(export gnc:account-get-balance-at-date)
(export gnc:account-get-comm-balance-at-date)
(export gnc:accounts-get-balance-helper)
@@ -547,6 +592,7 @@
(export gnc:report-percent-done)
(export gnc:report-finished)
(export gnc:accounts-count-splits)
+(export gnc:commodity-collector-allzero?)
(load-from-path "commodity-utilities.scm")
(load-from-path "html-barchart.scm")
@@ -558,6 +604,7 @@
(load-from-path "html-style-sheet.scm")
(load-from-path "html-table.scm")
(load-from-path "html-text.scm")
+(load-from-path "html-acct-table.scm")
(load-from-path "html-utilities.scm")
(load-from-path "options-utilities.scm")
(load-from-path "report-utilities.scm")
Index: html-table.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/html-table.scm,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -Lsrc/report/report-system/html-table.scm -Lsrc/report/report-system/html-table.scm -u -r1.1 -r1.1.6.1
--- src/report/report-system/html-table.scm
+++ src/report/report-system/html-table.scm
@@ -3,6 +3,8 @@
;; for simple style elements.
;; Copyright 2000 Bill Gribble <grib at gnumatic.com>
;;
+;; * 2004.06.18: David Montenegro, added gnc:html-table-get-cell
+;;
;; 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
@@ -21,6 +23,16 @@
;; Boston, MA 02111-1307, USA gnu at gnu.org
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; NB: In this code, "markup" and "/markup" *do not* refer to
+;; style information. Rather, they let you override the tag
+;; associated with an html-table row or cell. Style
+;; information is stored in addition to this "markup" (in
+;; an entirely different record field).
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
(define <html-table>
(make-record-type "<html-table>"
'(col-headers
@@ -125,6 +137,11 @@
(let* ((retval '())
(push (lambda (l) (set! retval (cons l retval))))
(style (gnc:html-table-cell-style cell)))
+
+; ;; why dont colspans export??!
+; (gnc:html-table-cell-set-style! cell "td"
+; 'attribute (list "colspan"
+; (or (gnc:html-table-cell-colspan cell) 1)))
(gnc:html-document-push-style doc style)
(push (gnc:html-document-markup-start
doc (gnc:html-table-cell-tag cell)
@@ -384,6 +401,19 @@
new-num-rows))
+;; list-set! is 0-based...
+;; (let ((a '(0 1 2))) (list-set! a 1 "x") a)
+;; => (0 "x" 2)
+(define (gnc:html-table-get-cell table row col)
+ (list-ref-safe (gnc:html-table-get-row table row) col))
+
+(define (gnc:html-table-get-row table row)
+ (let* ((dd (gnc:html-table-data table))
+ (len (length dd))
+ )
+ (list-ref-safe dd (- (- len 1) row))
+ ))
+
(define (gnc:html-table-set-cell! table row col . objects)
(let ((rowdata #f)
(row-loc #f)
@@ -518,6 +548,26 @@
remaining-elements)
#f))))
+;;
+;; It would be nice to have table row/col/cell accessor functions in here.
+;; It would also be nice to have table juxtaposition functions, too.
+;; i.e., (gnc:html-table-nth-row table n)
+;; (gnc:html-table-append-table-horizontal table add-table)
+;; (An old merge-table used to exist inside balance-sheet.scm/GnuCash 1.8.9.)
+;; Feel free to contribute! :-)
+;;
+
+;; This function was moved here from balance-sheet.scm.
+(define (gnc:html-table-merge t1 t2)
+ (begin
+ (gnc:html-table-set-data! t1
+ (append
+ (gnc:html-table-data t2)
+ (gnc:html-table-data t1)))
+ (gnc:html-table-set-num-rows-internal!
+ t1 (+ (gnc:html-table-num-rows t1)
+ (gnc:html-table-num-rows t2)))))
+
(define (gnc:html-table-render table doc)
(let* ((retval '())
(push (lambda (l) (set! retval (cons l retval)))))
Index: commodity-utilities.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/commodity-utilities.scm,v
retrieving revision 1.11.4.1
retrieving revision 1.11.4.2
diff -Lsrc/report/report-system/commodity-utilities.scm -Lsrc/report/report-system/commodity-utilities.scm -u -r1.11.4.1 -r1.11.4.2
--- src/report/report-system/commodity-utilities.scm
+++ src/report/report-system/commodity-utilities.scm
@@ -21,6 +21,15 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(define (gnc:commodity-collector-contains-commodity? collector commodity)
+ (let ((ret #f))
+ (gnc:commodity-collector-map
+ collector
+ (lambda (comm amt)
+ (set! ret (or ret (gnc:commodity-equiv? comm commodity)))))
+ ret
+ ))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions to get splits with interesting data from accounts.
Index: report-utilities.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/report-utilities.scm,v
retrieving revision 1.18.4.1
retrieving revision 1.18.4.2
diff -Lsrc/report/report-system/report-utilities.scm -Lsrc/report/report-system/report-utilities.scm -u -r1.18.4.1 -r1.18.4.2
--- src/report/report-system/report-utilities.scm
+++ src/report/report-system/report-utilities.scm
@@ -474,6 +474,17 @@
(define (gnc:commodity-collector-list collector)
(collector 'list #f #f))
+;; Returns the number of commodities in a commodity-collector.
+;; (If this were implemented as a record, I would be able to
+;; just (length ...) the alist, but....)
+(define (gnc:commodity-collector-commodity-count collector)
+ (let ((commodities 0))
+ (gnc:commodity-collector-map
+ collector
+ (lambda (comm amt) (set! commodities (+ commodities 1))))
+ commodities
+ ))
+
;; Returns zero if all entries in this collector are zero.
(define (gnc:commodity-collector-allzero? collector)
(let ((result #t))
Index: html-utilities.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/html-utilities.scm,v
retrieving revision 1.8.4.1
retrieving revision 1.8.4.2
diff -Lsrc/report/report-system/html-utilities.scm -Lsrc/report/report-system/html-utilities.scm -u -r1.8.4.1 -r1.8.4.2
--- src/report/report-system/html-utilities.scm
+++ src/report/report-system/html-utilities.scm
@@ -1,7 +1,9 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; html-utilities.scm: Useful functions when using the HTML generator.
-;; Copyright 2001 Christian Stimming <stimming at tu-harburg.de>
;;
+;; Modified slightly by David Montenegro 2004.06.18.
+;;
+;; Copyright 2001 Christian Stimming <stimming at tu-harburg.de>
;; 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
@@ -21,22 +23,23 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; returns a list with n #f (empty cell) values
+(define (gnc:html-make-empty-cell) #f)
(define (gnc:html-make-empty-cells n)
(if (> n 0)
(cons #f (gnc:html-make-empty-cells (- n 1)))
- '()))
+ (list)))
-(define (register-guid guid)
- (gnc:html-build-url gnc:url-type-register (string-append "guid=" guid) #f))
+(define (gnc:register-guid type guid)
+ (gnc:html-build-url gnc:url-type-register (string-append type guid) #f))
(define (gnc:account-anchor-text acct)
- (register-guid (gnc:account-get-guid acct)))
+ (gnc:register-guid "acct-guid=" (gnc:account-get-guid acct)))
(define (gnc:split-anchor-text split)
- (register-guid (gnc:split-get-guid split)))
+ (gnc:register-guid "split-guid=" (gnc:split-get-guid split)))
(define (gnc:transaction-anchor-text trans)
- (register-guid (gnc:transaction-get-guid trans)))
+ (gnc:register-guid (gnc:transaction-get-guid trans)))
(define (gnc:report-anchor-text report-id)
(gnc:html-build-url gnc:url-type-report
@@ -45,7 +48,7 @@
(define (gnc:price-anchor-text price)
(gnc:html-build-url gnc:url-type-price
- (string-append "guid=" (gnc:price-get-guid price))
+ (string-append "price-guid=" (gnc:price-get-guid price))
#f))
;; Make a new report and return the anchor to it. The new report of
@@ -117,22 +120,32 @@
(assign-colors (+ i 1)))))
(assign-colors 0))
-;; Appends a horizontal ruler to a html-table with the specified width
-;; colspan.
-(define (gnc:html-table-append-ruler! table colspan)
+;; Appends a horizontal ruler to a html-table with the specified
+;; colspan at, optionally, the specified column.
+(define (gnc:html-table-append-ruler/at! table colskip colspan)
+ (define empty-cell '())
(gnc:html-table-append-row!
table
- (list
- (gnc:make-html-table-cell/size
- 1 colspan (gnc:make-html-text (gnc:html-markup-hr))))))
-
-(define (gnc:html-table-append-ruler/markup! table markup colspan)
- (gnc:html-table-append-row/markup!
+ (append (make-list colskip empty-cell)
+ (list
+ (gnc:make-html-table-cell/size
+ 1 colspan (gnc:make-html-text (gnc:html-markup-hr)))))))
+
+(define (gnc:html-table-append-ruler/at/markup! table markup colskip colspan)
+ (define empty-cell "")
+ (gnc:html-table-append-row/markup!
table
markup
- (list
- (gnc:make-html-table-cell/size
- 1 colspan (gnc:make-html-text (gnc:html-markup-hr))))))
+ (append (make-list colskip empty-cell)
+ (list
+ (gnc:make-html-table-cell/size
+ 1 colspan (gnc:make-html-text (gnc:html-markup-hr)))))))
+
+(define (gnc:html-table-append-ruler! table colspan)
+ (gnc:html-table-append-ruler/at! table 0 colspan))
+
+(define (gnc:html-table-append-ruler/markup! table markup colspan)
+ (gnc:html-table-append-ruler/at/markup! table markup 0 colspan))
;; Creates a table cell with some text in it. The cell will be created
;; with the colspan 'colspan' (the rowspan==1), the content 'content'
@@ -140,10 +153,12 @@
;; string, or a <html-text> object. Returns a <html-table-cell>
;; object.
(define (gnc:html-acct-table-cell colspan content boldface?)
+ ;; instead of html-markup-b, just use the corresponding html-table-styles.
+ (define default-style "text-cell")
+ (define boldface-style "total-label-cell")
(gnc:make-html-table-cell/size/markup
1 colspan
- ;; instead of html-markup-b, just use the right html-table-styles.
- (if boldface? "total-label-cell" "text-cell")
+ (if boldface? boldface-style default-style)
content))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -194,8 +209,10 @@
;; in the appropriate name column. my-commodity (a
;; <gnc:commodity*>) is the "natural" balance of the current
;; account. balance (a commodity-collector) is the balance to be
-;; printed. If reverse-balance? == #t then the balance's signs get
+;; printed. If reverse-balance? == #t then the balances' signs get
;; reversed.
+;; DM: If you trace this function through gnc:html-build-acct-table,
+;; my-commodity always ends up being report-commodity.
(define (gnc:html-acct-table-comm-row-helper!
table tree-depth report-commodity exchange-fn
current-depth my-name my-commodity balance
@@ -232,12 +249,14 @@
"number-cell"
(gnc:make-html-text (gnc:html-markup-b domestic-balance)))))
(list
- (gnc:make-html-table-cell/markup
- "number-cell"
- foreign-balance)
- (gnc:make-html-table-cell/markup
- "number-cell"
- domestic-balance)))
+ (and foreign-balance
+ (gnc:make-html-table-cell/markup
+ "number-cell"
+ foreign-balance))
+ (and domestic-balance
+ (gnc:make-html-table-cell/markup
+ "number-cell"
+ domestic-balance))))
(gnc:html-make-empty-cells (* 2 (- current-depth
(if group-header-line? 0 1)))))))
@@ -288,7 +307,7 @@
(gnc:make-gnc-monetary curr val))))
(commodity-row-helper!
;; print no account name
- (car (gnc:html-make-empty-cells 1))
+ (gnc:html-make-empty-cell)
;; print the account balance in the respective
;; commodity
bal
@@ -375,6 +394,37 @@
show-total? get-total-fn
total-name group-types? show-parent-balance? show-parent-total?
show-other-curr? report-commodity exchange-fn show-zero-entries?)
+ ;; Select, here, which version of gnc:html-build-acct-table you want
+ ;; to use by default.
+ (define fn-version 'first)
+ (if (equal? fn-version 'second)
+ (gnc:second-html-build-acct-table
+ start-date end-date
+ tree-depth show-subaccts? accounts
+ start-percent delta-percent
+ show-col-headers?
+ show-total? get-total-fn
+ total-name group-types? show-parent-balance? show-parent-total?
+ show-other-curr? report-commodity exchange-fn show-zero-entries?)
+ (gnc:first-html-build-acct-table
+ start-date end-date
+ tree-depth show-subaccts? accounts
+ start-percent delta-percent
+ show-col-headers?
+ show-total? get-total-fn
+ total-name group-types? show-parent-balance? show-parent-total?
+ show-other-curr? report-commodity exchange-fn show-zero-entries?)
+ )
+ )
+
+(define (gnc:first-html-build-acct-table
+ start-date end-date
+ tree-depth show-subaccts? accounts
+ start-percent delta-percent
+ show-col-headers?
+ show-total? get-total-fn
+ total-name group-types? show-parent-balance? show-parent-total?
+ show-other-curr? report-commodity exchange-fn show-zero-entries?)
(let ((table (gnc:make-html-table))
(work-to-do 0)
(work-done 0)
@@ -410,7 +460,7 @@
this-collector x )))
(gnc:group-map-all-accounts
(lambda (a)
- ;; Important: Calculate the balance if and only of the
+ ;; Important: Calculate the balance if and only if the
;; account a is shown, i.e. (use-acct? a) == #t.
(and (use-acct? a)
(my-get-balance-nosub a)))
@@ -659,7 +709,7 @@
(gnc:html-table-set-style!
table "th"
- 'attribute '("align" "right")
+ 'attribute '("align" "center")
'attribute '("valign" "top"))
;; set some column headers
--- /dev/null
+++ src/report/report-system/html-acct-table.scm
@@ -0,0 +1,1102 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; html-acct-table.scm : generate a multi-columnar list of accounts
+;; including utilities to convert to <html-table> form
+;;
+;; By David Montenegro 2004.06.23 <sunrise2000 at comcast.net>
+;;
+;; Borrowed largely from html-table.scm by Bill Gribble <grib at gnumatic.com>
+;; and html-utilities.scm by Christian Stimming <stimming at tu-harburg.de>
+;;
+;; 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
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;
+;;
+;; DESCRIPTION
+;;
+;; The html-acct-table object is a utility object, not an html object.
+;; It is used to collect and then render a table whose leftmost column(s)
+;; are a list or chart of accounts.
+;;
+;; You start by creating the object and initializing it with a list of
+;; accounts and a few assorted parameters. It generates a table, which
+;; can be read using accessor functions, containing information which
+;; makes it easy(ier) to create a great variety of html-table forms.
+;;
+;; add-accounts add-account-balances
+;; account-list ------------> html-acct-table ----------> html-table
+;;
+;; This utility object was written because of some shortcomings
+;; inherent in how the gnc:html-build-acct-table function was
+;; designed. Ultimately, the intent is to replace
+;; gnc:html-build-acct-table with an html-acct-table with the
+;; appropriate thunks. But, because this is new, I'm leaving the
+;; original gnc:html-build-acct-table in place, just to be safe.
+;;
+;;
+;; ARGUMENTS
+;;
+;; For boolean arguments, #t and #f have their usual meanings. If a
+;; boolean argument is not set, a default value may be assumed. For
+;; non-boolean arguments, values may be specified. When #f is
+;; specified as the value of a non-boolean argument, it generally
+;; means to omit whatever function the argument controls. When #t is
+;; specified for such an argument, it generally means to use that
+;; functionality, but just accept whatever default functionality that
+;; option may have.
+;;
+;; The list of accounts which are to be placed in the
+;; gnc:html-acct-table object can be controled with the
+;; gnc:make-html-acct-table/accts, gnc:make-html-acct-table/accts/env,
+;; and gnc:html-table-add-accts! functions.
+;;
+;; The gnc:html-acct-table parameters, set with
+;; gnc:make-html-acct-table/env and gnc:make-html-acct-table/accts/env
+;; and fetched with gnc:html-acct-table-env; accept the following
+;; parameters:
+;;
+;; display-tree-depth: integer 'unlimited 'all #f
+;;
+;; the number of levels of accounts to display
+;; 'unlimited, 'all, and #f impose no depth limit.
+;; the default is 'all.
+;;
+;; depth-limit-behavior: 'summarize 'flatten 'truncate
+;;
+;; when the display tree reaches its depth limit, this option
+;; tells gnc:html-acct-table what to do. 'summarize tells it
+;; to omit accounts below the depth limit and summarize their
+;; contents as belonging to their parent account at the depth
+;; limit. 'flatten tells it to display every selected
+;; subaccount, all the way down the tree, but to position
+;; them, in the chart, at the depth limit. the default value
+;; is 'summarize
+;;
+;; initial-indent: integer
+;;
+;; the number of table cells to indent the first level of
+;; accounts displayed. this is merely a convenience. the
+;; default initial-indent is 0.
+;;
+;; account-less-p: binary_predicate #t #f
+;;
+;; used for sorting accounts, below each parent account, into
+;; the order in which they will be displayed. the function
+;; must take two Account arguments and represent a total
+;; ordering on Account-space. #t means to use the default
+;; sorting function. #f means to preform no sorting. the
+;; default sorting function is gnc:account-code-less-p.
+;;
+;; start-date: timepair
+;;
+;; the starting date of the reporting period over which to
+;; report balances for this account. if start-date is #f,
+;; will be no limit on how early a counted transaction may
+;; ocurr.
+;;
+;; end-date: timepair
+;;
+;; the ending date of the reporting period over which to
+;; report balances for this account. if end-date is #f, there
+;; will be no limit on how late a counted transaction may
+;; ocurr. note: i do not know if GnuCash, right now, supports
+;; transactions in the future. so be prepared for the
+;; possibility that this may match transactions which haven't
+;; ocurred, yet.
+;;
+;; report-commodity: commodity
+;;
+;; the commodity into which to convert any balances containing
+;; foreign currencies. the balance will be converted using
+;; the exchange function exchange-fn. the defalut is the
+;; currency returned by (gnc:default-report-currency).
+;;
+;; exchange-fn: commodity_exchange_function
+;;
+;; the commodity exchange function (you know, that weighted
+;; average, most recent, nearest in time fun stuff) used to
+;; convert balances which are not exclusively in the report
+;; commodity into the report commodity.
+;;
+;; column-header: html-table-header-cell #f #t
+;;
+;; the table column header cell (TH tag) with which to head
+;; the columns containing the account tree. if supplied, the
+;; header cell may contain style information. if #f, no
+;; column header cell will be used. if #t, a default header
+;; cell (reading "Account") will be used. the colspan of any
+;; header cell will be automatically set appropriately. this
+;; is for convenience only; gnc:html-acct-table does not use
+;; this data.
+;;
+;; account-label-mode: 'name 'anchor
+;;
+;; tells whether to render account labels as hyperlinks or
+;; text. stylesheets, really, should be able to remove
+;; link markup.
+;;
+;; parent-account-subtotal-mode: #t #f 'canonically-tabbed
+;;
+;; indicates whether or not to add a line, recursively
+;; subtotalling an account and its descendents, for any
+;; account with children (non-leaf account). if #t or
+;; #canonically-tabbed, a subtotal row will be created for
+;; each non-leaf account. if #f, no non-leaf account
+;; subtotal rows will be created. if 'canonically-tabbed,
+;; account total entry labels will be placed at the position
+;; specified by accounting texts (indented one column from
+;; the accounts being totalled, two columns from where
+;; gnc:html-acct-table would otherwise place them). the
+;; default is #f.
+;;
+;; zero-balance-mode: 'show-leaf-acct 'omit-leaf-acct
+;;
+;; indicates what to do with accounts with zero balance. if
+;; 'omit-leaf-acct, no account row will be generated for any
+;; account having a balance of zero. otherwise, a row will be
+;; generated for the account.
+;;
+;; account-type: unimplemented
+;; account-class: unimplemented
+;; row-thunk: unimplemented (for gnc:html-acct-table-render)
+;; row-list: unimplemented (list of all the rows ever added)
+;;
+;; The html-acct-table object lets you generate, store, and access the
+;; following parameters:
+;;
+;; account: Account
+;;
+;; the account in the current row
+;;
+;; account-parent: Account #f
+;;
+;; the parent account of the current account, if one exists.
+;; #f if the current account has no parent.
+;;
+;; account-path: string
+;;
+;; the full name of the account in the current row. i.e., if
+;; the name of the account is "Assets:Current Assets:Cash",
+;; the value will be "Assets:Current Assets:Cash".
+;;
+;; account-name: string
+;;
+;; the "basename" of the account in the current row. i.e., if
+;; the name of the account is "Assets:Current Assets:Cash",
+;; the value will be "Cash".
+;;
+;; account-code: string
+;;
+;; the account of the account in the current row, as returned
+;; by gnc:account-get-code.
+;;
+;; account-anchor: text(maybe?)
+;;
+;; a link to the account in the current row
+;;
+;; account-label: string
+;;
+;; the text used to label the account in the current row. if
+;; account-label-mode is 'name, this consists of account-name
+;; prepended, if row-type is 'subtotal-row, by "Total ". if
+;; account-label-mode is 'anchor, this consists of
+;; account-anchor prepended, if row-type is 'subtotal-row, by
+;; "Total ".
+;;
+;; account-depth: integer
+;;
+;; the depth at which the account in the current row resides
+;; in the account tree. note that this may differ from
+;; display-depth when depth-limit-behavior is 'flatten.
+;; unlike in gnc:html-build-acct-table, the first level of
+;; accounts is level 0.
+;;
+;; logical-depth: integer
+;;
+;; the depth at which the account in the current row resides
+;; in the effective account tree. this is the depth the
+;; account tree when ignoring unselected parent accounts.
+;; note that this may differ from account-depth when a
+;; selected account has a deselected ancestor.
+;;
+;; display-depth: integer
+;;
+;; the depth at which the account in the current row resides
+;; in the display tree. note that this may differ from
+;; account-depth when depth-limit-behavior is 'flatten.
+;; unlike in gnc:html-build-acct-table, the first level of
+;; accounts is level 0. this means that display-depth is also
+;; the number of empty cells which should preceed the account
+;; name in the gnc:html-table being generated.
+;;
+;; indented-depth: integer
+;;
+;; the depth at which the account in the current row resides
+;; in the indented display tree. also account-depth plus
+;; indent.
+;;
+;; logical-cols: integer
+;;
+;; the number of columns in which account labels were placed.
+;;
+;; label-cols: integer
+;;
+;; the number of columns in the group of account columns to
+;; which a row was assigned. also one more than the maximum
+;; column depth at which rows were positioned in the
+;; table. this value may be different from logical-cols when
+;; parent-account-subtotal-mode is 'canonically-tabbed.
+;;
+;; account-cols: integer
+;;
+;; the number of columns in the group of account columns. if
+;; display-tree-depth is #f, this is the value of label-cols
+;; plus any indent. if display-tree-depth is set, this is the
+;; value of display-tree-depth, plus indent plus zero, if
+;; parent-account-subotal-mode is not 'canonically-tabbed, or,
+;; if parent-account-subtotal-mode is 'canonically-tabbed,
+;; plus one. dont you just love english?
+;;
+;; account-colspan: integer
+;;
+;; the number of table columns which the account label of the
+;; account in the current row should span in the
+;; gnc:html-table being generated.
+;;
+;; account-children: list of Accounts
+;;
+;; a list of all children of the account in the current row.
+;;
+;; account-bal: commodity-collector
+;;
+;; the balance of the account in the current row, exclusive of
+;; any balances in any subaccounts. this is for convenience.
+;;
+;; recursive-bal: commodity-collector
+;;
+;; the balance of the account in the current row, recursively
+;; including all balances in any *selected* subaccounts. this
+;; is for convenience.
+;;
+;; report-comm-account-bal: commodity-collector
+;;
+;; the balance of the account in the current row, exclusive of
+;; any balances in any subaccounts, converted to
+;; report-commodity using exchange-fn. this is for
+;; convenience.
+;;
+;; report-comm-recursive-bal: commodity-collector
+;;
+;; the balance of the account in the current row, recursively
+;; including all balances in any *selected* subaccounts,
+;; converted to report-commodity using exchange-fn. this is
+;; for convenience.
+;;
+;; account-commodity: commodity
+;;
+;; returns the default commodity of the account in the current
+;; row, as returned by gnc:account-get-commodity. the g-wrap
+;; documentation string reads: "Get the commodity in which the
+;; account is denominated." note: afaik, gnucash accounts can
+;; only contain one commodity; but it's plausible that future
+;; releases may permit mixed-commodity accounts, so it's
+;; probably safest not to assume that an account contains only
+;; its default commodity.
+;;
+;; row-type: 'account-row 'subtotal-row
+;;
+;; indicates the nature of the current row. 'account-row
+;; indicates that the current row represents an account
+;; balance. 'subtotal-row indicates that it represents a
+;; subtotal.
+;;
+;;
+;; DIFFERENCES FROM PARAMETERS USED BY gnc:html-build-acct-table
+;;
+;; The show-subaccounts? option of gnc:html-build-acct-table, which
+;; used to select an accounts recursively like the "-R" option to ls,
+;; has been removed. I find it both confusing, as a user, and
+;; obfuscating, as a programmer. Any accounts which are to be
+;; included in the report may be selected in the Accounts options
+;; widget. While, when selecting whole subtrees of accounts, this may
+;; be tedious, this really is a GUI problem. The ideal solution would
+;; be to give the Account selection widget a "recursively select"
+;; option which selects (i.e., hilights) both the account selected and
+;; all its subaccounts. Note that, as a worst-case workaround, the
+;; user could always use the spacebar and arrow keys to select entire
+;; subtrees rather rapidly. It order to make this shortcoming as
+;; benign as possible, reports are advised to make the default account
+;; selection that which is closest to what the report user is likely
+;; to select. It is my hope that a recursive account selection widget
+;; will soon be implemented.
+;;
+;; The group-types? option of gnc:html-build-acct-table, which
+;; would display accounts by account type and supply header and
+;; total lines for each type (see source), has been removed.
+;; It is easy enough to duplicate this functionality, report-side,
+;; using the new gnc:html-acct-table object.
+;;
+;; The start-percent and delta-percent options of
+;; gnc:html-build-acct-table, which told the function to
+;; gnc:report-percent-done start-percent to
+;; (start-percent+start-delta) percent of the progress bar, has been
+;; removed. Most of the report building is done while reading the
+;; gnc:html-acct-table object, anyway, so this is not a great loss.
+;; This functionality should, however, be included as the amount of
+;; work required to build an gnc:html-acct-table object is
+;; non-trivial. Being non-critical as it is, this is left as a future
+;; project. Since much of the code for this has already been written
+;; (in gnc:html-build-acct-table), when the time comes, this
+;; functionality should not be difficult to add.
+;;
+;;
+;; INTERNALS
+;;
+;; Internally, html-acct-table uses an html-table object to store
+;; data. Since the html-acct-table object is arguably a more general
+;; class than html-table, one might think that the html-table object
+;; should be written to use an html-acct-table for data storage,
+;; manipulation, and access. The html-table class, as it happens, was
+;; written first, so the decision was made to use it rather than
+;; redesign the horse around the carriage.
+;;
+;; It may also be possible to have made html-acct-table a markup/style
+;; sheet pair. To do this, the html-acct-table (which would
+;; essentially be a markup object) would have to store thunks and call
+;; them when rendering its contents to its parent html-doc. This
+;; means that report code would be called during stylization, rather
+;; than while building the report. Making html-acct-table a utility
+;; object means that one can use it in a report generator in a
+;; programmatic manner, keeping clear the separation between report
+;; generation and stylization.
+;;
+;; The first cell in each row of the html-table consist of an a-list
+;; of row-parameters. These parameters are described in PARAMETERS
+;; above. Any remaining cells in the row represent data set by the
+;; user. This class simply maps its contents to the html-table.
+;;
+
+;; this is to work around a bug in the HTML export sytmem
+;; which causes COLSPAN= attributes not to be exported (!!)
+(define gnc:colspans-are-working-right #f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; <html-acct-table> class
+;; utility class for generating account tables
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define <html-acct-table>
+ (make-record-type "<html-acct-table>"
+ '(matrix ;; an html-table
+ env ;; an alist
+ )))
+
+(define gnc:html-acct-table?
+ (record-predicate <html-acct-table>))
+
+(define gnc:_make-html-acct-table_
+ (record-constructor <html-acct-table>))
+
+(define (gnc:make-html-acct-table)
+ (gnc:_make-html-acct-table_
+ (gnc:make-html-table) ;; matrix
+ #f ;; env
+ ))
+
+(define (gnc:make-html-acct-table/env env)
+ (let ((acct-table (gnc:make-html-acct-table)))
+ (gnc:html-acct-table-set-env! acct-table env)
+ acct-table))
+
+(define (gnc:make-html-acct-table/env/accts env accts)
+ (let ((acct-table (gnc:make-html-acct-table)))
+ ;; the env must be set *before* the accounts... because the env
+ ;; parameter end-date is required by
+ ;; gnc:html-acct-table-add-accounts!.
+ (gnc:_html-acct-table-set-env!_ acct-table env)
+ (gnc:html-acct-table-add-accounts! acct-table accts)
+ acct-table))
+
+(define gnc:_html-acct-table-matrix_
+ (record-accessor <html-acct-table> 'matrix))
+
+(define gnc:_html-acct-table-set-matrix!_
+ (record-modifier <html-acct-table> 'matrix))
+
+(define gnc:_html-acct-table-env_
+ (record-accessor <html-acct-table> 'env))
+
+(define gnc:_html-acct-table-set-env!_
+ (record-modifier <html-acct-table> 'env))
+
+;; some useful predicates to export
+(define (gnc:account-code-less-p a b)
+ (string<? (gnc:account-get-code a)
+ (gnc:account-get-code b)))
+(define (gnc:account-name-less-p a b)
+ (string<? (gnc:account-get-name a)
+ (gnc:account-get-name b)))
+(define (gnc:account-path-less-p a b)
+ (string<? (gnc:account-get-full-name a)
+ (gnc:account-get-full-name b)))
+
+(define (gnc:html-acct-table-add-accounts! acct-table accounts)
+ ;;
+ ;; This is where most of the html-acct-table functionality ends up....
+ ;;
+ ;; This function traverses the (current) account tree, adding
+ ;; information about the selected accounts to acct-table.
+ ;;
+
+ ;; helper for fetching values from the key/val environment alist
+ (define (get-val alist key)
+ (let ((lst (assoc-ref alist key)))
+ (if lst (car lst) lst)))
+
+ ;; helper to plop <env> in the next available env cell
+ (define (add-row env)
+ (let ((html-table (gnc:_html-acct-table-matrix_ acct-table)))
+ (gnc:html-table-set-cell!
+ html-table
+ (gnc:html-table-num-rows html-table)
+ 0
+ env)
+ )
+ )
+
+ (let* ((env (gnc:_html-acct-table-env_ acct-table))
+ ;; establish all input parameters and their defaults
+ (depth-limit (let ((lim (get-val env 'display-tree-depth)))
+ (if (or (equal? lim 'unlimited)
+ (equal? lim 'all))
+ #f
+ lim)))
+ (limit-behavior (or (get-val env 'depth-limit-behavior) 'summarize))
+ (indent (or (get-val env 'initial-indent) 0))
+ (less-p (let ((pred (get-val env 'account-less-p)))
+ (if (equal? pred #t) gnc:account-code-less-p pred)))
+ (start-date (get-val env 'start-date))
+ (end-date (or (get-val env 'end-date)
+ (cons 'absolute (cons (current-time) 0))))
+ (report-commodity (or (get-val env 'report-commodity)
+ (gnc:default-report-currency)))
+ (exchange-fn (or (get-val env 'exchange-fn)
+ 'weighted-average))
+ (column-header (let ((cell (get-val env 'column-header)))
+ (if (equal? cell #t)
+ (gnc:make-html-table-cell "Account name")
+ cell)))
+ (subtotal-mode (get-val env 'parent-account-subtotal-mode))
+ (zero-mode (let ((mode (get-val env 'zero-balance-mode)))
+ (or (if (equal? mode #t) 'show-leaf-acct mode)
+ 'show-leaf-acct)
+ ))
+ (label-mode (or (get-val env 'account-label-mode) 'anchor))
+ ;; local variables
+ (toplvl-accts (gnc:group-get-account-list (gnc:get-current-group)))
+ (acct-depth-reached 0)
+ (logi-depth-reached (if depth-limit (- depth-limit 1) 0))
+ (disp-depth-reached 0)
+ )
+
+ (define (traverse-accounts! accts acct-depth logi-depth)
+
+ (define (use-acct? acct)
+ (and (or (equal? limit-behavior 'flatten) (< logi-depth depth-limit))
+ (member acct accounts)
+ )
+ )
+
+ ;; the following two functions were lifted directly
+ ;; from html-utilities.scm
+ (define (my-get-balance-nosub account start-date end-date)
+ (if start-date
+ (gnc:account-get-comm-balance-interval
+ account start-date end-date #f)
+ (gnc:account-get-comm-balance-at-date
+ account end-date #f)))
+
+ ;; Additional function that includes the subaccounts as
+ ;; well. Note: It is necessary to define this here (instead of
+ ;; changing an argument for account-get-balance) because the
+ ;; use-acct? query is needed.
+ (define (my-get-balance account start-date end-date)
+ ;; this-collector for storing the result
+ (let ((this-collector
+ (my-get-balance-nosub account start-date end-date)))
+ (for-each
+ (lambda (x) (if x (gnc:commodity-collector-merge this-collector x)))
+ (gnc:group-map-all-accounts
+ (lambda (a)
+ ;; Important: Calculate the balance if and only if the
+ ;; account a is shown, i.e. (use-acct? a) == #t.
+ (and (use-acct? a)
+ (my-get-balance-nosub a start-date end-date)))
+ (gnc:account-get-children account)))
+ this-collector))
+
+ (let ((disp-depth
+ (if (integer? depth-limit)
+ (min (- depth-limit 1) logi-depth)
+ logi-depth))
+ )
+
+ (for-each
+ (lambda (acct)
+ (let* ((subaccts
+ (gnc:account-get-immediate-subaccounts acct))
+ ;; assign output parameters
+ (account acct)
+ (account-name (gnc:account-get-name acct))
+ (account-code (gnc:account-get-code acct))
+ (account-path (gnc:account-get-full-name acct))
+ (account-anchor (gnc:html-account-anchor acct))
+ (account-parent (gnc:account-get-parent-account acct))
+ (account-children subaccts)
+ (account-depth acct-depth)
+ (logical-depth logi-depth)
+ (account-commodity (gnc:account-get-commodity acct))
+ (account-bal (my-get-balance-nosub
+ acct start-date end-date))
+ (recursive-bal
+ (my-get-balance acct start-date end-date))
+ (report-comm-account-bal
+ (gnc:sum-collector-commodity
+ account-bal report-commodity exchange-fn))
+ (report-comm-recursive-bal
+ (gnc:sum-collector-commodity
+ recursive-bal report-commodity exchange-fn))
+ (grp-env
+ (append env
+ (list
+ (list 'initial-indent indent)
+ (list 'account account)
+ (list 'account-name account-name)
+ (list 'account-code account-code)
+ (list 'account-path account-path)
+ (list 'account-parent account-parent)
+ (list 'account-children account-children)
+ (list 'account-depth account-depth)
+ (list 'logical-depth logical-depth)
+ (list 'account-commodity account-commodity)
+ (list 'account-anchor account-anchor)
+ (list 'account-bal account-bal)
+ (list 'recursive-bal recursive-bal)
+ (list 'report-comm-account-bal
+ report-comm-account-bal)
+ (list 'report-comm-recursive-bal
+ report-comm-recursive-bal)
+ (list 'report-commodity report-commodity)
+ (list 'exchange-fn exchange-fn)
+ )))
+ (row-env #f)
+ (label (or (and (equal? label-mode 'anchor)
+ account-anchor)
+ (and (equal? label-mode 'name)
+ (gnc:make-html-text account-name))
+ ))
+ )
+ (set! acct-depth-reached (max acct-depth-reached acct-depth))
+ (set! logi-depth-reached (max logi-depth-reached logi-depth))
+ (set! disp-depth-reached (max disp-depth-reached disp-depth))
+ (or (not (use-acct? acct))
+ ;; ok, so we'll consider parent accounts with zero
+ ;; recursive-bal to be zero balance leaf accounts
+ (and (gnc:commodity-collector-allzero? recursive-bal)
+ (equal? zero-mode 'omit-leaf-acct))
+ (begin
+ (set! row-env
+ (append grp-env
+ (list
+ (list 'account-label label)
+ (list 'row-type 'account-row)
+ (list 'display-depth disp-depth)
+ (list 'indented-depth
+ (+ disp-depth indent))
+ )
+ ))
+ (add-row row-env)
+ )
+ )
+ ;; Dive into an account even if it isnt selected!
+ (traverse-accounts! subaccts
+ (+ acct-depth 1)
+ (if (use-acct? acct)
+ (+ logi-depth 1)
+ logi-depth)
+ )
+ (or (not (use-acct? acct))
+ (not subtotal-mode)
+ ;; ignore use-acct for subtotals...
+ ;; (not (use-acct acct))
+ (null? subaccts)
+ (let* ((lbl-txt (gnc:make-html-text (_ "Total") " ")))
+ (apply gnc:html-text-append! lbl-txt
+ (gnc:html-text-body label))
+ (if (equal? subtotal-mode 'canonically-tabbed)
+ (set! disp-depth (+ disp-depth 1))
+ (set! disp-depth-reached
+ (max disp-depth-reached disp-depth))
+ )
+ (set! row-env
+ (append grp-env
+ (list
+ (list 'account-label lbl-txt)
+ (list 'row-type 'subtotal-row)
+ (list 'display-depth disp-depth)
+ (list 'indented-depth
+ (+ disp-depth indent))
+ )
+ ))
+ (add-row row-env)
+ )
+ )
+ ))
+ (if less-p
+ (sort accts less-p)
+ accts)
+ ))
+ )
+
+ ;; do it
+ (traverse-accounts! toplvl-accts 0 0)
+
+ ;; set the column-header colspan
+ (if gnc:colspans-are-working-right
+ (if (gnc:html-table-cell? column-header)
+ (gnc:html-table-cell-set-colspan! column-header
+ (+ disp-depth-reached 1 indent))
+ )
+ )
+
+ ;; now set the account-colspan entries
+ ;; he he... (let ((x 0)) (while (< x 5) (display x) (set! x (+ x 1))))
+ ;; now I know how to loop in scheme... yay!
+ (let ((row 0)
+ (rows (gnc:html-acct-table-num-rows acct-table)))
+ (while (< row rows)
+ (let* ((orig-env
+ (gnc:html-acct-table-get-row-env acct-table row))
+ (display-depth (get-val orig-env 'display-depth))
+ (depth-limit (get-val orig-env 'display-tree-depth))
+ (indent (get-val orig-env 'initial-indent))
+ (indented-depth (get-val orig-env 'indented-depth))
+ (subtotal-mode
+ (get-val orig-env 'parent-account-subtotal-mode))
+ (label-cols (+ disp-depth-reached 1))
+ (logical-cols (if depth-limit
+ (min
+ (+ logi-depth-reached 1)
+ depth-limit)
+ (+ logi-depth-reached 1)))
+ (colspan (- label-cols display-depth))
+ ;; these parameters *should* always, by now, be set...
+ (new-env
+ (append
+ orig-env
+ (list
+ (list 'account-colspan colspan)
+ (list 'label-cols label-cols)
+ (list 'logical-cols logical-cols)
+ (list 'account-cols
+ (+ indent
+ (max label-cols
+ (if depth-limit depth-limit 0)
+ )
+ )
+ )
+ )
+ ))
+ )
+ (gnc:html-acct-table-set-row-env! acct-table row new-env)
+ (set! row (+ row 1))))
+ )
+
+ ;; done
+
+ )
+ )
+
+(define (gnc:html-acct-table-num-rows acct-table)
+ (gnc:html-table-num-rows (gnc:_html-acct-table-matrix_ acct-table)))
+
+(define (gnc:html-acct-table-num-cols acct-table)
+ (- (gnc:html-table-num-cols (gnc:_html-acct-table-matrix_ acct-table)) 1))
+
+(define (gnc:html-acct-table-get-cell acct-table row col)
+ ;; we'll only ever store one object in an html-table-cell
+ ;; returns the first object stored in that cell
+ (car (gnc:html-table-cell-data
+ (gnc:html-table-get-cell
+ (gnc:_html-acct-table-matrix_ acct-table)
+ row (+ col 1)))))
+
+(define (gnc:html-acct-table-set-cell! acct-table row col obj)
+ (gnc:html-table-set-cell!
+ (gnc:_html-acct-table-matrix_ acct-table)
+ row (+ col 1)
+ obj))
+
+(define (gnc:html-acct-table-get-row-env acct-table row)
+ (gnc:html-acct-table-get-cell acct-table row -1))
+
+(define (gnc:html-acct-table-set-row-env! acct-table row env)
+ (gnc:html-acct-table-set-cell! acct-table row -1 env))
+
+(define (gnc:html-acct-table-append-row acct-table objects)
+ (gnc:html-table-append-row!
+ (gnc:_html-acct-table-matrix_ acct-table)
+ (map
+ (lambda (x) (gnc:make-html-table-cell (list x)))
+ objects)))
+
+(define (gnc:html-acct-table-prepend-row! acct-table newrow)
+ (gnc:html-table-prepend-row!
+ (gnc:_html-acct-table-matrix_ acct-table)
+ (map
+ (lambda (x) (gnc:make-html-table-cell (list x)))
+ objects)))
+
+(define (gnc:html-acct-table-append-col acct-table objects)
+ (gnc:html-table-append-col!
+ (gnc:_html-acct-table-matrix_ acct-table)
+ (map
+ (lambda (x) (gnc:make-html-table-cell (list x)))
+ objects)))
+
+(define (gnc:html-acct-table-prepend-col! acct-table newrow)
+ (gnc:html-table-prepend-col!
+ (gnc:_html-acct-table-matrix_ acct-table)
+ (map
+ (lambda (x) (gnc:make-html-table-cell (list x)))
+ objects)))
+
+(define (gnc:html-acct-table-remove-last-row! acct-table)
+ (gnc:html-table-remove-last-row! (gnc:_html-acct-table-matrix_ acct-table)))
+
+(define (gnc:identity i) i)
+
+(define (gnc:html-acct-table-render acct-table doc)
+ ;; this will be used if we ever decide to let the utility object
+ ;; render a document by calling thunks registered in the row-envs...
+ ;; but, for now, this (optional) feature is left unimplemented...
+ #f
+ )
+
+;;
+;; Here are some standard functions to help process gnc:html-acct-tables.
+;;
+
+;; Stylesheets define the following cell styles which these functions
+;; use: "text-cell" "total-label-cell" "number-cell"
+;; "total-number-cell". Row styles include "normal-row",
+;; "alternate-row", "primary-subheading", "secondary-subheading", and
+;; "grand-total". there really should also be a "first-number-cell"
+;; and "last-number-cell" to put currency symbols and underlines,
+;; respectively, on the numbers.
+
+(define (gnc:html-table-add-labeled-amount-line!
+ html-table table-width row-markup total-rule?
+ label label-depth label-colspan label-markup
+ amount amount-depth amount-colspan amount-markup)
+ ;; function to add a label and/or amount (which we'll call a "line")
+ ;; to a gnc:html-table. all depths are zero-indexed.
+ ;; if total-rule?, an <hr> is placed in the cell previous to label
+ (let* ((lbl-depth (or label-depth 0))
+ (lbl-colspan (if gnc:colspans-are-working-right
+ (or label-colspan 1)
+ 1))
+ (amt-depth (or amount-depth (+ lbl-depth lbl-colspan)))
+ (amt-colspan (if gnc:colspans-are-working-right
+ (or amount-colspan 1)
+ 1))
+ (tbl-width (or table-width (+ amt-depth amt-colspan)))
+ (row
+ (append
+ (gnc:html-make-empty-cells lbl-depth)
+ (list
+ (if label-markup
+ (gnc:make-html-table-cell/size/markup
+ 1 lbl-colspan label-markup label)
+ (gnc:make-html-table-cell/size
+ 1 lbl-colspan label))
+ )
+ (gnc:html-make-empty-cells
+ (+ (- amt-depth (+ lbl-depth lbl-colspan))
+ (if total-rule? -1 0)
+ ))
+ (if total-rule?
+ (list (gnc:make-html-table-cell
+ (gnc:make-html-text (gnc:html-markup-hr))))
+ (list)
+ )
+ (list
+ (if amount-markup
+ (gnc:make-html-table-cell/size/markup
+ 1 amt-colspan amount-markup amount)
+ (gnc:make-html-table-cell/size
+ 1 amt-colspan amount))
+ )
+ (gnc:html-make-empty-cells
+ (- table-width (+ amt-depth amt-colspan)))
+ ))
+ )
+ (if row-markup
+ (gnc:html-table-append-row/markup! html-table row-markup row)
+ (gnc:html-table-append-row! html-table row))))
+
+(define (gnc:commodity-table amount report-commodity exchange-fn)
+ ;; this creates a small two-column table listing each commodity
+ ;; balance and its respective report balance. note that this
+ ;; shows report-commodity amounts twice: first as a commodity
+ ;; and second in the report commodity. though this may arguably
+ ;; be a bit redundant, i beleive that it makes the report more
+ ;; readable.
+ (let* ((table (gnc:make-html-table))
+ )
+ (gnc:commodity-collector-map
+ amount
+ (lambda (curr val)
+ (let ((bal (gnc:make-gnc-monetary curr val)))
+ (gnc:html-table-append-row!
+ table
+ (list
+ ;; add the account balance in the respective commodity
+ (gnc:make-html-table-cell/markup
+ "number-cell" bal)
+ ;; add the account balance in the report commodity
+ (gnc:make-html-table-cell/markup
+ "number-cell" (exchange-fn bal report-commodity))
+ )
+ )
+ )))
+ table)
+ )
+
+(define (gnc:uniform-commodity? amt report-commodity)
+ ;; function to see if the commodity-collector amt
+ ;; contains any foreign commodities
+ (lambda (amt)
+ (let ((elts (gnc:commodity-collector-commodity-count amt))
+ )
+ (or (equal? elts 0)
+ (and (equal? elts 1)
+ (gnc:commodity-collector-contains-commodity?
+ amt report-commodity)
+ )
+ )
+ )
+ ))
+
+;;
+;; This function adds all the lines from a gnc:html-acct-table to a
+;; gnc:html-table in "labeled amount" form.
+;;
+;; The resulting gnc:html-table is similar to what
+;; gnc:html-build-acct-table used to (and still should) produce.
+;;
+;; this function accepts the following additional parameters:
+;; parent-account-balance-mode: 'immediate-bal 'recursive-bal ['omit-bal/#f]
+;; zero-balance-display-mode: ['show-balance] 'omit-balance
+;; multicommodity-mode: [#f] 'table/#t
+;; rule-mode: #t [#f]
+;;
+(define (gnc:html-table-add-account-balances html-table acct-table params)
+ (let* ((num-rows (gnc:html-acct-table-num-rows acct-table))
+ (rownum 0)
+ (html-table (or html-table (gnc:make-html-table)))
+ (get-val (lambda (alist key)
+ (let ((lst (assoc-ref alist key)))
+ (if lst (car lst) lst))))
+ )
+
+ (while (< rownum num-rows)
+ (let* ((env (append
+ (gnc:html-acct-table-get-row-env acct-table rownum)
+ params))
+ (acct (get-val env 'account))
+ (children (get-val env 'account-children))
+ (label (get-val env 'account-label))
+ (acct-name (get-val env 'account-name)) ;; for diagnostics...
+ (report-commodity (get-val env 'report-commodity))
+ (exchange-fn (get-val env 'exchange-fn))
+ (account-cols (get-val env 'account-cols))
+ (logical-cols (get-val env 'logical-cols))
+ (label-cols (get-val env 'label-cols))
+ (logical-depth (get-val env 'logical-depth))
+ (display-depth (get-val env 'display-depth))
+ (display-tree-depth (get-val env 'display-tree-depth))
+ (subtotal-mode (get-val env 'subtotal-mode))
+ (row-type (get-val env 'row-type))
+ (rule-mode (and (equal? row-type 'subtotal-row)
+ (get-val env 'rule-mode)))
+ (multicommodity-mode (get-val env 'multicommodity-mode))
+ (limit-behavior
+ (or (get-val env 'depth-limit-behavior)
+ 'summarize))
+ (parent-acct-bal-mode
+ (or (get-val env 'parent-account-balance-mode)
+ 'omit-bal))
+ (bal-method
+ ;; figure out how to calculate our balance:
+ ;; 'immediate-bal|'recursive-bal|'omit-bal
+ (or (and (equal? row-type 'subtotal-row) 'recursive-bal)
+ (and (equal? (+ display-depth 1) display-tree-depth)
+ (if (equal? limit-behavior 'truncate)
+ 'immediate-bal
+ ;; 'summarize, 'flatten, and unknown
+ ;; depth limit behaviors yield
+ ;; 'recursive-bal. this is true
+ ;; whether a leaf account or not.
+ 'recursive-bal)
+ )
+ (if (null? children) #f parent-acct-bal-mode)
+ 'immediate-bal
+ )
+ )
+ (comm-amt
+ ;; this will be the immediate/recursize commodity
+ ;; balance or #f
+ (get-val env
+ (car (or (assoc-ref
+ '((immediate-bal account-bal)
+ (recursive-bal recursive-bal)
+ (omit-bal #f))
+ bal-method)
+ '(#f)
+ ))))
+ (zero-mode (let ((mode
+ (get-val
+ env 'zero-balance-display-mode)))
+ (or (if (equal? mode #t) 'show-balance mode)
+ 'show-balance)
+ ))
+ (reverse-balance (gnc:account-reverse-balance? acct))
+ (native-comm?
+ (lambda (amt)
+ (gnc:uniform-commodity? amt report-commodity)))
+ (amount (and comm-amt
+ (if (and (equal? zero-mode 'omit-balance)
+ (gnc:commodity-collector-allzero? comm-amt)
+ )
+ #f
+ ;; otherwise
+ (let*
+ ((amt (gnc:make-commodity-collector)))
+ (if reverse-balance
+ (amt 'minusmerge comm-amt #f)
+ (set! amt comm-amt))
+ (or (and (native-comm? amt)
+ (gnc:sum-collector-commodity
+ amt
+ report-commodity
+ exchange-fn)
+ )
+ (if (and (equal?
+ multicommodity-mode 'table)
+ (equal?
+ row-type 'account-row)
+ )
+ (gnc:commodity-table
+ amt
+ report-commodity
+ exchange-fn)
+ (gnc:sum-collector-commodity
+ amt
+ report-commodity
+ exchange-fn)
+ )
+ )
+ )
+ )
+ ))
+ (indented-depth (get-val env 'indented-depth))
+ (account-colspan (get-val env 'account-colspan))
+ )
+ (gnc:html-table-add-labeled-amount-line!
+ html-table
+ (+ account-cols logical-cols)
+ #f rule-mode
+ label indented-depth account-colspan #f ;"label-cell"
+ amount
+ (+ account-cols (- 0 1)
+ (- logical-cols display-depth)
+ ;; account for 'immediate-bal parents displaying children
+ ;; NOTE: before you go mucking with this, BE ABSOLUTELY
+ ;; SURE you know what youre doing... i spent A LOT of
+ ;; time trying to make sure this is right. i know, in
+ ;; some reports, the output might look incorrect. but,
+ ;; if you think long and hard about it, i think you'll
+ ;; find the current treatment correct... i think. -DM-
+ (- 0 (if (if (null? children)
+ #f
+ (equal? bal-method 'immediate-bal))
+ 1 0)
+ )
+ (if (equal? subtotal-mode 'canonically-tabbed) 1 0)
+ )
+ 1 "number-cell")
+ (set! rownum (+ rownum 1))
+ )
+ )
+ html-table
+ )
+ )
+
+(define (gnc:second-html-build-acct-table
+ start-date end-date
+ tree-depth show-subaccts? accounts
+ start-percent delta-percent
+ show-col-headers?
+ show-total? get-total-fn
+ total-name group-types? show-parent-balance? show-parent-total?
+ show-other-curr? report-commodity exchange-fn show-zero-entries?)
+ ;; THIS NEW FUNCTION DOES NOT IMPLEMENT SOME FEATURES OF THE OLD ONE
+ ;; of these options: start-percent/delta-percent, the balance column
+ ;; header, show-total?/get-total-fn/total-name, and group-types? are
+ ;; presently unimplemented. many of these functions are better left
+ ;; to the renderer, anyway. but if you *really* need them, you may
+ ;; still use gnc:first-html-build-acct-table.
+ (let* ((env (list
+ (list 'start-date start-date)
+ (list 'end-date end-date)
+ (list 'display-tree-depth tree-depth)
+ ;;(list 'progress-start-percent start-percent)
+ ;;(list 'progress-length-percent delta-percent)
+ (list 'column-header show-col-headers?)
+ (list 'parent-account-subtotal-mode show-parent-total?)
+ (list 'report-commodity report-commodity)
+ (list 'exchange-fn exchange-fn)
+ (list 'zero-balance-display-mode
+ (if show-zero-entries?
+ 'show-balance
+ 'omit-balance))
+ ))
+ (html-table (gnc:make-html-table))
+ (acct-table (gnc:make-html-acct-table/env/accts env accounts))
+ (params (list
+ (list 'parent-account-balance-mode
+ (if show-parent-balance? 'immediate-bal))
+ ))
+ )
+ (gnc:html-table-add-account-balances html-table acct-table params)
+ html-table
+ ))
+
+;; END
+
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/Makefile.am,v
retrieving revision 1.11.4.1
retrieving revision 1.11.4.2
diff -Lsrc/report/report-system/Makefile.am -Lsrc/report/report-system/Makefile.am -u -r1.11.4.1 -r1.11.4.2
--- src/report/report-system/Makefile.am
+++ src/report/report-system/Makefile.am
@@ -46,6 +46,7 @@
gncscmdir = ${GNC_SHAREDIR}/scm
gncscm_DATA = \
commodity-utilities.scm \
+ html-acct-table.scm \
html-barchart.scm \
html-document.scm \
html-piechart.scm \
Index: report.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-system/report.scm,v
retrieving revision 1.12.4.1
retrieving revision 1.12.4.2
diff -Lsrc/report/report-system/report.scm -Lsrc/report/report-system/report.scm -u -r1.12.4.1 -r1.12.4.2
--- src/report/report-system/report.scm
+++ src/report/report-system/report.scm
@@ -41,6 +41,7 @@
(define gnc:menuname-income-expense (N_ "_Income & Expense"))
(define gnc:menuname-taxes (N_ "_Taxes"))
(define gnc:menuname-utility (N_ "_Sample & Custom"))
+(define gnc:menuname-custom (N_ "_Custom"))
(define gnc:pagename-general (N_ "General"))
(define gnc:pagename-accounts (N_ "Accounts"))
(define gnc:pagename-display (N_ "Display"))
@@ -135,6 +136,12 @@
(gnc:report-template-name templ))
#f)))
+(define (gnc:report-template-renderer/name template-name)
+ (let ((templ (hash-ref *gnc:_report-templates_* template-name)))
+ (if templ
+ (gnc:report-template-renderer templ)
+ #f)))
+
(define (gnc:report-template-new-options report-template)
(let ((generator (gnc:report-template-options-generator report-template))
(namer
@@ -353,6 +360,38 @@
#f " (gnc:restore-report ~S ~S options))\n"
(gnc:report-id report) (gnc:report-type report))))
+(define (gnc:report-generate-saved-forms report)
+ ;; clean up the options if necessary. this is only needed
+ ;; in special cases.
+ (let* ((template
+ (hash-ref *gnc:_report-templates_*
+ (gnc:report-type report)))
+ (thunk (gnc:report-template-options-cleanup-cb template)))
+ (if thunk
+ (thunk report)))
+
+ ;; save them
+ (string-append
+ ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+ (simple-format #f ";; Options for saved report ~S, based on template ~S\n"
+ (gnc:report-name report) (gnc:report-type report))
+ (simple-format
+ #f "(let ()\n (define (options-gen)\n (let ((options (gnc:report-template-new-options/name ~S)))\n"
+ (gnc:report-type report))
+ (gnc:generate-restore-forms (gnc:report-options report) "options")
+ " options))\n"
+ (simple-format
+ #f " (gnc:define-report \n 'version 1\n 'name ~S\n 'options-generator options-gen\n 'menu-path (list gnc:menuname-custom)\n 'renderer (gnc:report-template-renderer/name ~S)))\n\n"
+ (gnc:report-name report)
+ (gnc:report-type report))))
+
+(define (gnc:report-save-to-savefile report)
+ (let ((conf-file-name gnc:current-saved-reports))
+ ;;(display conf-file-name)
+ (display (gnc:report-generate-saved-forms report)
+ (open-file conf-file-name "a"))
+ (force-output)))
+
(define (gnc:report-render-html report headers?)
(if (and (not (gnc:report-dirty? report))
(gnc:report-ctext report))
Index: standard-reports.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/standard-reports/standard-reports.scm,v
retrieving revision 1.14.4.1
retrieving revision 1.14.4.2
diff -Lsrc/report/standard-reports/standard-reports.scm -Lsrc/report/standard-reports/standard-reports.scm -u -r1.14.4.1 -r1.14.4.2
--- src/report/standard-reports/standard-reports.scm
+++ src/report/standard-reports/standard-reports.scm
@@ -71,6 +71,7 @@
(use-modules (gnucash report advanced-portfolio))
(use-modules (gnucash report average-balance))
(use-modules (gnucash report balance-sheet))
+(use-modules (gnucash report equity-statement))
(use-modules (gnucash report cash-flow))
(use-modules (gnucash report category-barchart))
(use-modules (gnucash report daily-reports))
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/standard-reports/Makefile.am,v
retrieving revision 1.12.4.1
retrieving revision 1.12.4.2
diff -Lsrc/report/standard-reports/Makefile.am -Lsrc/report/standard-reports/Makefile.am -u -r1.12.4.1 -r1.12.4.2
--- src/report/standard-reports/Makefile.am
+++ src/report/standard-reports/Makefile.am
@@ -30,6 +30,7 @@
cash-flow.scm \
category-barchart.scm \
daily-reports.scm \
+ equity-statement.scm \
net-barchart.scm \
pnl.scm \
portfolio.scm \
Index: transaction.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/standard-reports/transaction.scm,v
retrieving revision 1.15.4.1
retrieving revision 1.15.4.2
diff -Lsrc/report/standard-reports/transaction.scm -Lsrc/report/standard-reports/transaction.scm -u -r1.15.4.1 -r1.15.4.2
--- src/report/standard-reports/transaction.scm
+++ src/report/standard-reports/transaction.scm
@@ -55,6 +55,7 @@
(define optname-sec-subtotal (N_ "Secondary Subtotal"))
(define optname-sec-date-subtotal (N_ "Secondary Subtotal for Date Key"))
(define optname-void-transactions (N_ "Void Transactions?"))
+(define optname-table-export (N_ "Table for Exporting"))
(define def:grand-total-style "grand-total")
(define def:normal-row-style "normal-row")
(define def:alternate-row-style "alternate-row")
@@ -170,23 +171,32 @@
(define (add-subtotal-row table width subtotal-string subtotal-collector
- subtotal-style)
+ subtotal-style export?)
(let ((currency-totals (subtotal-collector
'format gnc:make-gnc-monetary #f))
(blanks (gnc:make-html-table-cell/size 1 (- width 1) #f)))
(gnc:html-table-append-row/markup!
table
subtotal-style
+ (if export?
+ (append! (cons (gnc:make-html-table-cell subtotal-string)
+ (gnc:html-make-empty-cells (- width 2)))
+ (list (gnc:make-html-table-cell/markup
+ "total-number-cell"
+ (car currency-totals))))
(list (gnc:make-html-table-cell/size 1 (- width 1)
subtotal-string)
(gnc:make-html-table-cell/markup
"total-number-cell"
- (car currency-totals))))
+ (car currency-totals)))))
(for-each (lambda (currency)
(gnc:html-table-append-row/markup!
table
subtotal-style
- (cons blanks
+ (append!
+ (if export?
+ (gnc:html-make-empty-cells (- width 1))
+ (list blanks))
(list (gnc:make-html-table-cell/markup
"total-number-cell" currency)))))
(cdr currency-totals))))
@@ -194,47 +204,47 @@
(define (total-string str) (string-append (_ "Total For ") str))
(define (render-account-subtotal
- table width split total-collector subtotal-style column-vector)
+ table width split total-collector subtotal-style column-vector export?)
(add-subtotal-row table width
(total-string (account-namestring (gnc:split-get-account split)
(used-sort-account-code column-vector)
#t
(used-sort-account-full-name column-vector)))
- total-collector subtotal-style))
+ total-collector subtotal-style export?))
(define (render-corresponding-account-subtotal
- table width split total-collector subtotal-style column-vector)
+ table width split total-collector subtotal-style column-vector export?)
(add-subtotal-row table width
(total-string (account-namestring (gnc:split-get-account
(gnc:split-get-other-split split))
(used-sort-account-code column-vector)
#t
(used-sort-account-full-name column-vector)))
- total-collector subtotal-style))
+ total-collector subtotal-style export?))
(define (render-month-subtotal
- table width split total-collector subtotal-style column-vector)
+ table width split total-collector subtotal-style column-vector export?)
(let ((tm (gnc:timepair->date (gnc:transaction-get-date-posted
(gnc:split-get-parent split)))))
(add-subtotal-row table width
(total-string (strftime "%B %Y" tm))
- total-collector subtotal-style)))
+ total-collector subtotal-style export?)))
(define (render-year-subtotal
- table width split total-collector subtotal-style column-vector)
+ table width split total-collector subtotal-style column-vector export?)
(let ((tm (gnc:timepair->date (gnc:transaction-get-date-posted
(gnc:split-get-parent split)))))
(add-subtotal-row table width
(total-string (strftime "%Y" tm))
- total-collector subtotal-style)))
+ total-collector subtotal-style export?)))
(define (render-grand-total
- table width total-collector)
+ table width total-collector export?)
(add-subtotal-row table width
(_ "Grand Total")
- total-collector def:grand-total-style))
+ total-collector def:grand-total-style export?))
(define account-types-to-reverse-assoc-list
(list (cons 'none '())
@@ -485,6 +495,11 @@
(vector 'single
(N_ "Single")
(N_ "Display 1 line")))))
+
+ (gnc:register-trep-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-general optname-table-export
+ "e" (N_ "Formats the table suitable for cut & paste exporting with extra cells") #f))
;; Accounts options
@@ -844,6 +859,11 @@
(gnc:lookup-option options gnc:pagename-general (N_ "Style")))
'multi-line))
+ (define (transaction-report-export-p options)
+ (gnc:option-value
+ (gnc:lookup-option options gnc:pagename-general
+ optname-table-export)))
+
(define (add-other-split-rows split table used-columns
row-style account-types-to-reverse)
(define (other-rows-driver split parent table used-columns i)
@@ -866,6 +886,7 @@
width
multi-rows?
odd-row?
+ export?
account-types-to-reverse
primary-subtotal-pred
secondary-subtotal-pred
@@ -888,7 +909,7 @@
(gnc:make-html-table-cell/size
1 width (gnc:make-html-text (gnc:html-markup-hr)))))
- (render-grand-total table width total-collector))
+ (render-grand-total table width total-collector export?))
(let* ((current (car splits))
(current-row-style (if multi-rows? def:normal-row-style
@@ -934,12 +955,13 @@
(secondary-subtotal-renderer
table width current
secondary-subtotal-collector
- def:secondary-subtotal-style used-columns)
+ def:secondary-subtotal-style used-columns export?)
(secondary-subtotal-collector 'reset #f #f)))
(primary-subtotal-renderer table width current
primary-subtotal-collector
- def:primary-subtotal-style used-columns)
+ def:primary-subtotal-style used-columns
+ export?)
(primary-subtotal-collector 'reset #f #f)
@@ -962,7 +984,7 @@
(begin (secondary-subtotal-renderer
table width current
secondary-subtotal-collector
- def:secondary-subtotal-style used-columns)
+ def:secondary-subtotal-style used-columns export?)
(secondary-subtotal-collector 'reset #f #f)
(if next
(secondary-subheading-renderer
@@ -975,6 +997,7 @@
width
multi-rows?
(not odd-row?)
+ export?
account-types-to-reverse
primary-subtotal-pred
secondary-subtotal-pred
@@ -989,6 +1012,7 @@
(let* ((table (gnc:make-html-table))
(width (num-columns-required used-columns))
(multi-rows? (transaction-report-multi-rows-p options))
+ (export? (transaction-report-export-p options))
(account-types-to-reverse
(get-account-types-to-reverse options)))
@@ -1006,7 +1030,8 @@
(car splits) table width def:secondary-subtotal-style used-columns))
(do-rows-with-subtotals splits table used-columns width
- multi-rows? #t
+ multi-rows? #t
+ export?
account-types-to-reverse
primary-subtotal-pred
secondary-subtotal-pred
Index: balance-sheet.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/standard-reports/balance-sheet.scm,v
retrieving revision 1.11.4.2
retrieving revision 1.11.4.3
diff -Lsrc/report/standard-reports/balance-sheet.scm -Lsrc/report/standard-reports/balance-sheet.scm -u -r1.11.4.2 -r1.11.4.3
--- src/report/standard-reports/balance-sheet.scm
+++ src/report/standard-reports/balance-sheet.scm
@@ -1,8 +1,50 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; balance-sheet.scm: balance sheet
+;; balance-sheet.scm: balance sheet
;;
;; By Robert Merkel <rgmerk at mira.net>
;;
+;; Heavily modified and Frankensteined by David Montenegro
+;; 2004.06.12-2004.06.23 <sunrise2000 at comcast.net>
+;;
+;; * Removed from-date & Net Profit from the report.
+;;
+;; * Updated to use the new gnc:html-acct-table utility object.
+;; Added *lots* of new options. The report can now probably
+;; be coerced into the form that *you* want. <grin>
+;;
+;; * BUGS:
+;;
+;; The Accounts option panel needs a way to select (and select by
+;; default) accounts representative of current & fixed assets &
+;; liabilities.
+;;
+;; There are some gnc:html-acct-table options which remain unused,
+;; mostly because I don't know how to make drop-down option
+;; controls.
+;;
+;; This code makes the assumption that you want your equity
+;; statement to no more than daily resolution.
+;;
+;; The Company Name field does not currently default to the name
+;; in (gnc:get-current-book).
+;;
+;; Line & column alignments still do not conform with
+;; textbook accounting practice (they're close though!).
+;;
+;; Progress bar functionality is currently mostly broken.
+;;
+;; The variables in this code could use more consistent naming.
+;;
+;; I'm not sure if I got (_ ) vs (N_ ) right. (What are they?)
+;;
+;; The multicurrency support has been tested, BUT IS ALPHA. I
+;; *think* it works right, but can make no guarantees.... In
+;; particular, I have made the educated assumption <grin> that a
+;; decrease in the value of a liability or equity also represents
+;; an unrealized loss. I *think* that is right, but am not sure.
+;;
+;; See also all the "FIXME"s in the code.
+;;
;; Largely borrowed from pnl.scm by:
;; Christian Stimming <stimming at tu-harburg.de>
;;
@@ -30,59 +72,110 @@
(use-modules (ice-9 slib))
(use-modules (gnucash gnc-module))
-(require 'printf)
-
(gnc:module-load "gnucash/report/report-system" 0)
(define reportname (N_ "Balance Sheet"))
-;; define all option's names so that they are properly defined
-;; in *one* place.
-(define optname-from-date (N_ "From"))
-(define optname-to-date (N_ "To"))
-
-(define optname-display-depth (N_ "Account Display Depth"))
-(define optname-show-subaccounts (N_ "Always show sub-accounts"))
-(define optname-accounts (N_ "Account"))
-
-(define optname-show-parent-balance (N_ "Show balances for parent accounts"))
-(define optname-show-parent-total (N_ "Show subtotals"))
+;; define all option's names and help text so that they are properly
+;; defined in *one* place.
+(define optname-report-title (N_ "Report Title"))
+(define opthelp-report-title (N_ "Title for this report"))
+
+(define optname-party-name (N_ "Company name"))
+(define opthelp-party-name (N_ "Name of company/individual"))
+
+(define optname-date (N_ "Balance Sheet Date"))
+(define opthelp-date (N_ "Balance sheet as-of date"))
+(define optname-report-form (N_ "Report form Balance Sheet"))
+(define opthelp-report-form
+ (N_ "Create report in report (as opposed to report) form"))
+;; FIXME this needs an indent option
+
+(define optname-accounts (N_ "Accounts to include"))
+(define opthelp-accounts
+ (N_ "Report on these accounts, if display depth allows."))
+(define optname-depth-limit (N_ "Levels of Subaccounts"))
+(define opthelp-depth-limit
+ (N_ "Maximum number of levels in the account tree displayed"))
+(define optname-bottom-behavior (N_ "Flatten list to depth limit"))
+(define opthelp-bottom-behavior
+ (N_ "Displays accounts which exceed the depth limit at the depth limit"))
+
+(define optname-show-parent-balance (N_ "Show any balance in parent accounts"))
+(define opthelp-show-parent-balance (N_ "Show any balance in parent accounts"))
+;; FIXME optname-show-parent-balance needs immediate/recursive/omit choices
+(define optname-show-parent-total (N_ "Show parent account subtotals"))
+(define opthelp-show-parent-total
+ (N_ "Show account subtotals for all selected accounts having children"))
+;; FIXME optname-show-parent-total needs a 'canonically-tabbed choice
+
+(define optname-show-zb-accts (N_ "Include accounts with zero total balances"))
+(define opthelp-show-zb-accts
+ (N_ "Include accounts with zero total (recursive) balances in this report"))
+(define optname-omit-zb-bals (N_ "Omit zero balance figures"))
+(define opthelp-omit-zb-bals
+ (N_ "Show blank space in place of any zero balances which would be shown"))
+
+(define optname-use-rules (N_ "Show accounting-style rules"))
+(define opthelp-use-rules
+ (N_ "Use rules beneath columns of added numbers like accountants do"))
+
+(define optname-account-links (N_ "Display accounts as hyperlinks"))
+(define opthelp-account-links (N_ "Shows each account in the table as a hyperlink to its register window"))
+
+(define optname-label-assets (N_ "Label the assets section"))
+(define opthelp-label-assets
+ (N_ "Whether or not to include a label for the assets section"))
+(define optname-total-assets (N_ "Include assets total"))
+(define opthelp-total-assets
+ (N_ "Whether or not to include a line indicating total assets"))
+(define optname-label-liabilities (N_ "Label the liabilities section"))
+(define opthelp-label-liabilities
+ (N_ "Whether or not to include a label for the liabilities section"))
+(define optname-total-liabilities (N_ "Include liabilities total"))
+(define opthelp-total-liabilities
+ (N_ "Whether or not to include a line indicating total liabilities"))
+(define optname-label-equity (N_ "Label the equity section"))
+(define opthelp-label-equity
+ (N_ "Whether or not to include a label for the equity section"))
+(define optname-total-equity (N_ "Include equity total"))
+(define opthelp-total-equity
+ (N_ "Whether or not to include a line indicating total equity"))
-(define optname-report-currency (N_ "Report's currency"))
+(define pagename-commodities (N_ "Commodities"))
+(define optname-report-commodity (N_ "Report's currency"))
(define optname-price-source (N_ "Price Source"))
(define optname-show-foreign (N_ "Show Foreign Currencies"))
+(define opthelp-show-foreign
+ (N_ "Display any foreign currency amount in an account"))
(define optname-show-rates (N_ "Show Exchange Rates"))
-(define optname-show-zeros (N_ "Show accounts with zero balance"))
+(define opthelp-show-rates (N_ "Show the exchange rates used"))
-;; Moderatly ugly hack here, i.e. this depends on the internal
-;; structure of html-table -- if that is changed, this might break.
-(define (html-table-merge t1 t2)
- (begin
- (gnc:html-table-set-data! t1
- (append
- (gnc:html-table-data t2)
- (gnc:html-table-data t1)))
- (gnc:html-table-set-num-rows-internal!
- t1 (+ (gnc:html-table-num-rows t1)
- (gnc:html-table-num-rows t2)))))
-
-(define (accountlist-get-comm-balance-at-date accountlist from date)
+;; This calculates the increase in the balance(s) of all accounts in
+;; <accountlist> over the period from <from-date> to <to-date>.
+;; Returns a commodity collector.
+;;
+;; Note: There is both a gnc:account-get-comm-balance-interval and
+;; gnc:group-get-comm-balance-interval which could replace this
+;; function....
+;;
+(define (accountlist-get-comm-balance-at-date accountlist from-date to-date)
;; (for-each (lambda (x) (display x))
-;; (list "computing from: " (gnc:print-date from) " to "
-;; (gnc:print-date date) "\n"))
+;; (list "computing from: " (gnc:print-date from-date) " to "
+;; (gnc:print-date to-date) "\n"))
(let ((collector (gnc:make-commodity-collector)))
(for-each (lambda (account)
(let* (
(start-balance
(gnc:account-get-comm-balance-at-date
- account from #f))
+ account from-date #f))
(sb (cadr (start-balance
'getpair
(gnc:account-get-commodity account)
#f)))
(end-balance
(gnc:account-get-comm-balance-at-date
- account date #f))
+ account to-date #f))
(eb (cadr (end-balance
'getpair
(gnc:account-get-commodity account)
@@ -100,371 +193,596 @@
;; options generator
(define (balance-sheet-options-generator)
- (let ((options (gnc:new-options)))
-
+ (let* ((options (gnc:new-options))
+ (add-option
+ (lambda (new-option)
+ (gnc:register-option options new-option))))
+
+ (add-option
+ (gnc:make-string-option
+ (N_ "General") optname-report-title
+ "a" opthelp-report-title reportname))
+ (add-option
+ (gnc:make-string-option
+ (N_ "General") optname-party-name
+ "b" opthelp-party-name (N_ "")))
+ ;; this should default to company name in (gnc:get-current-book)
+ ;; does anyone know the function to get the company name??
+ ;; (GnuCash is *so* well documented... sigh)
+
;; date at which to report balance
- (gnc:options-add-date-interval!
- options gnc:pagename-general
- optname-from-date optname-to-date "a")
-
+ (add-option
+ (gnc:make-date-option
+ (N_ "General") optname-date
+ "c" opthelp-date
+ (lambda () (cons 'absolute (cons (current-time) 0)))
+ #f 'both '(start-cal-year start-prev-year end-prev-year) ))
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-general optname-report-form
+ "d" opthelp-report-form #t))
+
+ ;; accounts to work on
+ (add-option
+ (gnc:make-account-list-option
+ gnc:pagename-accounts optname-accounts
+ "a"
+ opthelp-accounts
+ (lambda ()
+ (gnc:filter-accountlist-type
+ '(bank cash credit asset liability stock mutual-fund currency
+ payable receivable equity income expense)
+ (gnc:group-get-subaccounts (gnc:get-current-group))))
+ #f #t))
+ (gnc:options-add-account-levels!
+ options gnc:pagename-accounts optname-depth-limit
+ "b" opthelp-depth-limit 3)
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-accounts optname-bottom-behavior
+ "c" opthelp-bottom-behavior #f))
+
;; all about currencies
(gnc:options-add-currency!
- options gnc:pagename-general
- optname-report-currency "b")
-
+ options pagename-commodities
+ optname-report-commodity "a")
+
(gnc:options-add-price-source!
- options gnc:pagename-general
- optname-price-source "c" 'weighted-average)
-
- ;; accounts to work on
- (gnc:options-add-account-selection!
- options gnc:pagename-accounts
- optname-display-depth optname-show-subaccounts
- optname-accounts "a" 2
- (lambda ()
- (gnc:filter-accountlist-type
- '(bank cash credit asset liability stock mutual-fund currency
- payable receivable equity income expense)
- (gnc:group-get-subaccounts (gnc:get-current-group))))
- #t)
-
- ;; what to show about non-leaf accounts
- (gnc:register-option
- options
+ options pagename-commodities
+ optname-price-source "b" 'weighted-average)
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ pagename-commodities optname-show-foreign
+ "c" opthelp-show-foreign #t))
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ pagename-commodities optname-show-rates
+ "d" opthelp-show-rates #f))
+
+ ;; what to show for zero-balance accounts
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-show-zb-accts
+ "a" opthelp-show-zb-accts #t))
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-omit-zb-bals
+ "b" opthelp-omit-zb-bals #f))
+ ;; what to show for non-leaf accounts
+ (add-option
(gnc:make-simple-boolean-option
gnc:pagename-display optname-show-parent-balance
- "c" (N_ "Show balances for parent accounts") #t))
-
- ;; have a subtotal for each parent account?
- (gnc:register-option
- options
+ "c" opthelp-show-parent-balance #t))
+ (add-option
(gnc:make-simple-boolean-option
gnc:pagename-display optname-show-parent-total
- "d" (N_ "Show subtotals for parent accounts") #f))
-
- (gnc:register-option
- options
+ "d" opthelp-show-parent-total #f))
+ ;; some detailed formatting options
+ (add-option
(gnc:make-simple-boolean-option
- gnc:pagename-display optname-show-foreign
- "e" (N_ "Display the account's foreign currency amount?") #f))
-
- (gnc:register-option
- options
+ gnc:pagename-display optname-account-links
+ "e" opthelp-account-links #t))
+ (add-option
(gnc:make-simple-boolean-option
- gnc:pagename-display optname-show-rates
- "f" (N_ "Show the exchange rates used") #f))
-
- (gnc:register-option
- options
+ gnc:pagename-display optname-use-rules
+ "f" opthelp-use-rules #f))
+
+ (add-option
(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)
-
+ gnc:pagename-display optname-label-assets
+ "g" opthelp-label-assets #t))
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-total-assets
+ "h" opthelp-total-assets #t))
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-label-liabilities
+ "i" opthelp-label-liabilities #t))
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-total-liabilities
+ "j" opthelp-total-liabilities #t))
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-label-equity
+ "k" opthelp-label-equity #t))
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-total-equity
+ "l" opthelp-total-equity #t))
+
+ ;; Set the accounts page as default option tab
+ (gnc:options-set-default-section options gnc:pagename-accounts)
+
options))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; balance-sheet-renderer
;; set up the document and add the table
+;; then then return the document or, if
+;; requested, export it to a file
;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define (balance-sheet-renderer report-obj)
+(define (balance-sheet-renderer report-obj choice filename)
(define (get-option pagename optname)
(gnc:option-value
(gnc:lookup-option
(gnc:report-options report-obj) pagename optname)))
-
+ (define forever-ago (cons 0 0))
+
(gnc:report-starting reportname)
-
+
;; get all option's values
- (let* ((display-depth (get-option gnc:pagename-accounts
- optname-display-depth))
- (show-subaccts? (get-option gnc:pagename-accounts
- optname-show-subaccounts))
+ (let* (
+ (report-title (get-option gnc:pagename-general optname-report-title))
+ (company-name (get-option gnc:pagename-general optname-party-name))
+ (date-tp (gnc:timepair-end-day-time
+ (gnc:date-option-absolute-time
+ (get-option gnc:pagename-general
+ optname-date))))
+ (report-form? (get-option gnc:pagename-general
+ optname-report-form))
(accounts (get-option gnc:pagename-accounts
optname-accounts))
+ (depth-limit (get-option gnc:pagename-accounts
+ optname-depth-limit))
+ (bottom-behavior (get-option gnc:pagename-accounts
+ optname-bottom-behavior))
+ (report-commodity (get-option pagename-commodities
+ optname-report-commodity))
+ (price-source (get-option pagename-commodities
+ optname-price-source))
+ (show-fcur? (get-option pagename-commodities
+ optname-show-foreign))
+ (show-rates? (get-option pagename-commodities
+ optname-show-rates))
(show-parent-balance? (get-option gnc:pagename-display
optname-show-parent-balance))
(show-parent-total? (get-option gnc:pagename-display
optname-show-parent-total))
- (show-fcur? (get-option gnc:pagename-display
- optname-show-foreign))
- (report-currency (get-option gnc:pagename-general
- optname-report-currency))
- (price-source (get-option gnc:pagename-general
- 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)))
- (from-date-tp (gnc:timepair-end-day-time
- (gnc:timepair-previous-day from-date-printable)))
- (to-date-tp (gnc:timepair-end-day-time
- (gnc:date-option-absolute-time
- (get-option gnc:pagename-general
- optname-to-date))))
-
+ (show-zb-accts? (get-option gnc:pagename-display
+ optname-show-zb-accts))
+ (omit-zb-bals? (get-option gnc:pagename-display
+ optname-omit-zb-bals))
+ (label-assets? (get-option gnc:pagename-display
+ optname-label-assets))
+ (total-assets? (get-option gnc:pagename-display
+ optname-total-assets))
+ (label-liabilities? (get-option gnc:pagename-display
+ optname-label-liabilities))
+ (total-liabilities? (get-option gnc:pagename-display
+ optname-total-liabilities))
+ (label-equity? (get-option gnc:pagename-display
+ optname-label-equity))
+ (total-equity? (get-option gnc:pagename-display
+ optname-total-equity))
+ (use-links? (get-option gnc:pagename-display
+ optname-account-links))
+ (use-rules? (get-option gnc:pagename-display
+ optname-use-rules))
+ (indent 0)
+ (tabbing #f)
+
;; decompose the account list
(split-up-accounts (gnc:decompose-accountlist accounts))
(asset-accounts
- (assoc-ref split-up-accounts 'asset))
+ (assoc-ref split-up-accounts 'asset))
(liability-accounts
- (assoc-ref split-up-accounts 'liability))
+ (assoc-ref split-up-accounts 'liability))
(equity-accounts
(assoc-ref split-up-accounts 'equity))
(income-expense-accounts
(append (assoc-ref split-up-accounts 'income)
(assoc-ref split-up-accounts 'expense)))
-
+
(doc (gnc:make-html-document))
- (txt (gnc:make-html-text))
- (tree-depth (if (equal? display-depth 'all)
+ ;; this can occasionally put extra (blank) columns in our
+ ;; table (when there is one account at the maximum depth and
+ ;; it has at least one of its ancestors deselected), but this
+ ;; is the only simple way to ensure that all three tables
+ ;; (asset, liability, equity) have the same width.
+ (tree-depth (if (equal? depth-limit 'all)
(gnc:get-current-group-depth)
- display-depth))
- ;; calculate the exchange rates
- (exchange-fn #f)
- (totals-get-balance #f))
-
- ;; Wrapper to call the right html-utility function.
- (define (add-subtotal-line table label balance)
- (if show-fcur?
- (gnc:html-acct-table-comm-row-helper!
- table tree-depth report-currency exchange-fn
- 1 label report-currency
- (gnc:sum-collector-stocks balance report-currency exchange-fn)
- #f #f "primary-subheading" "primary-subheading" #t #f)
- (gnc:html-acct-table-row-helper!
- table tree-depth 1 label
- (gnc:sum-collector-commodity
- balance report-currency exchange-fn)
- #f "primary-subheading" #t #f)))
+ depth-limit))
+ ;; exchange rates calculation parameters
+ (exchange-fn
+ (gnc:case-exchange-fn price-source report-commodity date-tp))
+ )
+
+ ;; Wrapper to call gnc:html-table-add-labeled-amount-line!
+ ;; with the proper arguments.
+ (define (add-subtotal-line table pos-label neg-label signed-balance)
+ (define allow-same-column-totals #t)
+ (let* ((neg? (and signed-balance
+ (gnc:numeric-negative-p
+ (gnc:gnc-monetary-amount
+ (gnc:sum-collector-commodity
+ signed-balance report-commodity exchange-fn)))))
+ (label (if neg? (or neg-label pos-label) pos-label))
+ (balance (if neg?
+ (let ((bal (gnc:make-commodity-collector)))
+ (bal 'minusmerge signed-balance #f)
+ bal)
+ signed-balance))
+ )
+ (gnc:html-table-add-labeled-amount-line!
+ table
+ (+ indent (* tree-depth 2)
+ (if (equal? tabbing 'canonically-tabbed) 1 0))
+ "primary-subheading"
+ (and (not allow-same-column-totals) balance use-rules?)
+ label indent 1 "total-label-cell"
+ (gnc:sum-collector-commodity balance report-commodity exchange-fn)
+ (+ indent (* tree-depth 2) (- 0 1)
+ (if (equal? tabbing 'canonically-tabbed) 1 0))
+ 1 "total-number-cell")
+ )
+ )
+ ;; (gnc:sum-collector-stocks balance report-commodity exchange-fn)
+ ;; Hey! Look at that! This rolls the stocks into the balance!
+ ;; Can anyone think of a reason why this would be desireable?
+ ;; None come to (my) mind. Perhaps this should be a report option?
+
+ ;; Wrapper around gnc:html-table-append-ruler! since we call it so
+ ;; often.
+ (define (add-rule table)
+ (gnc:html-table-append-ruler!
+ table
+ (+ (* 2 tree-depth)
+ (if (equal? tabbing 'canonically-tabbed) 1 0))))
;;(gnc:warn "account names" liability-account-names)
(gnc:html-document-set-title!
- doc (sprintf #f "%s %s - %s"
- (get-option gnc:pagename-general gnc:optname-reportname)
- (gnc:print-date from-date-printable)
- (gnc:print-date to-date-tp)))
-
- (if (not (null? accounts))
+ doc (string-append report-title " " company-name " "
+ (gnc:print-date date-tp))
+ )
+
+ (if (null? accounts)
+
+ ;; error condition: no accounts specified
+ ;; is this *really* necessary??
+ ;; i'd be fine with an all-zero balance sheet
+ ;; that would, technically, be correct....
+ (gnc:html-document-add-object!
+ doc
+ (gnc:html-make-no-account-warning
+ reportname (gnc:report-id report-obj)))
+
;; Get all the balances for each account group.
(let* ((asset-balance #f)
+ (neg-liability-balance #f) ;; credit balances are < 0
(liability-balance #f)
+ (neg-equity-balance #f)
(equity-balance #f)
- (sign-reversed-liability-balance #f)
- (neg-net-profit-balance #f)
- (net-profit-balance #f)
- (neg-retained-earnings-balance #f)
- (retained-earnings-balance #f)
- (total-equity-balance #f)
- (equity-plus-liability #f)
+ (neg-retained-earnings #f) ;; credit, income - expenses, < 0
+ (retained-earnings #f)
(unrealized-gain-collector #f)
-
+ (total-equity-balance #f)
+ (liability-plus-equity #f)
+ (book-balance #f) ;; assets - liabilities - equity, norm 0
+
;; Create the account tables below where their
;; percentage time can be tracked.
- (asset-table #f)
- (liability-table #f)
- (equity-table #f))
-
- (gnc:report-percent-done 2)
- (set! totals-get-balance (lambda (account)
- (gnc:account-get-comm-balance-at-date
- account to-date-tp #f)))
+ (left-table (gnc:make-html-table)) ;; gnc:html-table
+ (right-table (if report-form? left-table
+ (gnc:make-html-table)))
+ (table-env #f) ;; parameters for :make-
+ (params #f) ;; and -add-account-
+ (asset-table #f) ;; gnc:html-acct-table
+ (liability-table #f) ;; gnc:html-acct-table
+ (equity-table #f) ;; gnc:html-acct-table
+ (get-total-balance-fn
+ (lambda (account)
+ (gnc:account-get-comm-balance-at-date
+ account date-tp #f)))
+ )
+
+ ;; If you ask me, any outstanding(TM) retained earnings and
+ ;; unrealized gains should be added directly into equity,
+ ;; since the balance sheet does not have a period over which
+ ;; to report earnings.... See discussion on bugzilla.
(gnc:report-percent-done 4)
+ ;; sum assets
(set! asset-balance
(gnc:accounts-get-comm-total-assets
- asset-accounts totals-get-balance))
+ asset-accounts get-total-balance-fn))
(gnc:report-percent-done 6)
- (set! liability-balance
+ ;; sum liabilities
+ (set! neg-liability-balance
(gnc:accounts-get-comm-total-assets
- liability-accounts totals-get-balance))
+ liability-accounts get-total-balance-fn))
+ (set! liability-balance
+ (gnc:make-commodity-collector))
+ (liability-balance 'minusmerge
+ neg-liability-balance
+ #f)
(gnc:report-percent-done 8)
- (set! equity-balance
+ ;; sum equities
+ (set! neg-equity-balance
(gnc:accounts-get-comm-total-assets
- equity-accounts totals-get-balance))
- (gnc:report-percent-done 10)
- (set! sign-reversed-liability-balance
- (gnc:make-commodity-collector))
+ equity-accounts get-total-balance-fn))
+ (set! equity-balance (gnc:make-commodity-collector))
+ (equity-balance 'minusmerge
+ neg-equity-balance
+ #f)
(gnc:report-percent-done 12)
- (set! neg-net-profit-balance
- (accountlist-get-comm-balance-at-date
- income-expense-accounts
- from-date-tp to-date-tp))
- (set! neg-retained-earnings-balance
+ ;; sum any retained earnings
+ (set! neg-retained-earnings
(accountlist-get-comm-balance-at-date
income-expense-accounts
- (cons 0 0) from-date-tp))
+ forever-ago date-tp))
+ (set! retained-earnings (gnc:make-commodity-collector))
+ (retained-earnings 'minusmerge
+ neg-retained-earnings
+ #f)
(gnc:report-percent-done 14)
- (set! net-profit-balance (gnc:make-commodity-collector))
- (set! retained-earnings-balance (gnc:make-commodity-collector))
- (gnc:report-percent-done 16)
- (set! total-equity-balance (gnc:make-commodity-collector))
- (gnc:report-percent-done 18)
- (set! equity-plus-liability (gnc:make-commodity-collector))
- (set! unrealized-gain-collector (gnc:make-commodity-collector))
-
- (gnc:report-percent-done 20)
- (set! exchange-fn (gnc:case-exchange-fn
- price-source report-currency to-date-tp))
- (gnc:report-percent-done 30)
-
- ;;; Arbitrarily declare that the building of these tables
- ;;; takes 50% of the total amount of time spent building
- ;;; this report. (from 30%-80%)
- (set! asset-table
- (gnc:html-build-acct-table
- #f to-date-tp
- tree-depth show-subaccts?
- asset-accounts
- 30 20
- #f #f #f #f #f
- show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn show-zeros?))
- (set! liability-table
- (gnc:html-build-acct-table
- #f to-date-tp
- tree-depth show-subaccts?
- liability-accounts
- 50 20
- #f #f #f #f #f
- show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn show-zeros?))
- (set! equity-table
- (gnc:html-build-acct-table
- #f to-date-tp
- tree-depth show-subaccts?
- equity-accounts
- 70 10
- #f #f #f #f #f
- show-parent-balance? show-parent-total?
- show-fcur? report-currency exchange-fn show-zeros?))
-
- (net-profit-balance 'minusmerge
- neg-net-profit-balance
- #f)
- (retained-earnings-balance 'minusmerge
- neg-retained-earnings-balance
- #f)
- (total-equity-balance 'minusmerge equity-balance #f)
- (total-equity-balance 'merge
- net-profit-balance
- #f)
- (total-equity-balance 'merge
- retained-earnings-balance
- #f)
- (sign-reversed-liability-balance 'minusmerge
- liability-balance
- #f)
- (equity-plus-liability 'merge
- sign-reversed-liability-balance
- #f)
- (equity-plus-liability 'merge
- total-equity-balance
- #f)
-
- ;; Now concatenate the tables. This first prepend-row has
- ;; to be written out by hand -- we can't use the function
- ;; append-something because we have to prepend.
- (gnc:report-percent-done 80)
- (gnc:html-table-prepend-row/markup!
- asset-table
- "primary-subheading"
- (append
- (list (gnc:html-acct-table-cell tree-depth
- (_ "Assets") #t))
- ;; Workaround to force gtkhtml into displaying wide
- ;; enough columns.
- (make-list (* (if show-fcur? 2 1) tree-depth)
- " \
- \
- ")))
-
- (add-subtotal-line
- asset-table (_ "Assets") asset-balance)
-
- ;; add a horizontal ruler
- (gnc:html-table-append-ruler!
- asset-table (* (if show-fcur? 3 2) tree-depth))
-
- (gnc:report-percent-done 85)
- (add-subtotal-line
- asset-table (_ "Liabilities") #f)
- (html-table-merge asset-table liability-table)
- (add-subtotal-line
- asset-table (_ "Liabilities") sign-reversed-liability-balance)
-
+ ;; sum any unrealized gains
+ ;;
+ ;; Hm... unrealized gains.... This is when you purchase
+ ;; something and its value increases/decreases (prior to
+ ;; your selling it) and you have to reflect that on your
+ ;; balance sheet.
+ ;;
+ ;; I *think* a decrease in the value of a liability or
+ ;; equity constitutes an unrealized loss. I'm unsure about
+ ;; that though....
+ ;;
+ (set! book-balance (gnc:make-commodity-collector))
+ (book-balance 'merge asset-balance #f)
+ (book-balance 'merge neg-liability-balance #f)
+ (book-balance 'merge neg-equity-balance #f)
+ (book-balance 'merge neg-retained-earnings #f)
+ (set! unrealized-gain-collector (gnc:make-commodity-collector))
(let* ((weighted-fn
(gnc:case-exchange-fn 'weighted-average
- report-currency to-date-tp))
-
+ report-commodity date-tp))
+
(value
(gnc:gnc-monetary-amount
- (gnc:sum-collector-commodity asset-balance
- report-currency
+ (gnc:sum-collector-commodity book-balance
+ report-commodity
exchange-fn)))
-
+
(cost
(gnc:gnc-monetary-amount
- (gnc:sum-collector-commodity asset-balance
- report-currency
+ (gnc:sum-collector-commodity book-balance
+ report-commodity
weighted-fn)))
-
+
(unrealized-gain (gnc:numeric-sub-fixed value cost)))
-
- (unrealized-gain-collector 'add report-currency unrealized-gain)
- (equity-plus-liability 'add report-currency unrealized-gain)
-
- (add-subtotal-line
- asset-table (_ "Unrealized Gains(Losses)")
- unrealized-gain-collector))
-
- (gnc:html-table-append-ruler!
- asset-table (* (if show-fcur? 3 2) tree-depth))
-
+
+ (unrealized-gain-collector 'add report-commodity unrealized-gain)
+ )
+ ;; calculate equity and liability+equity totals
+ (set! total-equity-balance (gnc:make-commodity-collector))
+ (total-equity-balance 'merge
+ equity-balance
+ #f)
+ (total-equity-balance 'merge
+ retained-earnings
+ #f)
+ (total-equity-balance 'merge
+ unrealized-gain-collector
+ #f)
+ (gnc:report-percent-done 18)
+ (set! liability-plus-equity (gnc:make-commodity-collector))
+ (liability-plus-equity 'merge
+ liability-balance
+ #f)
+ (liability-plus-equity 'merge
+ total-equity-balance
+ #f)
+
+ (gnc:report-percent-done 20)
+ (gnc:report-percent-done 30)
+
+ ;;; Arbitrarily declare that the building of these tables
+ ;;; takes 50% of the total amount of time spent building
+ ;;; this report. (from 30%-80%)
+
+ (set! table-env
+ (list
+ (list 'start-date #f)
+ (list 'end-date date-tp)
+ (list 'display-tree-depth tree-depth)
+ (list 'depth-limit-behavior (if bottom-behavior
+ 'flatten
+ 'summarize))
+ (list 'report-commodity report-commodity)
+ (list 'exchange-fn exchange-fn)
+ (list 'parent-account-subtotal-mode show-parent-total?)
+ (list 'zero-balance-mode (if show-zb-accts?
+ 'show-leaf-acct
+ 'omit-leaf-acct))
+ (list 'account-label-mode (if use-links?
+ 'anchor
+ 'name))
+ )
+ )
+ (set! params
+ (list
+ (list 'parent-account-balance-mode
+ (if show-parent-balance?
+ 'immediate-bal
+ 'omit-bal
+ ))
+ (list 'zero-balance-display-mode (if omit-zb-bals?
+ 'omit-balance
+ 'show-balance))
+ (list 'multicommodity-mode (if show-fcur? 'table #f))
+ (list 'rule-mode use-rules?)
+ )
+ )
+
+ ;(gnc:html-table-set-style!
+ ; left-table "table" 'attribute '("rules" "rows"))
+ ;(gnc:html-table-set-style!
+ ; right-table "table" 'attribute '("rules" "rows"))
+ ;; could also '("border" "1") or '("rules" "all")
+
+ ;; Workaround to force gtkhtml into displaying wide
+ ;; enough columns.
+ (let ((space
+ (make-list tree-depth " \
+ \
+ ")
+ ))
+ (gnc:html-table-append-row! left-table space)
+ (if (not report-form?)
+ (gnc:html-table-append-row! right-table space))
+ )
+
+ (gnc:report-percent-done 80)
+ (if label-assets? (add-subtotal-line left-table (_ "Assets") #f #f))
+ (set! asset-table
+ (gnc:make-html-acct-table/env/accts
+ table-env asset-accounts))
+ (gnc:html-table-add-account-balances
+ left-table asset-table params)
+ (if total-assets? (add-subtotal-line
+ left-table (_ "Total Assets") #f asset-balance))
+
+ (if report-form?
+ (add-rule left-table))
+ (if report-form?
+ (add-rule left-table))
+
+ (gnc:report-percent-done 85)
+ (if label-liabilities?
+ (add-subtotal-line
+ right-table (_ "Liabilities") #f #f))
+ (set! liability-table
+ (gnc:make-html-acct-table/env/accts
+ table-env liability-accounts))
+ (gnc:html-table-add-account-balances
+ right-table liability-table params)
+ (if total-liabilities?
+ (add-subtotal-line
+ right-table (_ "Total Liabilities") #f liability-balance))
+
+ (add-rule right-table)
+
(gnc:report-percent-done 88)
+ (if label-equity?
+ (add-subtotal-line
+ right-table (_ "Equity") #f #f))
+ (set! equity-table
+ (gnc:make-html-acct-table/env/accts
+ table-env equity-accounts))
+ (gnc:html-table-add-account-balances
+ right-table equity-table params)
+ ;; we omit retianed earnings & unrealized gains
+ ;; from the balance report, if zero, since they
+ ;; are not present on normal balance sheets
+ (and (not (gnc:commodity-collector-allzero?
+ retained-earnings))
+ (add-subtotal-line right-table
+ (N_ "Retained Earnings")
+ (N_ "Retained Losses")
+ retained-earnings))
+ (and (not (gnc:commodity-collector-allzero?
+ unrealized-gain-collector))
+ (add-subtotal-line right-table
+ (N_ "Unrealized Gains")
+ (N_ "Unrealized Losses")
+ unrealized-gain-collector))
+ (if total-equity?
+ (add-subtotal-line
+ right-table (_ "Total Equity") #f total-equity-balance))
+
+ (add-rule right-table)
+
(add-subtotal-line
- asset-table (_ "Equity") #f)
- (html-table-merge asset-table equity-table)
- (add-subtotal-line
- asset-table (_ "Retained Earnings") retained-earnings-balance)
- (add-subtotal-line
- asset-table (_ "Net Profit") net-profit-balance)
- (add-subtotal-line
- asset-table (_ "Total Equity") total-equity-balance)
-
- (gnc:html-table-append-ruler!
- asset-table (* (if show-fcur? 3 2) tree-depth))
- (add-subtotal-line
- asset-table (_ "Liabilities & Equity") equity-plus-liability)
- (gnc:html-document-add-object! doc asset-table)
-
- ;; add currency information
+ right-table (_ "Total Liabilities & Equity")
+ #f liability-plus-equity)
+
+ (gnc:html-document-add-object!
+ doc
+ (if report-form?
+ left-table
+ (let* ((build-table (gnc:make-html-table))
+ )
+ (gnc:html-table-append-row!
+ build-table
+ (list
+ (gnc:make-html-table-cell left-table)
+ (gnc:make-html-table-cell right-table)
+ )
+ )
+ (gnc:html-table-set-style!
+ build-table "td"
+ 'attribute '("align" "left")
+ 'attribute '("valign" "top"))
+ build-table
+ )
+ )
+ )
+
+ ;; add currency information if requested
(gnc:report-percent-done 90)
(if show-rates?
(gnc:html-document-add-object!
- doc ;;(gnc:html-markup-p
+ doc ;;(gnc:html-markup-p)
(gnc:html-make-exchangerates
- report-currency exchange-fn accounts)))
- (gnc:report-percent-done 100))
-
-
- ;; error condition: no accounts specified
-
- (gnc:html-document-add-object!
- doc
- (gnc:html-make-no-account-warning
- (_ "Balance Sheet") (gnc:report-id report-obj))))
+ report-commodity exchange-fn accounts)))
+ (gnc:report-percent-done 100)
+
+ ;; if sending the report to a file, do so now
+ ;; however, this still doesn't seem to get around the
+ ;; colspan bug... cf. gnc:colspans-are-working-right
+ (if filename
+ (let* ((port (open-output-file filename))
+ (gnc:display-report-list-item
+ (list doc) port " balance-sheet.scm ")
+ (close-output-port port)
+ )
+ )
+ )
+ )
+ )
+
(gnc:report-finished)
- doc))
+
+ doc
+ )
+ )
(gnc:define-report
- 'version 1
+ 'version 2
'name reportname
'menu-path (list gnc:menuname-asset-liability)
'options-generator balance-sheet-options-generator
- 'renderer balance-sheet-renderer)
+ 'renderer (lambda (report-obj)
+ (balance-sheet-renderer report-obj #f #f))
+ 'export-types #f
+ 'export-thunk (lambda (report-obj choice filename)
+ (balance-sheet-renderer report-obj #f filename)))
+
+;; END
+
--- /dev/null
+++ src/report/standard-reports/equity-statement.scm
@@ -0,0 +1,650 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; equity-statement.scm: statement of owner's equity (net worth)
+;;
+;; By David Montenegro 2004.06.23 <sunrise2000 at comcast.net>
+;;
+;; * Based on balance-sheet.scm by Robert Merkel <rgmerk at mira.net>
+;;
+;; * BUGS:
+;;
+;; The multicurrency support has NOT been tested and IS ALPHA. I
+;; really don't if I used the correct exchange functions. Search
+;; code for regexp "*exchange-fn".
+;;
+;; I have also made the educated assumption <grin> that a decrease
+;; in the value of a liability or equity also represents an
+;; unrealized loss. I *think* that is right, but am not sure.
+;;
+;; This code makes the assumption that you want your equity
+;; statement to no more than daily resolution.
+;;
+;; The Accounts option panel needs a way to select (and select by
+;; default) capital and draw accounts.
+;;
+;; The variables in this code could use more consistent naming.
+;;
+;; See also any "FIXME"s in the code.
+;;
+;; 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
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-module (gnucash report equity-statement))
+(use-modules (gnucash main)) ;; FIXME: delete after we finish modularizing.
+(use-modules (ice-9 slib))
+(use-modules (gnucash gnc-module))
+
+(require 'printf)
+
+(gnc:module-load "gnucash/report/report-system" 0)
+
+(define reportname (N_ "Equity Statement"))
+
+;; define all option's names and help text so that they are properly
+;; defined in *one* place.
+(define optname-report-title (N_ "Report Title"))
+(define opthelp-report-title (N_ "Title for this report"))
+
+(define optname-party-name (N_ "Company name"))
+(define opthelp-party-name (N_ "Name of company/individual"))
+
+(define optname-start-date (N_ "Equity Statement Start Date"))
+(define opthelp-start-date
+ (N_ "Start of the period this equity statement will cover"))
+(define optname-end-date (N_ "Equity Statement End Date"))
+(define opthelp-end-date
+ (N_ "End of the period this equity statement will cover"))
+
+(define optname-accounts (N_ "Accounts to include"))
+(define opthelp-accounts
+ (N_ "Report only on these accounts"))
+
+(define optname-use-rules (N_ "Show accounting-style rules"))
+(define opthelp-use-rules
+ (N_ "Use rules beneath columns of added numbers like accountants do"))
+
+(define pagename-commodities (N_ "Commodities"))
+(define optname-report-commodity (N_ "Report's currency"))
+(define optname-price-source (N_ "Price Source"))
+(define optname-show-foreign (N_ "Show Foreign Currencies"))
+(define opthelp-show-foreign
+ (N_ "Display any foreign currency amount in an account"))
+(define optname-show-rates (N_ "Show Exchange Rates"))
+(define opthelp-show-rates (N_ "Show the exchange rates used"))
+
+;; This calculates the increase in the balance(s) of all accounts in
+;; <accountlist> over the period from <start-date> to <end-date>.
+;; Returns a commodity collector.
+;;
+;; Note: There is both a gnc:account-get-comm-balance-interval and
+;; gnc:group-get-comm-balance-interval which could replace this
+;; function....
+;;
+(define (accountlist-get-comm-balance-at-date accountlist start-date end-date)
+;; (for-each (lambda (x) (display x))
+;; (list "computing from: " (gnc:print-date start-date) " to "
+;; (gnc:print-date end-date) "\n"))
+ (let ((collector (gnc:make-commodity-collector)))
+ (for-each (lambda (account)
+ (let* (
+ (start-balance
+ (gnc:account-get-comm-balance-at-date
+ account start-date #f))
+ (sb (cadr (start-balance
+ 'getpair
+ (gnc:account-get-commodity account)
+ #f)))
+ (end-balance
+ (gnc:account-get-comm-balance-at-date
+ account end-date #f))
+ (eb (cadr (end-balance
+ 'getpair
+ (gnc:account-get-commodity account)
+ #f)))
+ )
+;; (for-each (lambda (x) (display x))
+;; (list "Start balance: " sb " : "
+;; (gnc:account-get-name account) " : end balance: "
+;; eb "\n"))
+ (collector 'merge end-balance #f)
+ (collector 'minusmerge start-balance #f)
+ ))
+ accountlist)
+ collector))
+
+;; options generator
+(define (equity-statement-options-generator)
+ (let* ((options (gnc:new-options))
+ (add-option
+ (lambda (new-option)
+ (gnc:register-option options new-option))))
+
+ (add-option
+ (gnc:make-string-option
+ (N_ "General") optname-report-title
+ "a" opthelp-report-title reportname))
+ (add-option
+ (gnc:make-string-option
+ (N_ "General") optname-party-name
+ "b" opthelp-party-name (N_ "")))
+ ;; this should default to company name in (gnc:get-current-book)
+ ;; does anyone know the function to get the company name??
+ ;; (GnuCash is *so* well documented... sigh)
+
+ ;; date at which to report balance
+ (gnc:options-add-date-interval!
+ options gnc:pagename-general
+ optname-start-date optname-end-date "c")
+
+ ;; accounts to work on
+ (add-option
+ (gnc:make-account-list-option
+ gnc:pagename-accounts optname-accounts
+ "a"
+ opthelp-accounts
+ (lambda ()
+ (gnc:filter-accountlist-type
+ '(bank cash credit asset liability stock mutual-fund currency
+ payable receivable equity income expense)
+ (gnc:group-get-subaccounts (gnc:get-current-group))))
+ #f #t))
+
+ ;; all about currencies
+ (gnc:options-add-currency!
+ options pagename-commodities
+ optname-report-commodity "a")
+
+ (gnc:options-add-price-source!
+ options pagename-commodities
+ optname-price-source "b" 'weighted-average)
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ pagename-commodities optname-show-foreign
+ "c" opthelp-show-foreign #t))
+
+ (add-option
+ (gnc:make-simple-boolean-option
+ pagename-commodities optname-show-rates
+ "d" opthelp-show-rates #f))
+
+ ;; some detailed formatting options
+ (add-option
+ (gnc:make-simple-boolean-option
+ gnc:pagename-display optname-use-rules
+ "f" opthelp-use-rules #f))
+
+ ;; Set the accounts page as default option tab
+ (gnc:options-set-default-section options gnc:pagename-accounts)
+
+ options))
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; equity-statement-renderer
+;; set up the document and add the table
+;; then then return the document or, if
+;; requested, export it to a file
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (equity-statement-renderer report-obj choice filename)
+ (define (get-option pagename optname)
+ (gnc:option-value
+ (gnc:lookup-option
+ (gnc:report-options report-obj) pagename optname)))
+ (define forever-ago (cons 0 0))
+
+ (gnc:report-starting reportname)
+
+ ;; get all option's values
+ (let* (
+ (report-title (get-option gnc:pagename-general optname-report-title))
+ (company-name (get-option gnc:pagename-general optname-party-name))
+ ;; this code makes the assumption that you want your equity
+ ;; statement to no more than daily resolution
+ (start-date-printable (gnc:date-option-absolute-time
+ (get-option gnc:pagename-general
+ optname-start-date)))
+ (start-date-tp (gnc:timepair-end-day-time
+ (gnc:timepair-previous-day start-date-printable)))
+ (end-date-tp (gnc:timepair-end-day-time
+ (gnc:date-option-absolute-time
+ (get-option gnc:pagename-general
+ optname-end-date))))
+ ;;(end-date-printable (gnc:date-option-absolute-time
+ ;; (get-option gnc:pagename-general
+ ;; optname-end-date)))
+ ;; why dont we use this? why use any -printable at all?
+ (accounts (get-option gnc:pagename-accounts
+ optname-accounts))
+ (report-commodity (get-option pagename-commodities
+ optname-report-commodity))
+ (price-source (get-option pagename-commodities
+ optname-price-source))
+ (show-fcur? (get-option pagename-commodities
+ optname-show-foreign))
+ (show-rates? (get-option pagename-commodities
+ optname-show-rates))
+ (use-rules? (get-option gnc:pagename-display
+ optname-use-rules))
+
+ ;; decompose the account list
+ (split-up-accounts (gnc:decompose-accountlist accounts))
+ (asset-accounts
+ (assoc-ref split-up-accounts 'asset))
+ (liability-accounts
+ (assoc-ref split-up-accounts 'liability))
+ (income-expense-accounts
+ (append (assoc-ref split-up-accounts 'income)
+ (assoc-ref split-up-accounts 'expense)))
+ (equity-accounts
+ (assoc-ref split-up-accounts 'equity))
+ ;; N.B.: equity-accounts will also contain drawing accounts
+ ;; these must still be split-out and itemized separately
+ (capital-accounts #f)
+ (drawing-accounts #f)
+
+ (doc (gnc:make-html-document))
+ ;; exchange rates calculation parameters
+ (start-exchange-fn
+ (gnc:case-exchange-fn
+ price-source report-commodity start-date-tp))
+ (end-exchange-fn
+ (gnc:case-exchange-fn
+ price-source report-commodity end-date-tp))
+ )
+
+ (gnc:html-document-set-title!
+ doc (sprintf #f
+ (string-append "%s %s "
+ (N_ "For Period")
+ " %s "
+ (N_ "to")
+ " %s")
+ report-title company-name
+ (gnc:print-date start-date-printable)
+ (gnc:print-date end-date-tp)))
+
+ (if (null? accounts)
+
+ ;; error condition: no accounts specified is this *really*
+ ;; necessary?? i'd be fine with an all-zero income statement
+ ;; that would, technically, be correct....
+ (gnc:html-document-add-object!
+ doc
+ (gnc:html-make-no-account-warning
+ reportname (gnc:report-id report-obj)))
+
+ ;; Get all the balances for each account group.
+ (let* ((book-balance #f) ;; assets - liabilities - equity, norm 0
+ (start-asset-balance #f)
+ (end-asset-balance #f)
+ (neg-start-liability-balance #f) ;; credit balances are < 0
+ (neg-end-liability-balance #f)
+ (neg-pre-start-retained-earnings #f)
+ (neg-pre-end-retained-earnings #f)
+ (neg-net-income #f)
+ (net-income #f)
+
+ (neg-start-equity-balance #f)
+ (neg-end-equity-balance #f)
+
+ (start-capital-balance #f)
+ (end-capital-balance #f)
+ (start-drawing-balance #f)
+ (end-drawing-balance #f)
+
+ (start-book-balance #f)
+ (end-book-balance #f)
+
+ (start-unrealized-gains #f)
+ (end-unrealized-gains #f)
+ (net-unrealized-gains #f)
+
+ (start-total-equity #f)
+ (end-total-equity #f)
+
+ (investments #f)
+ (draws #f)
+
+ (capital-increase #f)
+
+ ;; Create the account table below where its
+ ;; percentage time can be tracked.
+ (build-table (gnc:make-html-table)) ;; gnc:html-table
+ (get-start-balance-fn
+ (lambda (account)
+ (gnc:account-get-comm-balance-at-date
+ account start-date-tp #f)))
+ (get-end-balance-fn
+ (lambda (account)
+ (gnc:account-get-comm-balance-at-date
+ account end-date-tp #f)))
+ (terse-period? #t)
+ (period-for (if terse-period?
+ (string-append " " (N_ "for Period"))
+ (string-append
+ ", "
+ (gnc:print-date start-date-printable) " "
+ (N_ "to") " "
+ (gnc:print-date end-date-tp)
+ )))
+ )
+
+ ;; a helper to add a line to our report
+ (define (report-line
+ table pos-label neg-label amount col
+ exchange-fn rule? row-style)
+ (let* ((neg? (and amount
+ (gnc:numeric-negative-p
+ (gnc:gnc-monetary-amount
+ (gnc:sum-collector-commodity
+ amount report-commodity exchange-fn)))))
+ (label (if neg? (or neg-label pos-label) pos-label))
+ (pos-bal (if neg?
+ (let ((bal (gnc:make-commodity-collector)))
+ (bal 'minusmerge amount #f)
+ bal)
+ amount))
+ (bal (gnc:sum-collector-commodity
+ pos-bal report-commodity exchange-fn))
+ (balance
+ (or (and (gnc:uniform-commodity? bal report-commodity) bal)
+ (and show-fucr?
+ (gnc:commodity-table
+ bal report-commodity exchange-fn))
+ bal
+ ))
+ (column (or col 0))
+ )
+ (gnc:html-table-add-labeled-amount-line!
+ table 3 row-style rule?
+ label 0 1 "text-cell"
+ bal (+ col 1) 1 "number-cell")
+ )
+ )
+
+ ;; sum any unrealized gains
+ ;;
+ ;; Hm... unrealized gains.... This is when you purchase
+ ;; something and its value increases/decreases (prior to
+ ;; your selling it) and you have to reflect that on your
+ ;; balance sheet.
+ ;;
+ ;; I *think* a decrease in the value of a liability or
+ ;; equity constitutes an unrealized loss. I'm unsure about
+ ;; that though....
+ ;;
+ (define (unrealized-gains-at-date book-balance exchange-fn date-tp)
+ (let* ((unrealized-gain-collector (gnc:make-commodity-collector))
+ (weighted-fn
+ (gnc:case-exchange-fn 'weighted-average
+ report-commodity date-tp))
+
+ (value
+ (gnc:gnc-monetary-amount
+ (gnc:sum-collector-commodity book-balance
+ report-commodity
+ exchange-fn)))
+
+ (cost
+ (gnc:gnc-monetary-amount
+ (gnc:sum-collector-commodity book-balance
+ report-commodity
+ weighted-fn)))
+
+ (unrealized-gain (gnc:numeric-sub-fixed value cost)))
+
+ (unrealized-gain-collector 'add report-commodity unrealized-gain)
+ unrealized-gain-collector
+ )
+ )
+
+ ;; If you ask me, any outstanding(TM) retained earnings and
+ ;; unrealized gains should be added directly into equity,
+ ;; both at the start and end dates of the reporting period.
+ (gnc:report-percent-done 4)
+
+ ;; start and end asset balances
+ (set! start-asset-balance
+ (gnc:accounts-get-comm-total-assets
+ asset-accounts get-start-balance-fn)) ; OK
+ (set! end-asset-balance
+ (gnc:accounts-get-comm-total-assets
+ asset-accounts get-end-balance-fn)) ; OK
+
+ ;; start and end liability balances
+ (set! neg-start-liability-balance
+ (gnc:accounts-get-comm-total-assets
+ liability-accounts get-start-balance-fn)) ; OK
+ (set! neg-end-liability-balance
+ (gnc:accounts-get-comm-total-assets
+ liability-accounts get-end-balance-fn)) ; OK
+
+ ;; start and end retained earnings (income - expenses)
+ (set! neg-pre-start-retained-earnings
+ (accountlist-get-comm-balance-at-date
+ income-expense-accounts
+ forever-ago start-date-tp)) ; OK
+ (set! neg-pre-end-retained-earnings
+ (accountlist-get-comm-balance-at-date
+ income-expense-accounts
+ forever-ago end-date-tp)) ; OK
+ (set! neg-net-income
+ (accountlist-get-comm-balance-at-date
+ income-expense-accounts
+ start-date-tp end-date-tp)) ; OK
+ (set! net-income (gnc:make-commodity-collector))
+ (net-income 'minusmerge neg-net-income #f)
+
+ ;; start and end (unadjusted) equity balances
+ (set! neg-start-equity-balance
+ (gnc:accounts-get-comm-total-assets
+ equity-accounts get-start-balance-fn)) ; OK
+ (set! neg-end-equity-balance
+ (gnc:accounts-get-comm-total-assets
+ equity-accounts get-end-balance-fn)) ; OK
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;
+ ;; beleive it or not, i think this part is right...
+ ;;
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ ;; start and end unrealized gains
+ (set! start-book-balance (gnc:make-commodity-collector))
+ (start-book-balance 'merge start-asset-balance #f)
+ (start-book-balance 'merge neg-start-liability-balance #f)
+ (start-book-balance 'merge neg-start-equity-balance #f)
+ (start-book-balance 'merge neg-pre-start-retained-earnings #f) ; OK
+
+ (set! end-book-balance (gnc:make-commodity-collector))
+ (end-book-balance 'merge end-asset-balance #f)
+ (end-book-balance 'merge neg-end-liability-balance #f)
+ (end-book-balance 'merge neg-end-equity-balance #f)
+ (end-book-balance 'merge neg-pre-end-retained-earnings #f) ; OK
+
+ (set! start-unrealized-gains
+ (unrealized-gains-at-date start-book-balance
+ start-exchange-fn
+ start-date-tp)) ; OK
+ (set! end-unrealized-gains
+ (unrealized-gains-at-date end-book-balance
+ end-exchange-fn
+ end-date-tp)) ; OK
+
+ ;; unrealized gains accrued during the reporting period...
+ (set! net-unrealized-gains (gnc:make-commodity-collector))
+ (net-unrealized-gains 'merge end-unrealized-gains #f)
+ (net-unrealized-gains 'minusmerge start-unrealized-gains #f) ; OK
+
+ ;; starting and ending total equity...
+ (set! start-total-equity (gnc:make-commodity-collector))
+ (start-total-equity 'minusmerge neg-start-equity-balance #f)
+ (start-total-equity 'minusmerge neg-pre-start-retained-earnings #f)
+ (start-total-equity 'merge start-unrealized-gains #f) ; OK
+
+ (set! end-total-equity (gnc:make-commodity-collector))
+ (end-total-equity 'minusmerge neg-end-equity-balance #f)
+ (end-total-equity 'minusmerge neg-pre-end-retained-earnings #f)
+ (end-total-equity 'merge end-unrealized-gains #f) ; OK
+
+ ;;
+ ;; calculate investments & draws...
+ ;;
+ ;; since, as this time, GnuCash does not have any
+ ;; contra-account types, i'm gonna have to fudge this a
+ ;; bit... i'll do a transaction query and classify the
+ ;; splits by debit/credit.
+ ;;
+
+ ;; FIXME: um... no. that sounds like too much work.
+ ;; ok, for now, just assume draws are zero and investments signed
+ (set! draws (gnc:make-commodity-collector)) ;; 0
+ (set! investments (gnc:make-commodity-collector)) ;; 0
+ (investments 'minusmerge neg-end-equity-balance #f) ;; > 0
+ (investments 'merge neg-start-equity-balance #f) ;; net increase
+
+ ;; increase in equity
+ (set! capital-increase (gnc:make-commodity-collector))
+ (capital-increase 'merge net-income #f)
+ (capital-increase 'merge investments #f)
+ (capital-increase 'minusmerge draws #f)
+ (capital-increase 'merge net-unrealized-gains #f)
+
+ (gnc:report-percent-done 30)
+
+ ;; Workaround to force gtkhtml into displaying wide
+ ;; enough columns.
+ (gnc:html-table-append-row!
+ build-table
+ (make-list 2 " \
+ \
+ ")
+ )
+
+ (gnc:report-percent-done 80)
+
+ (report-line
+ build-table
+ (string-append (N_ "Capital") ", "
+ (gnc:print-date start-date-printable))
+ #f start-total-equity
+ 1 start-exchange-fn #f "primary-subheading"
+ )
+ (report-line
+ build-table
+ (string-append (N_ "Net income") period-for)
+ (string-append (N_ "Net loss") period-for)
+ net-income
+ 0 end-exchange-fn #f #f
+ )
+ (report-line
+ build-table
+ (string-append (N_ "Investments less withdrawals") period-for)
+ #f
+ investments
+ 0 end-exchange-fn #f #f
+ )
+ (report-line
+ build-table
+ (string-append (N_ "Unrealized gains") period-for)
+ (string-append (N_ "Unrealized losses") period-for)
+ net-unrealized-gains
+ 0 end-exchange-fn #f #f
+ )
+ (report-line
+ build-table
+ (N_ "Increase in capital")
+ (N_ "Decrease in capital")
+ capital-increase
+ 1 end-exchange-fn use-rules? #f
+ )
+ (report-line
+ build-table
+ (string-append (N_ "Captial") ", "
+ (gnc:print-date end-date-tp))
+ #f
+ end-total-equity
+ 1 end-exchange-fn #f "primary-subheading"
+ )
+
+ (gnc:html-document-add-object! doc build-table)
+
+ ;; add currency information if requested
+ (gnc:report-percent-done 90)
+ (and show-rates?
+ (let* ((curr-tbl (gnc:make-html-table))
+ (headers (list
+ (gnc:print-date start-date-printable)
+ (gnc:print-date end-date-tp)
+ )
+ )
+ (then (gnc:html-make-exchangerates
+ report-commodity start-exchange-fn accounts))
+ (now (gnc:html-make-exchangerates
+ report-commodity end-exchange-fn accounts))
+ )
+
+ (gnc:html-table-set-col-headers! curr-tbl headers)
+ (gnc:html-table-set-style!
+ curr-tbl "table" 'attribute '("border" "1"))
+ (gnc:html-table-set-style!
+ then "table" 'attribute '("border" "0"))
+ (gnc:html-table-set-style!
+ now "table" 'attribute '("border" "0"))
+ (gnc:html-table-append-ruler! build-table 3)
+ (gnc:html-table-append-row! curr-tbl (list then now))
+ (gnc:html-document-add-object! doc curr-tbl)
+ )
+ )
+
+ (gnc:report-percent-done 100)
+
+ ;; if sending the report to a file, do so now
+ ;; however, this still doesn't seem to get around the
+ ;; colspan bug... cf. gnc:colspans-are-working-right
+ (if filename
+ (let* ((port (open-output-file filename))
+ (gnc:display-report-list-item
+ (list doc) port " equity-statement.scm ")
+ (close-output-port port)
+ )
+ )
+ )
+ )
+ )
+
+ (gnc:report-finished)
+
+ doc
+ )
+ )
+
+(gnc:define-report
+ 'version 1
+ 'name reportname
+ 'menu-path (list gnc:menuname-income-expense)
+ 'options-generator equity-statement-options-generator
+ 'renderer (lambda (report-obj)
+ (equity-statement-renderer report-obj #f #f))
+ 'export-types #f
+ 'export-thunk (lambda (report-obj choice filename)
+ (equity-statement-renderer report-obj #f filename)))
+
+;; END
+
Index: test-stuff.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/test-core/test-stuff.c,v
retrieving revision 1.7
retrieving revision 1.7.6.1
diff -Lsrc/test-core/test-stuff.c -Lsrc/test-core/test-stuff.c -u -r1.7 -r1.7.6.1
--- src/test-core/test-stuff.c
+++ src/test-core/test-stuff.c
@@ -139,7 +139,7 @@
failure_args( test_title, filename, line, "" );
}
- return result;
+ return result;
}
gboolean
@@ -161,7 +161,7 @@
}
va_end(ap);
- return result;
+ return result;
}
void
More information about the gnucash-changes
mailing list