diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cc | 24 | ||||
-rw-r--r-- | src/account.h | 7 | ||||
-rw-r--r-- | src/amount.cc | 6 | ||||
-rw-r--r-- | src/annotate.cc | 4 | ||||
-rw-r--r-- | src/annotate.h | 9 | ||||
-rw-r--r-- | src/archive.cc | 2 | ||||
-rw-r--r-- | src/balance.h | 35 | ||||
-rw-r--r-- | src/chain.cc | 11 | ||||
-rw-r--r-- | src/commodity.cc | 54 | ||||
-rw-r--r-- | src/commodity.h | 167 | ||||
-rw-r--r-- | src/filters.cc | 60 | ||||
-rw-r--r-- | src/filters.h | 3 | ||||
-rw-r--r-- | src/item.cc | 2 | ||||
-rw-r--r-- | src/item.h | 3 | ||||
-rw-r--r-- | src/iterators.cc | 4 | ||||
-rw-r--r-- | src/op.h | 4 | ||||
-rw-r--r-- | src/pool.cc | 28 | ||||
-rw-r--r-- | src/pool.h | 3 | ||||
-rw-r--r-- | src/post.cc | 17 | ||||
-rw-r--r-- | src/post.h | 2 | ||||
-rw-r--r-- | src/precmd.cc | 10 | ||||
-rw-r--r-- | src/predicate.cc | 36 | ||||
-rw-r--r-- | src/py_amount.cc | 148 | ||||
-rw-r--r-- | src/py_balance.cc | 280 | ||||
-rw-r--r-- | src/pyinterp.cc | 2 | ||||
-rw-r--r-- | src/report.cc | 2 | ||||
-rw-r--r-- | src/report.h | 6 | ||||
-rw-r--r-- | src/session.cc | 3 | ||||
-rw-r--r-- | src/session.h | 6 | ||||
-rw-r--r-- | src/temps.cc | 10 | ||||
-rw-r--r-- | src/temps.h | 2 | ||||
-rw-r--r-- | src/times.cc | 40 | ||||
-rw-r--r-- | src/xact.cc | 4 | ||||
-rw-r--r-- | src/xact.h | 1 |
34 files changed, 577 insertions, 418 deletions
diff --git a/src/account.cc b/src/account.cc index 52a6b436..23761049 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, @@ -55,7 +54,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); @@ -398,6 +397,21 @@ value_t account_t::amount(const optional<expr_t&>& 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..4ac69532 100644 --- a/src/account.h +++ b/src/account.h @@ -159,6 +159,7 @@ public: std::set<string> payees_referenced; optional<posts_list::const_iterator> last_post; + optional<posts_list::const_iterator> 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_value_t> sort_values; @@ -193,7 +195,6 @@ public: { TRACE_CTOR(account_t::xdata_t, "copy"); } - ~xdata_t() throw() { TRACE_DTOR(account_t::xdata_t); } 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<annotated_commodity_t, commodity_t, noncopyable> > { -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/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/balance.h b/src/balance.h index 5452510b..ad340aa5 100644 --- a/src/balance.h +++ b/src/balance.h @@ -207,7 +207,7 @@ public: template <typename T> 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(); } /** 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/commodity.cc b/src/commodity.cc index de529ac4..d896572f 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -38,10 +38,12 @@ namespace ledger { -void commodity_t::base_t::history_t::add_price(commodity_t& source, - const datetime_t& date, - const amount_t& price, - const bool reflexive) +bool commodity_t::european_by_default = false; + +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)") @@ -67,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); @@ -77,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, @@ -97,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); @@ -109,13 +110,12 @@ bool commodity_t::base_t::varied_history_t:: } optional<price_point_t> - commodity_t::base_t::history_t:: - find_price(const optional<datetime_t>& moment, - const optional<datetime_t>& oldest +commodity_t::history_t::find_price(const optional<datetime_t>& moment, + const optional<datetime_t>& oldest #if defined(DEBUG_ON) - , const int indent + , const int indent #endif - ) const + ) const { price_point_t point; bool found = false; @@ -220,15 +220,14 @@ optional<price_point_t> } optional<price_point_t> - commodity_t::base_t::varied_history_t:: - find_price(const commodity_t& source, - const optional<commodity_t&>& commodity, - const optional<datetime_t>& moment, - const optional<datetime_t>& oldest +commodity_t::varied_history_t::find_price(const commodity_t& source, + const optional<commodity_t&>& commodity, + const optional<datetime_t>& moment, + const optional<datetime_t>& oldest #if defined(DEBUG_ON) - , const int indent + , const int indent #endif - ) const + ) const { optional<price_point_t> point; optional<datetime_t> limit = oldest; @@ -352,9 +351,8 @@ optional<price_point_t> return none; } -optional<commodity_t::base_t::history_t&> - commodity_t::base_t::varied_history_t:: - history(const optional<commodity_t&>& commodity) +optional<commodity_t::history_t&> +commodity_t::varied_history_t::history(const optional<commodity_t&>& commodity) { commodity_t * comm = NULL; if (! commodity) { @@ -602,11 +600,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<annotated_commodity_t&>(leftcomm)); diff --git a/src/commodity.h b/src/commodity.h index 1df1ab18..25397131 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -86,87 +86,85 @@ class commodity_t : public delegates_flags<uint_least16_t>, public equality_comparable1<commodity_t, noncopyable> { - friend class commodity_pool_t; - public: - class base_t : public noncopyable, public supports_flags<uint_least16_t> - { - base_t() { - TRACE_CTOR(base_t, ""); - } - - public: - typedef std::map<const datetime_t, amount_t> history_map; + typedef std::map<const datetime_t, amount_t> history_map; - struct history_t - { - history_map prices; + 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); + 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<price_point_t> - find_price(const optional<datetime_t>& moment = none, - const optional<datetime_t>& oldest = none + optional<price_point_t> + find_price(const optional<datetime_t>& moment = none, + const optional<datetime_t>& oldest = none #if defined(DEBUG_ON) - , const int indent = 0 + , const int indent = 0 #endif - ) const; + ) const; #if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ + private: + /** Serialization. */ - friend class boost::serialization::access; + friend class boost::serialization::access; - template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { - ar & prices; - } + template<class Archive> + void serialize(Archive & ar, const unsigned int /* version */) { + ar & prices; + } #endif // HAVE_BOOST_SERIALIZATION - }; - - typedef std::map<commodity_t *, history_t> 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); + typedef std::map<commodity_t *, history_t> history_by_commodity_map; - optional<price_point_t> - find_price(const commodity_t& source, - const optional<commodity_t&>& commodity = none, - const optional<datetime_t>& moment = none, - const optional<datetime_t>& oldest = none + 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<price_point_t> + find_price(const commodity_t& source, + const optional<commodity_t&>& commodity = none, + const optional<datetime_t>& moment = none, + const optional<datetime_t>& oldest = none #if defined(DEBUG_ON) - , const int indent = 0 + , const int indent = 0 #endif - ) const; + ) const; - optional<history_t&> - history(const optional<commodity_t&>& commodity = none); + optional<history_t&> + history(const optional<commodity_t&>& commodity = none); #if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ + private: + /** Serialization. */ - friend class boost::serialization::access; + friend class boost::serialization::access; - template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { - ar & histories; - } + template<class Archive> + 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<uint_least16_t> + { + public: #define COMMODITY_STYLE_DEFAULTS 0x000 #define COMMODITY_STYLE_SUFFIXED 0x001 #define COMMODITY_STYLE_SEPARATED 0x002 @@ -190,7 +188,9 @@ public: public: explicit base_t(const string& _symbol) - : supports_flags<uint_least16_t>(COMMODITY_STYLE_DEFAULTS), + : supports_flags<uint_least16_t>(commodity_t::european_by_default ? + COMMODITY_STYLE_EUROPEAN : + COMMODITY_STYLE_DEFAULTS), symbol(_symbol), precision(0), searched(false) { TRACE_CTOR(base_t, "const string&"); } @@ -199,33 +199,31 @@ public: } #if defined(HAVE_BOOST_SERIALIZATION) - private: - /** Serialization. */ - - friend class boost::serialization::access; - - template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { - ar & boost::serialization::base_object<supports_flags<uint_least16_t> >(*this); - ar & symbol; - ar & precision; - ar & name; - ar & note; - ar & varied_history; - ar & smaller; - ar & larger; - } + private: + base_t() { + TRACE_CTOR(base_t, ""); + } + + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive & ar, const unsigned int /* version */) { + ar & boost::serialization::base_object<supports_flags<uint_least16_t> >(*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_t> base; commodity_pool_t * parent_; @@ -233,13 +231,16 @@ public: optional<string> mapping_key_; bool annotated; -public: explicit commodity_t(commodity_pool_t * _parent, const shared_ptr<base_t>& _base) : delegates_flags<uint_least16_t>(*_base.get()), base(_base), parent_(_parent), annotated(false) { TRACE_CTOR(commodity_t, "commodity_pool_t *, shared_ptr<base_t>"); } + +public: + static bool european_by_default; + virtual ~commodity_t() { TRACE_DTOR(commodity_t); } diff --git a/src/filters.cc b/src/filters.cc index da9e39ae..00e495dd 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<string>& 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<string>& 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<string> 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<string> 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; @@ -739,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(); @@ -785,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/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<post_t> { temporaries_t temps; - - xact_t * last_xact; + xact_t * last_xact; anonymize_posts(); 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<item_t> env(scope, "s"); if (optional<string> value = env->get_tag(env.get<string>(0))) return string_value(*value); - return false; + return string_value(empty_string); } value_t get_pathname(item_t& item) { @@ -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) { @@ -206,8 +207,8 @@ private: ar & _date; ar & _date_eff; ar & note; - ar & metadata; ar & pos; + ar & metadata; } #endif // HAVE_BOOST_SERIALIZATION }; 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(); @@ -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) 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 * @@ -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); diff --git a/src/post.cc b/src/post.cc index 7b5e5325..2a1663cb 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>); @@ -425,4 +436,10 @@ void post_t::add_to_value(value_t& value, const optional<expr_t&>& expr) const } } +void post_t::set_reported_account(account_t * account) +{ + xdata().account = account; + account->xdata().reported_posts.push_back(this); +} + } // namespace ledger @@ -193,6 +193,8 @@ public: void add_to_value(value_t& value, const optional<expr_t&>& 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/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<report_t>(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<report_t>(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; diff --git a/src/predicate.cc b/src/predicate.cc index b3926116..d5b41362 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") @@ -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); diff --git a/src/py_amount.cc b/src/py_amount.cc index 7fe12674..efae7514 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -42,59 +42,66 @@ namespace ledger { using namespace boost::python; -boost::optional<amount_t> py_value_0(const amount_t& amount) { - return amount.value(); -} -boost::optional<amount_t> py_value_1(const amount_t& amount, - const bool primary_only) { - return amount.value(primary_only); -} -boost::optional<amount_t> py_value_2(const amount_t& amount, - const bool primary_only, - const boost::optional<datetime_t>& moment) { - return amount.value(primary_only, moment); -} -boost::optional<amount_t> py_value_3(const amount_t& amount, - const bool primary_only, - const boost::optional<datetime_t>& moment, - const boost::optional<commodity_t&>& 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<PyFileObject *>(in.ptr())); - amount.parse(instr, flags); - } else { - PyErr_SetString(PyExc_IOError, - _("Argument to amount.parse(file) is not a file object")); + boost::optional<amount_t> py_value_0(const amount_t& amount) { + return amount.value(); + } + boost::optional<amount_t> py_value_1(const amount_t& amount, + const bool primary_only) { + return amount.value(primary_only); } -} -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); -} + boost::optional<amount_t> + py_value_2(const amount_t& amount, + const bool primary_only, + const boost::optional<datetime_t>& moment) { + return amount.value(primary_only, moment); + } -void py_print(amount_t& amount, object out) -{ - if (PyFile_Check(out.ptr())) { - pyofstream outstr(reinterpret_cast<PyFileObject *>(out.ptr())); - amount.print(outstr); - } else { - PyErr_SetString(PyExc_IOError, - _("Argument to amount.print_(file) is not a file object")); + boost::optional<amount_t> + py_value_3(const amount_t& amount, + const bool primary_only, + const boost::optional<datetime_t>& moment, + const boost::optional<commodity_t&>& in_terms_of) { + return amount.value(primary_only, moment, in_terms_of); } -} -void py_amount_initialize() { - amount_t::initialize(); -} + void py_parse_2(amount_t& amount, object in, unsigned char flags) { + if (PyFile_Check(in.ptr())) { + pyifstream instr(reinterpret_cast<PyFileObject *>(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<PyFileObject *>(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) { \ @@ -106,15 +113,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<reference_existing_object>())) + .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<reference_existing_object>())) - + .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 +139,8 @@ internal precision.")) .def(init<amount_t>()) - .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 +197,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 +210,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<reference_existing_object>()) + + .def("truncated", &amount_t::truncated) + .def("in_place_truncate", &amount_t::in_place_truncate, + return_value_policy<reference_existing_object>()) + .def("unrounded", &amount_t::unrounded) + .def("in_place_unround", &amount_t::in_place_unround, + return_value_policy<reference_existing_object>()) .def("reduced", &amount_t::reduced) .def("in_place_reduce", &amount_t::in_place_reduce, @@ -207,9 +233,11 @@ internal precision.")) return_value_policy<reference_existing_object>()) .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 +250,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<reference_existing_object>()) + .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) @@ -256,7 +283,6 @@ internal precision.")) .staticmethod("parse_conversion") .def("print_", py_print) - .def("dump", &amount_t::dump) .def("valid", &amount_t::valid) 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,69 +32,90 @@ #include <system.hh> #include "pyinterp.h" +#include "pyutils.h" +#include "pyfstream.h" +#include "commodity.h" +#include "annotate.h" +#include "balance.h" namespace ledger { using namespace boost::python; -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ +namespace { + + boost::optional<balance_t> py_value_0(const balance_t& balance) { + return balance.value(); + } + boost::optional<balance_t> py_value_1(const balance_t& balance, + const bool primary_only) { + return balance.value(primary_only); } -EXC_TRANSLATOR(balance_error) + boost::optional<balance_t> + py_value_2(const balance_t& balance, + const bool primary_only, + const boost::optional<datetime_t>& moment) { + return balance.value(primary_only, moment); + } -void export_balance() -{ -#if 0 - class_< balance_t > ("Balance") - ; -#endif + boost::optional<balance_t> + py_value_3(const balance_t& balance, + const bool primary_only, + const boost::optional<datetime_t>& moment, + const boost::optional<commodity_t&>& in_terms_of) { + return balance.value(primary_only, moment, in_terms_of); + } - //register_optional_to_python<amount_t>(); + boost::optional<amount_t> + py_commodity_amount_0(const balance_t& balance) { + return balance.commodity_amount(); + } - //implicitly_convertible<string, amount_t>(); + boost::optional<amount_t> + py_commodity_amount_1(const balance_t& balance, + const boost::optional<const commodity_t&>& commodity) { + return balance.commodity_amount(commodity); + } -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); + void py_print(balance_t& balance, object out) { + if (PyFile_Check(out.ptr())) { + pyofstream outstr(reinterpret_cast<PyFileObject *>(out.ptr())); + balance.print(outstr); + } else { + PyErr_SetString(PyExc_IOError, + _("Argument to balance.print_(file) is not a file object")); + } + } - //EXC_TRANSLATE(balance_error); -} + long balance_len(balance_t& bal) { + return bal.amounts.size(); + } -} // namespace ledger + amount_t balance_getitem(balance_t& bal, long i) { + long len = bal.amounts.size(); -#if 0 -unsigned int balance_len(balance_t& bal) -{ - return bal.amounts.size(); -} + if (labs(i) >= len) { + PyErr_SetString(PyExc_IndexError, _("Index out of range")); + throw_error_already_set(); + } -amount_t balance_getitem(balance_t& bal, int i) -{ - std::size_t len = bal.amounts.size(); + long x = i < 0 ? len + i : i; + balance_t::amounts_map::iterator elem = bal.amounts.begin(); + while (--x >= 0) + elem++; - if (abs(i) >= len) { - PyErr_SetString(PyExc_IndexError, _("Index out of range")); - throw_error_already_set(); + return (*elem).second; } - int x = i < 0 ? len + i : i; - balance_t::amounts_map::iterator elem = bal.amounts.begin(); - while (--x >= 0) - elem++; +} // unnamed namespace - return (*elem).second; -} - -unsigned int balance_pair_len(balance_pair_t& bal_pair) -{ - return balance_len(bal_pair.quantity); -} +#define EXC_TRANSLATOR(type) \ + void exc_translate_ ## type(const type& err) { \ + PyErr_SetString(PyExc_ArithmeticError, err.what()); \ + } -amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i) -{ - return balance_getitem(bal_pair.quantity, i); -} +EXC_TRANSLATOR(balance_error) void export_balance() { @@ -102,8 +123,7 @@ void export_balance() .def(init<balance_t>()) .def(init<amount_t>()) .def(init<long>()) - .def(init<unsigned long>()) - .def(init<double>()) + .def(init<string>()) .def(self += self) .def(self += other<amount_t>()) @@ -117,32 +137,16 @@ void export_balance() .def(self - self) .def(self - other<amount_t>()) .def(self - long()) - .def(self *= self) .def(self *= other<amount_t>()) .def(self *= long()) - .def(self * self) .def(self * other<amount_t>()) .def(self * long()) - .def(self /= self) .def(self /= other<amount_t>()) .def(self /= long()) - .def(self / self) .def(self / other<amount_t>()) .def(self / long()) .def(- self) - .def(self < self) - .def(self < other<amount_t>()) - .def(self < long()) - .def(self <= self) - .def(self <= other<amount_t>()) - .def(self <= long()) - .def(self > self) - .def(self > other<amount_t>()) - .def(self > long()) - .def(self >= self) - .def(self >= other<amount_t>()) - .def(self >= long()) .def(self == self) .def(self == other<amount_t>()) .def(self == long()) @@ -153,114 +157,70 @@ void export_balance() .def(self_ns::str(self)) + .def("negated", &balance_t::negated) + .def("in_place_negate", &balance_t::in_place_negate, + return_value_policy<reference_existing_object>()) + .def(- self) + + .def("abs", &balance_t::abs) .def("__abs__", &balance_t::abs) + .def("__len__", balance_len) .def("__getitem__", balance_getitem) - .def("valid", &balance_t::valid) + .def("rounded", &balance_t::rounded) + .def("in_place_round", &balance_t::in_place_round, + return_value_policy<reference_existing_object>()) - .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) - ; + .def("truncated", &balance_t::truncated) + .def("in_place_truncate", &balance_t::in_place_truncate, + return_value_policy<reference_existing_object>()) - class_< balance_pair_t > ("BalancePair") - .def(init<balance_pair_t>()) - .def(init<balance_t>()) - .def(init<amount_t>()) - .def(init<long>()) - .def(init<unsigned long>()) - .def(init<double>()) + .def("unrounded", &balance_t::unrounded) + .def("in_place_unround", &balance_t::in_place_unround, + return_value_policy<reference_existing_object>()) - .def(self += self) - .def(self += other<balance_t>()) - .def(self += other<amount_t>()) - .def(self += long()) - .def(self + self) - .def(self + other<balance_t>()) - .def(self + other<amount_t>()) - .def(self + long()) - .def(self -= self) - .def(self -= other<balance_t>()) - .def(self -= other<amount_t>()) - .def(self -= long()) - .def(self - self) - .def(self - other<balance_t>()) - .def(self - other<amount_t>()) - .def(self - long()) - .def(self *= self) - .def(self *= other<balance_t>()) - .def(self *= other<amount_t>()) - .def(self *= long()) - .def(self * self) - .def(self * other<balance_t>()) - .def(self * other<amount_t>()) - .def(self * long()) - .def(self /= self) - .def(self /= other<balance_t>()) - .def(self /= other<amount_t>()) - .def(self /= long()) - .def(self / self) - .def(self / other<balance_t>()) - .def(self / other<amount_t>()) - .def(self / long()) - .def(- self) + .def("reduced", &balance_t::reduced) + .def("in_place_reduce", &balance_t::in_place_reduce, + return_value_policy<reference_existing_object>()) - .def(self < self) - .def(self < other<balance_t>()) - .def(self < other<amount_t>()) - .def(self < long()) - .def(self <= self) - .def(self <= other<balance_t>()) - .def(self <= other<amount_t>()) - .def(self <= long()) - .def(self > self) - .def(self > other<balance_t>()) - .def(self > other<amount_t>()) - .def(self > long()) - .def(self >= self) - .def(self >= other<balance_t>()) - .def(self >= other<amount_t>()) - .def(self >= long()) - .def(self == self) - .def(self == other<balance_t>()) - .def(self == other<amount_t>()) - .def(self == long()) - .def(self != self) - .def(self != other<balance_t>()) - .def(self != other<amount_t>()) - .def(self != long()) - .def(! self) + .def("unreduced", &balance_t::unreduced) + .def("in_place_unreduce", &balance_t::in_place_unreduce, + return_value_policy<reference_existing_object>()) - .def(self_ns::str(self)) + .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("__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<reference_existing_object>())) + .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) ; + +#define EXC_TRANSLATE(type) \ + register_exception_translator<type>(&exc_translate_ ## type); + + EXC_TRANSLATE(balance_error); } -#endif + +} // namespace ledger 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 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> * 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..e00c6460 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); @@ -652,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 } } } @@ -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]); 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> * 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..58e33f6b 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 { @@ -105,6 +106,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); @@ -124,6 +126,10 @@ public: OPTION(session_t, cache_); OPTION(session_t, download); // -Q + OPTION_(session_t, european, DO() { + commodity_t::european_by_default = true; + }); + OPTION__ (session_t, price_exp_, // -Z CTOR(session_t, price_exp_) { value = 24L * 3600L; } diff --git a/src/temps.cc b/src/temps.cc index f2dee159..012a573b 100644 --- a/src/temps.cc +++ b/src/temps.cc @@ -49,6 +49,13 @@ temporaries_t::~temporaries_t() post.account->remove_post(&post); } } + + if (acct_temps) { + foreach (account_t& acct, *acct_temps) { + if (acct.parent && ! acct.parent->has_flags(ACCOUNT_TEMP)) + acct.parent->remove_account(&acct); + } + } } xact_t& temporaries_t::copy_xact(xact_t& origin) @@ -120,6 +127,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(); 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<date_t::year_type> 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<date_t::year_type> year, bool& saw_year) + optional<date_t::year_type> 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<date_io_t>& 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::year_type>) date_t parse_date(const char * str, optional<date_t::year_type> 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/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"); } @@ -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) { |