From 48f024a42aa02f36220cf5e06ed005c65cc3fa76 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:12:57 -0500 Subject: [PATCH 01/39] Increased size of buffer used to split account names --- src/account.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/account.cc b/src/account.cc index 52a6b436..31d86bd2 100644 --- a/src/account.cc +++ b/src/account.cc @@ -55,7 +55,7 @@ account_t * account_t::find_account(const string& name, if (i != accounts.end()) return (*i).second; - char buf[256]; + char buf[8192]; string::size_type sep = name.find(':'); assert(sep < 256|| sep == string::npos); From 6b6ca6d4c70df0e4a3009ee093cf2f83ecee2675 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:14:05 -0500 Subject: [PATCH 02/39] Improved the way account temporaries are managed --- src/account.cc | 7 +++---- src/filters.cc | 54 +++++++++++++++++++++++++++++++++++++++----------- src/temps.cc | 8 ++++++++ src/temps.h | 2 +- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/account.cc b/src/account.cc index 31d86bd2..b14520d3 100644 --- a/src/account.cc +++ b/src/account.cc @@ -42,10 +42,9 @@ account_t::~account_t() { TRACE_DTOR(account_t); - foreach (accounts_map::value_type& pair, accounts) { - assert(! pair.second->has_flags(ACCOUNT_TEMP)); - checked_delete(pair.second); - } + foreach (accounts_map::value_type& pair, accounts) + if (! pair.second->has_flags(ACCOUNT_TEMP)) + checked_delete(pair.second); } account_t * account_t::find_account(const string& name, diff --git a/src/filters.cc b/src/filters.cc index da9e39ae..76326ac1 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -133,6 +133,40 @@ void sort_posts::post_accumulated_posts() posts.clear(); } +namespace { + void split_string(const string& str, const char ch, + std::list& strings) + { + const char * b = str.c_str(); + for (const char * p = b; *p; p++) { + if (*p == ch) { + strings.push_back(string(b, p - b)); + b = p + 1; + } + } + strings.push_back(string(b)); + } + + account_t * create_temp_account_from_path(std::list& account_names, + temporaries_t& temps, + account_t * master) + { + account_t * new_account = NULL; + foreach (const string& name, account_names) { + if (new_account) { + new_account = new_account->find_account(name); + } else { + new_account = master->find_account(name, false); + if (! new_account) + new_account = &temps.create_account(name, master); + } + } + + assert(new_account != NULL); + return new_account; + } +} + void anonymize_posts::operator()(post_t& post) { SHA1 sha; @@ -158,27 +192,19 @@ void anonymize_posts::operator()(post_t& post) } std::list account_names; - account_t * new_account = NULL; for (account_t * acct = post.account; acct; acct = acct->parent) { - if (! acct->parent) { - new_account = acct; - break; - } - sha.Reset(); sha << acct->name.c_str(); sha.Result(message_digest); account_names.push_front(to_hex(message_digest)); } - assert(new_account); - - foreach (const string& name, account_names) - new_account = new_account->find_account(name); + account_t * new_account = + create_temp_account_from_path(account_names, temps, xact.journal->master); post_t& temp = temps.copy_post(post, xact, new_account); temp.note = none; @@ -685,11 +711,15 @@ void transfer_details::operator()(post_t& post) case SET_PAYEE: xact.payee = expr.calc(bound_scope).to_string(); break; - case SET_ACCOUNT: + case SET_ACCOUNT: { + std::list account_names; temp.account->remove_post(&temp); - temp.account = master->find_account(expr.calc(bound_scope).to_string()); + split_string(expr.calc(bound_scope).to_string(), ':', account_names); + temp.account = create_temp_account_from_path(account_names, temps, + xact.journal->master); temp.account->add_post(&temp); break; + } default: assert(false); break; diff --git a/src/temps.cc b/src/temps.cc index f2dee159..e44aaaa7 100644 --- a/src/temps.cc +++ b/src/temps.cc @@ -48,6 +48,11 @@ temporaries_t::~temporaries_t() if (! post.account->has_flags(ACCOUNT_TEMP)) post.account->remove_post(&post); } + + foreach (account_t& acct, *acct_temps) { + if (! acct.has_flags(ACCOUNT_TEMP)) + acct.remove_account(&acct); + } } } @@ -120,6 +125,9 @@ account_t& temporaries_t::create_account(const string& name, acct_temps->push_back(account_t(parent, name)); account_t& temp(acct_temps->back()); + if (parent) + parent->add_account(&temp); + temp.add_flags(ACCOUNT_TEMP); return temp; } diff --git a/src/temps.h b/src/temps.h index 646f4dcd..34494ba8 100644 --- a/src/temps.h +++ b/src/temps.h @@ -68,7 +68,7 @@ public: post_t& last_post() { return post_temps->back(); } - account_t& create_account(const string& name, + account_t& create_account(const string& name = "", account_t * parent = NULL); account_t& last_account() { return acct_temps->back(); From caff01ba75d5929eeb502bfc2e73d28fceec60c1 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:14:18 -0500 Subject: [PATCH 03/39] Whitespace fixes --- src/filters.h | 3 +-- src/xact.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/filters.h b/src/filters.h index 7c1f169c..0dcf5e41 100644 --- a/src/filters.h +++ b/src/filters.h @@ -288,8 +288,7 @@ public: class anonymize_posts : public item_handler { temporaries_t temps; - - xact_t * last_xact; + xact_t * last_xact; anonymize_posts(); diff --git a/src/xact.h b/src/xact.h index 59ddd1bc..7de30ee8 100644 --- a/src/xact.h +++ b/src/xact.h @@ -65,7 +65,6 @@ class xact_base_t : public item_t { public: journal_t * journal; - posts_list posts; xact_base_t() : item_t(), journal(NULL) { From 52d1441646969797d4a0582c6344da46f56904e1 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:14:34 -0500 Subject: [PATCH 04/39] Fixed copy constructors for transactions --- src/xact.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xact.cc b/src/xact.cc index 3670cb94..3291c5be 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -39,8 +39,8 @@ namespace ledger { -xact_base_t::xact_base_t(const xact_base_t&) - : item_t(), journal(NULL) +xact_base_t::xact_base_t(const xact_base_t& xact_base) + : item_t(xact_base), journal(xact_base.journal) { TRACE_CTOR(xact_base_t, "copy"); } From 449c7ca790f62b30594e845e0c1bab07c44850af Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:15:11 -0500 Subject: [PATCH 05/39] New: --set-reported-account, --set-reported-payee --- src/chain.cc | 11 +++++++++++ src/report.cc | 2 ++ src/report.h | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/src/chain.cc b/src/chain.cc index db52269c..defa2e97 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -159,6 +159,17 @@ post_handler_ptr chain_post_handlers(report_t& report, handler.reset(new sort_posts(handler, "date")); } + if (report.HANDLED(set_reported_account_)) + handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, + report.session.journal->master, + report.HANDLER(set_reported_account_).str(), + report)); + else if (report.HANDLED(set_reported_payee_)) + handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE, + report.session.journal->master, + report.HANDLER(set_reported_payee_).str(), + report)); + // related_posts will pass along all posts related to the post received. If // the `related_all' handler is on, then all the xact's posts are passed; // meaning that if one post of an xact is to be printed, all the post for diff --git a/src/report.cc b/src/report.cc index 9f15a2d5..60f6955c 100644 --- a/src/report.cc +++ b/src/report.cc @@ -664,6 +664,8 @@ option_t * report_t::lookup_option(const char * p) case 's': OPT(set_account_); else OPT(set_payee_); + else OPT(set_reported_account_); + else OPT(set_reported_payee_); else OPT(sort_); else OPT(sort_all_); else OPT(sort_xacts_); diff --git a/src/report.h b/src/report.h index 0fe7d05b..e321cb44 100644 --- a/src/report.h +++ b/src/report.h @@ -284,6 +284,8 @@ public: HANDLER(seed_).report(out); HANDLER(set_account_).report(out); HANDLER(set_payee_).report(out); + HANDLER(set_reported_account_).report(out); + HANDLER(set_reported_payee_).report(out); HANDLER(sort_).report(out); HANDLER(sort_all_).report(out); HANDLER(sort_xacts_).report(out); @@ -805,6 +807,8 @@ public: OPTION(report_t, seed_); OPTION(report_t, set_account_); OPTION(report_t, set_payee_); + OPTION(report_t, set_reported_account_); + OPTION(report_t, set_reported_payee_); OPTION_(report_t, sort_, DO_(args) { // -S on_with(args[0].as_string(), args[1]); From 2ae2c47a38fb9ba93da4c58245b662ed4a7951b2 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:15:31 -0500 Subject: [PATCH 06/39] When copying an item, copy its metadata --- src/item.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/item.h b/src/item.h index 28eb3f80..c9c4af26 100644 --- a/src/item.h +++ b/src/item.h @@ -143,6 +143,7 @@ public: _date_eff = item._date_eff; note = item.note; pos = item.pos; + metadata = item.metadata; } virtual bool operator==(const item_t& xact) { From 6a78c24463c9b582a819c2dced770b8303cd58bf Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:15:46 -0500 Subject: [PATCH 07/39] Stream out item metadata last in item_t::serialize --- src/archive.cc | 2 +- src/item.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archive.cc b/src/archive.cc index b3aff7d7..d54b1179 100644 --- a/src/archive.cc +++ b/src/archive.cc @@ -43,7 +43,7 @@ #include "xact.h" #define LEDGER_MAGIC 0x4c454447 -#define ARCHIVE_VERSION 0x03000002 +#define ARCHIVE_VERSION 0x03000003 //BOOST_IS_ABSTRACT(ledger::scope_t) BOOST_CLASS_EXPORT(ledger::scope_t) diff --git a/src/item.h b/src/item.h index c9c4af26..b65d482a 100644 --- a/src/item.h +++ b/src/item.h @@ -207,8 +207,8 @@ private: ar & _date; ar & _date_eff; ar & note; - ar & metadata; ar & pos; + ar & metadata; } #endif // HAVE_BOOST_SERIALIZATION }; From 0849bf24b1be711c8e981038758b64d74edd462a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:16:01 -0500 Subject: [PATCH 08/39] Fixed a typo in the processing of "note" query term --- src/predicate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/predicate.cc b/src/predicate.cc index b3926116..c3c3cba7 100644 --- a/src/predicate.cc +++ b/src/predicate.cc @@ -156,7 +156,7 @@ query_lexer_t::token_t query_lexer_t::next_token() else if (ident == "code") return token_t(token_t::TOK_CODE); else if (ident == "note") - return token_t(token_t::TOK_NOT); + return token_t(token_t::TOK_NOTE); else if (ident == "tag") return token_t(token_t::TOK_META); else if (ident == "meta") From 1482298e4182ecb06b2d45559a81e579b7919ba5 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:16:31 -0500 Subject: [PATCH 09/39] Implemented "meta" query report operator --- src/predicate.cc | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/predicate.cc b/src/predicate.cc index c3c3cba7..d5b41362 100644 --- a/src/predicate.cc +++ b/src/predicate.cc @@ -242,7 +242,39 @@ query_parser_t::parse_query_term(query_lexer_t::token_t::kind_t tok_context) case query_lexer_t::token_t::TERM: assert(tok.value); if (tok_context == query_lexer_t::token_t::TOK_META) { - assert(0); + node = new expr_t::op_t(expr_t::op_t::O_CALL); + + expr_t::ptr_op_t ident; + ident = new expr_t::op_t(expr_t::op_t::IDENT); + ident->set_ident("has_tag"); + node->set_left(ident); + + expr_t::ptr_op_t arg1; + arg1 = new expr_t::op_t(expr_t::op_t::VALUE); + arg1->set_value(mask_t(*tok.value)); + + tok = lexer.peek_token(); + if (tok.kind == query_lexer_t::token_t::TOK_EQ) { + tok = lexer.next_token(); + tok = lexer.next_token(); + if (tok.kind != query_lexer_t::token_t::TERM) + throw_(parse_error, + _("Metadata equality operator not followed by term")); + + expr_t::ptr_op_t cons; + cons = new expr_t::op_t(expr_t::op_t::O_CONS); + + expr_t::ptr_op_t arg2; + arg2 = new expr_t::op_t(expr_t::op_t::VALUE); + assert(tok.value); + arg2->set_value(mask_t(*tok.value)); + + cons->set_left(arg1); + cons->set_right(arg2); + node->set_right(cons); + } else { + node->set_right(arg1); + } } else { node = new expr_t::op_t(expr_t::op_t::O_MATCH); From a0a91a61c44cc08353568c25f0e0887248bfb947 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:16:47 -0500 Subject: [PATCH 10/39] If an item doesn't have a given tag, return "" --- src/item.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/item.cc b/src/item.cc index debda7a3..37e19a82 100644 --- a/src/item.cc +++ b/src/item.cc @@ -237,7 +237,7 @@ namespace { in_context_t env(scope, "s"); if (optional value = env->get_tag(env.get(0))) return string_value(*value); - return false; + return string_value(empty_string); } value_t get_pathname(item_t& item) { From 39973b1277ee1655cfb82b187a9d0d523e1d5f6f Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:17:23 -0500 Subject: [PATCH 11/39] A posting's note includes its parent xact's note --- src/post.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/post.cc b/src/post.cc index 7b5e5325..0d6ab8a0 100644 --- a/src/post.cc +++ b/src/post.cc @@ -141,6 +141,12 @@ namespace { return string_value(post.xact->payee); } + value_t get_note(post_t& post) { + string note = post.note ? *post.note : empty_string; + note += post.xact->note ? *post.xact->note : empty_string; + return string_value(note); + } + value_t get_magnitude(post_t& post) { return post.xact->magnitude(); } @@ -318,6 +324,11 @@ expr_t::ptr_op_t post_t::lookup(const string& name) return WRAP_FUNCTOR(get_wrapper<&get_magnitude>); break; + case 'n': + if (name == "note") + return WRAP_FUNCTOR(get_wrapper<&get_note>); + break; + case 'p': if (name == "post") return WRAP_FUNCTOR(get_wrapper<&get_this>); From 6538a2d1b8630d2a8224e517bf35ce51ab561d3a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:17:53 -0500 Subject: [PATCH 12/39] Extended xact example used by some pre-commands --- src/precmd.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/precmd.cc b/src/precmd.cc index 590d2553..a08fd2d6 100644 --- a/src/precmd.cc +++ b/src/precmd.cc @@ -42,7 +42,7 @@ namespace ledger { namespace { - post_t * get_sample_post(report_t& report) + post_t * get_sample_xact(report_t& report) { { string str; @@ -50,7 +50,11 @@ namespace { std::ostringstream buf; buf << "2004/05/27 Book Store\n" + << " ; This note applies to all postings. :SecondTag:\n" << " Expenses:Books 20 BOOK @ $10\n" + << " ; Metadata: Some Value\n" + << " ; :ExampleTag:\n" + << " ; Here follows a note describing the posting.\n" << " Liabilities:MasterCard $-200.00\n"; str = buf.str(); @@ -82,7 +86,7 @@ value_t parse_command(call_scope_t& args) report_t& report(find_scope(args)); std::ostream& out(report.output_stream); - post_t * post = get_sample_post(report); + post_t * post = get_sample_xact(report); out << _("--- Input expression ---") << std::endl; out << arg << std::endl; @@ -131,7 +135,7 @@ value_t format_command(call_scope_t& args) report_t& report(find_scope(args)); std::ostream& out(report.output_stream); - post_t * post = get_sample_post(report); + post_t * post = get_sample_xact(report); out << _("--- Input format string ---") << std::endl; out << arg << std::endl << std::endl; From 46a419a5dabcc6b02231f12357b20f70a14cfe63 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 1 Nov 2009 21:18:09 -0500 Subject: [PATCH 13/39] Added DocTests to verify documentation examples --- test/doc/transaction-codes-1.test | 22 ++++++++++++++++++++++ test/doc/transaction-codes-2.test | 24 ++++++++++++++++++++++++ test/doc/transaction-notes-1.test | 24 ++++++++++++++++++++++++ test/doc/transaction-notes-2.test | 23 +++++++++++++++++++++++ test/doc/transaction-notes-3.test | 23 +++++++++++++++++++++++ test/doc/transaction-notes-4.test | 27 +++++++++++++++++++++++++++ test/doc/transaction-status-1.test | 19 +++++++++++++++++++ test/doc/transaction-status-2.test | 17 +++++++++++++++++ test/doc/transaction-status-3.test | 18 ++++++++++++++++++ test/doc/transaction-status-4.test | 17 +++++++++++++++++ tools/Makefile.am | 12 +++++++++++- 11 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 test/doc/transaction-codes-1.test create mode 100644 test/doc/transaction-codes-2.test create mode 100644 test/doc/transaction-notes-1.test create mode 100644 test/doc/transaction-notes-2.test create mode 100644 test/doc/transaction-notes-3.test create mode 100644 test/doc/transaction-notes-4.test create mode 100644 test/doc/transaction-status-1.test create mode 100644 test/doc/transaction-status-2.test create mode 100644 test/doc/transaction-status-3.test create mode 100644 test/doc/transaction-status-4.test diff --git a/test/doc/transaction-codes-1.test b/test/doc/transaction-codes-1.test new file mode 100644 index 00000000..878c5cac --- /dev/null +++ b/test/doc/transaction-codes-1.test @@ -0,0 +1,22 @@ +reg --columns=60 food and code xfer +<<< +2009/10/29 (XFER) Panera Bread + Expenses:Food $4.50 + Assets:Checking + +2009/10/30 (DEP) Pay day! + Assets:Checking $20.00 + Income + +2009/10/30 (XFER) Panera Bread + Expenses:Food $4.50 + Assets:Checking + +2009/10/31 (559385768438A8D7) Panera Bread + Expenses:Food $4.50 + Liabilities:Credit Card +>>>1 +09-Oct-29 Panera Bread Expenses:Food $4.50 $4.50 +09-Oct-30 Panera Bread Expenses:Food $4.50 $9.00 +>>>2 +=== 0 diff --git a/test/doc/transaction-codes-2.test b/test/doc/transaction-codes-2.test new file mode 100644 index 00000000..4e4c76cf --- /dev/null +++ b/test/doc/transaction-codes-2.test @@ -0,0 +1,24 @@ +bal checking --set-reported-account=code +<<< +2009/10/29 (XFER) Panera Bread + Expenses:Food $4.50 + Assets:Checking + +2009/10/30 (DEP) Pay day! + Assets:Checking $20.00 + Income + +2009/10/30 (XFER) Panera Bread + Expenses:Food $4.50 + Assets:Checking + +2009/10/31 (559385768438A8D7) Panera Bread + Expenses:Food $4.50 + Liabilities:Credit Card +>>>1 + $20.00 DEP + $-9.00 XFER +-------------------- + $11.00 +>>>2 +=== 0 diff --git a/test/doc/transaction-notes-1.test b/test/doc/transaction-notes-1.test new file mode 100644 index 00000000..d3fab3b6 --- /dev/null +++ b/test/doc/transaction-notes-1.test @@ -0,0 +1,24 @@ +reg --columns=60 food and note eat +<<< +2009/11/01 Panera Bread ; Got something to eat + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Coffee + ; Let’s see, I ate a whole bunch of stuff, drank some coffee, + ; pondered a bagel, then decided against the donut. + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Dining + ; :Eating: + ; This is another long note, after the metadata. + Expenses:Food $4.50 + Assets:Checking +>>>1 +09-Nov-01 Panera Bread Expenses:Food $4.50 $4.50 +09-Nov-01 Panera Bread Expenses:Food $4.50 $9.00 +>>>2 +=== 0 diff --git a/test/doc/transaction-notes-2.test b/test/doc/transaction-notes-2.test new file mode 100644 index 00000000..b7a258e0 --- /dev/null +++ b/test/doc/transaction-notes-2.test @@ -0,0 +1,23 @@ +reg --columns=60 food and tag eating +<<< +2009/11/01 Panera Bread ; Got something to eat + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Coffee + ; Let’s see, I ate a whole bunch of stuff, drank some coffee, + ; pondered a bagel, then decided against the donut. + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Dining + ; :Eating: + ; This is another long note, after the metadata. + Expenses:Food $4.50 + Assets:Checking +>>>1 +09-Nov-01 Panera Bread Expenses:Food $4.50 $4.50 +>>>2 +=== 0 diff --git a/test/doc/transaction-notes-3.test b/test/doc/transaction-notes-3.test new file mode 100644 index 00000000..9d532d5f --- /dev/null +++ b/test/doc/transaction-notes-3.test @@ -0,0 +1,23 @@ +reg --columns=60 food and tag type=dining +<<< +2009/11/01 Panera Bread ; Got something to eat + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Coffee + ; Let’s see, I ate a whole bunch of stuff, drank some coffee, + ; pondered a bagel, then decided against the donut. + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Dining + ; :Eating: + ; This is another long note, after the metadata. + Expenses:Food $4.50 + Assets:Checking +>>>1 +09-Nov-01 Panera Bread Expenses:Food $4.50 $4.50 +>>>2 +=== 0 diff --git a/test/doc/transaction-notes-4.test b/test/doc/transaction-notes-4.test new file mode 100644 index 00000000..516094c7 --- /dev/null +++ b/test/doc/transaction-notes-4.test @@ -0,0 +1,27 @@ +bal food and tag type --set-reported-account='"Tags:" + tag("Type")' +<<< +2009/11/01 Panera Bread ; Got something to eat + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Coffee + ; Let’s see, I ate a whole bunch of stuff, drank some coffee, + ; pondered a bagel, then decided against the donut. + Expenses:Food $4.50 + Assets:Checking + +2009/11/01 Panera Bread + ; Type: Dining + ; :Eating: + ; This is another long note, after the metadata. + Expenses:Food $4.50 + Assets:Checking +>>>1 + $9.00 Tags + $4.50 Coffee + $4.50 Dining +-------------------- + $9.00 +>>>2 +=== 0 diff --git a/test/doc/transaction-status-1.test b/test/doc/transaction-status-1.test new file mode 100644 index 00000000..4bdf893a --- /dev/null +++ b/test/doc/transaction-status-1.test @@ -0,0 +1,19 @@ +reg --columns=60 food +<<< +2009/10/31 * Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/01 ! Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/02 Panera Bread + Expenses:Food $4.50 + Assets +>>>1 +09-Oct-31 Panera Bread Expenses:Food $4.50 $4.50 +09-Nov-01 Panera Bread Expenses:Food $4.50 $9.00 +09-Nov-02 Panera Bread Expenses:Food $4.50 $13.50 +>>>2 +=== 0 diff --git a/test/doc/transaction-status-2.test b/test/doc/transaction-status-2.test new file mode 100644 index 00000000..dbbb04ae --- /dev/null +++ b/test/doc/transaction-status-2.test @@ -0,0 +1,17 @@ +reg --columns=60 food --cleared +<<< +2009/10/31 * Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/01 ! Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/02 Panera Bread + Expenses:Food $4.50 + Assets +>>>1 +09-Oct-31 Panera Bread Expenses:Food $4.50 $4.50 +>>>2 +=== 0 diff --git a/test/doc/transaction-status-3.test b/test/doc/transaction-status-3.test new file mode 100644 index 00000000..1e6467ef --- /dev/null +++ b/test/doc/transaction-status-3.test @@ -0,0 +1,18 @@ +reg --columns=60 food --uncleared +<<< +2009/10/31 * Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/01 ! Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/02 Panera Bread + Expenses:Food $4.50 + Assets +>>>1 +09-Nov-01 Panera Bread Expenses:Food $4.50 $4.50 +09-Nov-02 Panera Bread Expenses:Food $4.50 $9.00 +>>>2 +=== 0 diff --git a/test/doc/transaction-status-4.test b/test/doc/transaction-status-4.test new file mode 100644 index 00000000..5275eec3 --- /dev/null +++ b/test/doc/transaction-status-4.test @@ -0,0 +1,17 @@ +reg --columns=60 food --pending +<<< +2009/10/31 * Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/01 ! Panera Bread + Expenses:Food $4.50 + Assets + +2009/11/02 Panera Bread + Expenses:Food $4.50 + Assets +>>>1 +09-Nov-01 Panera Bread Expenses:Food $4.50 $4.50 +>>>2 +=== 0 diff --git a/tools/Makefile.am b/tools/Makefile.am index 13ea4e7f..d84229f4 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -247,7 +247,7 @@ endif TESTS = if HAVE_PYTHON -TESTS += RegressTests BaselineTests ConfirmTests GenerateTests +TESTS += RegressTests BaselineTests DocTests ConfirmTests GenerateTests endif if HAVE_CPPUNIT @@ -381,6 +381,14 @@ BaselineTests: $(srcdir)/test/RegressTests.py echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/baseline \"\$$@\"" > $@ chmod 755 $@ +DocTests_SOURCES = test/RegressTests.py + +EXTRA_DIST += test/doc + +DocTests: $(srcdir)/test/RegressTests.py + echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/doc \"\$$@\"" > $@ + chmod 755 $@ + ConfirmTests_SOURCES = test/ConfirmTests.py EXTRA_DIST += test/input @@ -424,10 +432,12 @@ endif fullcheck: cppunittests @$(top_builddir)/RegressTests --verify @$(top_builddir)/BaselineTests --verify + @$(top_builddir)/DocTests --verify @$(top_builddir)/ConfirmTests --verify @$(top_builddir)/GenerateTests --verify @$(top_builddir)/RegressTests --gmalloc @$(top_builddir)/BaselineTests --gmalloc + @$(top_builddir)/DocTests --gmalloc # @$(top_builddir)/ConfirmTests --gmalloc # @$(top_builddir)/GenerateTests --gmalloc From 1b7640dbb0e96928bfac76337024ead803652849 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 00:32:18 -0500 Subject: [PATCH 14/39] Don't delete acct_temps if it was never set --- src/temps.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/temps.cc b/src/temps.cc index e44aaaa7..bf295997 100644 --- a/src/temps.cc +++ b/src/temps.cc @@ -48,7 +48,9 @@ temporaries_t::~temporaries_t() if (! post.account->has_flags(ACCOUNT_TEMP)) post.account->remove_post(&post); } + } + if (acct_temps) { foreach (account_t& acct, *acct_temps) { if (! acct.has_flags(ACCOUNT_TEMP)) acct.remove_account(&acct); From 307b63be77f932ce7cf9685be261f1c3786ea719 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 00:32:34 -0500 Subject: [PATCH 15/39] Fixed baseline tests relating to earlier changes --- test/baseline/opt-anon.test | 4 ++-- test/regress/F559EC12.test | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/baseline/opt-anon.test b/test/baseline/opt-anon.test index f9244451..6fe6b75f 100644 --- a/test/baseline/opt-anon.test +++ b/test/baseline/opt-anon.test @@ -4,8 +4,8 @@ reg --anon Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00 Income:Dividends:Vanguard:VMMXX $-0.35 >>>1 -07-Feb-02 6a93dcb3 20:5d:27:988a9c3a 0.350 VMMXX 0.350 VMMXX - 1c:b6:27:988a9c3a $-0.35 $-0.35 +07-Feb-02 6a93dcb3 da:20:5d:27:988a9c3a 0.350 VMMXX 0.350 VMMXX + da:1c:b6:27:988a9c3a $-0.35 $-0.35 0.350 VMMXX >>>2 === 0 diff --git a/test/regress/F559EC12.test b/test/regress/F559EC12.test index 7900b60d..c8b686db 100644 --- a/test/regress/F559EC12.test +++ b/test/regress/F559EC12.test @@ -3,7 +3,11 @@ format "%-12(scrub(amount))" >>>1 --- Context is first posting of the following transaction --- 2004/05/27 Book Store + ; This note applies to all postings. :SecondTag: Expenses:Books 20 BOOK @ $10 + ; Metadata: Some Value + ; :ExampleTag: + ; Here follows a note describing the posting. Liabilities:MasterCard $-200.00 --- Input format string --- @@ -20,7 +24,11 @@ format "%12(scrub(amount))" >>>1 --- Context is first posting of the following transaction --- 2004/05/27 Book Store + ; This note applies to all postings. :SecondTag: Expenses:Books 20 BOOK @ $10 + ; Metadata: Some Value + ; :ExampleTag: + ; Here follows a note describing the posting. Liabilities:MasterCard $-200.00 --- Input format string --- From 95e08cc46fb499866f2491b4a8aad9fe29ac6a00 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 00:45:39 -0500 Subject: [PATCH 16/39] Make the source directory available to all tests --- test/ConfirmTests.py | 2 +- test/GenerateTests.py | 6 +++--- test/LedgerHarness.py | 25 +++++++++++++++---------- test/RegressTests.py | 10 +++++++--- tools/Makefile.am | 10 +++++----- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/test/ConfirmTests.py b/test/ConfirmTests.py index 0b3d4897..901ae7cd 100755 --- a/test/ConfirmTests.py +++ b/test/ConfirmTests.py @@ -10,7 +10,7 @@ import re from LedgerHarness import LedgerHarness harness = LedgerHarness(sys.argv) -tests = sys.argv[2] +tests = sys.argv[3] if not os.path.isdir(tests) and not os.path.isfile(tests): sys.exit(1) diff --git a/test/GenerateTests.py b/test/GenerateTests.py index aa36737d..d60e0581 100755 --- a/test/GenerateTests.py +++ b/test/GenerateTests.py @@ -104,9 +104,9 @@ def generation_test(seed): beg_range = 1 end_range = 20 -if len(sys.argv) > 3: - beg_range = int(sys.argv[2]) - end_range = int(sys.argv[3]) +if len(sys.argv) > 4: + beg_range = int(sys.argv[3]) + end_range = int(sys.argv[4]) for i in range(beg_range, end_range): if generation_test(i): diff --git a/test/LedgerHarness.py b/test/LedgerHarness.py index cf65f590..7e8cfa3d 100755 --- a/test/LedgerHarness.py +++ b/test/LedgerHarness.py @@ -7,22 +7,27 @@ import re from subprocess import Popen, PIPE class LedgerHarness: - ledger = None - succeeded = 0 - failed = 0 - verify = False - gmalloc = False + ledger = None + sourcepath = None + succeeded = 0 + failed = 0 + verify = False + gmalloc = False def __init__(self, argv): if not os.path.isfile(argv[1]): print "Cannot find ledger at '%s'" % argv[1] sys.exit(1) + if not os.path.isdir(argv[2]): + print "Cannot find source path at '%s'" % argv[2] + sys.exit(1) - self.ledger = argv[1] - self.succeeded = 0 - self.failed = 0 - self.verify = '--verify' in argv - self.gmalloc = '--gmalloc' in argv + self.ledger = argv[1] + self.sourcepath = argv[2] + self.succeeded = 0 + self.failed = 0 + self.verify = '--verify' in argv + self.gmalloc = '--gmalloc' in argv def run(self, command, verify=None, gmalloc=None, columns=True): env = os.environ.copy() diff --git a/test/RegressTests.py b/test/RegressTests.py index 4d23f6b5..13a0a113 100755 --- a/test/RegressTests.py +++ b/test/RegressTests.py @@ -11,7 +11,7 @@ from difflib import unified_diff from LedgerHarness import LedgerHarness harness = LedgerHarness(sys.argv) -tests = sys.argv[2] +tests = sys.argv[3] if not os.path.isdir(tests) and not os.path.isfile(tests): sys.exit(1) @@ -27,11 +27,15 @@ class RegressFile: line == ">>>2\n" or \ line.startswith("===") + def transform_line(self, line): + line = re.sub('\$sourcepath', harness.sourcepath, line) + return line + def read_section(self): lines = [] line = self.fd.readline() while not self.is_directive(line): - lines.append(line) + lines.append(self.transform_line(line)) line = self.fd.readline() return (lines, line) @@ -60,7 +64,7 @@ class RegressFile: test['exitcode'] = int(match.group(1)) return test else: - test['command'] = line + test['command'] = self.transform_line(line) line = self.fd.readline() return None diff --git a/tools/Makefile.am b/tools/Makefile.am index d84229f4..4662e73d 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -370,7 +370,7 @@ RegressTests_SOURCES = test/RegressTests.py EXTRA_DIST += test/regress test/convert.py test/LedgerHarness.py RegressTests: $(srcdir)/test/RegressTests.py - echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/regress \"\$$@\"" > $@ + echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/regress \"\$$@\"" > $@ chmod 755 $@ BaselineTests_SOURCES = test/RegressTests.py @@ -378,7 +378,7 @@ BaselineTests_SOURCES = test/RegressTests.py EXTRA_DIST += test/baseline BaselineTests: $(srcdir)/test/RegressTests.py - echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/baseline \"\$$@\"" > $@ + echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/baseline \"\$$@\"" > $@ chmod 755 $@ DocTests_SOURCES = test/RegressTests.py @@ -386,7 +386,7 @@ DocTests_SOURCES = test/RegressTests.py EXTRA_DIST += test/doc DocTests: $(srcdir)/test/RegressTests.py - echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/doc \"\$$@\"" > $@ + echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/doc \"\$$@\"" > $@ chmod 755 $@ ConfirmTests_SOURCES = test/ConfirmTests.py @@ -401,13 +401,13 @@ test/input/mondo.dat: test/input/standard.dat done ConfirmTests: $(srcdir)/test/ConfirmTests.py - echo "$(PYTHON) $(srcdir)/test/ConfirmTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/input \"\$$@\"" > $@ + echo "$(PYTHON) $(srcdir)/test/ConfirmTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/input \"\$$@\"" > $@ chmod 755 $@ GenerateTests_SOURCES = test/GenerateTests.py GenerateTests: $(srcdir)/test/GenerateTests.py - echo "$(PYTHON) $(srcdir)/test/GenerateTests.py $(top_builddir)/ledger$(EXEEXT) 1 20 \"\$$@\"" > $@ + echo "$(PYTHON) $(srcdir)/test/GenerateTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) 1 20 \"\$$@\"" > $@ chmod 755 $@ FULLCHECK=$(srcdir)/test/fullcheck.sh From c0fe2b530003adee5a8cc7423e9c1c4022cf314a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:21:28 -0500 Subject: [PATCH 17/39] Fixed a bug with budgeting It only occurred if you asked for a budget report on the day that a budgeting period started. --- src/filters.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/filters.cc b/src/filters.cc index 76326ac1..201fddf1 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -769,11 +769,11 @@ void budget_posts::report_budget_items(const date_t& date) } assert(begin); - if (*begin < date && + if (*begin <= date && (! pair.first.end || *begin < *pair.first.end)) { post_t& post = *pair.second; - DEBUG("ledger.walk.budget", "Reporting budget for " + DEBUG("budget.generate", "Reporting budget for " << post.reported_account()->fullname()); xact_t& xact = temps.create_xact(); From aef7510f199932d4c11cbabd2467de53a32f275e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:21:35 -0500 Subject: [PATCH 18/39] Renamed two debug categories --- src/op.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/op.h b/src/op.h index 8d474b80..b27384ec 100644 --- a/src/op.h +++ b/src/op.h @@ -232,13 +232,13 @@ public: private: void acquire() const { - DEBUG("ledger.xpath.memory", + DEBUG("op.memory", "Acquiring " << this << ", refc now " << refc + 1); assert(refc >= 0); refc++; } void release() const { - DEBUG("ledger.xpath.memory", + DEBUG("op.memory", "Releasing " << this << ", refc now " << refc - 1); assert(refc > 0); if (--refc == 0) From 4db60bb46429ced93770afe69b42477c03c47e72 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:21:45 -0500 Subject: [PATCH 19/39] Added several new regression tests --- test/regress/25A099C9.test | 19 ++++++ test/regress/373540CC.test | 9 +++ test/regress/5F1BAF17.test | 130 +++++++++++++++++++++++++++++++++++++ test/regress/8254755E.test | 20 ++++++ 4 files changed, 178 insertions(+) create mode 100644 test/regress/25A099C9.test create mode 100644 test/regress/373540CC.test create mode 100644 test/regress/5F1BAF17.test create mode 100644 test/regress/8254755E.test diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test new file mode 100644 index 00000000..fb5613e2 --- /dev/null +++ b/test/regress/25A099C9.test @@ -0,0 +1,19 @@ +-f $sourcepath/src/amount.h reg +<<< +>>>1 +>>>2 +While parsing file "$sourcepath/src/amount.h", line 67: +Error: No quantity specified for amount +While parsing file "$sourcepath/src/amount.h", line 707: +Error: Invalid date/time: line amount_t amoun +While parsing file "$sourcepath/src/amount.h", line 713: +Error: Invalid date/time: line string amount_ +While parsing file "$sourcepath/src/amount.h", line 719: +Error: Invalid date/time: line string amount_ +While parsing file "$sourcepath/src/amount.h", line 725: +Error: Invalid date/time: line string amount_ +While parsing file "$sourcepath/src/amount.h", line 731: +Error: Invalid date/time: line std::ostream& +While parsing file "$sourcepath/src/amount.h", line 738: +Error: Invalid date/time: line std::istream& +=== 7 diff --git a/test/regress/373540CC.test b/test/regress/373540CC.test new file mode 100644 index 00000000..5c589ec9 --- /dev/null +++ b/test/regress/373540CC.test @@ -0,0 +1,9 @@ +bal --sort total --flat -X '$' not '(Income|Liabilities)' +<<< +2004/05/27 Book Store + Expenses:Books 20 BOOK @ $10 + Liabilities:MasterCard $-200.00 +>>>1 + $200.00 Expenses:Books +>>>2 +=== 0 diff --git a/test/regress/5F1BAF17.test b/test/regress/5F1BAF17.test new file mode 100644 index 00000000..f52ffb86 --- /dev/null +++ b/test/regress/5F1BAF17.test @@ -0,0 +1,130 @@ +bal da39 --flat --sort amount --display-total amount +<<< +2006/02/16 b5f40e96 + da39a3ee:8d437dbf:ee2bf9bd:f61e33bf $713.35 + Assets + +2006/03/27 c7ab1f2d + da39a3ee:8d437dbf:ee2bf9bd:9b69a35a $139.62 + Assets + +2006/03/30 f32ea1dc + da39a3ee:8d437dbf:ee2bf9bd:d219c681 $1,600.00 + Assets + +2006/04/21 d449d51e + da39a3ee:8d437dbf:ee2bf9bd:75b04b88 $698.10 + Assets + +2006/05/02 b02f8323 + da39a3ee:8d437dbf:ee2bf9bd $42.22 + Assets + +2006/05/05 2a6f6850 + da39a3ee:8d437dbf:ee2bf9bd:75b04b88:b3850e04 $2,468.00 + Assets + +2006/05/09 59f92263 + da39a3ee:8d437dbf:ee2bf9bd:071c929a $132.82 + Assets + +2006/05/18 f78a7a51 + da39a3ee:8d437dbf:ee2bf9bd:e97de844 $368.05 + Assets + +2006/05/19 f35c594c + da39a3ee:8d437dbf:ee2bf9bd:d4e7d7d3 $386.62 + Assets + +2006/05/22 0233a991 + da39a3ee:8d437dbf:ee2bf9bd:9c6e5a3f $141.98 + Assets + +2006/05/23 56ccae7f + da39a3ee:8d437dbf:ee2bf9bd:d31d367b $81.78 + Assets + +2006/05/24 d449d51e + da39a3ee:8d437dbf:ee2bf9bd:75b04b88 $65.00 + Assets + +2006/05/25 dc833c91 + da39a3ee:8d437dbf:ee2bf9bd:d31d367b $34.37 + Assets + +2006/05/31 6822b496 + da39a3ee:8d437dbf:ee2bf9bd:e97de844 $41.78 + Assets + +2006/06/02 dff8ccb2 + da39a3ee:8d437dbf:ee2bf9bd:14e351e1 $67.36 + Assets + +2006/06/02 e1eb3f4b + da39a3ee:8d437dbf:ee2bf9bd:2c7a078f $14.00 + Assets + +2006/06/04 feec73ea + da39a3ee:8d437dbf:ee2bf9bd:131260cb $144.99 + Assets + +2006/06/04 e8f65e0a + da39a3ee:8d437dbf:ee2bf9bd:d219c681 $75.00 + Assets + +2006/06/04 3fd43f7b + da39a3ee:8d437dbf:ee2bf9bd:9c4ba7d0 $239.59 + Assets + +2006/06/06 754be754 + da39a3ee:8d437dbf:ee2bf9bd:35b25929 $1,160.14 + Assets + +2006/06/06 00c16d44 + da39a3ee:8d437dbf:ee2bf9bd:e97de844 $78.45 + Assets + +2006/06/08 e7b0b317 + da39a3ee:8d437dbf:ee2bf9bd $443.00 + Assets + +2006/07/17 a30c4c31 + da39a3ee:8d437dbf:ee2bf9bd $880.80 + Assets + +2006/08/08 e31a0cf9 + da39a3ee:8d437dbf:ee2bf9bd $104.53 + Assets + +2006/08/10 f0c0c688 + da39a3ee:8d437dbf:ee2bf9bd $196.70 + Assets + +2006/09/12 1bc59c63 + da39a3ee:8d437dbf:ee2bf9bd $217.79 + Assets + +2007/07/16 557e3a00 + da39a3ee:8d437dbf:ee2bf9bd:f61e33bf $117.80 + Assets +>>>1 + $14.00 da39a3ee:8d437dbf:ee2bf9bd:2c7a078f + $67.36 da39a3ee:8d437dbf:ee2bf9bd:14e351e1 + $116.15 da39a3ee:8d437dbf:ee2bf9bd:d31d367b + $132.82 da39a3ee:8d437dbf:ee2bf9bd:071c929a + $139.62 da39a3ee:8d437dbf:ee2bf9bd:9b69a35a + $141.98 da39a3ee:8d437dbf:ee2bf9bd:9c6e5a3f + $144.99 da39a3ee:8d437dbf:ee2bf9bd:131260cb + $239.59 da39a3ee:8d437dbf:ee2bf9bd:9c4ba7d0 + $386.62 da39a3ee:8d437dbf:ee2bf9bd:d4e7d7d3 + $488.28 da39a3ee:8d437dbf:ee2bf9bd:e97de844 + $763.10 da39a3ee:8d437dbf:ee2bf9bd:75b04b88 + $831.15 da39a3ee:8d437dbf:ee2bf9bd:f61e33bf + $1,160.14 da39a3ee:8d437dbf:ee2bf9bd:35b25929 + $1,675.00 da39a3ee:8d437dbf:ee2bf9bd:d219c681 + $1,885.04 da39a3ee:8d437dbf:ee2bf9bd + $2,468.00 da39a3ee:8d437dbf:ee2bf9bd:75b04b88:b3850e04 +-------------------- + 0 +>>>2 +=== 0 diff --git a/test/regress/8254755E.test b/test/regress/8254755E.test new file mode 100644 index 00000000..26baf52d --- /dev/null +++ b/test/regress/8254755E.test @@ -0,0 +1,20 @@ +bal --flat food:out +<<< +~ Monthly + Expenses:Auto:Fuel $120.00 + Expenses:Food:Out $100.00 + Expenses:Food:Groceries $350.00 + Assets + +2009/11/01 + Expenses:Food:Out $50.00 + Assets +>>>1 + $50.00 Expenses:Food:Out +>>>2 +=== 0 +bal --flat --budget food:out +>>>1 + $-50.00 Expenses:Food:Out +>>>2 +=== 0 From 3a0879aff0b1ea0037098ae4f602b92719ff9a84 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:39:18 -0500 Subject: [PATCH 20/39] Added "reported posts" into account xdata This is necessary because sometimes, a post from one account will get reported as though it were in another account (this happens with --budget, to show child account postings within their parent account). In that case, the account needs to remember which postings have been reported as being within it, so that it can add these amounts to its own total in the balance report. --- src/account.cc | 15 +++++++++++++++ src/account.h | 6 ++++-- src/filters.cc | 2 +- src/post.cc | 6 ++++++ src/post.h | 2 ++ test/regress/D060256A.test | 16 ++++++++++++++++ 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 test/regress/D060256A.test diff --git a/src/account.cc b/src/account.cc index b14520d3..23761049 100644 --- a/src/account.cc +++ b/src/account.cc @@ -397,6 +397,21 @@ value_t account_t::amount(const optional& expr) const xdata_->self_details.last_post = i; } + if (xdata_->self_details.last_reported_post) + i = *xdata_->self_details.last_reported_post; + else + i = xdata_->reported_posts.begin(); + + for (; i != xdata_->reported_posts.end(); i++) { + if ((*i)->xdata().has_flags(POST_EXT_VISITED)) { + if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) { + (*i)->add_to_value(xdata_->self_details.total, expr); + (*i)->xdata().add_flags(POST_EXT_CONSIDERED); + } + } + xdata_->self_details.last_reported_post = i; + } + return xdata_->self_details.total; } else { return NULL_VALUE; diff --git a/src/account.h b/src/account.h index ce0a7a66..c8f6bdbd 100644 --- a/src/account.h +++ b/src/account.h @@ -159,6 +159,7 @@ public: std::set payees_referenced; optional last_post; + optional last_reported_post; details_t() : calculated(false), @@ -176,8 +177,9 @@ public: void update(post_t& post, bool gather_all = false); }; - details_t self_details; - details_t family_details; + details_t self_details; + details_t family_details; + posts_list reported_posts; std::list sort_values; diff --git a/src/filters.cc b/src/filters.cc index 201fddf1..00e495dd 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -815,7 +815,7 @@ void budget_posts::operator()(post_t& post) post_in_budget = true; // Report the post as if it had occurred in the parent account. if (post.reported_account() != acct) - post.xdata().account = acct; + post.set_reported_account(acct); goto handle; } } diff --git a/src/post.cc b/src/post.cc index 0d6ab8a0..2a1663cb 100644 --- a/src/post.cc +++ b/src/post.cc @@ -436,4 +436,10 @@ void post_t::add_to_value(value_t& value, const optional& expr) const } } +void post_t::set_reported_account(account_t * account) +{ + xdata().account = account; + account->xdata().reported_posts.push_back(this); +} + } // namespace ledger diff --git a/src/post.h b/src/post.h index a89ce3bc..5fdee968 100644 --- a/src/post.h +++ b/src/post.h @@ -193,6 +193,8 @@ public: void add_to_value(value_t& value, const optional& expr = none) const; + void set_reported_account(account_t * account); + account_t * reported_account() { if (xdata_) if (account_t * acct = xdata_->account) diff --git a/test/regress/D060256A.test b/test/regress/D060256A.test new file mode 100644 index 00000000..26c30351 --- /dev/null +++ b/test/regress/D060256A.test @@ -0,0 +1,16 @@ +budget --now=2009/11/01 --end=2009/11/30 +<<< +~ Monthly + Expenses:Food $500.00 + Assets + +2009/11/01 Sample + Expenses:Food:Dining $20.00 + Assets +>>>1 + $-20.00 $-500.00 $480.00 4% Assets + $20.00 $500.00 $-480.00 4% Expenses:Food +------------ ------------ ------------ ----- + 0 0 0 0 +>>>2 +=== 0 From 90c7298049546bd8d1f4f64aeedd6569780f9259 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:58:53 -0500 Subject: [PATCH 21/39] Renamed the DocTests to ManualTests --- test/{doc => manual}/transaction-codes-1.test | 0 test/{doc => manual}/transaction-codes-2.test | 0 test/{doc => manual}/transaction-notes-1.test | 0 test/{doc => manual}/transaction-notes-2.test | 0 test/{doc => manual}/transaction-notes-3.test | 0 test/{doc => manual}/transaction-notes-4.test | 0 test/{doc => manual}/transaction-status-1.test | 0 test/{doc => manual}/transaction-status-2.test | 0 test/{doc => manual}/transaction-status-3.test | 0 test/{doc => manual}/transaction-status-4.test | 0 tools/Makefile.am | 14 +++++++------- 11 files changed, 7 insertions(+), 7 deletions(-) rename test/{doc => manual}/transaction-codes-1.test (100%) rename test/{doc => manual}/transaction-codes-2.test (100%) rename test/{doc => manual}/transaction-notes-1.test (100%) rename test/{doc => manual}/transaction-notes-2.test (100%) rename test/{doc => manual}/transaction-notes-3.test (100%) rename test/{doc => manual}/transaction-notes-4.test (100%) rename test/{doc => manual}/transaction-status-1.test (100%) rename test/{doc => manual}/transaction-status-2.test (100%) rename test/{doc => manual}/transaction-status-3.test (100%) rename test/{doc => manual}/transaction-status-4.test (100%) diff --git a/test/doc/transaction-codes-1.test b/test/manual/transaction-codes-1.test similarity index 100% rename from test/doc/transaction-codes-1.test rename to test/manual/transaction-codes-1.test diff --git a/test/doc/transaction-codes-2.test b/test/manual/transaction-codes-2.test similarity index 100% rename from test/doc/transaction-codes-2.test rename to test/manual/transaction-codes-2.test diff --git a/test/doc/transaction-notes-1.test b/test/manual/transaction-notes-1.test similarity index 100% rename from test/doc/transaction-notes-1.test rename to test/manual/transaction-notes-1.test diff --git a/test/doc/transaction-notes-2.test b/test/manual/transaction-notes-2.test similarity index 100% rename from test/doc/transaction-notes-2.test rename to test/manual/transaction-notes-2.test diff --git a/test/doc/transaction-notes-3.test b/test/manual/transaction-notes-3.test similarity index 100% rename from test/doc/transaction-notes-3.test rename to test/manual/transaction-notes-3.test diff --git a/test/doc/transaction-notes-4.test b/test/manual/transaction-notes-4.test similarity index 100% rename from test/doc/transaction-notes-4.test rename to test/manual/transaction-notes-4.test diff --git a/test/doc/transaction-status-1.test b/test/manual/transaction-status-1.test similarity index 100% rename from test/doc/transaction-status-1.test rename to test/manual/transaction-status-1.test diff --git a/test/doc/transaction-status-2.test b/test/manual/transaction-status-2.test similarity index 100% rename from test/doc/transaction-status-2.test rename to test/manual/transaction-status-2.test diff --git a/test/doc/transaction-status-3.test b/test/manual/transaction-status-3.test similarity index 100% rename from test/doc/transaction-status-3.test rename to test/manual/transaction-status-3.test diff --git a/test/doc/transaction-status-4.test b/test/manual/transaction-status-4.test similarity index 100% rename from test/doc/transaction-status-4.test rename to test/manual/transaction-status-4.test diff --git a/tools/Makefile.am b/tools/Makefile.am index 4662e73d..4dd4a871 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -247,7 +247,7 @@ endif TESTS = if HAVE_PYTHON -TESTS += RegressTests BaselineTests DocTests ConfirmTests GenerateTests +TESTS += RegressTests BaselineTests ManualTests ConfirmTests GenerateTests endif if HAVE_CPPUNIT @@ -381,12 +381,12 @@ BaselineTests: $(srcdir)/test/RegressTests.py echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/baseline \"\$$@\"" > $@ chmod 755 $@ -DocTests_SOURCES = test/RegressTests.py +ManualTests_SOURCES = test/RegressTests.py -EXTRA_DIST += test/doc +EXTRA_DIST += test/manual -DocTests: $(srcdir)/test/RegressTests.py - echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/doc \"\$$@\"" > $@ +ManualTests: $(srcdir)/test/RegressTests.py + echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/manual \"\$$@\"" > $@ chmod 755 $@ ConfirmTests_SOURCES = test/ConfirmTests.py @@ -432,12 +432,12 @@ endif fullcheck: cppunittests @$(top_builddir)/RegressTests --verify @$(top_builddir)/BaselineTests --verify - @$(top_builddir)/DocTests --verify + @$(top_builddir)/ManualTests --verify @$(top_builddir)/ConfirmTests --verify @$(top_builddir)/GenerateTests --verify @$(top_builddir)/RegressTests --gmalloc @$(top_builddir)/BaselineTests --gmalloc - @$(top_builddir)/DocTests --gmalloc + @$(top_builddir)/ManualTests --gmalloc # @$(top_builddir)/ConfirmTests --gmalloc # @$(top_builddir)/GenerateTests --gmalloc From 4a249d6172773db571556f469be6ee2c1c3690e9 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:59:04 -0500 Subject: [PATCH 22/39] Fixed issues with period strings like "2009/10" --- src/times.cc | 40 +++++---- test/baseline/opt-add-budget.test | 144 +++++++++++++++--------------- test/baseline/opt-budget.test | 96 ++++++++++---------- test/regress/7F3650FD.test | 50 +++++++++++ 4 files changed, 194 insertions(+), 136 deletions(-) create mode 100644 test/regress/7F3650FD.test diff --git a/src/times.cc b/src/times.cc index 667f65a3..b737b2a0 100644 --- a/src/times.cc +++ b/src/times.cc @@ -55,12 +55,13 @@ namespace { #endif // USE_BOOST_FACETS public: - bool has_year; - bool input; + bool has_year; + bool has_day; + bool input; temporal_io_t(const char * _fmt_str, bool _input) : fmt_str(_fmt_str), has_year(icontains(fmt_str, "%y")), - input(_input) { + has_day(icontains(fmt_str, "%d")), input(_input) { #if defined(USE_BOOST_FACETS) if (input) { input_facet = new InputFacetType(fmt_str); @@ -75,6 +76,7 @@ namespace { void set_format(const char * fmt) { fmt_str = fmt; has_year = icontains(fmt_str, "%y"); + has_day = icontains(fmt_str, "%d"); #if defined(USE_BOOST_FACETS) if (input) @@ -190,7 +192,7 @@ namespace { date_t parse_date_mask_routine(const char * date_str, date_io_t& io, optional year, - bool& saw_year) + bool& saw_year, bool& saw_day) { date_t when; @@ -220,26 +222,30 @@ namespace { if (when.month() > CURRENT_DATE().month()) when -= gregorian::years(1); - } else { + } + else { saw_year = true; } + + saw_day = io.has_day; } return when; } date_t parse_date_mask(const char * date_str, - optional year, bool& saw_year) + optional year, + bool& saw_year, bool& saw_day) { if (input_date_io.get()) { date_t when = parse_date_mask_routine(date_str, *input_date_io.get(), - year, saw_year); + year, saw_year, saw_day); if (! when.is_not_a_date()) return when; } foreach (shared_ptr& reader, readers) { date_t when = parse_date_mask_routine(date_str, *reader.get(), - year, saw_year); + year, saw_year, saw_day); if (! when.is_not_a_date()) return when; } @@ -311,7 +317,8 @@ datetime_t parse_datetime(const char * str, optional) date_t parse_date(const char * str, optional current_year) { bool saw_year; - return parse_date_mask(str, current_year, saw_year); + bool saw_day; + return parse_date_mask(str, current_year, saw_year, saw_day); } std::ostream& operator<<(std::ostream& out, @@ -549,7 +556,8 @@ namespace { date_t * end) { bool saw_year = true; - date_t when = parse_date_mask(word.c_str(), none, saw_year); + bool saw_day = true; + date_t when = parse_date_mask(word.c_str(), none, saw_year, saw_day); if (when.is_not_a_date()) throw_(date_error, _("Could not parse date mask: %1") << word); @@ -558,8 +566,8 @@ namespace { *begin = when; if (end) { - if (saw_year) - *end = *begin + gregorian::years(1); + if (saw_day) + *end = *begin + gregorian::days(1); else *end = *begin + gregorian::months(1); } @@ -728,17 +736,17 @@ void date_interval_t::parse(std::istream& in) if (wday) { while (start->day_of_week() != *wday) - *start = duration_t(duration_t::DAYS, 1).subtract(*start); + *start -= gregorian::days(1); if (! end) - end = duration_t(duration_t::DAYS, 1).add(*start); + end = *start + gregorian::days(1); } else { bool overwrite_end = false; if (year) { start = date_t(*year, 1, 1); if (! end) { - end = duration_t(duration_t::YEARS, 1).add(*start); + end = *start + gregorian::years(1); overwrite_end = true; } } @@ -746,7 +754,7 @@ void date_interval_t::parse(std::istream& in) if (mon) { start = date_t(start->year(), *mon, 1); if (! end || overwrite_end) - end = duration_t(duration_t::MONTHS, 1).add(*start); + end = *start + gregorian::months(1); } } } diff --git a/test/baseline/opt-add-budget.test b/test/baseline/opt-add-budget.test index 20dfd320..535335d3 100644 --- a/test/baseline/opt-add-budget.test +++ b/test/baseline/opt-add-budget.test @@ -244,124 +244,124 @@ reg --add-budget books cards Liabilities:Cards $120.00 Assets:Cash >>>1 -08-Jan-01 January Expenses:Books $10.00 $10.00 - Liabilities:Cards $10.00 $20.00 -08-Jan-01 Budget transaction Expenses:Books $-10.00 $10.00 +08-Jan-01 Budget transaction Expenses:Books $-10.00 $-10.00 +08-Jan-01 January Expenses:Books $10.00 0 + Liabilities:Cards $10.00 $10.00 08-Jan-31 End of January Expenses:Books $10.00 $20.00 Liabilities:Cards $10.00 $30.00 -08-Feb-01 February Expenses:Books $20.00 $50.00 - Liabilities:Cards $20.00 $70.00 -08-Feb-01 Budget transaction Expenses:Books $-10.00 $60.00 +08-Feb-01 Budget transaction Expenses:Books $-10.00 $20.00 +08-Feb-01 February Expenses:Books $20.00 $40.00 + Liabilities:Cards $20.00 $60.00 08-Feb-28 End of February Expenses:Books $20.00 $80.00 Liabilities:Cards $20.00 $100.00 -08-Mar-01 March Expenses:Books $30.00 $130.00 - Liabilities:Cards $30.00 $160.00 -08-Mar-01 Budget transaction Expenses:Books $-10.00 $150.00 +08-Mar-01 Budget transaction Expenses:Books $-10.00 $90.00 +08-Mar-01 March Expenses:Books $30.00 $120.00 + Liabilities:Cards $30.00 $150.00 08-Mar-31 End of March Expenses:Books $30.00 $180.00 Liabilities:Cards $30.00 $210.00 -08-Apr-01 April Expenses:Books $40.00 $250.00 - Liabilities:Cards $40.00 $290.00 -08-Apr-01 Budget transaction Expenses:Books $-10.00 $280.00 +08-Apr-01 Budget transaction Expenses:Books $-10.00 $200.00 +08-Apr-01 April Expenses:Books $40.00 $240.00 + Liabilities:Cards $40.00 $280.00 08-Apr-30 End of April Expenses:Books $40.00 $320.00 Liabilities:Cards $40.00 $360.00 -08-May-01 May Expenses:Books $50.00 $410.00 - Liabilities:Cards $50.00 $460.00 -08-May-01 Budget transaction Expenses:Books $-10.00 $450.00 +08-May-01 Budget transaction Expenses:Books $-10.00 $350.00 +08-May-01 May Expenses:Books $50.00 $400.00 + Liabilities:Cards $50.00 $450.00 08-May-31 End of May Expenses:Books $50.00 $500.00 Liabilities:Cards $50.00 $550.00 -08-Jun-01 June Expenses:Books $60.00 $610.00 - Liabilities:Cards $60.00 $670.00 -08-Jun-01 Budget transaction Expenses:Books $-10.00 $660.00 +08-Jun-01 Budget transaction Expenses:Books $-10.00 $540.00 +08-Jun-01 June Expenses:Books $60.00 $600.00 + Liabilities:Cards $60.00 $660.00 08-Jun-30 End of June Expenses:Books $60.00 $720.00 Liabilities:Cards $60.00 $780.00 -08-Jul-01 July Expenses:Books $70.00 $850.00 - Liabilities:Cards $70.00 $920.00 -08-Jul-01 Budget transaction Expenses:Books $-10.00 $910.00 +08-Jul-01 Budget transaction Expenses:Books $-10.00 $770.00 +08-Jul-01 July Expenses:Books $70.00 $840.00 + Liabilities:Cards $70.00 $910.00 08-Jul-31 End of July Expenses:Books $70.00 $980.00 Liabilities:Cards $70.00 $1050.00 -08-Aug-01 August Expenses:Books $80.00 $1130.00 - Liabilities:Cards $80.00 $1210.00 -08-Aug-01 Budget transaction Expenses:Books $-10.00 $1200.00 +08-Aug-01 Budget transaction Expenses:Books $-10.00 $1040.00 +08-Aug-01 August Expenses:Books $80.00 $1120.00 + Liabilities:Cards $80.00 $1200.00 08-Aug-31 End of August Expenses:Books $80.00 $1280.00 Liabilities:Cards $80.00 $1360.00 -08-Sep-01 September Expenses:Books $90.00 $1450.00 - Liabilities:Cards $90.00 $1540.00 -08-Sep-01 Budget transaction Expenses:Books $-10.00 $1530.00 +08-Sep-01 Budget transaction Expenses:Books $-10.00 $1350.00 +08-Sep-01 September Expenses:Books $90.00 $1440.00 + Liabilities:Cards $90.00 $1530.00 08-Sep-30 End of September Expenses:Books $90.00 $1620.00 Liabilities:Cards $90.00 $1710.00 -08-Oct-01 October Expenses:Books $100.00 $1810.00 - Liabilities:Cards $100.00 $1910.00 -08-Oct-01 Budget transaction Expenses:Books $-10.00 $1900.00 +08-Oct-01 Budget transaction Expenses:Books $-10.00 $1700.00 +08-Oct-01 October Expenses:Books $100.00 $1800.00 + Liabilities:Cards $100.00 $1900.00 08-Oct-31 End of October Expenses:Books $100.00 $2000.00 Liabilities:Cards $100.00 $2100.00 -08-Nov-01 November Expenses:Books $110.00 $2210.00 - Liabilities:Cards $110.00 $2320.00 -08-Nov-01 Budget transaction Expenses:Books $-10.00 $2310.00 +08-Nov-01 Budget transaction Expenses:Books $-10.00 $2090.00 +08-Nov-01 November Expenses:Books $110.00 $2200.00 + Liabilities:Cards $110.00 $2310.00 08-Nov-30 End of November Expenses:Books $110.00 $2420.00 Liabilities:Cards $110.00 $2530.00 -08-Dec-01 December Expenses:Books $120.00 $2650.00 - Liabilities:Cards $120.00 $2770.00 -08-Dec-01 Budget transaction Expenses:Books $-10.00 $2760.00 +08-Dec-01 Budget transaction Expenses:Books $-10.00 $2520.00 +08-Dec-01 December Expenses:Books $120.00 $2640.00 + Liabilities:Cards $120.00 $2760.00 08-Dec-31 End of December Expenses:Books $120.00 $2880.00 Liabilities:Cards $120.00 $3000.00 -09-Jan-01 January Expenses:Books $10.00 $3010.00 - Liabilities:Cards $10.00 $3020.00 -09-Jan-01 Budget transaction Expenses:Books $-10.00 $3010.00 +09-Jan-01 Budget transaction Expenses:Books $-10.00 $2990.00 +09-Jan-01 January Expenses:Books $10.00 $3000.00 + Liabilities:Cards $10.00 $3010.00 09-Jan-31 End of January Expenses:Books $10.00 $3020.00 Liabilities:Cards $10.00 $3030.00 -09-Feb-01 February Expenses:Books $20.00 $3050.00 - Liabilities:Cards $20.00 $3070.00 -09-Feb-01 Budget transaction Expenses:Books $-10.00 $3060.00 +09-Feb-01 Budget transaction Expenses:Books $-10.00 $3020.00 +09-Feb-01 February Expenses:Books $20.00 $3040.00 + Liabilities:Cards $20.00 $3060.00 09-Feb-28 End of February Expenses:Books $20.00 $3080.00 Liabilities:Cards $20.00 $3100.00 -09-Mar-01 March Expenses:Books $30.00 $3130.00 - Liabilities:Cards $30.00 $3160.00 -09-Mar-01 Budget transaction Expenses:Books $-10.00 $3150.00 +09-Mar-01 Budget transaction Expenses:Books $-10.00 $3090.00 +09-Mar-01 March Expenses:Books $30.00 $3120.00 + Liabilities:Cards $30.00 $3150.00 09-Mar-31 End of March Expenses:Books $30.00 $3180.00 Liabilities:Cards $30.00 $3210.00 -09-Apr-01 April Expenses:Books $40.00 $3250.00 - Liabilities:Cards $40.00 $3290.00 -09-Apr-01 Budget transaction Expenses:Books $-10.00 $3280.00 +09-Apr-01 Budget transaction Expenses:Books $-10.00 $3200.00 +09-Apr-01 April Expenses:Books $40.00 $3240.00 + Liabilities:Cards $40.00 $3280.00 09-Apr-30 End of April Expenses:Books $40.00 $3320.00 Liabilities:Cards $40.00 $3360.00 -09-May-01 May Expenses:Books $50.00 $3410.00 - Liabilities:Cards $50.00 $3460.00 -09-May-01 Budget transaction Expenses:Books $-10.00 $3450.00 +09-May-01 Budget transaction Expenses:Books $-10.00 $3350.00 +09-May-01 May Expenses:Books $50.00 $3400.00 + Liabilities:Cards $50.00 $3450.00 09-May-31 End of May Expenses:Books $50.00 $3500.00 Liabilities:Cards $50.00 $3550.00 -09-Jun-01 June Expenses:Books $60.00 $3610.00 - Liabilities:Cards $60.00 $3670.00 -09-Jun-01 Budget transaction Expenses:Books $-10.00 $3660.00 +09-Jun-01 Budget transaction Expenses:Books $-10.00 $3540.00 +09-Jun-01 June Expenses:Books $60.00 $3600.00 + Liabilities:Cards $60.00 $3660.00 09-Jun-30 End of June Expenses:Books $60.00 $3720.00 Liabilities:Cards $60.00 $3780.00 -09-Jul-01 July Expenses:Books $70.00 $3850.00 - Liabilities:Cards $70.00 $3920.00 -09-Jul-01 Budget transaction Expenses:Books $-10.00 $3910.00 +09-Jul-01 Budget transaction Expenses:Books $-10.00 $3770.00 +09-Jul-01 July Expenses:Books $70.00 $3840.00 + Liabilities:Cards $70.00 $3910.00 09-Jul-31 End of July Expenses:Books $70.00 $3980.00 Liabilities:Cards $70.00 $4050.00 -09-Aug-01 August Expenses:Books $80.00 $4130.00 - Liabilities:Cards $80.00 $4210.00 -09-Aug-01 Budget transaction Expenses:Books $-10.00 $4200.00 +09-Aug-01 Budget transaction Expenses:Books $-10.00 $4040.00 +09-Aug-01 August Expenses:Books $80.00 $4120.00 + Liabilities:Cards $80.00 $4200.00 09-Aug-31 End of August Expenses:Books $80.00 $4280.00 Liabilities:Cards $80.00 $4360.00 -09-Sep-01 September Expenses:Books $90.00 $4450.00 - Liabilities:Cards $90.00 $4540.00 -09-Sep-01 Budget transaction Expenses:Books $-10.00 $4530.00 +09-Sep-01 Budget transaction Expenses:Books $-10.00 $4350.00 +09-Sep-01 September Expenses:Books $90.00 $4440.00 + Liabilities:Cards $90.00 $4530.00 09-Sep-30 End of September Expenses:Books $90.00 $4620.00 Liabilities:Cards $90.00 $4710.00 -09-Oct-01 October Expenses:Books $100.00 $4810.00 - Liabilities:Cards $100.00 $4910.00 -09-Oct-01 Budget transaction Expenses:Books $-10.00 $4900.00 +09-Oct-01 Budget transaction Expenses:Books $-10.00 $4700.00 +09-Oct-01 October Expenses:Books $100.00 $4800.00 + Liabilities:Cards $100.00 $4900.00 09-Oct-31 End of October Expenses:Books $100.00 $5000.00 Liabilities:Cards $100.00 $5100.00 -09-Nov-01 November Expenses:Books $110.00 $5210.00 - Liabilities:Cards $110.00 $5320.00 -09-Nov-01 Budget transaction Expenses:Books $-10.00 $5310.00 +09-Nov-01 Budget transaction Expenses:Books $-10.00 $5090.00 +09-Nov-01 November Expenses:Books $110.00 $5200.00 + Liabilities:Cards $110.00 $5310.00 09-Nov-30 End of November Expenses:Books $110.00 $5420.00 Liabilities:Cards $110.00 $5530.00 -09-Dec-01 December Expenses:Books $120.00 $5650.00 - Liabilities:Cards $120.00 $5770.00 -09-Dec-01 Budget transaction Expenses:Books $-10.00 $5760.00 +09-Dec-01 Budget transaction Expenses:Books $-10.00 $5520.00 +09-Dec-01 December Expenses:Books $120.00 $5640.00 + Liabilities:Cards $120.00 $5760.00 09-Dec-31 End of December Expenses:Books $120.00 $5880.00 Liabilities:Cards $120.00 $6000.00 >>>2 diff --git a/test/baseline/opt-budget.test b/test/baseline/opt-budget.test index 097d19d8..eb2ade9d 100644 --- a/test/baseline/opt-budget.test +++ b/test/baseline/opt-budget.test @@ -245,77 +245,77 @@ reg --budget books Liabilities:Cards $120.00 Assets:Cash >>>1 -08-Jan-01 January Expenses:Books $10.00 $10.00 -08-Jan-01 Budget transaction Expenses:Books $-10.00 0 +08-Jan-01 Budget transaction Expenses:Books $-10.00 $-10.00 +08-Jan-01 January Expenses:Books $10.00 0 08-Jan-31 End of January Expenses:Books $10.00 $10.00 -08-Feb-01 February Expenses:Books $20.00 $30.00 -08-Feb-01 Budget transaction Expenses:Books $-10.00 $20.00 +08-Feb-01 Budget transaction Expenses:Books $-10.00 0 +08-Feb-01 February Expenses:Books $20.00 $20.00 08-Feb-28 End of February Expenses:Books $20.00 $40.00 -08-Mar-01 March Expenses:Books $30.00 $70.00 -08-Mar-01 Budget transaction Expenses:Books $-10.00 $60.00 +08-Mar-01 Budget transaction Expenses:Books $-10.00 $30.00 +08-Mar-01 March Expenses:Books $30.00 $60.00 08-Mar-31 End of March Expenses:Books $30.00 $90.00 -08-Apr-01 April Expenses:Books $40.00 $130.00 -08-Apr-01 Budget transaction Expenses:Books $-10.00 $120.00 +08-Apr-01 Budget transaction Expenses:Books $-10.00 $80.00 +08-Apr-01 April Expenses:Books $40.00 $120.00 08-Apr-30 End of April Expenses:Books $40.00 $160.00 -08-May-01 May Expenses:Books $50.00 $210.00 -08-May-01 Budget transaction Expenses:Books $-10.00 $200.00 +08-May-01 Budget transaction Expenses:Books $-10.00 $150.00 +08-May-01 May Expenses:Books $50.00 $200.00 08-May-31 End of May Expenses:Books $50.00 $250.00 -08-Jun-01 June Expenses:Books $60.00 $310.00 -08-Jun-01 Budget transaction Expenses:Books $-10.00 $300.00 +08-Jun-01 Budget transaction Expenses:Books $-10.00 $240.00 +08-Jun-01 June Expenses:Books $60.00 $300.00 08-Jun-30 End of June Expenses:Books $60.00 $360.00 -08-Jul-01 July Expenses:Books $70.00 $430.00 -08-Jul-01 Budget transaction Expenses:Books $-10.00 $420.00 +08-Jul-01 Budget transaction Expenses:Books $-10.00 $350.00 +08-Jul-01 July Expenses:Books $70.00 $420.00 08-Jul-31 End of July Expenses:Books $70.00 $490.00 -08-Aug-01 August Expenses:Books $80.00 $570.00 -08-Aug-01 Budget transaction Expenses:Books $-10.00 $560.00 +08-Aug-01 Budget transaction Expenses:Books $-10.00 $480.00 +08-Aug-01 August Expenses:Books $80.00 $560.00 08-Aug-31 End of August Expenses:Books $80.00 $640.00 -08-Sep-01 September Expenses:Books $90.00 $730.00 -08-Sep-01 Budget transaction Expenses:Books $-10.00 $720.00 +08-Sep-01 Budget transaction Expenses:Books $-10.00 $630.00 +08-Sep-01 September Expenses:Books $90.00 $720.00 08-Sep-30 End of September Expenses:Books $90.00 $810.00 -08-Oct-01 October Expenses:Books $100.00 $910.00 -08-Oct-01 Budget transaction Expenses:Books $-10.00 $900.00 +08-Oct-01 Budget transaction Expenses:Books $-10.00 $800.00 +08-Oct-01 October Expenses:Books $100.00 $900.00 08-Oct-31 End of October Expenses:Books $100.00 $1000.00 -08-Nov-01 November Expenses:Books $110.00 $1110.00 -08-Nov-01 Budget transaction Expenses:Books $-10.00 $1100.00 +08-Nov-01 Budget transaction Expenses:Books $-10.00 $990.00 +08-Nov-01 November Expenses:Books $110.00 $1100.00 08-Nov-30 End of November Expenses:Books $110.00 $1210.00 -08-Dec-01 December Expenses:Books $120.00 $1330.00 -08-Dec-01 Budget transaction Expenses:Books $-10.00 $1320.00 +08-Dec-01 Budget transaction Expenses:Books $-10.00 $1200.00 +08-Dec-01 December Expenses:Books $120.00 $1320.00 08-Dec-31 End of December Expenses:Books $120.00 $1440.00 -09-Jan-01 January Expenses:Books $10.00 $1450.00 -09-Jan-01 Budget transaction Expenses:Books $-10.00 $1440.00 +09-Jan-01 Budget transaction Expenses:Books $-10.00 $1430.00 +09-Jan-01 January Expenses:Books $10.00 $1440.00 09-Jan-31 End of January Expenses:Books $10.00 $1450.00 -09-Feb-01 February Expenses:Books $20.00 $1470.00 -09-Feb-01 Budget transaction Expenses:Books $-10.00 $1460.00 +09-Feb-01 Budget transaction Expenses:Books $-10.00 $1440.00 +09-Feb-01 February Expenses:Books $20.00 $1460.00 09-Feb-28 End of February Expenses:Books $20.00 $1480.00 -09-Mar-01 March Expenses:Books $30.00 $1510.00 -09-Mar-01 Budget transaction Expenses:Books $-10.00 $1500.00 +09-Mar-01 Budget transaction Expenses:Books $-10.00 $1470.00 +09-Mar-01 March Expenses:Books $30.00 $1500.00 09-Mar-31 End of March Expenses:Books $30.00 $1530.00 -09-Apr-01 April Expenses:Books $40.00 $1570.00 -09-Apr-01 Budget transaction Expenses:Books $-10.00 $1560.00 +09-Apr-01 Budget transaction Expenses:Books $-10.00 $1520.00 +09-Apr-01 April Expenses:Books $40.00 $1560.00 09-Apr-30 End of April Expenses:Books $40.00 $1600.00 -09-May-01 May Expenses:Books $50.00 $1650.00 -09-May-01 Budget transaction Expenses:Books $-10.00 $1640.00 +09-May-01 Budget transaction Expenses:Books $-10.00 $1590.00 +09-May-01 May Expenses:Books $50.00 $1640.00 09-May-31 End of May Expenses:Books $50.00 $1690.00 -09-Jun-01 June Expenses:Books $60.00 $1750.00 -09-Jun-01 Budget transaction Expenses:Books $-10.00 $1740.00 +09-Jun-01 Budget transaction Expenses:Books $-10.00 $1680.00 +09-Jun-01 June Expenses:Books $60.00 $1740.00 09-Jun-30 End of June Expenses:Books $60.00 $1800.00 -09-Jul-01 July Expenses:Books $70.00 $1870.00 -09-Jul-01 Budget transaction Expenses:Books $-10.00 $1860.00 +09-Jul-01 Budget transaction Expenses:Books $-10.00 $1790.00 +09-Jul-01 July Expenses:Books $70.00 $1860.00 09-Jul-31 End of July Expenses:Books $70.00 $1930.00 -09-Aug-01 August Expenses:Books $80.00 $2010.00 -09-Aug-01 Budget transaction Expenses:Books $-10.00 $2000.00 +09-Aug-01 Budget transaction Expenses:Books $-10.00 $1920.00 +09-Aug-01 August Expenses:Books $80.00 $2000.00 09-Aug-31 End of August Expenses:Books $80.00 $2080.00 -09-Sep-01 September Expenses:Books $90.00 $2170.00 -09-Sep-01 Budget transaction Expenses:Books $-10.00 $2160.00 +09-Sep-01 Budget transaction Expenses:Books $-10.00 $2070.00 +09-Sep-01 September Expenses:Books $90.00 $2160.00 09-Sep-30 End of September Expenses:Books $90.00 $2250.00 -09-Oct-01 October Expenses:Books $100.00 $2350.00 -09-Oct-01 Budget transaction Expenses:Books $-10.00 $2340.00 +09-Oct-01 Budget transaction Expenses:Books $-10.00 $2240.00 +09-Oct-01 October Expenses:Books $100.00 $2340.00 09-Oct-31 End of October Expenses:Books $100.00 $2440.00 -09-Nov-01 November Expenses:Books $110.00 $2550.00 -09-Nov-01 Budget transaction Expenses:Books $-10.00 $2540.00 +09-Nov-01 Budget transaction Expenses:Books $-10.00 $2430.00 +09-Nov-01 November Expenses:Books $110.00 $2540.00 09-Nov-30 End of November Expenses:Books $110.00 $2650.00 -09-Dec-01 December Expenses:Books $120.00 $2770.00 -09-Dec-01 Budget transaction Expenses:Books $-10.00 $2760.00 +09-Dec-01 Budget transaction Expenses:Books $-10.00 $2640.00 +09-Dec-01 December Expenses:Books $120.00 $2760.00 09-Dec-31 End of December Expenses:Books $120.00 $2880.00 >>>2 === 0 diff --git a/test/regress/7F3650FD.test b/test/regress/7F3650FD.test new file mode 100644 index 00000000..0eb3a96f --- /dev/null +++ b/test/regress/7F3650FD.test @@ -0,0 +1,50 @@ +period --now=2010/11/01 12/01 +<<< +>>>1 +global details => + + start: 09-Dec-01 + end: 09-Dec-02 + factor: 1 +>>>2 +=== 0 +period --now=2010/11/01 10/01 +<<< +>>>1 +global details => + + start: 10-Oct-01 + end: 10-Oct-02 + factor: 1 +>>>2 +=== 0 +period --now=2010/11/01 2009/10 +<<< +>>>1 +global details => + + start: 09-Oct-01 + end: 09-Nov-01 + factor: 1 +>>>2 +=== 0 +period --now=2010/11/01 2009/10/01 +<<< +>>>1 +global details => + + start: 09-Oct-01 + end: 09-Oct-02 + factor: 1 +>>>2 +=== 0 +period --now=2010/11/01 2009 +<<< +>>>1 +global details => + + start: 09-Jan-01 + end: 10-Jan-01 + factor: 1 +>>>2 +=== 0 From 0a9cc833adebadc876e3e09f1c344b08b23e59f8 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 01:59:33 -0500 Subject: [PATCH 23/39] Added a regression test relating to forecasting --- test/regress/E627C594.test | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 test/regress/E627C594.test diff --git a/test/regress/E627C594.test b/test/regress/E627C594.test new file mode 100644 index 00000000..0dfbf778 --- /dev/null +++ b/test/regress/E627C594.test @@ -0,0 +1,18 @@ +reg --forecast-while="d<[2010/03/01]" --now=2009/11/01 +<<< +~ Monthly + Expenses:Food $500.00 + Assets + +2009/11/01 Sample + Expenses:Food:Dining $20.00 + Assets +>>>1 +09-Nov-01 Sample Expenses:Food:Dining $20.00 $20.00 + Assets $-20.00 0 +10-Jan-01 Forecast transaction Expenses:Food $500.00 $500.00 +10-Jan-01 Forecast transaction Assets $-500.00 0 +10-Feb-01 Forecast transaction Expenses:Food $500.00 $500.00 +10-Feb-01 Forecast transaction Assets $-500.00 0 +>>>2 +=== 0 From 094794c640dafaab37a0b227908d8602d29f7daa Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 02:39:31 -0500 Subject: [PATCH 24/39] Added a --european flag, to use commas for decimals Ledger can often figure this out for itself, but this flag just makes it the default behavior. It is meant to be added to one's ~/.ledgerrc file. --- src/commodity.cc | 2 ++ src/commodity.h | 6 +++++- src/session.cc | 3 +++ src/session.h | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/commodity.cc b/src/commodity.cc index de529ac4..689cf466 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -38,6 +38,8 @@ namespace ledger { +bool commodity_t::base_t::european_by_default = false; + void commodity_t::base_t::history_t::add_price(commodity_t& source, const datetime_t& date, const amount_t& price, diff --git a/src/commodity.h b/src/commodity.h index 1df1ab18..af92271e 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -188,9 +188,13 @@ public: mutable bool searched; + static bool european_by_default; + public: explicit base_t(const string& _symbol) - : supports_flags(COMMODITY_STYLE_DEFAULTS), + : supports_flags(european_by_default ? + COMMODITY_STYLE_EUROPEAN : + COMMODITY_STYLE_DEFAULTS), symbol(_symbol), precision(0), searched(false) { TRACE_CTOR(base_t, "const string&"); } diff --git a/src/session.cc b/src/session.cc index 3f29716d..33c27165 100644 --- a/src/session.cc +++ b/src/session.cc @@ -264,6 +264,9 @@ option_t * session_t::lookup_option(const char * p) case 'd': OPT(download); // -Q break; + case 'e': + OPT(european); + break; case 'f': OPT_(file_); // -f break; diff --git a/src/session.h b/src/session.h index c1e0243b..4b8d2380 100644 --- a/src/session.h +++ b/src/session.h @@ -105,6 +105,7 @@ public: HANDLER(account_).report(out); HANDLER(cache_).report(out); HANDLER(download).report(out); + HANDLER(european).report(out); HANDLER(file_).report(out); HANDLER(input_date_format_).report(out); HANDLER(price_db_).report(out); @@ -123,6 +124,7 @@ public: OPTION(session_t, account_); // -a OPTION(session_t, cache_); OPTION(session_t, download); // -Q + OPTION(session_t, european); OPTION__ (session_t, price_exp_, // -Z From a8db7bd303b6ecab8de975511e1ea9ccc27a2c81 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 02:55:22 -0500 Subject: [PATCH 25/39] Set default LESS options to -FRSX --- src/report.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/report.h b/src/report.h index e321cb44..e00c6460 100644 --- a/src/report.h +++ b/src/report.h @@ -654,7 +654,7 @@ public: if (have_less) { on(none, "less"); - setenv("LESS", "--quit-if-one-screen -R", 0); + setenv("LESS", "-FRSX", 0); // don't overwrite } } } From 1d1b9465e40cf122ad30e7aac21ebdba8513f5d9 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 03:44:32 -0500 Subject: [PATCH 26/39] Wire up the --european option --- src/session.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/session.h b/src/session.h index 4b8d2380..d8bfa05f 100644 --- a/src/session.h +++ b/src/session.h @@ -50,6 +50,7 @@ #include "account.h" #include "journal.h" #include "option.h" +#include "commodity.h" namespace ledger { @@ -124,7 +125,10 @@ public: OPTION(session_t, account_); // -a OPTION(session_t, cache_); OPTION(session_t, download); // -Q - OPTION(session_t, european); + + OPTION_(session_t, european, DO() { + commodity_t::base_t::european_by_default = true; + }); OPTION__ (session_t, price_exp_, // -Z From 60d016a21cabf35d6f1a97f713d217398f303f2b Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 03:50:26 -0500 Subject: [PATCH 27/39] Fleshed out the Python bindings for amount_t --- src/py_amount.cc | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/py_amount.cc b/src/py_amount.cc index 7fe12674..16e1807a 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -106,15 +106,18 @@ EXC_TRANSLATOR(amount_error) void export_amount() { class_< amount_t > ("Amount") + .add_static_property("current_pool", + make_getter(&amount_t::current_pool, + return_value_policy())) + .def("initialize", py_amount_initialize) // only for the PyUnitTests .staticmethod("initialize") .def("shutdown", &amount_t::shutdown) .staticmethod("shutdown") - .add_static_property("current_pool", - make_getter(&amount_t::current_pool, - return_value_policy())) - + .add_static_property("is_initialized", + make_getter(&amount_t::is_initialized), + make_setter(&amount_t::is_initialized)) .add_static_property("stream_fullstrings", make_getter(&amount_t::stream_fullstrings), make_setter(&amount_t::stream_fullstrings)) @@ -129,7 +132,8 @@ internal precision.")) .def(init()) - .def("compare", &amount_t::compare) + .def("compare", &amount_t::compare, args("amount"), + _("Compare two amounts for equality, returning <0, 0 or >0.")) .def(self == self) .def(self == long()) @@ -186,6 +190,10 @@ internal precision.")) .def(long() / self) .def("precision", &amount_t::precision) + .def("keep_precision", &amount_t::keep_precision) + .def("set_keep_precision", &amount_t::set_keep_precision, args("keep"), + _("Set whether an amount should always display at full precision.")) + .def("display_precision", &amount_t::display_precision) .def("negated", &amount_t::negated) .def("in_place_negate", &amount_t::in_place_negate, @@ -195,8 +203,19 @@ internal precision.")) .def("abs", &amount_t::abs) .def("__abs__", &amount_t::abs) + .def("inverted", &amount_t::inverted) + .def("rounded", &amount_t::rounded) + .def("in_place_round", &amount_t::in_place_round, + return_value_policy()) + + .def("truncated", &amount_t::truncated) + .def("in_place_truncate", &amount_t::in_place_truncate, + return_value_policy()) + .def("unrounded", &amount_t::unrounded) + .def("in_place_unround", &amount_t::in_place_unround, + return_value_policy()) .def("reduced", &amount_t::reduced) .def("in_place_reduce", &amount_t::in_place_reduce, @@ -207,9 +226,11 @@ internal precision.")) return_value_policy()) .def("value", py_value_0) - .def("value", py_value_1) - .def("value", py_value_2) - .def("value", py_value_3) + .def("value", py_value_1, args("primary_only")) + .def("value", py_value_2, args("primary_only", "moment")) + .def("value", py_value_3, args("primary_only", "moment", "in_terms_of")) + + .def("price", &amount_t::price) .def("sign", &amount_t::sign) .def("__nonzero__", &amount_t::is_nonzero) @@ -222,22 +243,21 @@ internal precision.")) .def("__float__", &amount_t::to_double) .def("to_long", &amount_t::to_long) .def("__int__", &amount_t::to_long) + .def("fits_in_long", &amount_t::fits_in_long) + .def("to_string", &amount_t::to_string) .def("__str__", &amount_t::to_string) .def("to_fullstring", &amount_t::to_fullstring) .def("__repr__", &amount_t::to_fullstring) - - .def("fits_in_long", &amount_t::fits_in_long) - .def("quantity_string", &amount_t::quantity_string) .def("commodity", &amount_t::commodity, return_value_policy()) + .def("has_commodity", &amount_t::has_commodity) .def("set_commodity", &amount_t::set_commodity, with_custodian_and_ward<1, 2>()) - - .def("has_commodity", &amount_t::has_commodity) .def("clear_commodity", &amount_t::clear_commodity) + .def("number", &amount_t::number) .def("annotate", &amount_t::annotate) From f9b833b685251e0787a8282a256588328bd68ad7 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 04:40:51 -0500 Subject: [PATCH 28/39] Corrected balance_t's arithmetic interface --- src/balance.h | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/balance.h b/src/balance.h index 5452510b..ad340aa5 100644 --- a/src/balance.h +++ b/src/balance.h @@ -207,7 +207,7 @@ public: template bool operator==(const T& val) const { - return *this == balance_t(val); + return *this == amount_t(val); } /** @@ -217,11 +217,29 @@ public: */ balance_t& operator+=(const balance_t& bal); balance_t& operator+=(const amount_t& amt); + balance_t& operator+=(const double val) { + return *this += amount_t(val); + } + balance_t& operator+=(const unsigned long val) { + return *this += amount_t(val); + } + balance_t& operator+=(const long val) { + return *this += amount_t(val); + } + balance_t& operator-=(const balance_t& bal); balance_t& operator-=(const amount_t& amt); + balance_t& operator-=(const double val) { + return *this -= amount_t(val); + } + balance_t& operator-=(const unsigned long val) { + return *this -= amount_t(val); + } + balance_t& operator-=(const long val) { + return *this -= amount_t(val); + } balance_t& operator*=(const amount_t& amt); - balance_t& operator*=(const double val) { return *this *= amount_t(val); } @@ -233,7 +251,6 @@ public: } balance_t& operator/=(const amount_t& amt); - balance_t& operator/=(const double val) { return *this /= amount_t(val); } @@ -278,7 +295,7 @@ public: * in_place_reduce() * in_place_unreduce() */ - balance_t negate() const { + balance_t negated() const { balance_t temp(*this); temp.in_place_negate(); return temp; @@ -288,7 +305,7 @@ public: pair.second.in_place_negate(); } balance_t operator-() const { - return negate(); + return negated(); } balance_t abs() const { @@ -388,6 +405,13 @@ public: * it. */ operator bool() const { + return is_nonzero(); + } + + bool is_nonzero() const { + if (is_empty()) + return false; + foreach (const amounts_map::value_type& pair, amounts) if (pair.second.is_nonzero()) return true; @@ -433,6 +457,7 @@ public: else throw_(balance_error, _("Cannot convert a balance with multiple commodities to an amount")); + return amount_t(); } /** From 4e78dcff3f7aa9b829ce543022cf0f5f42769db9 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 04:41:07 -0500 Subject: [PATCH 29/39] Fixes to the Python bindings for amount_t --- src/py_amount.cc | 106 +++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/src/py_amount.cc b/src/py_amount.cc index 16e1807a..efae7514 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -42,59 +42,66 @@ namespace ledger { using namespace boost::python; -boost::optional py_value_0(const amount_t& amount) { - return amount.value(); -} -boost::optional py_value_1(const amount_t& amount, - const bool primary_only) { - return amount.value(primary_only); -} -boost::optional py_value_2(const amount_t& amount, - const bool primary_only, - const boost::optional& moment) { - return amount.value(primary_only, moment); -} -boost::optional py_value_3(const amount_t& amount, - const bool primary_only, - const boost::optional& moment, - const boost::optional& in_terms_of) { - return amount.value(primary_only, moment, in_terms_of); -} +namespace { -void py_parse_2(amount_t& amount, object in, unsigned char flags) { - if (PyFile_Check(in.ptr())) { - pyifstream instr(reinterpret_cast(in.ptr())); - amount.parse(instr, flags); - } else { - PyErr_SetString(PyExc_IOError, - _("Argument to amount.parse(file) is not a file object")); + boost::optional py_value_0(const amount_t& amount) { + return amount.value(); } -} -void py_parse_1(amount_t& amount, object in) { - py_parse_2(amount, in, 0); -} - -void py_parse_str_1(amount_t& amount, const string& str) { - amount.parse(str); -} -void py_parse_str_2(amount_t& amount, const string& str, unsigned char flags) { - amount.parse(str, flags); -} - -void py_print(amount_t& amount, object out) -{ - if (PyFile_Check(out.ptr())) { - pyofstream outstr(reinterpret_cast(out.ptr())); - amount.print(outstr); - } else { - PyErr_SetString(PyExc_IOError, - _("Argument to amount.print_(file) is not a file object")); + boost::optional py_value_1(const amount_t& amount, + const bool primary_only) { + return amount.value(primary_only); } -} -void py_amount_initialize() { - amount_t::initialize(); -} + boost::optional + py_value_2(const amount_t& amount, + const bool primary_only, + const boost::optional& moment) { + return amount.value(primary_only, moment); + } + + boost::optional + py_value_3(const amount_t& amount, + const bool primary_only, + const boost::optional& moment, + const boost::optional& in_terms_of) { + return amount.value(primary_only, moment, in_terms_of); + } + + void py_parse_2(amount_t& amount, object in, unsigned char flags) { + if (PyFile_Check(in.ptr())) { + pyifstream instr(reinterpret_cast(in.ptr())); + amount.parse(instr, flags); + } else { + PyErr_SetString(PyExc_IOError, + _("Argument to amount.parse(file) is not a file object")); + } + } + void py_parse_1(amount_t& amount, object in) { + py_parse_2(amount, in, 0); + } + + void py_parse_str_1(amount_t& amount, const string& str) { + amount.parse(str); + } + void py_parse_str_2(amount_t& amount, const string& str, unsigned char flags) { + amount.parse(str, flags); + } + + void py_print(amount_t& amount, object out) { + if (PyFile_Check(out.ptr())) { + pyofstream outstr(reinterpret_cast(out.ptr())); + amount.print(outstr); + } else { + PyErr_SetString(PyExc_IOError, + _("Argument to amount.print_(file) is not a file object")); + } + } + + void py_amount_initialize() { + amount_t::initialize(); + } + +} // unnamed namespace #define EXC_TRANSLATOR(type) \ void exc_translate_ ## type(const type& err) { \ @@ -276,7 +283,6 @@ internal precision.")) .staticmethod("parse_conversion") .def("print_", py_print) - .def("dump", &amount_t::dump) .def("valid", &amount_t::valid) From c03fd75d09a1c6f9855030726df638f6489b693f Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 04:41:14 -0500 Subject: [PATCH 30/39] Completed Python bindings for balance_t --- src/py_balance.cc | 378 +++++++++++++++++++++------------------------- 1 file changed, 169 insertions(+), 209 deletions(-) diff --git a/src/py_balance.cc b/src/py_balance.cc index 086b7b12..2d940876 100644 --- a/src/py_balance.cc +++ b/src/py_balance.cc @@ -32,11 +32,84 @@ #include #include "pyinterp.h" +#include "pyutils.h" +#include "pyfstream.h" +#include "commodity.h" +#include "annotate.h" +#include "balance.h" namespace ledger { using namespace boost::python; +namespace { + + boost::optional py_value_0(const balance_t& balance) { + return balance.value(); + } + boost::optional py_value_1(const balance_t& balance, + const bool primary_only) { + return balance.value(primary_only); + } + + boost::optional + py_value_2(const balance_t& balance, + const bool primary_only, + const boost::optional& moment) { + return balance.value(primary_only, moment); + } + + boost::optional + py_value_3(const balance_t& balance, + const bool primary_only, + const boost::optional& moment, + const boost::optional& in_terms_of) { + return balance.value(primary_only, moment, in_terms_of); + } + + boost::optional + py_commodity_amount_0(const balance_t& balance) { + return balance.commodity_amount(); + } + + boost::optional + py_commodity_amount_1(const balance_t& balance, + const boost::optional& commodity) { + return balance.commodity_amount(commodity); + } + + void py_print(balance_t& balance, object out) { + if (PyFile_Check(out.ptr())) { + pyofstream outstr(reinterpret_cast(out.ptr())); + balance.print(outstr); + } else { + PyErr_SetString(PyExc_IOError, + _("Argument to balance.print_(file) is not a file object")); + } + } + + long balance_len(balance_t& bal) { + return bal.amounts.size(); + } + + amount_t balance_getitem(balance_t& bal, long i) { + long len = bal.amounts.size(); + + if (labs(i) >= len) { + PyErr_SetString(PyExc_IndexError, _("Index out of range")); + throw_error_already_set(); + } + + long x = i < 0 ? len + i : i; + balance_t::amounts_map::iterator elem = bal.amounts.begin(); + while (--x >= 0) + elem++; + + return (*elem).second; + } + +} // unnamed namespace + #define EXC_TRANSLATOR(type) \ void exc_translate_ ## type(const type& err) { \ PyErr_SetString(PyExc_ArithmeticError, err.what()); \ @@ -46,221 +119,108 @@ EXC_TRANSLATOR(balance_error) void export_balance() { -#if 0 class_< balance_t > ("Balance") + .def(init()) + .def(init()) + .def(init()) + .def(init()) + + .def(self += self) + .def(self += other()) + .def(self += long()) + .def(self + self) + .def(self + other()) + .def(self + long()) + .def(self -= self) + .def(self -= other()) + .def(self -= long()) + .def(self - self) + .def(self - other()) + .def(self - long()) + .def(self *= other()) + .def(self *= long()) + .def(self * other()) + .def(self * long()) + .def(self /= other()) + .def(self /= long()) + .def(self / other()) + .def(self / long()) + .def(- self) + + .def(self == self) + .def(self == other()) + .def(self == long()) + .def(self != self) + .def(self != other()) + .def(self != long()) + .def(! self) + + .def(self_ns::str(self)) + + .def("negated", &balance_t::negated) + .def("in_place_negate", &balance_t::in_place_negate, + return_value_policy()) + .def(- self) + + .def("abs", &balance_t::abs) + .def("__abs__", &balance_t::abs) + + .def("__len__", balance_len) + .def("__getitem__", balance_getitem) + + .def("rounded", &balance_t::rounded) + .def("in_place_round", &balance_t::in_place_round, + return_value_policy()) + + .def("truncated", &balance_t::truncated) + .def("in_place_truncate", &balance_t::in_place_truncate, + return_value_policy()) + + .def("unrounded", &balance_t::unrounded) + .def("in_place_unround", &balance_t::in_place_unround, + return_value_policy()) + + .def("reduced", &balance_t::reduced) + .def("in_place_reduce", &balance_t::in_place_reduce, + return_value_policy()) + + .def("unreduced", &balance_t::unreduced) + .def("in_place_unreduce", &balance_t::in_place_unreduce, + return_value_policy()) + + .def("value", py_value_0) + .def("value", py_value_1, args("primary_only")) + .def("value", py_value_2, args("primary_only", "moment")) + .def("value", py_value_3, args("primary_only", "moment", "in_terms_of")) + + .def("price", &balance_t::price) + + .def("__nonzero__", &balance_t::is_nonzero) + .def("is_nonzero", &balance_t::is_nonzero) + .def("is_zero", &balance_t::is_zero) + .def("is_realzero", &balance_t::is_realzero) + + .def("is_empty", &balance_t::is_empty) + .def("single_amount", &balance_t::single_amount) + + .def("to_amount", &balance_t::to_amount) + + .def("commodity_count", &balance_t::commodity_count) + .def("commodity_amount", py_commodity_amount_0) + .def("commodity_amount", py_commodity_amount_1) + + .def("strip_annotations", &balance_t::strip_annotations) + + .def("print_", py_print) + .def("dump", &balance_t::dump) + + .def("valid", &balance_t::valid) ; -#endif - - //register_optional_to_python(); - - //implicitly_convertible(); #define EXC_TRANSLATE(type) \ register_exception_translator(&exc_translate_ ## type); - //EXC_TRANSLATE(balance_error); + EXC_TRANSLATE(balance_error); } } // namespace ledger - -#if 0 -unsigned int balance_len(balance_t& bal) -{ - return bal.amounts.size(); -} - -amount_t balance_getitem(balance_t& bal, int i) -{ - std::size_t len = bal.amounts.size(); - - if (abs(i) >= len) { - PyErr_SetString(PyExc_IndexError, _("Index out of range")); - throw_error_already_set(); - } - - int x = i < 0 ? len + i : i; - balance_t::amounts_map::iterator elem = bal.amounts.begin(); - while (--x >= 0) - elem++; - - return (*elem).second; -} - -unsigned int balance_pair_len(balance_pair_t& bal_pair) -{ - return balance_len(bal_pair.quantity); -} - -amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i) -{ - return balance_getitem(bal_pair.quantity, i); -} - -void export_balance() -{ - class_< balance_t > ("Balance") - .def(init()) - .def(init()) - .def(init()) - .def(init()) - .def(init()) - - .def(self += self) - .def(self += other()) - .def(self += long()) - .def(self + self) - .def(self + other()) - .def(self + long()) - .def(self -= self) - .def(self -= other()) - .def(self -= long()) - .def(self - self) - .def(self - other()) - .def(self - long()) - .def(self *= self) - .def(self *= other()) - .def(self *= long()) - .def(self * self) - .def(self * other()) - .def(self * long()) - .def(self /= self) - .def(self /= other()) - .def(self /= long()) - .def(self / self) - .def(self / other()) - .def(self / long()) - .def(- self) - - .def(self < self) - .def(self < other()) - .def(self < long()) - .def(self <= self) - .def(self <= other()) - .def(self <= long()) - .def(self > self) - .def(self > other()) - .def(self > long()) - .def(self >= self) - .def(self >= other()) - .def(self >= long()) - .def(self == self) - .def(self == other()) - .def(self == long()) - .def(self != self) - .def(self != other()) - .def(self != long()) - .def(! self) - - .def(self_ns::str(self)) - - .def("__abs__", &balance_t::abs) - .def("__len__", balance_len) - .def("__getitem__", balance_getitem) - - .def("valid", &balance_t::valid) - - .def("realzero", &balance_t::realzero) - .def("amount", &balance_t::amount) - .def("value", &balance_t::value) - .def("price", &balance_t::price) - .def("date", &balance_t::date) - .def("strip_annotations", &balance_t::strip_annotations) - .def("write", &balance_t::write) - .def("round", &balance_t::round) - .def("negate", &balance_t::negate) - .def("negated", &balance_t::negated) - ; - - class_< balance_pair_t > ("BalancePair") - .def(init()) - .def(init()) - .def(init()) - .def(init()) - .def(init()) - .def(init()) - - .def(self += self) - .def(self += other()) - .def(self += other()) - .def(self += long()) - .def(self + self) - .def(self + other()) - .def(self + other()) - .def(self + long()) - .def(self -= self) - .def(self -= other()) - .def(self -= other()) - .def(self -= long()) - .def(self - self) - .def(self - other()) - .def(self - other()) - .def(self - long()) - .def(self *= self) - .def(self *= other()) - .def(self *= other()) - .def(self *= long()) - .def(self * self) - .def(self * other()) - .def(self * other()) - .def(self * long()) - .def(self /= self) - .def(self /= other()) - .def(self /= other()) - .def(self /= long()) - .def(self / self) - .def(self / other()) - .def(self / other()) - .def(self / long()) - .def(- self) - - .def(self < self) - .def(self < other()) - .def(self < other()) - .def(self < long()) - .def(self <= self) - .def(self <= other()) - .def(self <= other()) - .def(self <= long()) - .def(self > self) - .def(self > other()) - .def(self > other()) - .def(self > long()) - .def(self >= self) - .def(self >= other()) - .def(self >= other()) - .def(self >= long()) - .def(self == self) - .def(self == other()) - .def(self == other()) - .def(self == long()) - .def(self != self) - .def(self != other()) - .def(self != other()) - .def(self != long()) - .def(! self) - - .def(self_ns::str(self)) - - .def("__abs__", &balance_pair_t::abs) - .def("__len__", balance_pair_len) - .def("__getitem__", balance_pair_getitem) - - .def("valid", &balance_pair_t::valid) - - .def("realzero", &balance_pair_t::realzero) - .def("amount", &balance_pair_t::amount) - .def("value", &balance_pair_t::value) - .def("price", &balance_pair_t::price) - .def("date", &balance_pair_t::date) - .def("strip_annotations", &balance_pair_t::strip_annotations) - .def("write", &balance_pair_t::write) - .def("round", &balance_pair_t::round) - .def("negate", &balance_pair_t::negate) - .def("negated", &balance_pair_t::negated) - - .add_property("cost", - make_getter(&balance_pair_t::cost, - return_value_policy())) - ; -} -#endif From 5e1886b147df2e3265304246d06272e6bac049a5 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 04:41:32 -0500 Subject: [PATCH 31/39] Only --args-only is needed in LedgerHarness.py --- test/LedgerHarness.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/LedgerHarness.py b/test/LedgerHarness.py index 7e8cfa3d..8a5af123 100755 --- a/test/LedgerHarness.py +++ b/test/LedgerHarness.py @@ -53,10 +53,8 @@ class LedgerHarness: if columns: insert += ' --columns=80' - command = re.sub('\$ledger', '%s%s %s %s %s %s' % \ - (self.ledger, insert, '--args-only', - '--no-color', '--pager=none', - '--date-format=%y-%b-%d'), command) + command = re.sub('\$ledger', '%s%s %s' % \ + (self.ledger, insert, '--args-only'), command) return Popen(command, shell=True, close_fds=True, env=env, stdin=PIPE, stdout=PIPE, stderr=PIPE) From ede73e8889ce4c5b45ce837f312047b8d259fecf Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 16:00:32 -0500 Subject: [PATCH 32/39] Corrected an incorrect call to remove_account --- src/temps.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/temps.cc b/src/temps.cc index bf295997..012a573b 100644 --- a/src/temps.cc +++ b/src/temps.cc @@ -52,8 +52,8 @@ temporaries_t::~temporaries_t() if (acct_temps) { foreach (account_t& acct, *acct_temps) { - if (! acct.has_flags(ACCOUNT_TEMP)) - acct.remove_account(&acct); + if (acct.parent && ! acct.parent->has_flags(ACCOUNT_TEMP)) + acct.parent->remove_account(&acct); } } } From 3f8c126c798d575d27d199ee3337499f338dc1ee Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 16:57:53 -0500 Subject: [PATCH 33/39] Use is_annotated() method rather than "annotated" --- src/amount.cc | 6 +++--- src/annotate.cc | 4 ++-- src/annotate.h | 9 +++++++-- src/commodity.cc | 8 ++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 3ac47c59..435cdea4 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -783,7 +783,7 @@ void amount_t::annotate(const annotation_t& details) else if (! has_commodity()) return; // ignore attempt to annotate a "bare commodity - if (commodity().annotated) { + if (commodity().is_annotated()) { this_ann = &as_annotated_commodity(commodity()); this_base = &this_ann->referent(); } else { @@ -811,9 +811,9 @@ bool amount_t::is_annotated() const throw_(amount_error, _("Cannot determine if an uninitialized amount's commodity is annotated")); - assert(! has_commodity() || ! commodity().annotated || + assert(! has_commodity() || ! commodity().is_annotated() || as_annotated_commodity(commodity()).details); - return has_commodity() && commodity().annotated; + return has_commodity() && commodity().is_annotated(); } annotation_t& amount_t::annotation() diff --git a/src/annotate.cc b/src/annotate.cc index c6084f7f..9c676086 100644 --- a/src/annotate.cc +++ b/src/annotate.cc @@ -135,13 +135,13 @@ void annotation_t::print(std::ostream& out, bool keep_base) const bool keep_details_t::keep_all(const commodity_t& comm) const { - return (! comm.annotated || + return (! comm.is_annotated() || (keep_price && keep_date && keep_tag && ! only_actuals)); } bool keep_details_t::keep_any(const commodity_t& comm) const { - return comm.annotated && (keep_price || keep_date || keep_tag); + return comm.is_annotated() && (keep_price || keep_date || keep_tag); } bool annotated_commodity_t::operator==(const commodity_t& comm) const diff --git a/src/annotate.h b/src/annotate.h index 77dd9372..cb2a1161 100644 --- a/src/annotate.h +++ b/src/annotate.h @@ -185,9 +185,10 @@ class annotated_commodity_t equality_comparable2 > { -public: +protected: + friend class commodity_pool_t; + commodity_t * ptr; - annotation_t details; explicit annotated_commodity_t(commodity_t * _ptr, const annotation_t& _details) @@ -195,6 +196,10 @@ public: TRACE_CTOR(annotated_commodity_t, "commodity_t *, annotation_t"); annotated = true; } + +public: + annotation_t details; + virtual ~annotated_commodity_t() { TRACE_DTOR(annotated_commodity_t); } diff --git a/src/commodity.cc b/src/commodity.cc index 689cf466..26038a0b 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -604,11 +604,11 @@ bool compare_amount_commodities::operator()(const amount_t * left, if (cmp != 0) return cmp < 0; - if (! leftcomm.annotated) { - return rightcomm.annotated; + if (! leftcomm.is_annotated()) { + return rightcomm.is_annotated(); } - else if (! rightcomm.annotated) { - return ! leftcomm.annotated; + else if (! rightcomm.is_annotated()) { + return ! leftcomm.is_annotated(); } else { annotated_commodity_t& aleftcomm(static_cast(leftcomm)); From cec0f5ec4932e31aa9a0a09af63b9f4f0bca1d85 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 16:58:10 -0500 Subject: [PATCH 34/39] Moved make_qualified_name into commodity_pool_t --- src/pool.cc | 28 +++++++++++++--------------- src/pool.h | 3 +++ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/pool.cc b/src/pool.cc index 68ba3ed7..06a4706c 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -108,25 +108,23 @@ commodity_pool_t::create(const string& symbol, const annotation_t& details) return new_comm; } -namespace { - string make_qualified_name(const commodity_t& comm, - const annotation_t& details) - { - assert(details); +string commodity_pool_t::make_qualified_name(const commodity_t& comm, + const annotation_t& details) +{ + assert(details); - if (details.price && details.price->sign() < 0) - throw_(amount_error, _("A commodity's price may not be negative")); + if (details.price && details.price->sign() < 0) + throw_(amount_error, _("A commodity's price may not be negative")); - std::ostringstream name; - comm.print(name); - details.print(name, comm.parent().keep_base); + std::ostringstream name; + comm.print(name); + details.print(name, comm.parent().keep_base); - DEBUG("amounts.commodities", "make_qualified_name for " - << *comm.qualified_symbol << std::endl << details); - DEBUG("amounts.commodities", "qualified_name is " << name.str()); + DEBUG("amounts.commodities", "make_qualified_name for " + << *comm.qualified_symbol << std::endl << details); + DEBUG("amounts.commodities", "qualified_name is " << name.str()); - return name.str(); - } + return name.str(); } commodity_t * diff --git a/src/pool.h b/src/pool.h index 6fce0c59..7e54e595 100644 --- a/src/pool.h +++ b/src/pool.h @@ -98,6 +98,9 @@ public: checked_delete(pair.second); } + string make_qualified_name(const commodity_t& comm, + const annotation_t& details); + commodity_t * create(const string& symbol); commodity_t * find(const string& name); commodity_t * find_or_create(const string& symbol); From dea9530cb7d65486143b866b60d9bd1e4914aa56 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 17:04:49 -0500 Subject: [PATCH 35/39] Renamed Python global "session" to "current_session" --- src/pyinterp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyinterp.cc b/src/pyinterp.cc index f5b1a543..9ad9a906 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -83,7 +83,7 @@ void initialize_for_python() export_value(); export_xact(); - scope().attr("session") = python_session; + scope().attr("current_session") = python_session; } struct python_run From e663a13502b8813a28b8aebbc611fbc040d4246b Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 17:05:51 -0500 Subject: [PATCH 36/39] Changed protection level of many parts of commodity_t --- src/commodity.cc | 46 +++++------ src/commodity.h | 199 +++++++++++++++++++++++------------------------ src/iterators.cc | 4 +- src/session.h | 2 +- 4 files changed, 122 insertions(+), 129 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index 26038a0b..d896572f 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -38,12 +38,12 @@ namespace ledger { -bool commodity_t::base_t::european_by_default = false; +bool commodity_t::european_by_default = false; -void commodity_t::base_t::history_t::add_price(commodity_t& source, - const datetime_t& date, - const amount_t& price, - const bool reflexive) +void commodity_t::history_t::add_price(commodity_t& source, + const datetime_t& date, + const amount_t& price, + const bool reflexive) { DEBUG("commodity.prices.add", "add_price to " << source << (reflexive ? " (secondary)" : " (primary)") @@ -69,7 +69,7 @@ void commodity_t::base_t::history_t::add_price(commodity_t& source, } } -bool commodity_t::base_t::history_t::remove_price(const datetime_t& date) +bool commodity_t::history_t::remove_price(const datetime_t& date) { DEBUG("commodity.prices.add", "remove_price: " << date); @@ -79,7 +79,7 @@ bool commodity_t::base_t::history_t::remove_price(const datetime_t& date) return false; } -void commodity_t::base_t::varied_history_t:: +void commodity_t::varied_history_t:: add_price(commodity_t& source, const datetime_t& date, const amount_t& price, @@ -99,9 +99,8 @@ void commodity_t::base_t::varied_history_t:: hist->add_price(source, date, price, reflexive); } -bool commodity_t::base_t::varied_history_t:: - remove_price(const datetime_t& date, - commodity_t& comm) +bool commodity_t::varied_history_t::remove_price(const datetime_t& date, + commodity_t& comm) { DEBUG("commodity.prices.add", "varied_remove_price: " << date << ", " << comm); @@ -111,13 +110,12 @@ bool commodity_t::base_t::varied_history_t:: } optional - commodity_t::base_t::history_t:: - find_price(const optional& moment, - const optional& oldest +commodity_t::history_t::find_price(const optional& moment, + const optional& oldest #if defined(DEBUG_ON) - , const int indent + , const int indent #endif - ) const + ) const { price_point_t point; bool found = false; @@ -222,15 +220,14 @@ optional } optional - commodity_t::base_t::varied_history_t:: - find_price(const commodity_t& source, - const optional& commodity, - const optional& moment, - const optional& oldest +commodity_t::varied_history_t::find_price(const commodity_t& source, + const optional& commodity, + const optional& moment, + const optional& oldest #if defined(DEBUG_ON) - , const int indent + , const int indent #endif - ) const + ) const { optional point; optional limit = oldest; @@ -354,9 +351,8 @@ optional return none; } -optional - commodity_t::base_t::varied_history_t:: - history(const optional& commodity) +optional +commodity_t::varied_history_t::history(const optional& commodity) { commodity_t * comm = NULL; if (! commodity) { diff --git a/src/commodity.h b/src/commodity.h index af92271e..25397131 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -86,87 +86,85 @@ class commodity_t : public delegates_flags, public equality_comparable1 { - friend class commodity_pool_t; - public: + typedef std::map history_map; + + struct history_t + { + history_map prices; + + void add_price(commodity_t& source, + const datetime_t& date, + const amount_t& price, + const bool reflexive = true); + bool remove_price(const datetime_t& date); + + optional + find_price(const optional& moment = none, + const optional& oldest = none +#if defined(DEBUG_ON) + , const int indent = 0 +#endif + ) const; + +#if defined(HAVE_BOOST_SERIALIZATION) + private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive & ar, const unsigned int /* version */) { + ar & prices; + } +#endif // HAVE_BOOST_SERIALIZATION + }; + + typedef std::map history_by_commodity_map; + + struct varied_history_t + { + history_by_commodity_map histories; + + void add_price(commodity_t& source, + const datetime_t& date, + const amount_t& price, + const bool reflexive = true); + bool remove_price(const datetime_t& date, commodity_t& commodity); + + optional + find_price(const commodity_t& source, + const optional& commodity = none, + const optional& moment = none, + const optional& oldest = none +#if defined(DEBUG_ON) + , const int indent = 0 +#endif + ) const; + + optional + history(const optional& commodity = none); + +#if defined(HAVE_BOOST_SERIALIZATION) + private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive & ar, const unsigned int /* version */) { + ar & histories; + } +#endif // HAVE_BOOST_SERIALIZATION + }; + +protected: + friend class commodity_pool_t; + friend class annotated_commodity_t; + class base_t : public noncopyable, public supports_flags { - base_t() { - TRACE_CTOR(base_t, ""); - } - public: - typedef std::map history_map; - - struct history_t - { - history_map prices; - - void add_price(commodity_t& source, - const datetime_t& date, - const amount_t& price, - const bool reflexive = true); - bool remove_price(const datetime_t& date); - - optional - find_price(const optional& moment = none, - const optional& oldest = none -#if defined(DEBUG_ON) - , const int indent = 0 -#endif - ) const; - -#if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ - - friend class boost::serialization::access; - - template - void serialize(Archive & ar, const unsigned int /* version */) { - ar & prices; - } -#endif // HAVE_BOOST_SERIALIZATION - }; - - typedef std::map history_by_commodity_map; - - struct varied_history_t - { - history_by_commodity_map histories; - - void add_price(commodity_t& source, - const datetime_t& date, - const amount_t& price, - const bool reflexive = true); - bool remove_price(const datetime_t& date, commodity_t& commodity); - - optional - find_price(const commodity_t& source, - const optional& commodity = none, - const optional& moment = none, - const optional& oldest = none -#if defined(DEBUG_ON) - , const int indent = 0 -#endif - ) const; - - optional - history(const optional& commodity = none); - -#if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ - - friend class boost::serialization::access; - - template - void serialize(Archive & ar, const unsigned int /* version */) { - ar & histories; - } -#endif // HAVE_BOOST_SERIALIZATION - }; - #define COMMODITY_STYLE_DEFAULTS 0x000 #define COMMODITY_STYLE_SUFFIXED 0x001 #define COMMODITY_STYLE_SEPARATED 0x002 @@ -188,11 +186,9 @@ public: mutable bool searched; - static bool european_by_default; - public: explicit base_t(const string& _symbol) - : supports_flags(european_by_default ? + : supports_flags(commodity_t::european_by_default ? COMMODITY_STYLE_EUROPEAN : COMMODITY_STYLE_DEFAULTS), symbol(_symbol), precision(0), searched(false) { @@ -203,33 +199,31 @@ public: } #if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ + private: + base_t() { + TRACE_CTOR(base_t, ""); + } - friend class boost::serialization::access; + /** Serialization. */ - template - void serialize(Archive & ar, const unsigned int /* version */) { - ar & boost::serialization::base_object >(*this); - ar & symbol; - ar & precision; - ar & name; - ar & note; - ar & varied_history; - ar & smaller; - ar & larger; - } + friend class boost::serialization::access; + + template + void serialize(Archive & ar, const unsigned int /* version */) { + ar & boost::serialization::base_object >(*this); + ar & symbol; + ar & precision; + ar & name; + ar & note; + ar & varied_history; + ar & smaller; + ar & larger; + } #endif // HAVE_BOOST_SERIALIZATION }; -public: static bool symbol_needs_quotes(const string& symbol); - typedef base_t::history_t history_t; - typedef base_t::history_map history_map; - typedef base_t::varied_history_t varied_history_t; - typedef base_t::history_by_commodity_map history_by_commodity_map; - shared_ptr base; commodity_pool_t * parent_; @@ -237,13 +231,16 @@ public: optional mapping_key_; bool annotated; -public: explicit commodity_t(commodity_pool_t * _parent, const shared_ptr& _base) : delegates_flags(*_base.get()), base(_base), parent_(_parent), annotated(false) { TRACE_CTOR(commodity_t, "commodity_pool_t *, shared_ptr"); } + +public: + static bool european_by_default; + virtual ~commodity_t() { TRACE_DTOR(commodity_t); } diff --git a/src/iterators.cc b/src/iterators.cc index 50c67ade..540ba8ae 100644 --- a/src/iterators.cc +++ b/src/iterators.cc @@ -94,9 +94,9 @@ void posts_commodities_iterator::reset(journal_t& journal) comm->varied_history()) { account_t * account = journal.master->find_account(comm->symbol()); - foreach (commodity_t::base_t::history_by_commodity_map::value_type pair, + foreach (commodity_t::history_by_commodity_map::value_type pair, history->histories) { - foreach (commodity_t::base_t::history_map::value_type hpair, + foreach (commodity_t::history_map::value_type hpair, pair.second.prices) { xact_t * xact; string symbol = hpair.second.commodity().symbol(); diff --git a/src/session.h b/src/session.h index d8bfa05f..58e33f6b 100644 --- a/src/session.h +++ b/src/session.h @@ -127,7 +127,7 @@ public: OPTION(session_t, download); // -Q OPTION_(session_t, european, DO() { - commodity_t::base_t::european_by_default = true; + commodity_t::european_by_default = true; }); OPTION__ From 142c3ab7bfd04a099857d511f705cf4bf08e5e07 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 17:17:00 -0500 Subject: [PATCH 37/39] Removed an unnecessary second call to phase_makeall --- acprep | 2 -- 1 file changed, 2 deletions(-) diff --git a/acprep b/acprep index 3ee47026..915d3dca 100755 --- a/acprep +++ b/acprep @@ -1337,8 +1337,6 @@ class PrepareBuild(CommandLineApp): def phase_proof(self, *args): self.log.info('Executing phase: proof') - self.phase_makeall(reset=False, *args) - self.log.info('=== Copying source tree ===') self.phase_rsync() self.phase_makeall(reset=True, *args) From ff5506801d1b6dcb48e7015a01bbf6792585292a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 17:19:53 -0500 Subject: [PATCH 38/39] Whitespace fix --- src/account.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/account.h b/src/account.h index c8f6bdbd..4ac69532 100644 --- a/src/account.h +++ b/src/account.h @@ -195,7 +195,6 @@ public: { TRACE_CTOR(account_t::xdata_t, "copy"); } - ~xdata_t() throw() { TRACE_DTOR(account_t::xdata_t); } From d6790072eff9cb2a938ee9ed204263ee277a6874 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Nov 2009 17:34:59 -0500 Subject: [PATCH 39/39] Wrap the call to acprep proof in a call to "time" --- tools/proof | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/proof b/tools/proof index ede22558..7c5a16f2 100755 --- a/tools/proof +++ b/tools/proof @@ -14,7 +14,7 @@ fi rm -fr ~/Products/ledger* -./acprep -j16 --warn proof 2>&1 | tee ~/Desktop/proof.log +time ./acprep -j16 --warn proof 2>&1 | tee ~/Desktop/proof.log if egrep -q '(ERROR|CRITICAL)' ~/Desktop/proof.log; then if [[ "$1" = "--alert" ]]; then