diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/account.cc | 45 | ||||
-rw-r--r-- | src/account.h | 37 | ||||
-rw-r--r-- | src/balance.h | 3 | ||||
-rw-r--r-- | src/filters.cc | 113 | ||||
-rw-r--r-- | src/filters.h | 99 | ||||
-rw-r--r-- | src/item.h | 1 | ||||
-rw-r--r-- | src/op.cc | 2 | ||||
-rw-r--r-- | src/output.cc | 6 | ||||
-rw-r--r-- | src/post.cc | 22 | ||||
-rw-r--r-- | src/report.cc | 36 | ||||
-rw-r--r-- | src/report.h | 44 | ||||
-rw-r--r-- | src/temps.cc | 124 | ||||
-rw-r--r-- | src/temps.h | 84 | ||||
-rw-r--r-- | src/textual.cc | 6 | ||||
-rw-r--r-- | src/utils.h | 5 | ||||
-rw-r--r-- | src/value.cc | 40 | ||||
-rw-r--r-- | src/xact.cc | 63 | ||||
-rw-r--r-- | src/xact.h | 4 |
19 files changed, 523 insertions, 213 deletions
diff --git a/Makefile.am b/Makefile.am index 2556e1df..d4494fa7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -76,6 +76,7 @@ libledger_report_la_SOURCES = \ src/precmd.cc \ src/chain.cc \ src/filters.cc \ + src/temps.cc \ src/report.cc \ src/session.cc @@ -124,6 +125,7 @@ pkginclude_HEADERS = \ src/session.h \ src/report.h \ src/filters.h \ + src/temps.h \ src/chain.h \ src/precmd.h \ src/derive.h \ diff --git a/src/account.cc b/src/account.cc index c2628134..c8fd3a6a 100644 --- a/src/account.cc +++ b/src/account.cc @@ -110,6 +110,14 @@ account_t * account_t::find_account_re(const string& regexp) return find_account_re_(this, mask_t(regexp)); } +bool account_t::remove_post(post_t * post) +{ + assert(! posts.empty()); + posts.remove(post); + post->account = NULL; + return true; +} + string account_t::fullname() const { if (! _fullname.empty()) { @@ -140,7 +148,7 @@ string account_t::partial_name(bool flat) const if (! flat) { std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY); assert(count > 0); - if (count > 1 || acct->has_flags(ACCOUNT_EXT_TO_DISPLAY)) + if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY)) break; } pname = acct->name + ":" + pname; @@ -206,7 +214,7 @@ namespace { acct = acct->parent) { std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY); assert(count > 0); - if (count > 1 || acct->has_flags(ACCOUNT_EXT_TO_DISPLAY)) + if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY)) depth++; } @@ -217,6 +225,11 @@ namespace { return string_value(out.str()); } + value_t get_latest_cleared(account_t& account) + { + return account.self_details().latest_cleared_post; + } + template <value_t (*Func)(account_t&)> value_t get_wrapper(call_scope_t& scope) { return (*Func)(find_scope<account_t>(scope)); @@ -256,6 +269,11 @@ expr_t::ptr_op_t account_t::lookup(const string& name) return WRAP_FUNCTOR(get_wrapper<&get_true>); break; + case 'l': + if (name == "latest_cleared") + return WRAP_FUNCTOR(get_wrapper<&get_latest_cleared>); + break; + case 'p': if (name == "partial_account") return WRAP_FUNCTOR(get_partial_name); @@ -310,7 +328,7 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const bool grandchildren_visited = false; foreach (const accounts_map::value_type& pair, accounts) { - if (pair.second->has_flags(flags) || + if (pair.second->has_xflags(flags) || pair.second->children_with_flags(flags)) count++; } @@ -362,21 +380,22 @@ account_t::xdata_t::details_t::operator+=(const details_t& other) value_t account_t::self_total(const optional<expr_t&>& expr) const { if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) { - if (! xdata_) xdata_ = xdata_t(); - - posts_deque::const_iterator i = - posts.begin() + xdata_->self_details.last_size; + posts_list::const_iterator i; + if (xdata_->self_details.last_post) + i = *xdata_->self_details.last_post; + else + i = posts.begin(); for (; i != posts.end(); i++) { - if ((*i)->xdata().has_flags(POST_EXT_VISITED) && - ! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) { - (*i)->add_to_value(xdata_->self_details.total, expr); - (*i)->xdata().add_flags(POST_EXT_CONSIDERED); + 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_post = i; } - xdata_->self_details.last_size = posts.size(); - return xdata_->self_details.total; } else { return NULL_VALUE; diff --git a/src/account.h b/src/account.h index 56c0c72b..428f6c63 100644 --- a/src/account.h +++ b/src/account.h @@ -55,7 +55,7 @@ class account_t; class xact_t; class post_t; -typedef std::deque<post_t *> posts_deque; +typedef std::list<post_t *> posts_list; typedef std::map<const string, account_t *> accounts_map; /** @@ -63,35 +63,37 @@ typedef std::map<const string, account_t *> accounts_map; * * Long. */ -class account_t : public scope_t +class account_t : public supports_flags<>, public scope_t { - public: +#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account +#define ACCOUNT_KNOWN 0x01 +#define ACCOUNT_TEMP 0x02 // account is a temporary object + +public: account_t * parent; string name; optional<string> note; unsigned short depth; accounts_map accounts; - posts_deque posts; - bool known; + posts_list posts; mutable string _fullname; account_t(account_t * _parent = NULL, const string& _name = "", const optional<string>& _note = none) - : scope_t(), parent(_parent), name(_name), note(_note), - depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)), - known(false) { + : supports_flags<>(), scope_t(), parent(_parent), + name(_name), note(_note), + depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)) { TRACE_CTOR(account_t, "account_t *, const string&, const string&"); } account_t(const account_t& other) - : scope_t(), + : supports_flags<>(other.flags()), scope_t(), parent(other.parent), name(other.name), note(other.note), depth(other.depth), - accounts(other.accounts), - known(other.known) { + accounts(other.accounts) { TRACE_CTOR(account_t, "copy"); } ~account_t(); @@ -116,6 +118,7 @@ class account_t : public scope_t void add_post(post_t * post) { posts.push_back(post); } + bool remove_post(post_t * post); virtual expr_t::ptr_op_t lookup(const string& name); @@ -140,7 +143,6 @@ class account_t : public scope_t bool calculated; bool gathered; - // The following are only calculated if --totals is enabled std::size_t posts_count; std::size_t posts_virtuals_count; std::size_t posts_cleared_count; @@ -153,13 +155,12 @@ class account_t : public scope_t date_t latest_post; date_t latest_cleared_post; - std::size_t last_size; - - // The following are only calculated if --gather is enabled std::set<path> filenames; std::set<string> accounts_referenced; std::set<string> payees_referenced; + optional<posts_list::const_iterator> last_post; + details_t() : calculated(false), gathered(false), @@ -169,9 +170,7 @@ class account_t : public scope_t posts_cleared_count(0), posts_last_7_count(0), posts_last_30_count(0), - posts_this_month_count(0), - - last_size(0) {} + posts_this_month_count(0) {} details_t& operator+=(const details_t& other); @@ -229,7 +228,7 @@ class account_t : public scope_t const xdata_t::details_t& self_details(bool gather_all = true) const; const xdata_t::details_t& family_details(bool gather_all = true) const; - bool has_flags(xdata_t::flags_t flags) const { + bool has_xflags(xdata_t::flags_t flags) const { return xdata_ && xdata_->has_flags(flags); } std::size_t children_with_flags(xdata_t::flags_t flags) const; diff --git a/src/balance.h b/src/balance.h index 765c46dd..fe8afe2b 100644 --- a/src/balance.h +++ b/src/balance.h @@ -417,6 +417,9 @@ public: bool is_empty() const { return amounts.size() == 0; } + bool single_amount() const { + return amounts.size() == 1; + } /** * Conversion methods. A balance can be converted to an amount, but diff --git a/src/filters.cc b/src/filters.cc index 08e7a22f..25649ad0 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -140,11 +140,11 @@ void anonymize_posts::operator()(post_t& post) bool copy_xact_details = false; if (last_xact != post.xact) { - xact_temps.push_back(*post.xact); + temps.copy_xact(*post.xact); last_xact = post.xact; copy_xact_details = true; } - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.last_xact(); if (copy_xact_details) { xact.copy_details(*post.xact); @@ -157,10 +157,6 @@ void anonymize_posts::operator()(post_t& post) xact.note = none; } - post_temps.push_back(post); - post_t& temp = post_temps.back(); - temp.xact = &xact; - std::list<string> account_names; account_t * new_account = NULL; @@ -183,13 +179,8 @@ void anonymize_posts::operator()(post_t& post) foreach (const string& name, account_names) new_account = new_account->find_account(name); - temp.copy_details(post); - - temp.account = new_account; - temp.note = none; - temp.add_flags(ITEM_TEMP); - - xact.add_post(&temp); + post_t& temp = temps.copy_post(post, xact, new_account); + temp.note = none; (*handler)(temp); } @@ -227,18 +218,14 @@ namespace { void handle_value(const value_t& value, account_t * account, xact_t * xact, - std::list<post_t>& temps, + temporaries_t& temps, item_handler<post_t>& handler, const date_t& date = date_t(), const value_t& total = value_t(), const bool direct_amount = false, const optional<post_functor_t>& functor = none) { - temps.push_back(post_t(account)); - post_t& post(temps.back()); - post.xact = xact; - post.add_flags(ITEM_TEMP); - xact->add_post(&post); + post_t& post = temps.create_post(*xact, account); // If the account for this post is all virtual, then report the post as // such. This allows subtotal reports to show "(Account)" for accounts @@ -325,14 +312,13 @@ void collapse_posts::report_subtotal() earliest_date = reported; } - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = last_xact->payee; xact._date = (is_valid(earliest_date) ? earliest_date : last_xact->_date); DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date); - handle_value(subtotal, &totals_account, &xact, post_temps, *handler); + handle_value(subtotal, &totals_account, &xact, temps, *handler); } component_posts.clear(); @@ -427,12 +413,11 @@ void changed_value_posts::output_revaluation(post_t * post, const date_t& date) DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = " << diff.strip_annotations(report.what_to_keep())); - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = _("Commodities revalued"); xact._date = is_valid(date) ? date : post->date(); - handle_value(diff, &revalued_account, &xact, post_temps, *handler, + handle_value(diff, &revalued_account, &xact, temps, *handler, *xact._date, repriced_total, false, optional<post_functor_t> (bind(&changed_value_posts::output_rounding, this, _1))); @@ -465,13 +450,12 @@ void changed_value_posts::output_rounding(post_t * post) DEBUG("filter.changed_value.rounding", "rounding.diff = " << diff); - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = _("Commodity rounding"); xact._date = post->date(); - handle_value(diff, &rounding_account, &xact, post_temps, - *handler, *xact._date, precise_display_total, true); + handle_value(diff, &rounding_account, &xact, temps, *handler, + *xact._date, precise_display_total, true); } } } @@ -526,13 +510,12 @@ void subtotal_posts::report_subtotal(const char * spec_fmt, out_date << "- " << format_date(*range_finish); } - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = out_date.str(); xact._date = *range_start; foreach (values_map::value_type& pair, values) - handle_value(pair.second.value, pair.second.account, &xact, post_temps, + handle_value(pair.second.value, pair.second.account, &xact, temps, *handler); values.clear(); @@ -596,16 +579,12 @@ void interval_posts::operator()(post_t& post) // Generate a null posting, so the intervening periods can be // seen when -E is used, or if the calculated amount ends up being // non-zero - xact_temps.push_back(xact_t()); - xact_t& null_xact = xact_temps.back(); - null_xact.add_flags(ITEM_TEMP); + xact_t& null_xact = temps.create_xact(); null_xact._date = last_interval.inclusive_end(); - post_temps.push_back(post_t(&empty_account)); - post_t& null_post = post_temps.back(); - null_post.add_flags(ITEM_TEMP | POST_CALCULATED); + post_t& null_post = temps.create_post(null_xact, &empty_account); + null_post.add_flags(POST_CALCULATED); null_post.amount = 0L; - null_xact.add_post(&null_post); last_post = &null_post; subtotal_posts::operator()(null_post); @@ -637,14 +616,13 @@ void posts_as_equity::report_subtotal() } component_posts.clear(); - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = _("Opening Balances"); xact._date = finish; value_t total = 0L; foreach (values_map::value_type& pair, values) { - handle_value(pair.second.value, pair.second.account, &xact, post_temps, + handle_value(pair.second.value, pair.second.account, &xact, temps, *handler); total += pair.second.value; } @@ -653,19 +631,13 @@ void posts_as_equity::report_subtotal() if (total.is_balance()) { foreach (balance_t::amounts_map::value_type pair, total.as_balance().amounts) { - post_temps.push_back(post_t(balance_account)); - post_t& balance_post = post_temps.back(); - balance_post.add_flags(ITEM_TEMP); + post_t& balance_post = temps.create_post(xact, balance_account); balance_post.amount = - pair.second; - xact.add_post(&balance_post); (*handler)(balance_post); } } else { - post_temps.push_back(post_t(balance_account)); - post_t& balance_post = post_temps.back(); - balance_post.add_flags(ITEM_TEMP); + post_t& balance_post = temps.create_post(xact, balance_account); balance_post.amount = - total.to_amount(); - xact.add_post(&balance_post); (*handler)(balance_post); } } @@ -701,16 +673,11 @@ void by_payee_posts::operator()(post_t& post) void transfer_details::operator()(post_t& post) { - xact_temps.push_back(*post.xact); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.copy_xact(*post.xact); xact._date = post.date(); - post_temps.push_back(post); - post_t& temp = post_temps.back(); - temp.xact = &xact; + post_t& temp = temps.copy_post(post, xact); temp.set_state(post.state()); - temp.add_flags(ITEM_TEMP); - xact.add_post(&temp); bind_scope_t bound_scope(scope, temp); @@ -720,6 +687,7 @@ void transfer_details::operator()(post_t& post) break; case SET_ACCOUNT: temp.account = master->find_account(expr.calc(bound_scope).to_string()); + temp.account->add_post(&temp); break; default: assert(false); @@ -777,17 +745,21 @@ void budget_posts::report_budget_items(const date_t& date) DEBUG("ledger.walk.budget", "Reporting budget for " << post.reported_account()->fullname()); - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = _("Budget transaction"); xact._date = begin; - post_temps.push_back(post); - post_t& temp = post_temps.back(); - temp.xact = &xact; - temp.add_flags(ITEM_TEMP); + post_t& temp = temps.copy_post(post, xact); temp.amount.in_place_negate(); - xact.add_post(&temp); + + if (flags & BUDGET_WRAP_VALUES) { + value_t seq; + seq.push_back(0L); + seq.push_back(temp.amount); + + temp.xdata().compound_value = seq; + temp.xdata().add_flags(POST_EXT_COMPOUND); + } ++pair.first; begin = *pair.first.start; @@ -810,8 +782,8 @@ void budget_posts::operator()(post_t& post) acct = acct->parent) { if (acct == (*pair.second).reported_account()) { post_in_budget = true; - // Report the post as if it had occurred in the parent - // account. + // Report the post as if it had occurred in the parent account. + // jww (2009-10-27): What about calling add_post here? if (post.reported_account() != acct) post.xdata().account = acct; goto handle; @@ -867,16 +839,11 @@ void forecast_posts::flush() post_t& post = *(*least).second; - xact_temps.push_back(xact_t()); - xact_t& xact = xact_temps.back(); + xact_t& xact = temps.create_xact(); xact.payee = _("Forecast transaction"); xact._date = begin; - post_temps.push_back(post); - post_t& temp = post_temps.back(); - temp.xact = &xact; - temp.add_flags(ITEM_TEMP); - xact.add_post(&temp); + post_t& temp = temps.copy_post(post, xact); date_t next = *(*least).first.next; ++(*least).first; diff --git a/src/filters.h b/src/filters.h index a03d3160..3eb5da8d 100644 --- a/src/filters.h +++ b/src/filters.h @@ -50,6 +50,7 @@ #include "xact.h" #include "post.h" #include "account.h" +#include "temps.h" namespace ledger { @@ -279,11 +280,6 @@ public: } }; -inline void clear_xacts_posts(std::list<xact_t>& xacts_list) { - foreach (xact_t& xact, xacts_list) - xact.posts.clear(); -} - /** * @brief Brief * @@ -291,8 +287,7 @@ inline void clear_xacts_posts(std::list<xact_t>& xacts_list) { */ class anonymize_posts : public item_handler<post_t> { - std::list<xact_t> xact_temps; - std::list<post_t> post_temps; + temporaries_t temps; xact_t * last_xact; @@ -305,7 +300,6 @@ public: } virtual ~anonymize_posts() { TRACE_DTOR(anonymize_posts); - clear_xacts_posts(xact_temps); } virtual void operator()(post_t& post); @@ -346,18 +340,16 @@ public: */ class collapse_posts : public item_handler<post_t> { - expr_t& amount_expr; - item_predicate display_predicate; - item_predicate only_predicate; - value_t subtotal; - std::size_t count; - xact_t * last_xact; - post_t * last_post; - account_t totals_account; - bool only_collapse_if_zero; - - std::list<xact_t> xact_temps; - std::list<post_t> post_temps; + expr_t& amount_expr; + item_predicate display_predicate; + item_predicate only_predicate; + value_t subtotal; + std::size_t count; + xact_t * last_xact; + post_t * last_post; + temporaries_t temps; + account_t& totals_account; + bool only_collapse_if_zero; std::list<post_t *> component_posts; collapse_posts(); @@ -372,13 +364,12 @@ public: display_predicate(_display_predicate), only_predicate(_only_predicate), count(0), last_xact(NULL), last_post(NULL), - totals_account(NULL, _("<Total>")), + totals_account(temps.create_account(_("<Total>"))), only_collapse_if_zero(_only_collapse_if_zero) { TRACE_CTOR(collapse_posts, "post_handler_ptr"); } virtual ~collapse_posts() { TRACE_DTOR(collapse_posts); - clear_xacts_posts(xact_temps); } virtual void flush() { @@ -432,19 +423,17 @@ class changed_value_posts : public item_handler<post_t> // This filter requires that calc_posts be used at some point // later in the chain. - expr_t display_amount_expr; - expr_t total_expr; - expr_t display_total_expr; - report_t& report; - bool changed_values_only; - post_t * last_post; - value_t last_total; - value_t last_display_total; - account_t revalued_account; - account_t rounding_account; - - std::list<xact_t> xact_temps; - std::list<post_t> post_temps; + expr_t display_amount_expr; + expr_t total_expr; + expr_t display_total_expr; + report_t& report; + bool changed_values_only; + post_t * last_post; + value_t last_total; + value_t last_display_total; + temporaries_t temps; + account_t& revalued_account; + account_t& rounding_account; changed_value_posts(); @@ -459,14 +448,13 @@ public: display_amount_expr(_display_amount_expr), total_expr(_total_expr), display_total_expr(_display_total_expr), report(_report), changed_values_only(_changed_values_only), last_post(NULL), - revalued_account(NULL, _("<Revalued>")), - rounding_account(NULL, _("<Rounding>")){ + revalued_account(temps.create_account(_("<Revalued>"))), + rounding_account(temps.create_account(_("<Rounding>"))) { TRACE_CTOR(changed_value_posts, "post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool"); } virtual ~changed_value_posts() { TRACE_DTOR(changed_value_posts); - clear_xacts_posts(xact_temps); } virtual void flush(); @@ -517,8 +505,7 @@ protected: expr_t& amount_expr; values_map values; optional<string> date_format; - std::list<xact_t> xact_temps; - std::list<post_t> post_temps; + temporaries_t temps; std::list<post_t *> component_posts; public: @@ -531,7 +518,6 @@ public: } virtual ~subtotal_posts() { TRACE_DTOR(subtotal_posts); - clear_xacts_posts(xact_temps); } void report_subtotal(const char * spec_fmt = NULL, @@ -555,7 +541,7 @@ class interval_posts : public subtotal_posts date_interval_t interval; date_interval_t last_interval; post_t * last_post; - account_t empty_account; + account_t& empty_account; bool exact_periods; bool generate_empty_posts; @@ -569,11 +555,11 @@ public: bool _exact_periods = false, bool _generate_empty_posts = false) : subtotal_posts(_handler, amount_expr), interval(_interval), - last_post(NULL), empty_account(NULL, _("<None>")), + last_post(NULL), empty_account(temps.create_account(_("<None>"))), exact_periods(_exact_periods), generate_empty_posts(_generate_empty_posts) { TRACE_CTOR(interval_posts, - "post_handler_ptr, expr_t&, interval_t, account_t *, bool, bool"); + "post_handler_ptr, expr_t&, date_interval_t, bool, bool"); } virtual ~interval_posts() throw() { TRACE_DTOR(interval_posts); @@ -594,7 +580,7 @@ public: class posts_as_equity : public subtotal_posts { post_t * last_post; - account_t equity_account; + account_t& equity_account; account_t * balance_account; posts_as_equity(); @@ -602,7 +588,7 @@ class posts_as_equity : public subtotal_posts public: posts_as_equity(post_handler_ptr _handler, expr_t& amount_expr) : subtotal_posts(_handler, amount_expr), - equity_account(NULL, _("Equity")) { + equity_account(temps.create_account(_("Equity"))) { TRACE_CTOR(posts_as_equity, "post_handler_ptr, expr_t&"); balance_account = equity_account.find_account(_("Opening Balances")); } @@ -653,11 +639,10 @@ class by_payee_posts : public item_handler<post_t> */ class transfer_details : public item_handler<post_t> { - std::list<xact_t> xact_temps; - std::list<post_t> post_temps; - account_t * master; - expr_t expr; - scope_t& scope; + account_t * master; + expr_t expr; + scope_t& scope; + temporaries_t temps; transfer_details(); @@ -679,7 +664,6 @@ public: } virtual ~transfer_details() { TRACE_DTOR(transfer_details); - clear_xacts_posts(xact_temps); } virtual void operator()(post_t& post); @@ -725,8 +709,7 @@ protected: typedef std::list<pending_posts_pair> pending_posts_list; pending_posts_list pending_posts; - std::list<xact_t> xact_temps; - std::list<post_t> post_temps; + temporaries_t temps; public: generate_posts(post_handler_ptr handler) @@ -736,7 +719,6 @@ public: virtual ~generate_posts() { TRACE_DTOR(generate_posts); - clear_xacts_posts(xact_temps); } void add_period_xacts(period_xacts_list& period_xacts); @@ -751,9 +733,10 @@ public: */ class budget_posts : public generate_posts { -#define BUDGET_NO_BUDGET 0x00 -#define BUDGET_BUDGETED 0x01 -#define BUDGET_UNBUDGETED 0x02 +#define BUDGET_NO_BUDGET 0x00 +#define BUDGET_BUDGETED 0x01 +#define BUDGET_UNBUDGETED 0x02 +#define BUDGET_WRAP_VALUES 0x04 uint_least8_t flags; @@ -59,6 +59,7 @@ class item_t : public supports_flags<>, public scope_t { public: #define ITEM_NORMAL 0x00 // no flags at all, a basic posting +// jww (2009-10-27): I'm not consistent on the difference between these two. #define ITEM_GENERATED 0x01 // posting was not found in a journal #define ITEM_TEMP 0x02 // posting is a temporary object @@ -637,7 +637,7 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const void expr_t::op_t::dump(std::ostream& out, const int depth) const { out.setf(std::ios::left); - out.width(10); + out.width((sizeof(void *) * 2) + 2); out << this; for (int i = 0; i < depth; i++) diff --git a/src/output.cc b/src/output.cc index a0c2581b..b1a8cb1b 100644 --- a/src/output.cc +++ b/src/output.cc @@ -169,7 +169,7 @@ format_accounts::mark_accounts(account_t& account, const bool flat) #if defined(DEBUG_ON) DEBUG("account.display", "Considering account: " << account.fullname()); - if (account.has_flags(ACCOUNT_EXT_VISITED)) + if (account.has_xflags(ACCOUNT_EXT_VISITED)) DEBUG("account.display", " it was visited itself"); DEBUG("account.display", " it has " << visited << " visited children"); DEBUG("account.display", @@ -177,11 +177,11 @@ format_accounts::mark_accounts(account_t& account, const bool flat) #endif if (account.parent && - (account.has_flags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) { + (account.has_xflags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) { bind_scope_t bound_scope(report, account); if ((! flat && to_display > 1) || ((flat || to_display != 1 || - account.has_flags(ACCOUNT_EXT_VISITED)) && + account.has_xflags(ACCOUNT_EXT_VISITED)) && disp_pred(bound_scope))) { account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY); DEBUG("account.display", "Marking account as TO_DISPLAY"); diff --git a/src/post.cc b/src/post.cc index 90c10a3b..89d69ec1 100644 --- a/src/post.cc +++ b/src/post.cc @@ -141,6 +141,16 @@ namespace { return string_value(post.xact->payee); } + value_t get_magnitude(post_t& post) { + return post.xact->magnitude(); + } + value_t get_idstring(post_t& post) { + return string_value(post.xact->idstring()); + } + value_t get_id(post_t& post) { + return string_value(post.xact->id()); + } + value_t get_amount(post_t& post) { if (post.has_xdata() && post.xdata().has_flags(POST_EXT_COMPOUND)) return post.xdata().compound_value; @@ -296,6 +306,18 @@ expr_t::ptr_op_t post_t::lookup(const string& name) return WRAP_FUNCTOR(get_wrapper<&get_has_cost>); break; + case 'i': + if (name == "id") + return WRAP_FUNCTOR(get_wrapper<&get_id>); + else if (name == "idstring") + return WRAP_FUNCTOR(get_wrapper<&get_idstring>); + break; + + case 'm': + if (name == "magnitude") + return WRAP_FUNCTOR(get_wrapper<&get_magnitude>); + break; + case 'p': if (name == "post") return WRAP_FUNCTOR(get_wrapper<&get_this>); diff --git a/src/report.cc b/src/report.cc index 53426f39..7f31b615 100644 --- a/src/report.cc +++ b/src/report.cc @@ -77,8 +77,13 @@ void report_t::xact_report(post_handler_ptr handler, xact_t& xact) void report_t::accounts_report(acct_handler_ptr handler) { journal_posts_iterator walker(*session.journal.get()); - pass_down_posts(chain_post_handlers(*this, post_handler_ptr(new ignore_posts), - true), walker); + + // The lifetime of the chain object controls the lifetime of all temporary + // objects created within it during the call to pass_down_posts, which will + // be needed later by the pass_down_accounts. + post_handler_ptr chain = + chain_post_handlers(*this, post_handler_ptr(new ignore_posts), true); + pass_down_posts(chain, walker); scoped_ptr<accounts_iterator> iter; if (! HANDLED(sort_)) { @@ -695,19 +700,42 @@ expr_t::ptr_op_t report_t::lookup(const string& name) if (WANT_CMD()) { const char * q = p + CMD_PREFIX_LEN; switch (*q) { case 'b': - if (*(q + 1) == '\0' || is_eq(q, "bal") || is_eq(q, "balance")) + if (*(q + 1) == '\0' || is_eq(q, "bal") || is_eq(q, "balance")) { return expr_t::op_t::wrap_functor (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> (new format_accounts(*this, report_format(HANDLER(balance_format_))), *this, "#balance")); + } + else if (is_eq(q, "budget")) { + HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)"); + + budget_flags |= BUDGET_WRAP_VALUES; + if (! (budget_flags & ~BUDGET_WRAP_VALUES)) + budget_flags |= BUDGET_BUDGETED; + + return expr_t::op_t::wrap_functor + (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> + (new format_accounts(*this, report_format(HANDLER(budget_format_))), + *this, "#budget")); + } break; case 'c': - if (is_eq(q, "csv")) + if (is_eq(q, "csv")) { return WRAP_FUNCTOR (reporter<> (new format_posts(*this, report_format(HANDLER(csv_format_))), *this, "#csv")); + } + else if (is_eq(q, "cleared")) { + HANDLER(amount_).set_expr(string("#cleared"), + "(amount, cleared ? amount : 0)"); + + return expr_t::op_t::wrap_functor + (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> + (new format_accounts(*this, report_format(HANDLER(cleared_format_))), + *this, "#cleared")); + } break; case 'e': diff --git a/src/report.h b/src/report.h index f0052128..8c66c88a 100644 --- a/src/report.h +++ b/src/report.h @@ -117,9 +117,10 @@ public: session_t& session; output_stream_t output_stream; -#define BUDGET_NO_BUDGET 0x00 -#define BUDGET_BUDGETED 0x01 -#define BUDGET_UNBUDGETED 0x02 +#define BUDGET_NO_BUDGET 0x00 +#define BUDGET_BUDGETED 0x01 +#define BUDGET_UNBUDGETED 0x02 +#define BUDGET_WRAP_VALUES 0x04 datetime_t terminus; uint_least8_t budget_flags; @@ -205,8 +206,10 @@ public: HANDLER(basis).report(out); HANDLER(begin_).report(out); HANDLER(budget).report(out); + HANDLER(budget_format_).report(out); HANDLER(by_payee).report(out); HANDLER(cleared).report(out); + HANDLER(cleared_format_).report(out); HANDLER(code_as_payee).report(out); HANDLER(comm_as_payee).report(out); HANDLER(code_as_account).report(out); @@ -314,7 +317,7 @@ public: }); OPTION_(report_t, add_budget, DO() { - parent->budget_flags = BUDGET_BUDGETED | BUDGET_UNBUDGETED; + parent->budget_flags |= BUDGET_BUDGETED | BUDGET_UNBUDGETED; }); OPTION__ @@ -368,7 +371,23 @@ public: }); OPTION_(report_t, budget, DO() { - parent->budget_flags = BUDGET_BUDGETED; + parent->budget_flags |= BUDGET_BUDGETED; + }); + + OPTION__(report_t, budget_format_, CTOR(report_t, budget_format_) { + on(none, + "%(justify(scrub(get_at(total_expr, 0)), 12, -1, true, color))" + " %(justify(scrub(- get_at(total_expr, 1)), 12, -1, true, color))" + " %(justify(scrub(get_at(total_expr, 1) + get_at(total_expr, 0)), 12, -1, true, color))" + " %(justify(scrub((100% * get_at(total_expr, 0)) / - get_at(total_expr, 1)), 5, -1, true, color))" + " %(!options.flat ? depth_spacer : \"\")" + "%-(ansify_if(partial_account(options.flat), blue if color))\n" + "%/" + "%(justify(scrub(get_at(total_expr, 0)), 12, -1, true, color))" + " %(justify(scrub(- get_at(total_expr, 1)), 12, -1, true, color))" + " %(justify(scrub(get_at(total_expr, 1) + get_at(total_expr, 0)), 12, -1, true, color))" + " %(justify(scrub((100% * get_at(total_expr, 0)) / - get_at(total_expr, 1)), 5, -1, true, color))\n%/" + "------------ ------------ ------------ -----\n"); }); OPTION(report_t, by_payee); // -P @@ -377,6 +396,19 @@ public: parent->HANDLER(limit_).on(string("--cleared"), "cleared"); }); + OPTION__(report_t, cleared_format_, CTOR(report_t, cleared_format_) { + on(none, + "%(justify(scrub(get_at(total_expr, 0)), 16, -1, true, color))" + " %(justify(scrub(get_at(total_expr, 1)), 16, -1, true, color))" + " %(latest_cleared ? format_date(latest_cleared) : \" \")" + " %(!options.flat ? depth_spacer : \"\")" + "%-(ansify_if(partial_account(options.flat), blue if color))\n%/" + "%(justify(scrub(get_at(total_expr, 0)), 16, -1, true, color))" + " %(justify(scrub(get_at(total_expr, 1)), 16, -1, true, color))" + " %(latest_cleared ? format_date(latest_cleared) : \" \")\n%/" + "---------------- ---------------- ---------\n"); + }); + OPTION(report_t, code_as_payee); OPTION(report_t, comm_as_payee); OPTION(report_t, code_as_account); @@ -772,7 +804,7 @@ public: }); OPTION_(report_t, unbudgeted, DO() { - parent->budget_flags = BUDGET_UNBUDGETED; + parent->budget_flags |= BUDGET_UNBUDGETED; }); OPTION_(report_t, uncleared, DO() { // -U diff --git a/src/temps.cc b/src/temps.cc new file mode 100644 index 00000000..a9ecc2a1 --- /dev/null +++ b/src/temps.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <system.hh> + +#include "temps.h" + +namespace ledger { + +temporaries_t::~temporaries_t() +{ + if (post_temps) { + foreach (post_t& post, *post_temps) { + if (! post.xact->has_flags(ITEM_TEMP)) + post.xact->remove_post(&post); + + if (! post.account->has_flags(ACCOUNT_TEMP)) + post.account->remove_post(&post); + } + } +} + +xact_t& temporaries_t::copy_xact(xact_t& origin) +{ + if (! xact_temps) + xact_temps = std::list<xact_t>(); + + xact_temps->push_back(origin); + xact_t& temp(xact_temps->back()); + + temp.add_flags(ITEM_TEMP); + return temp; +} + +xact_t& temporaries_t::create_xact() +{ + if (! xact_temps) + xact_temps = std::list<xact_t>(); + + xact_temps->push_back(xact_t()); + xact_t& temp(xact_temps->back()); + + temp.add_flags(ITEM_TEMP); + return temp; +} + +post_t& temporaries_t::copy_post(post_t& origin, xact_t& xact, + account_t * account) +{ + if (! post_temps) + post_temps = std::list<post_t>(); + + post_temps->push_back(origin); + post_t& temp(post_temps->back()); + + if (account) + temp.account = account; + temp.add_flags(ITEM_TEMP); + + temp.account->add_post(&temp); + xact.add_post(&temp); + + return temp; +} + +post_t& temporaries_t::create_post(xact_t& xact, account_t * account) +{ + if (! post_temps) + post_temps = std::list<post_t>(); + + post_temps->push_back(post_t(account)); + post_t& temp(post_temps->back()); + + temp.account = account; + temp.add_flags(ITEM_TEMP); + + temp.account->add_post(&temp); + xact.add_post(&temp); + + return temp; +} + +account_t& temporaries_t::create_account(const string& name, + account_t * parent) +{ + if (! acct_temps) + acct_temps = std::list<account_t>(); + + acct_temps->push_back(account_t(parent, name)); + account_t& temp(acct_temps->back()); + + temp.add_flags(ACCOUNT_TEMP); + return temp; +} + +} // namespace ledger diff --git a/src/temps.h b/src/temps.h new file mode 100644 index 00000000..acd9cbd7 --- /dev/null +++ b/src/temps.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup report + */ + +/** + * @file temps.h + * @author John Wiegley + * + * @ingroup report + * + * @brief Brief + * + * Long. + */ +#ifndef _TEMPS_H +#define _TEMPS_H + +#include "xact.h" +#include "post.h" +#include "account.h" + +namespace ledger { + +class temporaries_t +{ + optional<std::list<xact_t> > xact_temps; + optional<std::list<post_t> > post_temps; + optional<std::list<account_t> > acct_temps; + +public: + ~temporaries_t(); + + xact_t& copy_xact(xact_t& origin); + xact_t& create_xact(); + xact_t& last_xact() { + return xact_temps->back(); + } + post_t& copy_post(post_t& origin, xact_t& xact, + account_t * account = NULL); + post_t& create_post(xact_t& xact, account_t * account); + post_t& last_post() { + return post_temps->back(); + } + account_t& create_account(const string& name, + account_t * parent = NULL); + account_t& last_account() { + return acct_temps->back(); + } +}; + +} // namespace ledger + +#endif // _TEMPS_H diff --git a/src/textual.cc b/src/textual.cc index 56c67ef3..09cd8360 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -446,7 +446,7 @@ void instance_t::default_commodity_directive(char * line) void instance_t::default_account_directive(char * line) { journal.basket = account_stack.front()->find_account(skip_ws(line + 1)); - journal.basket->known = true; + journal.basket->add_flags(ACCOUNT_KNOWN); } void instance_t::price_conversion_directive(char * line) @@ -845,11 +845,11 @@ post_t * instance_t::parse_post(char * line, if (! post->account) post->account = account->find_account(name); - if (honor_strict && strict && ! post->account->known) { + if (honor_strict && strict && ! post->account->has_flags(ACCOUNT_KNOWN)) { if (post->_state == item_t::UNCLEARED) warning_(_("\"%1\", line %2: Unknown account '%3'") << pathname << linenum << post->account->fullname()); - post->account->known = true; + post->account->add_flags(ACCOUNT_KNOWN); } // Parse the optional amount diff --git a/src/utils.h b/src/utils.h index 98bdf9af..e3ae5dda 100644 --- a/src/utils.h +++ b/src/utils.h @@ -596,7 +596,7 @@ inline char peek_next_nonws(std::istream& in) { *_p = '\0'; \ } -inline string to_hex(uint_least32_t * message_digest) +inline string to_hex(uint_least32_t * message_digest, const int len = 1) { std::ostringstream buf; @@ -604,7 +604,8 @@ inline string to_hex(uint_least32_t * message_digest) buf.width(8); buf.fill('0'); buf << std::hex << message_digest[i]; - break; // only output the first dword + if (i + 1 >= len) + break; // only output the first LEN dwords } return buf.str(); } diff --git a/src/value.cc b/src/value.cc index 6ce46f5c..cd4c4aa1 100644 --- a/src/value.cc +++ b/src/value.cc @@ -254,7 +254,7 @@ value_t::sequence_t value_t::to_sequence() const void value_t::in_place_simplify() { #if defined(DEBUG_ON) - LOGGER("amounts.values.simplify"); + LOGGER("value.simplify"); #endif if (is_realzero()) { @@ -263,11 +263,11 @@ void value_t::in_place_simplify() return; } - if (is_balance() && as_balance().amounts.size() == 1) { + if (is_balance() && as_balance().single_amount()) { DEBUG_("Reducing balance to amount"); - DEBUG("ledger.value.reduce", "as a balance it looks like: " << *this); + DEBUG_("as a balance it looks like: " << *this); in_place_cast(AMOUNT); - DEBUG("ledger.value.reduce", "as an amount it looks like: " << *this); + DEBUG_("as an amount it looks like: " << *this); } #ifdef REDUCE_TO_INTEGER // this is off by default @@ -585,10 +585,11 @@ value_t& value_t::operator*=(const value_t& val) as_amount_lval() *= val.as_long(); return *this; case AMOUNT: - if (as_amount().commodity() == val.as_amount().commodity() || - ! as_amount().has_commodity() || - ! val.as_amount().has_commodity()) { - as_amount_lval() *= val.as_amount(); + as_amount_lval() *= val.as_amount(); + return *this; + case BALANCE: + if (val.as_balance().single_amount()) { + as_amount_lval() *= val.simplified().as_amount(); return *this; } break; @@ -603,7 +604,12 @@ value_t& value_t::operator*=(const value_t& val) as_balance_lval() *= val.as_long(); return *this; case AMOUNT: - if (! val.as_amount().has_commodity()) { + if (as_balance().single_amount()) { + in_place_simplify(); + as_amount_lval() *= val.as_amount(); + return *this; + } + else if (! val.as_amount().has_commodity()) { as_balance_lval() *= val.as_amount(); return *this; } @@ -617,6 +623,9 @@ value_t& value_t::operator*=(const value_t& val) break; } + DEBUG("value.multiply.error", "Left: " << *this); + DEBUG("value.multiply.error", "Right: " << val); + throw_(value_error, _("Cannot multiply %1 with %2") << label() << val.label()); return *this; @@ -647,6 +656,12 @@ value_t& value_t::operator/=(const value_t& val) case AMOUNT: as_amount_lval() /= val.as_amount(); return *this; + case BALANCE: + if (val.as_balance().single_amount()) { + as_amount_lval() /= val.simplified().as_amount(); + return *this; + } + break; default: break; } @@ -658,7 +673,12 @@ value_t& value_t::operator/=(const value_t& val) as_balance_lval() /= val.as_long(); return *this; case AMOUNT: - if (! val.as_amount().has_commodity()) { + if (as_balance().single_amount()) { + in_place_simplify(); + as_amount_lval() /= val.as_amount(); + return *this; + } + else if (! val.as_amount().has_commodity()) { as_balance_lval() /= val.as_amount(); return *this; } diff --git a/src/xact.cc b/src/xact.cc index 175a1467..6ea8d8f9 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -65,7 +65,7 @@ void xact_base_t::add_post(post_t * post) bool xact_base_t::remove_post(post_t * post) { posts.remove(post); - post->xact = NULL; + post->xact = NULL; return true; } @@ -163,11 +163,14 @@ bool xact_base_t::finalize() null_post->amount = balance.as_amount().negated(); null_post->add_flags(POST_CALCULATED); } + else if (balance.is_long()) { + null_post->amount = amount_t(- balance.as_long()); + null_post->add_flags(POST_CALCULATED); + } else if (! balance.is_null() && ! balance.is_realzero()) { throw_(balance_error, _("Transaction does not balance")); } balance = NULL_VALUE; - } else if (balance.is_balance() && balance.as_balance().amounts.size() == 2) { @@ -314,6 +317,7 @@ bool xact_base_t::finalize() if (dynamic_cast<xact_t *>(this)) { bool all_null = true; bool some_null = false; + foreach (post_t * post, posts) { if (! post->amount.is_null()) { all_null = false; @@ -327,6 +331,7 @@ bool xact_base_t::finalize() post->xdata().add_flags(POST_EXT_VISITED); post->account->xdata().add_flags(ACCOUNT_EXT_VISITED); } + if (all_null) return false; // ignore this xact completely else if (some_null) @@ -351,32 +356,48 @@ void xact_t::add_post(post_t * post) xact_base_t::add_post(post); } -namespace { - value_t get_magnitude(xact_t& xact) { - balance_t halfbal; - foreach (post_t * post, xact.posts) - if (post->amount.sign() > 0) +value_t xact_t::magnitude() const +{ + value_t halfbal = 0L; + foreach (const post_t * post, posts) { + if (post->amount.sign() > 0) { + if (post->cost) + halfbal += post->cost->number(); + else halfbal += post->amount.number(); - return halfbal; + } } + return halfbal; +} - value_t get_idstring(xact_t& xact) { - std::ostringstream buf; - buf << *xact._date; - buf << xact.payee; +string xact_t::idstring() const +{ + std::ostringstream buf; + buf << format_date(*_date, FMT_WRITTEN); + buf << payee; + magnitude().print(buf); + return buf.str(); +} - get_magnitude(xact).print(buf); +string xact_t::id() const +{ + SHA1 sha; + sha.Reset(); + sha << idstring().c_str(); + uint_least32_t message_digest[5]; + sha.Result(message_digest); + return to_hex(message_digest, 5); +} - return string_value(buf.str()); +namespace { + value_t get_magnitude(xact_t& xact) { + return xact.magnitude(); + } + value_t get_idstring(xact_t& xact) { + return string_value(xact.idstring()); } value_t get_id(xact_t& xact) { - SHA1 sha; - sha.Reset(); - sha << get_idstring(xact).as_string().c_str(); - - uint_least32_t message_digest[5]; - sha.Result(message_digest); - return string_value(to_hex(message_digest)); + return string_value(xact.id()); } value_t get_code(xact_t& xact) { @@ -104,6 +104,10 @@ public: virtual void add_post(post_t * post); + value_t magnitude() const; + string idstring() const; + string id() const; + virtual expr_t::ptr_op_t lookup(const string& name); virtual bool valid() const; |