summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-04 19:55:27 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-04 19:55:27 -0400
commit2d941730b1c60342be5b108d2d654723b3b7c2cb (patch)
tree6a3f4b7305857e85d2684670492007bafc3668d0 /src
parent73cf3b01fbd50c3a8a4fd96ff69643c28394d8fe (diff)
downloadfork-ledger-2d941730b1c60342be5b108d2d654723b3b7c2cb.tar.gz
fork-ledger-2d941730b1c60342be5b108d2d654723b3b7c2cb.tar.bz2
fork-ledger-2d941730b1c60342be5b108d2d654723b3b7c2cb.zip
Largely removed all of Ledger's use of global variables, for the REPL's sake.
Diffstat (limited to 'src')
-rw-r--r--src/account.cc36
-rw-r--r--src/account.h3
-rw-r--r--src/amount.cc77
-rw-r--r--src/amount.h114
-rw-r--r--src/balance.cc9
-rw-r--r--src/balance.h5
-rw-r--r--src/chain.cc18
-rw-r--r--src/commodity.cc23
-rw-r--r--src/commodity.h66
-rw-r--r--src/derive.cc26
-rw-r--r--src/emacs.cc2
-rw-r--r--src/entry.cc3
-rw-r--r--src/entry.h4
-rw-r--r--src/expr.cc43
-rw-r--r--src/expr.h12
-rw-r--r--src/filters.cc168
-rw-r--r--src/filters.h57
-rw-r--r--src/format.cc24
-rw-r--r--src/format.h9
-rw-r--r--src/item.cc22
-rw-r--r--src/item.h10
-rw-r--r--src/journal.cc14
-rw-r--r--src/journal.h4
-rw-r--r--src/op.cc67
-rw-r--r--src/op.h3
-rw-r--r--src/output.cc44
-rw-r--r--src/precmd.cc7
-rw-r--r--src/predicate.h20
-rw-r--r--src/report.cc80
-rw-r--r--src/report.h85
-rw-r--r--src/scope.h77
-rw-r--r--src/session.cc95
-rw-r--r--src/session.h34
-rw-r--r--src/textual.cc53
-rw-r--r--src/timelog.cc2
-rw-r--r--src/times.cc43
-rw-r--r--src/times.h46
-rw-r--r--src/utils.cc22
-rw-r--r--src/value.cc79
-rw-r--r--src/value.h14
-rw-r--r--src/work.cc36
-rw-r--r--src/work.h1
-rw-r--r--src/xact.cc13
-rw-r--r--src/xact.h4
44 files changed, 776 insertions, 798 deletions
diff --git a/src/account.cc b/src/account.cc
index 9d7bf1e5..376097f2 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -30,7 +30,6 @@
*/
#include "account.h"
-#include "report.h"
namespace ledger {
@@ -87,6 +86,25 @@ account_t * account_t::find_account(const string& name,
return account;
}
+namespace {
+ account_t * find_account_re_(account_t * account, const mask_t& regexp)
+ {
+ if (regexp.match(account->fullname()))
+ return account;
+
+ foreach (accounts_map::value_type& pair, account->accounts)
+ if (account_t * a = find_account_re_(pair.second, regexp))
+ return a;
+
+ return NULL;
+ }
+}
+
+account_t * account_t::find_account_re(const string& regexp)
+{
+ return find_account_re_(this, mask_t(regexp));
+}
+
string account_t::fullname() const
{
if (! _fullname.empty()) {
@@ -114,7 +132,8 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
}
namespace {
- value_t get_partial_name(account_t& account) {
+ value_t get_partial_name(account_t& account)
+ {
string name;
for (account_t * acct = &account;
@@ -152,7 +171,8 @@ namespace {
return long(account.depth);
}
- value_t get_depth_spacer(account_t& account) {
+ value_t get_depth_spacer(account_t& account)
+ {
std::ostringstream out;
for (account_t * acct = &account;
acct;
@@ -197,7 +217,7 @@ expr_t::ptr_op_t account_t::lookup(const string& name)
break;
}
- return session_t::current->global_scope->lookup(name);
+ return expr_t::ptr_op_t();
}
bool account_t::valid() const
@@ -222,12 +242,13 @@ bool account_t::valid() const
return true;
}
-void account_t::calculate_sums(expr_t& amount_expr)
+void account_t::calculate_sums(expr_t& amount_expr,
+ scope_t& scope)
{
xdata_t& xd(xdata());
foreach (accounts_map::value_type& pair, accounts) {
- (*pair.second).calculate_sums(amount_expr);
+ (*pair.second).calculate_sums(amount_expr, scope);
xdata_t& child_xd((*pair.second).xdata());
if (! child_xd.total.is_null()) {
@@ -239,7 +260,8 @@ void account_t::calculate_sums(expr_t& amount_expr)
}
}
- call_scope_t args(*this);
+ bind_scope_t bound_scope(scope, *this);
+ call_scope_t args(bound_scope);
value_t amount(amount_expr.calc(args));
if (! amount.is_null()) {
add_or_set_value(xd.total, amount);
diff --git a/src/account.h b/src/account.h
index ad59a5b8..565a11af 100644
--- a/src/account.h
+++ b/src/account.h
@@ -112,6 +112,7 @@ class account_t : public scope_t
}
account_t * find_account(const string& name, bool auto_create = true);
+ account_t * find_account_re(const string& regexp);
virtual expr_t::ptr_op_t lookup(const string& name);
@@ -177,7 +178,7 @@ class account_t : public scope_t
return *xdata_;
}
- void calculate_sums(expr_t& amount_expr);
+ void calculate_sums(expr_t& amount_expr, scope_t& scope);
};
std::ostream& operator<<(std::ostream& out, const account_t& account);
diff --git a/src/amount.cc b/src/amount.cc
index 9a1dd12b..bfbb591e 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -33,14 +33,6 @@
namespace ledger {
-commodity_pool_t * amount_t::current_pool = NULL;
-
-bool amount_t::keep_base = false;
-
-bool amount_t::keep_price = false;
-bool amount_t::keep_date = false;
-bool amount_t::keep_tag = false;
-
bool amount_t::stream_fullstrings = false;
#if !defined(THREADSAFE)
@@ -93,39 +85,31 @@ struct amount_t::bigint_t : public supports_flags<>
}
};
-void amount_t::initialize()
+shared_ptr<commodity_pool_t> amount_t::current_pool;
+
+void amount_t::initialize(shared_ptr<commodity_pool_t> pool)
{
mpz_init(temp);
mpq_init(tempq);
mpfr_init(tempf);
mpfr_init(tempfb);
- if (! current_pool)
- current_pool = new commodity_pool_t;
-
- // Add time commodity conversions, so that timelog's may be parsed
- // in terms of seconds, but reported as minutes or hours.
- if (commodity_t * commodity = current_pool->create("s")) {
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ current_pool = pool;
+}
- parse_conversion("1.0m", "60s");
- parse_conversion("1.0h", "60m");
- } else {
- assert(false);
- }
+void amount_t::initialize()
+{
+ initialize(shared_ptr<commodity_pool_t>(new commodity_pool_t));
}
void amount_t::shutdown()
{
+ current_pool.reset();
+
mpz_clear(temp);
mpq_clear(tempq);
mpfr_clear(tempf);
mpfr_clear(tempfb);
-
- if (current_pool) {
- checked_delete(current_pool);
- current_pool = NULL;
- }
}
void amount_t::_copy(const amount_t& amt)
@@ -426,8 +410,7 @@ void amount_t::set_keep_precision(const bool keep) const
quantity->drop_flags(BIGINT_KEEP_PREC);
}
-amount_t::precision_t
-amount_t::display_precision(const bool full_precision) const
+amount_t::precision_t amount_t::display_precision() const
{
if (! quantity)
throw_(amount_error,
@@ -435,7 +418,7 @@ amount_t::display_precision(const bool full_precision) const
commodity_t& comm(commodity());
- if (! comm || full_precision || keep_precision())
+ if (! comm || keep_precision())
return quantity->prec;
else if (comm.precision() != quantity->prec)
return comm.precision();
@@ -728,22 +711,18 @@ annotation_t& amount_t::annotation()
return ann_comm.details;
}
-amount_t amount_t::strip_annotations(const bool _keep_price,
- const bool _keep_date,
- const bool _keep_tag) const
+amount_t amount_t::strip_annotations(const keep_details_t& what_to_keep) const
{
if (! quantity)
throw_(amount_error,
"Cannot strip commodity annotations from an uninitialized amount");
- if (! commodity().annotated ||
- (_keep_price && _keep_date && _keep_tag))
- return *this;
-
- amount_t t(*this);
- t.set_commodity(as_annotated_commodity(commodity()).
- strip_annotations(_keep_price, _keep_date, _keep_tag));
- return t;
+ if (! what_to_keep.keep_all(commodity())) {
+ amount_t t(*this);
+ t.set_commodity(commodity().strip_annotations(what_to_keep));
+ return t;
+ }
+ return *this;
}
@@ -964,8 +943,7 @@ void amount_t::parse_conversion(const string& larger_str,
smaller.commodity().set_larger(larger);
}
-void amount_t::print(std::ostream& _out, bool omit_commodity,
- bool full_precision) const
+void amount_t::print(std::ostream& _out) const
{
assert(valid());
@@ -974,25 +952,20 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
return;
}
- amount_t base(*this);
- if (! amount_t::keep_base)
- base.in_place_unreduce();
-
std::ostringstream out;
- commodity_t& comm(base.commodity());
+ commodity_t& comm(commodity());
precision_t precision = 0;
- if (! omit_commodity && ! comm.has_flags(COMMODITY_STYLE_SUFFIXED)) {
+ if (! comm.has_flags(COMMODITY_STYLE_SUFFIXED)) {
comm.print(out);
if (comm.has_flags(COMMODITY_STYLE_SEPARATED))
out << " ";
}
- stream_out_mpq(out, MP(quantity), base.display_precision(full_precision),
- omit_commodity ? optional<commodity_t&>() : comm);
+ stream_out_mpq(out, MP(quantity), display_precision(), comm);
- if (! omit_commodity && comm.has_flags(COMMODITY_STYLE_SUFFIXED)) {
+ if (comm.has_flags(COMMODITY_STYLE_SUFFIXED)) {
if (comm.has_flags(COMMODITY_STYLE_SEPARATED))
out << " ";
comm.print(out);
@@ -1001,7 +974,7 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
// If there are any annotations associated with this commodity,
// output them now.
- if (! omit_commodity && comm.annotated) {
+ if (comm.annotated) {
annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm));
assert(&*ann.details.price != this);
ann.write_annotations(out);
diff --git a/src/amount.h b/src/amount.h
index 8229b015..4405e058 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -59,6 +59,7 @@ namespace ledger {
class commodity_t;
class annotation_t;
+class keep_details_t;
class commodity_pool_t;
DECLARE_EXCEPTION(amount_error, std::runtime_error);
@@ -80,8 +81,12 @@ class amount_t
ordered_field_operators<amount_t, long> > > >
{
public:
+ /** Indicates which commodity pool should be used. */
+ static shared_ptr<commodity_pool_t> current_pool;
+
/** Ready the amount subsystem for use.
@note Normally called by session_t::initialize(). */
+ static void initialize(shared_ptr<commodity_pool_t> pool);
static void initialize();
/** Shutdown the amount subsystem and free all resources.
@note Normally called by session_t::shutdown(). */
@@ -94,47 +99,9 @@ public:
avoid losing precision during division and multiplication. */
static const std::size_t extend_by_digits = 6U;
- /** Indicates which commodity pool should be used. */
- static commodity_pool_t * current_pool;
-
- /** If scalable commodities are automatically converted to their most
- reduced form for printing.
-
- For example, Ledger supports time values specified in seconds,
- hours or minutes. Internally, such amounts are always kept as
- quantities of seconds. However, when streaming the amount, Ledger
- converts it to its "least representation", which is \c 5.2h in the
- second case. If \c keep_base is \c true this amount is displayed
- as \c 18720s. */
- static bool keep_base;
-
- /** If the lot price is considered whenever working with commoditized
- values.
-
- Let's say a user adds two values of the following form:
- @code
- 10 AAPL + 10 AAPL {$20}
- @endcode
-
- This expression adds ten shares of Apple stock with another ten
- shares that were purchased for \c $20 a share. If \c keep_price
- is false, the result of this expression is an amount equal to
- <tt>20 AAPL</tt>. If \c keep_price is \c true the expression
- yields an exception for adding amounts with different commodities.
- In that case, a \link balance_t \endlink object must be used to
- store the combined sum. */
- static bool keep_price;
-
- /** If the lot date is considered whenever working with commoditized
- values. @see keep_date */
- static bool keep_date;
- /** If the lot note is considered whenever working with commoditized
- values. @see keep_tag */
- static bool keep_tag;
-
/** If amounts should be streamed using to_fullstring() rather than
- to_string(), so that complete precision is always displayed no
- matter what the precision of an individual commodity may be. */
+ to_string(), so that complete precision is always displayed no matter
+ what the precision of an individual commodity may be. */
static bool stream_fullstrings;
protected:
@@ -317,7 +284,7 @@ public:
precision_t precision() const;
bool keep_precision() const;
void set_keep_precision(const bool keep = true) const;
- precision_t display_precision(const bool full_precision = false) const;
+ precision_t display_precision() const;
/** Returns the negated value of an amount.
@see operator-()
@@ -556,12 +523,8 @@ public:
commodity's annotations. The structure returns will evaluate as
boolean false if there are no details.
- strip_annotations([keep_price, keep_date, keep_tag]) returns an
- amount whose commodity's annotations have been stripped. The
- three `keep_' arguments determine which annotation detailed are
- kept, meaning that the default is to follow whatever
- amount_t::keep_price, amount_t::keep_date and amount_t::keep_tag
- have been set to (which all default to false).
+ strip_annotations() returns an amount whose commodity's annotations have
+ been stripped.
*/
void annotate(const annotation_t& details);
bool is_annotated() const;
@@ -571,9 +534,22 @@ public:
return const_cast<amount_t&>(*this).annotation();
}
- amount_t strip_annotations(const bool _keep_price = keep_price,
- const bool _keep_date = keep_date,
- const bool _keep_tag = keep_tag) const;
+ /** If the lot price is considered whenever working with commoditized
+ values.
+
+ Let's say a user adds two values of the following form:
+ @code
+ 10 AAPL + 10 AAPL {$20}
+ @endcode
+
+ This expression adds ten shares of Apple stock with another ten
+ shares that were purchased for \c $20 a share. If \c keep_price
+ is false, the result of this expression is an amount equal to
+ <tt>20 AAPL</tt>. If \c keep_price is \c true the expression
+ yields an exception for adding amounts with different commodities.
+ In that case, a \link balance_t \endlink object must be used to
+ store the combined sum. */
+ amount_t strip_annotations(const keep_details_t& what_to_keep) const;
/*@}*/
@@ -649,23 +625,20 @@ public:
*/
/*@{*/
- /** An amount may be output to a stream using the
- `print' method. There is also a global operator<< defined which
- simply calls print for an amount on the given stream. There is
- one form of the print method, which takes one required argument
- and two arguments with default values:
-
- print(ostream, bool omit_commodity = false, bool full_precision =
- false) prints an amounts to the given output stream, using its
- commodity's default display characteristics. If `omit_commodity'
- is true, the commodity will not be displayed, only the amount
- (although the commodity's display precision is still used). If
- `full_precision' is true, the full internal precision of the
- amount is displayed, regardless of its commodity's display
- precision.
+ /** An amount may be output to a stream using the `print' method. There is
+ also a global operator<< defined which simply calls print for an amount
+ on the given stream. There is one form of the print method, which takes
+ one required argument and two arguments with default values:
+
+ print(ostream, bool omit_commodity = false, bool full_precision = false)
+ prints an amounts to the given output stream, using its commodity's
+ default display characteristics. If `omit_commodity' is true, the
+ commodity will not be displayed, only the amount (although the
+ commodity's display precision is still used). If `full_precision' is
+ true, the full internal precision of the amount is displayed, regardless
+ of its commodity's display precision.
*/
- void print(std::ostream& out, bool omit_commodity = false,
- bool full_precision = false) const;
+ void print(std::ostream& out) const;
/*@}*/
@@ -709,18 +682,21 @@ inline string amount_t::to_string() const {
inline string amount_t::to_fullstring() const {
std::ostringstream bufstream;
- print(bufstream, false, true);
+ unrounded().print(bufstream);
return bufstream.str();
}
inline string amount_t::quantity_string() const {
std::ostringstream bufstream;
- print(bufstream, true);
+ number().print(bufstream);
return bufstream.str();
}
inline std::ostream& operator<<(std::ostream& out, const amount_t& amt) {
- amt.print(out, false, amount_t::stream_fullstrings);
+ if (amount_t::stream_fullstrings)
+ amt.unrounded().print(out);
+ else
+ amt.print(out);
return out;
}
inline std::istream& operator>>(std::istream& in, amount_t& amt) {
diff --git a/src/balance.cc b/src/balance.cc
index 7b1ed4dd..c9ca148d 100644
--- a/src/balance.cc
+++ b/src/balance.cc
@@ -181,6 +181,7 @@ balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
if (amounts.size() == 1) {
return amounts.begin()->second;
}
+#if 0
else if (amounts.size() > 1) {
// Try stripping annotations before giving an error.
balance_t temp(strip_annotations());
@@ -190,6 +191,7 @@ balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
throw_(amount_error,
"Requested amount of a balance with multiple commodities: " << temp);
}
+#endif
}
else if (amounts.size() > 0) {
amounts_map::const_iterator i = amounts.find(&*commodity);
@@ -199,14 +201,13 @@ balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
return none;
}
-balance_t balance_t::strip_annotations(const bool keep_price,
- const bool keep_date,
- const bool keep_tag) const
+balance_t
+balance_t::strip_annotations(const keep_details_t& what_to_keep) const
{
balance_t temp;
foreach (const amounts_map::value_type& pair, amounts)
- temp += pair.second.strip_annotations(keep_price, keep_date, keep_tag);
+ temp += pair.second.strip_annotations(what_to_keep);
return temp;
}
diff --git a/src/balance.h b/src/balance.h
index d1e4301b..a0231717 100644
--- a/src/balance.h
+++ b/src/balance.h
@@ -446,10 +446,7 @@ public:
* their commodity annotations likewise stripped. See
* amount_t::strip_annotations for more details.
*/
- balance_t
- strip_annotations(const bool keep_price = amount_t::keep_price,
- const bool keep_date = amount_t::keep_date,
- const bool keep_tag = amount_t::keep_tag) const;
+ balance_t strip_annotations(const keep_details_t& what_to_keep) const;
/**
* Printing methods. A balance may be output to a stream using the
diff --git a/src/chain.cc b/src/chain.cc
index d3ccf11c..f79da543 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -55,7 +55,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// filter_xacts will only pass through xacts matching the
// `display_predicate'.
if (! report.display_predicate.empty())
- handler.reset(new filter_xacts(handler, report.display_predicate));
+ handler.reset(new filter_xacts
+ (handler, item_predicate<xact_t>(report.display_predicate,
+ report.what_to_keep)));
// calc_xacts computes the running total. When this
// appears will determine, for example, whether filtered
@@ -81,7 +83,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
descend_exprs.rbegin();
i != descend_exprs.rend();
i++)
- handler.reset(new component_xacts(handler, *i));
+ handler.reset(new component_xacts
+ (handler,
+ item_predicate<xact_t>(*i, report.what_to_keep)));
remember_components = true;
}
@@ -90,7 +94,7 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// xacts which can be reconciled to a given balance
// (calculated against the xacts which it receives).
if (! report.reconcile_balance.empty()) {
- date_t cutoff = current_date;
+ date_t cutoff = CURRENT_DATE();
if (! report.reconcile_date.empty())
cutoff = parse_date(report.reconcile_date);
handler.reset(new reconcile_xacts
@@ -100,7 +104,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// filter_xacts will only pass through xacts
// matching the `secondary_predicate'.
if (! report.secondary_predicate.empty())
- handler.reset(new filter_xacts(handler, report.secondary_predicate));
+ handler.reset(new filter_xacts
+ (handler, item_predicate<xact_t>(report.secondary_predicate,
+ report.what_to_keep)));
// sort_xacts will sort all the xacts it sees, based
// on the `sort_order' value expression.
@@ -176,7 +182,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
if (! report.predicate.empty()) {
DEBUG("report.predicate",
"Report predicate expression = " << report.predicate);
- handler.reset(new filter_xacts(handler, report.predicate));
+ handler.reset(new filter_xacts
+ (handler, item_predicate<xact_t>(report.predicate,
+ report.what_to_keep)));
}
#if 0
diff --git a/src/commodity.cc b/src/commodity.cc
index ef705065..d651f8ae 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -721,27 +721,26 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
}
commodity_t&
-annotated_commodity_t::strip_annotations(const bool _keep_price,
- const bool _keep_date,
- const bool _keep_tag)
+annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
{
DEBUG("commodity.annotated.strip",
"Reducing commodity " << *this << std::endl
- << " keep price " << _keep_price << " "
- << " keep date " << _keep_date << " "
- << " keep tag " << _keep_tag);
+ << " keep price " << what_to_keep.keep_price << " "
+ << " keep date " << what_to_keep.keep_date << " "
+ << " keep tag " << what_to_keep.keep_tag);
commodity_t * new_comm;
- if ((_keep_price && details.price) ||
- (_keep_date && details.date) ||
- (_keep_tag && details.tag))
+ if (what_to_keep.keep_any(*this) &&
+ ((what_to_keep.keep_price && details.price) ||
+ (what_to_keep.keep_date && details.date) ||
+ (what_to_keep.keep_tag && details.tag)))
{
new_comm = parent().find_or_create
(referent(),
- annotation_t(_keep_price ? details.price : none,
- _keep_date ? details.date : none,
- _keep_tag ? details.tag : none));
+ annotation_t(what_to_keep.keep_price ? details.price : none,
+ what_to_keep.keep_date ? details.date : none,
+ what_to_keep.keep_tag ? details.tag : none));
} else {
new_comm = parent().find_or_create(base_symbol());
}
diff --git a/src/commodity.h b/src/commodity.h
index c8a1e815..ac1d15ba 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -49,6 +49,8 @@
namespace ledger {
+class keep_details_t;
+
DECLARE_EXCEPTION(commodity_error, std::runtime_error);
/**
@@ -211,6 +213,17 @@ public:
return base.get() == comm.base.get();
}
+ virtual commodity_t& referent() {
+ return *this;
+ }
+ virtual const commodity_t& referent() const {
+ return *this;
+ }
+ virtual commodity_t& strip_annotations(const keep_details_t& what_to_keep) {
+ return *this;
+ }
+ virtual void write_annotations(std::ostream& out) const {}
+
commodity_pool_t& parent() const {
return *parent_;
}
@@ -421,6 +434,49 @@ struct annotation_t : public equality_comparable<annotation_t>
}
};
+struct keep_details_t
+{
+ bool keep_price;
+ bool keep_date;
+ bool keep_tag;
+ bool keep_base;
+
+ explicit keep_details_t(bool _keep_price = false,
+ bool _keep_date = false,
+ bool _keep_tag = false,
+ bool _keep_base = false)
+ : keep_price(_keep_price),
+ keep_date(_keep_date),
+ keep_tag(_keep_tag),
+ keep_base(_keep_base)
+ {
+ TRACE_CTOR(keep_details_t, "bool, bool, bool, bool");
+ }
+ keep_details_t(const keep_details_t& other)
+ : keep_price(other.keep_price), keep_date(other.keep_date),
+ keep_tag(other.keep_tag), keep_base(other.keep_base) {
+ TRACE_CTOR(keep_details_t, "copy");
+ }
+
+ ~keep_details_t() throw() {
+ TRACE_DTOR(keep_details_t);
+ }
+
+ bool keep_all() const {
+ return keep_price && keep_date && keep_tag;
+ }
+ bool keep_all(const commodity_t& comm) const {
+ return ! comm.annotated || (keep_price && keep_date && keep_tag);
+ }
+
+ bool keep_any() const {
+ return keep_price || keep_date || keep_tag;
+ }
+ bool keep_any(const commodity_t& comm) const {
+ return comm.annotated && (keep_price || keep_date || keep_tag);
+ }
+};
+
inline std::ostream& operator<<(std::ostream& out, const annotation_t& details) {
details.print(out);
return out;
@@ -456,18 +512,16 @@ public:
return *this == static_cast<const commodity_t&>(comm);
}
- commodity_t& referent() {
+ virtual commodity_t& referent() {
return *ptr;
}
- const commodity_t& referent() const {
+ virtual const commodity_t& referent() const {
return *ptr;
}
- commodity_t& strip_annotations(const bool _keep_price,
- const bool _keep_date,
- const bool _keep_tag);
+ virtual commodity_t& strip_annotations(const keep_details_t& what_to_keep);
- void write_annotations(std::ostream& out) const {
+ virtual void write_annotations(std::ostream& out) const {
annotated_commodity_t::write_annotations(out, details);
}
diff --git a/src/derive.cc b/src/derive.cc
index 7ee530d1..712fd807 100644
--- a/src/derive.cc
+++ b/src/derive.cc
@@ -35,7 +35,7 @@
namespace ledger {
-entry_t * derive_new_entry(report_t& report,
+entry_t * derive_new_entry(report_t& report,
strings_list::iterator i,
strings_list::iterator end)
{
@@ -71,12 +71,12 @@ entry_t * derive_new_entry(report_t& report,
if (! matching) {
account_t * acct;
if (i == end || ((*i)[0] == '-' || std::isdigit((*i)[0]))) {
- acct = session.find_account("Expenses");
+ acct = session.master->find_account("Expenses");
}
else if (i != end) {
- acct = session.find_account_re(*i);
+ acct = session.master->find_account_re(*i);
if (! acct)
- acct = session.find_account(*i);
+ acct = session.master->find_account(*i);
assert(acct);
i++;
}
@@ -106,16 +106,16 @@ entry_t * derive_new_entry(report_t& report,
if (i != end) {
if (! acct)
- acct = session.find_account_re(*i);
+ acct = session.master->find_account_re(*i);
if (! acct)
- acct = session.find_account(*i);
+ acct = session.master->find_account(*i);
}
if (! acct) {
if (matching && matching->journal->basket)
acct = matching->journal->basket;
else
- acct = session.find_account("Equity");
+ acct = session.master->find_account("Equity");
}
added->add_xact(new xact_t(acct));
@@ -144,9 +144,9 @@ entry_t * derive_new_entry(report_t& report,
added->add_xact(xact);
if (i != end) {
- account_t * acct = session.find_account_re(*i);
+ account_t * acct = session.master->find_account_re(*i);
if (! acct)
- acct = session.find_account(*i);
+ acct = session.master->find_account(*i);
assert(acct);
added->xacts.back()->account = acct;
}
@@ -185,16 +185,16 @@ entry_t * derive_new_entry(report_t& report,
strings_list::iterator x = i;
if (i != end && ++x == end) {
- draw_acct = session.find_account_re(*i);
+ draw_acct = session.master->find_account_re(*i);
if (! draw_acct)
- draw_acct = session.find_account(*i);
+ draw_acct = session.master->find_account(*i);
i++;
}
if (! acct)
- acct = session.find_account_re(re_pat);
+ acct = session.master->find_account_re(re_pat);
if (! acct)
- acct = session.find_account(re_pat);
+ acct = session.master->find_account(re_pat);
xact = new xact_t(acct, amount);
if (! xact->amount.commodity()) {
diff --git a/src/emacs.cc b/src/emacs.cc
index 714302c5..3c3c1b7b 100644
--- a/src/emacs.cc
+++ b/src/emacs.cc
@@ -39,7 +39,7 @@ void format_emacs_xacts::write_entry(entry_t& entry)
out << "\"" << entry.pathname << "\" "
<< (static_cast<std::size_t>(entry.beg_line) + 1) << " ";
- tm when = gregorian::to_tm(*entry.date());
+ tm when = gregorian::to_tm(entry.date());
std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local?
out << "(" << (date / 65536) << " " << (date % 65536) << " 0) ";
diff --git a/src/entry.cc b/src/entry.cc
index 27968614..815186f0 100644
--- a/src/entry.cc
+++ b/src/entry.cc
@@ -247,8 +247,7 @@ bool entry_base_t::finalize()
DEBUG("entry.finalize.totals",
"Total for " << xact->account->fullname() << " + "
- << xact->amount.strip_annotations() << ": "
- << xact->account->xdata().value.strip_annotations());
+ << xact->amount << ": " << xact->account->xdata().value);
}
}
if (all_null)
diff --git a/src/entry.h b/src/entry.h
index 37456199..ceea6aed 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -135,10 +135,10 @@ public:
: entry_base_t(), predicate(other.predicate) {
TRACE_CTOR(auto_entry_t, "copy");
}
- auto_entry_t(const string& _predicate)
+ auto_entry_t(const item_predicate<xact_t>& _predicate)
: predicate(_predicate)
{
- TRACE_CTOR(auto_entry_t, "const string&");
+ TRACE_CTOR(auto_entry_t, "const item_predicate<xact_t>&");
}
virtual ~auto_entry_t() {
diff --git a/src/expr.cc b/src/expr.cc
index da45bb82..a655edf0 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -35,8 +35,6 @@
namespace ledger {
-std::auto_ptr<expr_t::parser_t> expr_t::parser;
-
expr_t::expr_t() : compiled(false)
{
TRACE_CTOR(expr_t, "");
@@ -52,17 +50,15 @@ expr_t::expr_t(const string& _str, const uint_least8_t flags)
: str(_str), compiled(false)
{
TRACE_CTOR(expr_t, "const string&");
-
if (! _str.empty())
- ptr = parser->parse(str, flags);
+ parse(str, flags);
}
expr_t::expr_t(std::istream& in, const uint_least8_t flags)
: compiled(false)
{
TRACE_CTOR(expr_t, "std::istream&");
-
- ptr = parser->parse(in, flags);
+ parse(in, flags);
}
expr_t::expr_t(const ptr_op_t& _ptr, const string& _str)
@@ -88,22 +84,18 @@ expr_t& expr_t::operator=(const expr_t& _expr)
void expr_t::parse(const string& _str, const uint32_t flags)
{
- if (! parser.get())
- throw_(parse_error, "Value expression parser not initialized");
-
+ parser_t parser;
str = _str;
- ptr = parser->parse(str, flags);
+ ptr = parser.parse(str, flags);
compiled = false;
}
void expr_t::parse(std::istream& in, const uint32_t flags,
const string * original_string)
{
- if (! parser.get())
- throw_(parse_error, "Value expression parser not initialized");
-
+ parser_t parser;
str = "<stream>";
- ptr = parser->parse(in, flags, original_string);
+ ptr = parser.parse(in, flags, original_string);
compiled = false;
}
@@ -131,7 +123,18 @@ value_t expr_t::calc(scope_t& scope)
dump(*_log_stream);
}
}
- return ptr->calc(scope);
+
+ ptr_op_t context;
+ try {
+ return ptr->calc(scope, &context);
+ }
+ catch (const std::exception& err) {
+ if (context) {
+ add_error_context("While evaluating value expression:");
+ add_error_context(op_context(ptr, context));
+ }
+ throw;
+ }
}
return NULL_VALUE;
}
@@ -182,16 +185,6 @@ void expr_t::dump(std::ostream& out) const
if (ptr) ptr->dump(out, 0);
}
-void expr_t::initialize()
-{
- parser.reset(new expr_t::parser_t);
-}
-
-void expr_t::shutdown()
-{
- parser.reset();
-}
-
std::ostream& operator<<(std::ostream& out, const expr_t& expr) {
expr.print(out);
return out;
diff --git a/src/expr.h b/src/expr.h
index 7f4cd9b5..8104be35 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -68,9 +68,7 @@ typedef function<value_t (call_scope_t&)> function_t;
class expr_t
{
struct token_t;
-
- class parser_t;
- static std::auto_ptr<parser_t> parser;
+ class parser_t;
public:
class op_t;
@@ -92,14 +90,6 @@ private:
bool compiled;
public:
- /**
- * The initialize and shutdown methods ready the amount subsystem for
- * use. Normally they are called by `session_t::initialize' and
- * `session_t::shutdown'.
- */
- static void initialize();
- static void shutdown();
-
expr_t();
expr_t(const expr_t& other);
expr_t(const ptr_op_t& _ptr, const string& _str = "");
diff --git a/src/filters.cc b/src/filters.cc
index 9be7e486..b3d1e2fe 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -102,7 +102,9 @@ void set_account_value::operator()(xact_t& xact)
account_t * acct = xact.reported_account();
account_t::xdata_t& xdata(acct->xdata());
+ DEBUG("account.sums", "Account value was = " << xdata.value);
xact.add_to_value(xdata.value);
+ DEBUG("account.sums", "Account value is = " << xdata.value);
xdata.count++;
if (xact.has_flags(XACT_VIRTUAL))
@@ -218,73 +220,74 @@ void invert_xacts::operator()(xact_t& xact)
}
-static inline
-void handle_value(const value_t& value,
- account_t * account,
- entry_t * entry,
- unsigned int flags,
- std::list<xact_t>& temps,
- item_handler<xact_t>& handler,
- const date_t& date = date_t(),
- xacts_list * component_xacts = NULL)
-{
- temps.push_back(xact_t(account));
- xact_t& xact(temps.back());
- xact.entry = entry;
- xact.add_flags(ITEM_TEMP);
- entry->add_xact(&xact);
-
- // If there are component xacts to associate with this
- // temporary, do so now.
-
- if (component_xacts)
- xact.xdata().copy_component_xacts(*component_xacts);
-
- // If the account for this xact is all virtual, then report
- // the xact as such. This allows subtotal reports to show
- // "(Account)" for accounts that contain only virtual xacts.
-
- if (account && account->has_xdata())
- if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS)) {
- xact.add_flags(XACT_VIRTUAL);
- if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS))
- xact.add_flags(XACT_MUST_BALANCE);
- }
+namespace {
+ void handle_value(const value_t& value,
+ account_t * account,
+ entry_t * entry,
+ unsigned int flags,
+ std::list<xact_t>& temps,
+ item_handler<xact_t>& handler,
+ const date_t& date = date_t(),
+ xacts_list * component_xacts = NULL)
+ {
+ temps.push_back(xact_t(account));
+ xact_t& xact(temps.back());
+ xact.entry = entry;
+ xact.add_flags(ITEM_TEMP);
+ entry->add_xact(&xact);
+
+ // If there are component xacts to associate with this temporary, do so
+ // now.
+
+ if (component_xacts)
+ xact.xdata().copy_component_xacts(*component_xacts);
+
+ // If the account for this xact is all virtual, then report the xact as
+ // such. This allows subtotal reports to show "(Account)" for accounts
+ // that contain only virtual xacts.
+
+ if (account && account->has_xdata())
+ if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS)) {
+ xact.add_flags(XACT_VIRTUAL);
+ if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS))
+ xact.add_flags(XACT_MUST_BALANCE);
+ }
+
+ xact_t::xdata_t& xdata(xact.xdata());
- xact_t::xdata_t& xdata(xact.xdata());
+ if (is_valid(date))
+ xdata.date = date;
- if (is_valid(date))
- xdata.date = date;
-
- value_t temp(value);
-
- switch (value.type()) {
- case value_t::BOOLEAN:
- case value_t::DATETIME:
- case value_t::DATE:
- case value_t::INTEGER:
- temp.cast(value_t::AMOUNT);
- // fall through...
-
- case value_t::AMOUNT:
- xact.amount = temp.as_amount();
- break;
-
- case value_t::BALANCE:
- case value_t::BALANCE_PAIR:
- xdata.value = temp;
- flags |= XACT_EXT_COMPOUND;
- break;
-
- default:
- assert(false); // jww (2008-04-24): What to do here?
- break;
- }
+ value_t temp(value);
- if (flags)
- xdata.add_flags(flags);
+ switch (value.type()) {
+ case value_t::BOOLEAN:
+ case value_t::DATETIME:
+ case value_t::DATE:
+ case value_t::INTEGER:
+ temp.cast(value_t::AMOUNT);
+ // fall through...
- handler(xact);
+ case value_t::AMOUNT:
+ xact.amount = temp.as_amount();
+ break;
+
+ case value_t::BALANCE:
+ case value_t::BALANCE_PAIR:
+ xdata.value = temp;
+ flags |= XACT_EXT_COMPOUND;
+ break;
+
+ default:
+ assert(false); // jww (2008-04-24): What to do here?
+ break;
+ }
+
+ if (flags)
+ xdata.add_flags(flags);
+
+ handler(xact);
+ }
}
void collapse_xacts::report_subtotal()
@@ -405,12 +408,16 @@ void component_xacts::operator()(xact_t& xact)
void subtotal_xacts::report_subtotal(const char * spec_fmt)
{
std::ostringstream out_date;
- if (! spec_fmt) {
+ if (spec_fmt) {
+ out_date << format_date(finish, string(spec_fmt));
+ }
+ else if (date_format) {
string fmt = "- ";
- fmt += output_date_format;
+ fmt += *date_format;
out_date << format_date(finish, string(fmt));
- } else {
- out_date << format_date(finish, string(spec_fmt));
+ }
+ else {
+ out_date << format_date(finish);
}
entry_temps.push_back(entry_t());
@@ -428,9 +435,9 @@ void subtotal_xacts::report_subtotal(const char * spec_fmt)
void subtotal_xacts::operator()(xact_t& xact)
{
if (! is_valid(start) || xact.date() < start)
- start = *xact.date();
+ start = xact.date();
if (! is_valid(finish) || xact.date() > finish)
- finish = *xact.date();
+ finish = xact.date();
account_t * acct = xact.reported_account();
assert(acct);
@@ -470,7 +477,7 @@ void interval_xacts::report_subtotal(const date_t& date)
if (is_valid(date))
finish = date - gregorian::days(1);
else
- finish = *last_xact->date();
+ finish = last_xact->date();
subtotal_xacts::report_subtotal();
@@ -479,7 +486,7 @@ void interval_xacts::report_subtotal(const date_t& date)
void interval_xacts::operator()(xact_t& xact)
{
- const date_t& date(*xact.date());
+ const date_t& date(xact.date());
if ((is_valid(interval.begin) && date < interval.begin) ||
(is_valid(interval.end) && date >= interval.end))
@@ -550,7 +557,7 @@ void by_payee_xacts::operator()(xact_t& xact)
}
if (xact.date() > (*i).second->start)
- (*i).second->start = *xact.date();
+ (*i).second->start = xact.date();
(*(*i).second)(xact);
}
@@ -691,7 +698,7 @@ void budget_xacts::operator()(xact_t& xact)
handle:
if (xact_in_budget && flags & BUDGET_BUDGETED) {
- report_budget_items(*xact.date());
+ report_budget_items(xact.date());
item_handler<xact_t>::operator()(xact);
}
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
@@ -705,10 +712,10 @@ void forecast_xacts::add_xact(const interval_t& period, xact_t& xact)
interval_t& i = pending_xacts.back().first;
if (! is_valid(i.begin)) {
- i.set_start(current_date);
+ i.set_start(CURRENT_DATE());
i.begin = i.increment(i.begin);
} else {
- while (i.begin < current_date)
+ while (i.begin < CURRENT_DATE())
i.begin = i.increment(i.begin);
}
}
@@ -758,7 +765,7 @@ void forecast_xacts::flush()
temp.xdata().has_flags(XACT_EXT_MATCHES)) {
if (! pred(temp))
break;
- last = *temp.date();
+ last = temp.date();
passed.clear();
} else {
bool found = false;
@@ -779,15 +786,16 @@ void forecast_xacts::flush()
item_handler<xact_t>::flush();
}
-pass_down_accounts::pass_down_accounts(acct_handler_ptr handler,
- accounts_iterator& iter,
- const expr_t& predicate)
+pass_down_accounts::pass_down_accounts
+ (acct_handler_ptr handler,
+ accounts_iterator& iter,
+ const optional<item_predicate<account_t> >& predicate)
: item_handler<account_t>(handler), pred(predicate)
{
TRACE_CTOR(pass_down_accounts,
"acct_handler_ptr, accounts_iterator");
for (account_t * account = iter(); account; account = iter())
- if (pred(*account))
+ if (! pred || (*pred)(*account))
item_handler<account_t>::operator()(*account);
item_handler<account_t>::flush();
diff --git a/src/filters.h b/src/filters.h
index 50e02a50..c6ae1a4d 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -273,18 +273,11 @@ class filter_xacts : public item_handler<xact_t>
filter_xacts();
public:
- filter_xacts(xact_handler_ptr handler,
- const expr_t& predicate)
+ filter_xacts(xact_handler_ptr handler,
+ const item_predicate<xact_t>& predicate)
: item_handler<xact_t>(handler), pred(predicate) {
TRACE_CTOR(filter_xacts,
- "xact_handler_ptr, const value_expr&");
- }
-
- filter_xacts(xact_handler_ptr handler,
- const string& predicate)
- : item_handler<xact_t>(handler), pred(predicate) {
- TRACE_CTOR(filter_xacts,
- "xact_handler_ptr, const string&");
+ "xact_handler_ptr, const item_predicate<xact_t>&");
}
virtual ~filter_xacts() {
TRACE_DTOR(filter_xacts);
@@ -421,17 +414,11 @@ class component_xacts : public item_handler<xact_t>
component_xacts();
public:
- component_xacts(xact_handler_ptr handler,
- const expr_t& predicate)
- : item_handler<xact_t>(handler), pred(predicate) {
- TRACE_CTOR(component_xacts,
- "xact_handler_ptr, const value_expr&");
- }
- component_xacts(xact_handler_ptr handler,
- const string& predicate)
+ component_xacts(xact_handler_ptr handler,
+ const item_predicate<xact_t>& predicate)
: item_handler<xact_t>(handler), pred(predicate) {
TRACE_CTOR(component_xacts,
- "xact_handler_ptr, const string&");
+ "xact_handler_ptr, const item_predicate<xact_t>&");
}
virtual ~component_xacts() throw() {
TRACE_DTOR(component_xacts);
@@ -507,7 +494,7 @@ public:
virtual void flush() {
if (last_xact) {
- output_diff(current_date);
+ output_diff(CURRENT_DATE());
last_xact = NULL;
}
item_handler<xact_t>::flush();
@@ -557,9 +544,9 @@ class subtotal_xacts : public item_handler<xact_t>
subtotal_xacts();
protected:
- values_map values;
- bool remember_components;
-
+ values_map values;
+ bool remember_components;
+ optional<string> date_format;
std::list<entry_t> entry_temps;
std::list<xact_t> xact_temps;
@@ -568,9 +555,11 @@ public:
date_t finish;
subtotal_xacts(xact_handler_ptr handler,
- bool _remember_components = false)
+ bool _remember_components = false,
+ optional<string> _date_format = none)
: item_handler<xact_t>(handler),
- remember_components(_remember_components) {
+ remember_components(_remember_components),
+ date_format(_date_format) {
TRACE_CTOR(subtotal_xacts,
"xact_handler_ptr, bool");
}
@@ -735,7 +724,7 @@ public:
virtual void flush();
virtual void operator()(xact_t& xact) {
- days_of_the_week[xact.date()->day_of_week()].push_back(&xact);
+ days_of_the_week[xact.date().day_of_week()].push_back(&xact);
}
};
@@ -812,13 +801,11 @@ class forecast_xacts : public generate_xacts
item_predicate<xact_t> pred;
public:
- forecast_xacts(xact_handler_ptr handler, const expr_t& predicate)
- : generate_xacts(handler), pred(predicate) {
- TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const expr_t&");
- }
- forecast_xacts(xact_handler_ptr handler, const string& predicate)
+ forecast_xacts(xact_handler_ptr handler,
+ const item_predicate<xact_t>& predicate)
: generate_xacts(handler), pred(predicate) {
- TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const string&");
+ TRACE_CTOR(forecast_xacts,
+ "xact_handler_ptr, const item_predicate<xact_t>&");
}
virtual ~forecast_xacts() throw() {
TRACE_DTOR(forecast_xacts);
@@ -858,12 +845,12 @@ class pass_down_accounts : public item_handler<account_t>
{
pass_down_accounts();
- item_predicate<account_t> pred;
+ optional<item_predicate<account_t> > pred;
public:
pass_down_accounts(acct_handler_ptr handler,
- accounts_iterator& iter,
- const expr_t& predicate = expr_t());
+ accounts_iterator& iter,
+ const optional<item_predicate<account_t> >& predicate = none);
virtual ~pass_down_accounts() {
TRACE_DTOR(pass_down_accounts);
diff --git a/src/format.cc b/src/format.cc
index eeaf6fe4..c4683876 100644
--- a/src/format.cc
+++ b/src/format.cc
@@ -34,13 +34,6 @@
namespace ledger {
-format_t::elision_style_t
- format_t::elision_style = ABBREVIATE;
-int format_t::abbrev_length = 2;
-
-bool format_t::ansi_codes = false;
-bool format_t::ansi_invert = false;
-
void format_t::element_t::dump(std::ostream& out) const
{
out << "Element: ";
@@ -295,7 +288,8 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
value = elem->expr.calc(scope);
}
DEBUG("format.expr", "value = (" << value << ")");
- value.strip_annotations().dump(out, elem->min_width);
+
+ value.print(out, elem->min_width);
}
catch (const calc_error&) {
add_error_context("While calculating format expression:");
@@ -326,7 +320,7 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
}
string format_t::truncate(const unistring& ustr, std::size_t width,
- const bool is_account)
+ const int account_abbrev_length)
{
assert(width < 4095);
@@ -336,7 +330,11 @@ string format_t::truncate(const unistring& ustr, std::size_t width,
std::ostringstream buf;
- switch (elision_style) {
+ elision_style_t style = TRUNCATE_TRAILING;
+ if (account_abbrev_length > 0)
+ style = ABBREVIATE;
+
+ switch (style) {
case TRUNCATE_LEADING:
// This method truncates at the beginning.
buf << ".." << ustr.extract(len - width, width);
@@ -351,7 +349,7 @@ string format_t::truncate(const unistring& ustr, std::size_t width,
break;
case ABBREVIATE:
- if (is_account) {
+ if (account_abbrev_length > 0) {
std::list<string> parts;
string::size_type beg = 0;
string strcopy(ustr.extract());
@@ -376,8 +374,8 @@ string format_t::truncate(const unistring& ustr, std::size_t width,
if (newlen > width) {
unistring temp(*i);
- result << temp.extract(0, abbrev_length) << ":";
- newlen -= temp.length() - abbrev_length;
+ result << temp.extract(0, account_abbrev_length) << ":";
+ newlen -= temp.length() - account_abbrev_length;
} else {
result << *i << ":";
}
diff --git a/src/format.h b/src/format.h
index 439cb70b..66c226b2 100644
--- a/src/format.h
+++ b/src/format.h
@@ -169,13 +169,6 @@ public:
};
private:
- // jww (2008-08-02): Should these four be here, or in session_t?
- static elision_style_t elision_style;
- static int abbrev_length;
-
- static bool ansi_codes;
- static bool ansi_invert;
-
static element_t * parse_elements(const string& fmt);
friend class report_t;
@@ -207,7 +200,7 @@ public:
}
static string truncate(const unistring& str, std::size_t width,
- const bool is_account = false);
+ const int account_abbrev_length = -1);
};
} // namespace ledger
diff --git a/src/item.cc b/src/item.cc
index 27d28782..a4e2f2f1 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -30,8 +30,6 @@
*/
#include "item.h"
-#include "session.h"
-#include "report.h"
namespace ledger {
@@ -69,7 +67,7 @@ void item_t::set_tag(const string& tag,
assert(result.second);
}
-void item_t::parse_tags(const char * p)
+void item_t::parse_tags(const char * p, int current_year)
{
if (char * b = std::strchr(p, '[')) {
if (char * e = std::strchr(p, ']')) {
@@ -79,10 +77,10 @@ void item_t::parse_tags(const char * p)
if (char * p = std::strchr(buf, '=')) {
*p++ = '\0';
- _date_eff = parse_date(p);
+ _date_eff = parse_date(p, current_year);
}
if (buf[0])
- _date = parse_date(buf);
+ _date = parse_date(buf, current_year);
}
}
@@ -114,7 +112,7 @@ void item_t::parse_tags(const char * p)
}
}
-void item_t::append_note(const char * p)
+void item_t::append_note(const char * p, int current_year)
{
if (note)
*note += p;
@@ -122,7 +120,7 @@ void item_t::append_note(const char * p)
note = p;
*note += '\n';
- parse_tags(p);
+ parse_tags(p, current_year);
}
namespace {
@@ -250,14 +248,6 @@ value_t get_comment(item_t& item)
}
}
-optional<date_t> item_t::date() const
-{
- if (use_effective_date && _date_eff)
- return effective_date();
- else
- return actual_date();
-}
-
expr_t::ptr_op_t item_t::lookup(const string& name)
{
switch (name[0]) {
@@ -321,7 +311,7 @@ expr_t::ptr_op_t item_t::lookup(const string& name)
break;
}
- return session_t::current->global_scope->lookup(name);
+ return expr_t::ptr_op_t();
}
bool item_t::valid() const
diff --git a/src/item.h b/src/item.h
index fbaab14b..c4d01b1d 100644
--- a/src/item.h
+++ b/src/item.h
@@ -126,16 +126,16 @@ public:
virtual optional<string> get_tag(const string& tag) const;
virtual void set_tag(const string& tag,
const optional<string>& value = none);
- virtual void parse_tags(const char * p);
- virtual void append_note(const char * p);
+ virtual void parse_tags(const char * p, int current_year = -1);
+ virtual void append_note(const char * p, int current_year = -1);
- virtual optional<date_t> actual_date() const {
- return _date;
+ virtual date_t date() const {
+ assert(_date);
+ return *_date;
}
virtual optional<date_t> effective_date() const {
return _date_eff;
}
- optional<date_t> date() const;
void set_state(state_t new_state) {
_state = new_state;
diff --git a/src/journal.cc b/src/journal.cc
index c1da2fc9..403e7c81 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -36,12 +36,6 @@ namespace ledger {
const string version = PACKAGE_VERSION;
-journal_t::journal_t() : basket(NULL)
-{
- TRACE_CTOR(journal_t, "");
- master = session_t::current->master.get();
-}
-
journal_t::~journal_t()
{
TRACE_DTOR(journal_t);
@@ -70,22 +64,22 @@ journal_t::~journal_t()
void journal_t::add_account(account_t * acct)
{
- session_t::current->add_account(acct);
+ master->add_account(acct);
}
bool journal_t::remove_account(account_t * acct)
{
- return session_t::current->remove_account(acct);
+ return master->remove_account(acct);
}
account_t * journal_t::find_account(const string& name, bool auto_create)
{
- return session_t::current->find_account(name, auto_create);
+ return master->find_account(name, auto_create);
}
account_t * journal_t::find_account_re(const string& regexp)
{
- return session_t::current->find_account_re(regexp);
+ return master->find_account_re(regexp);
}
bool journal_t::add_entry(entry_t * entry)
diff --git a/src/journal.h b/src/journal.h
index ff060d76..1b5607cc 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -76,7 +76,9 @@ public:
hooks_t<entry_finalizer_t, entry_t> entry_finalize_hooks;
- journal_t();
+ journal_t(account_t * _master = NULL) : master(_master) {
+ TRACE_CTOR(journal_t, "");
+ }
~journal_t();
// These four methods are delegated to the current session, since all
diff --git a/src/op.cc b/src/op.cc
index 1e23d3fe..685c65bf 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -72,28 +72,10 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope)
return intermediate;
}
-namespace {
- expr_t::ptr_op_t context_op_ptr;
-}
-
-value_t expr_t::op_t::calc(scope_t& scope)
+value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * context)
{
try {
- context_op_ptr = ptr_op_t();
- return opcalc(scope);
- }
- catch (const std::exception& err) {
- if (context_op_ptr) {
- add_error_context("While evaluating value expression:");
- add_error_context(op_context(this, context_op_ptr));
- }
- throw;
- }
-}
-value_t expr_t::op_t::opcalc(scope_t& scope)
-{
- try {
switch (kind) {
case VALUE:
return as_value();
@@ -101,7 +83,7 @@ value_t expr_t::op_t::opcalc(scope_t& scope)
case IDENT:
if (! left())
throw_(calc_error, "Unknown identifier '" << as_ident() << "'");
- return left()->opcalc(scope);
+ return left()->calc(scope, context);
case FUNCTION: {
// Evaluating a FUNCTION is the same as calling it directly; this happens
@@ -136,7 +118,7 @@ value_t expr_t::op_t::opcalc(scope_t& scope)
call_scope_t call_args(scope);
if (has_right())
- call_args.set_args(right()->opcalc(scope));
+ call_args.set_args(right()->calc(scope, context));
ptr_op_t func = left();
const string& name(func->as_ident());
@@ -153,7 +135,8 @@ value_t expr_t::op_t::opcalc(scope_t& scope)
if (! right()->is_value() || ! right()->as_value().is_mask())
throw_(calc_error, "Right-hand argument to match operator must be a regex");
#endif
- return right()->opcalc(scope).as_mask().match(left()->opcalc(scope).to_string());
+ return (right()->calc(scope, context).as_mask()
+ .match(left()->calc(scope, context).to_string()));
case INDEX: {
const call_scope_t& args(downcast<const call_scope_t>(scope));
@@ -166,42 +149,43 @@ value_t expr_t::op_t::opcalc(scope_t& scope)
}
case O_EQ:
- return left()->opcalc(scope) == right()->opcalc(scope);
+ return left()->calc(scope, context) == right()->calc(scope, context);
case O_LT:
- return left()->opcalc(scope) < right()->opcalc(scope);
+ return left()->calc(scope, context) < right()->calc(scope, context);
case O_LTE:
- return left()->opcalc(scope) <= right()->opcalc(scope);
+ return left()->calc(scope, context) <= right()->calc(scope, context);
case O_GT:
- return left()->opcalc(scope) > right()->opcalc(scope);
+ return left()->calc(scope, context) > right()->calc(scope, context);
case O_GTE:
- return left()->opcalc(scope) >= right()->opcalc(scope);
+ return left()->calc(scope, context) >= right()->calc(scope, context);
case O_ADD:
- return left()->opcalc(scope) + right()->opcalc(scope);
+ return left()->calc(scope, context) + right()->calc(scope, context);
case O_SUB:
- return left()->opcalc(scope) - right()->opcalc(scope);
+ return left()->calc(scope, context) - right()->calc(scope, context);
case O_MUL:
- return left()->opcalc(scope) * right()->opcalc(scope);
+ return left()->calc(scope, context) * right()->calc(scope, context);
case O_DIV:
- return left()->opcalc(scope) / right()->opcalc(scope);
+ return left()->calc(scope, context) / right()->calc(scope, context);
case O_NEG:
- return left()->opcalc(scope).negate();
+ return left()->calc(scope, context).negate();
case O_NOT:
- return ! left()->opcalc(scope);
+ return ! left()->calc(scope, context);
case O_AND:
- return ! left()->opcalc(scope) ? value_t(false) : right()->opcalc(scope);
+ return (! left()->calc(scope, context) ? value_t(false) :
+ right()->calc(scope, context));
case O_OR:
- if (value_t temp = left()->opcalc(scope))
+ if (value_t temp = left()->calc(scope, context))
return temp;
else
- return right()->opcalc(scope);
+ return right()->calc(scope, context);
case O_COMMA: {
- value_t result(left()->opcalc(scope));
+ value_t result(left()->calc(scope, context));
ptr_op_t next = right();
while (next) {
@@ -214,7 +198,7 @@ value_t expr_t::op_t::opcalc(scope_t& scope)
next = NULL;
}
- result.push_back(value_op->opcalc(scope));
+ result.push_back(value_op->calc(scope, context));
}
return result;
}
@@ -226,10 +210,11 @@ value_t expr_t::op_t::opcalc(scope_t& scope)
}
return NULL_VALUE;
+
}
- catch (const std::exception& err) {
- if (! context_op_ptr)
- context_op_ptr = this;
+ catch (const std::exception& err) {
+ if (context && ! *context)
+ *context = this;
throw;
}
}
diff --git a/src/op.h b/src/op.h
index a2b20c73..1c6b246e 100644
--- a/src/op.h
+++ b/src/op.h
@@ -277,8 +277,7 @@ private:
public:
ptr_op_t compile(scope_t& scope);
- value_t calc(scope_t& scope);
- value_t opcalc(scope_t& scope);
+ value_t calc(scope_t& scope, ptr_op_t * context = NULL);
struct context_t
{
diff --git a/src/output.cc b/src/output.cc
index c24bf111..f833b722 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -62,16 +62,21 @@ void format_xacts::operator()(xact_t& xact)
if (! xact.has_xdata() ||
! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
if (last_entry != xact.entry) {
- if (last_entry)
- between_format.format(out, *last_entry);
- first_line_format.format(out, xact);
+ if (last_entry) {
+ bind_scope_t bound_scope(report, *last_entry);
+ between_format.format(out, bound_scope);
+ }
+ bind_scope_t bound_scope(report, xact);
+ first_line_format.format(out, bound_scope);
last_entry = xact.entry;
}
else if (last_xact && last_xact->date() != xact.date()) {
- first_line_format.format(out, xact);
+ bind_scope_t bound_scope(report, xact);
+ first_line_format.format(out, bound_scope);
}
else {
- next_lines_format.format(out, xact);
+ bind_scope_t bound_scope(report, xact);
+ next_lines_format.format(out, bound_scope);
}
xact.xdata().add_flags(XACT_EXT_DISPLAYED);
@@ -88,10 +93,12 @@ void format_entries::format_last_entry()
if (xact->has_xdata() &&
xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
if (first) {
- first_line_format.format(out, *xact);
+ bind_scope_t bound_scope(report, *xact);
+ first_line_format.format(out, bound_scope);
first = false;
} else {
- next_lines_format.format(out, *xact);
+ bind_scope_t bound_scope(report, *xact);
+ next_lines_format.format(out, bound_scope);
}
xact->xdata().add_flags(XACT_EXT_DISPLAYED);
}
@@ -155,7 +162,8 @@ void format_accounts::flush()
if (! report.show_collapsed && xdata.total) {
out << "--------------------\n";
xdata.value = xdata.total;
- format.format(out, *report.session.master);
+ bind_scope_t bound_scope(report, *report.session.master);
+ format.format(out, bound_scope);
}
}
@@ -168,7 +176,8 @@ void format_accounts::operator()(account_t& account)
if (! account.parent) {
account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
} else {
- format.format(report.output_stream, account);
+ bind_scope_t bound_scope(report, account);
+ format.format(report.output_stream, bound_scope);
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
}
}
@@ -245,8 +254,9 @@ format_equity::format_equity(report_t& _report, const string& _format)
entry_t header_entry;
header_entry.payee = "Opening Balances";
- header_entry._date = current_date;
- first_line_format.format(report.output_stream, header_entry);
+ header_entry._date = CURRENT_DATE();
+ bind_scope_t bound_scope(report, header_entry);
+ first_line_format.format(report.output_stream, bound_scope);
}
void format_equity::flush()
@@ -270,10 +280,12 @@ void format_equity::flush()
foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
xdata.value = pair.second;
xdata.value.negate();
- next_lines_format.format(out, summary);
+ bind_scope_t bound_scope(report, summary);
+ next_lines_format.format(out, bound_scope);
}
} else {
- next_lines_format.format(out, summary);
+ bind_scope_t bound_scope(report, summary);
+ next_lines_format.format(out, bound_scope);
}
out.flush();
}
@@ -297,11 +309,13 @@ void format_equity::operator()(account_t& account)
foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
account.xdata().value = pair.second;
- next_lines_format.format(out, account);
+ bind_scope_t bound_scope(report, account);
+ next_lines_format.format(out, bound_scope);
}
account.xdata().value = val;
} else {
- next_lines_format.format(out, account);
+ bind_scope_t bound_scope(report, account);
+ next_lines_format.format(out, bound_scope);
}
total += val;
}
diff --git a/src/precmd.cc b/src/precmd.cc
index 5cefe435..fd6a2457 100644
--- a/src/precmd.cc
+++ b/src/precmd.cc
@@ -63,7 +63,7 @@ value_t parse_command(call_scope_t& args)
out << std::endl << "--- Calculated value ---" << std::endl;
value_t result(expr.calc(args));
- result.print(out);
+ result.dump(out);
out << std::endl;
return 0L;
@@ -82,7 +82,8 @@ value_t eval_command(call_scope_t& args)
std::ostream& out(report.output_stream);
expr_t expr(*arg);
- out << expr.calc(args).strip_annotations() << std::endl;
+ out << expr.calc(args).strip_annotations(report.what_to_keep)
+ << std::endl;
return 0L;
}
@@ -150,7 +151,7 @@ value_t args_command(call_scope_t& args)
value_t::sequence_t::const_iterator end = args.value().end();
out << "--- Input arguments ---" << std::endl;
- args.value().print(out);
+ args.value().dump(out);
out << std::endl << std::endl;
string predicate = args_to_predicate_expr(begin, end);
diff --git a/src/predicate.h b/src/predicate.h
index 5e2057ca..dfdcd256 100644
--- a/src/predicate.h
+++ b/src/predicate.h
@@ -60,26 +60,32 @@ template <typename T>
class item_predicate
{
public:
- expr_t predicate;
+ expr_t predicate;
+ keep_details_t what_to_keep;
item_predicate() {
TRACE_CTOR(item_predicate, "");
}
- item_predicate(const item_predicate& other) : predicate(other.predicate) {
+ item_predicate(const item_predicate& other)
+ : predicate(other.predicate), what_to_keep(other.what_to_keep) {
TRACE_CTOR(item_predicate, "copy");
}
- item_predicate(const expr_t& _predicate) : predicate(_predicate) {
- TRACE_CTOR(item_predicate, "const expr_t&");
+ item_predicate(const expr_t& _predicate,
+ const keep_details_t& _what_to_keep)
+ : predicate(_predicate), what_to_keep(_what_to_keep) {
+ TRACE_CTOR(item_predicate, "const expr_t&, const keep_details_t&");
}
- item_predicate(const string& _predicate) : predicate(expr_t(_predicate)) {
- TRACE_CTOR(item_predicate, "const string&");
+ item_predicate(const string& _predicate,
+ const keep_details_t& _what_to_keep)
+ : predicate(expr_t(_predicate)), what_to_keep(_what_to_keep) {
+ TRACE_CTOR(item_predicate, "const string&, const keep_details_t&");
}
~item_predicate() throw() {
TRACE_DTOR(item_predicate);
}
bool operator()(T& item) {
- return ! predicate || predicate.calc(item).strip_annotations();
+ return ! predicate || predicate.calc(item).strip_annotations(what_to_keep);
}
};
diff --git a/src/report.cc b/src/report.cc
index f72798ec..6a75632d 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -42,18 +42,14 @@ void report_t::xacts_report(xact_handler_ptr handler)
{
session_xacts_iterator walker(session);
pass_down_xacts(chain_xact_handlers(*this, handler), walker);
-
- if (DO_VERIFY())
- session.clean_xacts();
+ session.clean_xacts();
}
void report_t::entry_report(xact_handler_ptr handler, entry_t& entry)
{
entry_xacts_iterator walker(entry);
pass_down_xacts(chain_xact_handlers(*this, handler), walker);
-
- if (DO_VERIFY())
- session.clean_xacts(entry);
+ session.clean_xacts(entry);
}
void report_t::sum_all_accounts()
@@ -62,7 +58,8 @@ void report_t::sum_all_accounts()
pass_down_xacts
(chain_xact_handlers(*this, xact_handler_ptr(new set_account_value), false),
walker);
- session.master->calculate_sums(amount_expr);
+
+ session.master->calculate_sums(amount_expr, *this);
}
void report_t::accounts_report(acct_handler_ptr handler)
@@ -71,16 +68,16 @@ void report_t::accounts_report(acct_handler_ptr handler)
if (sort_string.empty()) {
basic_accounts_iterator walker(*session.master);
- pass_down_accounts(handler, walker, expr_t("total"));
+ pass_down_accounts(handler, walker,
+ item_predicate<account_t>("total", what_to_keep));
} else {
sorted_accounts_iterator walker(*session.master, sort_string);
- pass_down_accounts(handler, walker, expr_t("total"));
+ pass_down_accounts(handler, walker,
+ item_predicate<account_t>("total", what_to_keep));
}
- if (DO_VERIFY()) {
- session.clean_xacts();
- session.clean_accounts();
- }
+ session.clean_xacts();
+ session.clean_accounts();
}
void report_t::commodities_report(const string& format)
@@ -125,6 +122,8 @@ value_t report_t::f_market_value(call_scope_t& args)
namespace {
value_t print_balance(call_scope_t& args)
{
+ report_t& report(find_scope<report_t>(args));
+
var_t<long> first_width(args, 1);
var_t<long> latter_width(args, 2);
#if 0
@@ -132,10 +131,40 @@ namespace {
#endif
std::ostringstream out;
- args[0].strip_annotations().dump(out, *first_width, *latter_width);
+ args[0].strip_annotations(report.what_to_keep)
+ .print(out, *first_width, *latter_width);
return string_value(out.str());
}
+ value_t strip_annotations(call_scope_t& args)
+ {
+ report_t& report(find_scope<report_t>(args));
+ return args[0].strip_annotations(report.what_to_keep);
+ }
+
+ value_t truncate(call_scope_t& args)
+ {
+ report_t& report(find_scope<report_t>(args));
+
+ var_t<long> width(args, 1);
+ var_t<long> account_abbrev(args, 2);
+
+ return string_value(format_t::truncate(args[0].as_string(), *width,
+ account_abbrev ? *account_abbrev : -1));
+ }
+
+ value_t display_date(call_scope_t& args)
+ {
+ report_t& report(find_scope<report_t>(args));
+ item_t& item(find_scope<item_t>(args));
+
+ if (item.use_effective_date) {
+ if (optional<date_t> date = item.effective_date())
+ return string_value(format_date(*date, report.output_date_format));
+ }
+ return string_value(format_date(item.date(), report.output_date_format));
+ }
+
template <class Type = xact_t,
class handler_ptr = xact_handler_ptr,
void (report_t::*report_method)(handler_ptr) =
@@ -178,13 +207,14 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 'd':
if (std::strcmp(p, "display_total") == 0)
return MAKE_FUNCTOR(report_t::get_display_total);
+ else if (std::strcmp(p, "display_date") == 0)
+ return WRAP_FUNCTOR(display_date);
break;
case 'l':
if (std::strncmp(p, "ledger_cmd_", 11) == 0) {
-#define FORMAT(str) \
- (format_string.empty() ? session. str : format_string)
+#define FORMAT(str) (format_string.empty() ? session. str : format_string)
#if 0
// Commands yet to implement:
@@ -313,6 +343,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
return MAKE_FUNCTOR(report_t::option_dow);
else if (std::strcmp(p, "date-format_") == 0)
return MAKE_FUNCTOR(report_t::option_date_format_);
+ else if (std::strcmp(p, "debug_") == 0)
+ return MAKE_FUNCTOR(report_t::option_ignore_);
break;
case 'e':
@@ -409,6 +441,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
return MAKE_FUNCTOR(report_t::option_totals);
else if (std::strcmp(p, "tail_") == 0)
return MAKE_FUNCTOR(report_t::option_tail_);
+ else if (std::strcmp(p, "trace_") == 0)
+ return MAKE_FUNCTOR(report_t::option_ignore_);
break;
case 'u':
@@ -416,6 +450,13 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
return MAKE_FUNCTOR(report_t::option_uncleared);
break;
+ case 'v':
+ if (! *(p + 1) || std::strcmp(p, "verbose") == 0)
+ return MAKE_FUNCTOR(report_t::option_ignore);
+ else if (std::strcmp(p, "verify") == 0)
+ return MAKE_FUNCTOR(report_t::option_ignore);
+ break;
+
case 'w':
if (std::strcmp(p, "weekly") == 0)
return MAKE_FUNCTOR(report_t::option_weekly);
@@ -516,11 +557,16 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
return WRAP_FUNCTOR(print_balance);
break;
+ case 's':
+ if (std::strcmp(p, "strip") == 0)
+ return WRAP_FUNCTOR(strip_annotations);
+ break;
+
case 't':
if (std::strcmp(p, "total_expr") == 0)
return MAKE_FUNCTOR(report_t::get_total_expr);
else if (std::strcmp(p, "truncate") == 0)
- return MAKE_FUNCTOR(report_t::get_total_expr);
+ return WRAP_FUNCTOR(truncate);
break;
}
diff --git a/src/report.h b/src/report.h
index d8796741..e7e2ac0e 100644
--- a/src/report.h
+++ b/src/report.h
@@ -109,7 +109,7 @@ public:
output_stream_t output_stream;
string format_string;
- string date_output_format;
+ string output_date_format;
string predicate;
string secondary_predicate;
string display_predicate;
@@ -143,12 +143,12 @@ public:
bool code_as_payee;
bool show_revalued;
bool show_revalued_only;
- bool keep_price;
- bool keep_date;
- bool keep_tag;
bool entry_sort;
bool sort_all;
bool anonymize;
+ bool use_effective_date;
+
+ keep_details_t what_to_keep;
string account;
optional<path> pager_path;
@@ -158,7 +158,9 @@ public:
session_t& session;
explicit report_t(session_t& _session)
- : amount_expr("amount"),
+ : output_date_format("%y-%b-%d"),
+
+ amount_expr("amount"),
total_expr("total"),
display_total("total_expr"),
@@ -178,12 +180,10 @@ public:
code_as_payee(false),
show_revalued(false),
show_revalued_only(false),
- keep_price(false),
- keep_date(false),
- keep_tag(false),
entry_sort(false),
sort_all(false),
anonymize(false),
+ use_effective_date(false),
raw_mode(false),
@@ -194,6 +194,7 @@ public:
virtual ~report_t() {
TRACE_DTOR(report_t);
+ output_stream.close();
}
//
@@ -268,15 +269,23 @@ public:
value_t option_account(call_scope_t& args) { // a:
config->account = optarg;
}
+#endif
//////////////////////////////////////////////////////////////////////
//
// Report filtering
+ value_t option_ignore(call_scope_t& args) {
+ return true;
+ }
+ value_t option_ignore_(call_scope_t& args) {
+ return true;
+ }
+
value_t option_effective(call_scope_t& args) {
- item_t::use_effective_date = true;
+ use_effective_date = true;
+ return true;
}
-#endif
value_t option_begin_(call_scope_t& args) { // b:
interval_t interval(args[0].to_string());
@@ -348,21 +357,21 @@ public:
}
value_t option_lots(call_scope_t& args) {
- report->keep_price =
- report->keep_date =
- report->keep_tag = true;
+ what_to_keep.keep_price = true;
+ what_to_keep.keep_date = true;
+ what_to_keep.keep_tag = true;
}
value_t option_lot_prices(call_scope_t& args) {
- report->keep_price = true;
+ what_to_keep.keep_price = true;
}
value_t option_lot_dates(call_scope_t& args) {
- report->keep_date = true;
+ what_to_keep.keep_date = true;
}
value_t option_lot_tags(call_scope_t& args) {
- report->keep_tag = true;
+ what_to_keep.keep_tag = true;
}
#endif
@@ -376,7 +385,7 @@ public:
}
value_t option_date_format_(call_scope_t& args) { // y:
- ledger::output_date_format = args[0].as_string();
+ output_date_format = args[0].as_string();
return true;
}
@@ -710,14 +719,18 @@ public:
}
value_t option_ansi(call_scope_t& args) {
+#if 0
format_t::ansi_codes = true;
format_t::ansi_invert = false;
+#endif
return true;
}
value_t option_ansi_invert(call_scope_t& args) {
+#if 0
format_t::ansi_codes =
format_t::ansi_invert = true;
+#endif
return true;
}
@@ -726,7 +739,7 @@ public:
// Commodity reporting
value_t option_base(call_scope_t& args) { // :
- amount_t::keep_base = true;
+ what_to_keep.keep_base = true;
return true;
}
@@ -775,27 +788,25 @@ public:
}
#if 0
- namespace {
- void parse_price_setting(const char * optarg)
- {
- char * equals = std::strchr(optarg, '=');
- if (! equals)
- return;
-
- while (std::isspace(*optarg))
- optarg++;
- while (equals > optarg && std::isspace(*(equals - 1)))
- equals--;
-
- std::string symbol(optarg, 0, equals - optarg);
- amount_t price(equals + 1);
-
- if (commodity_t * commodity = commodity_t::find_or_create(symbol)) {
- commodity->add_price(datetime_t::now, price);
+ void parse_price_setting(const char * optarg)
+ {
+ char * equals = std::strchr(optarg, '=');
+ if (! equals)
+ return;
+
+ while (std::isspace(*optarg))
+ optarg++;
+ while (equals > optarg && std::isspace(*(equals - 1)))
+ equals--;
+
+ std::string symbol(optarg, 0, equals - optarg);
+ amount_t price(equals + 1);
+
+ if (commodity_t * commodity = commodity_t::find_or_create(symbol)) {
+ commodity->add_price(datetime_t::now, price);
#if 0
- commodity->history()->bogus_time = datetime_t::now;
+ commodity->history()->bogus_time = datetime_t::now;
#endif
- }
}
}
#endif
diff --git a/src/scope.h b/src/scope.h
index 174d52fe..3d1e5108 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -105,23 +105,6 @@ public:
}
};
-
-template <typename T>
-inline T& find_scope(child_scope_t& scope, bool skip_this = true)
-{
- for (scope_t * ptr = (skip_this ? scope.parent : &scope); ptr; ) {
- T * sought = dynamic_cast<T *>(ptr);
- if (sought)
- return *sought;
- if (child_scope_t * scope = dynamic_cast<child_scope_t *>(ptr))
- ptr = scope->parent;
- else
- ptr = NULL;
- }
- throw_(std::runtime_error, "Could not find scope");
- return reinterpret_cast<T&>(scope); // never executed
-}
-
/**
* @brief Brief
*
@@ -209,6 +192,66 @@ public:
*
* Long.
*/
+class bind_scope_t : public child_scope_t
+{
+ bind_scope_t();
+
+public:
+ scope_t& grandchild;
+
+ explicit bind_scope_t(scope_t& _parent,
+ scope_t& _grandchild)
+ : child_scope_t(_parent), grandchild(_grandchild) {
+ TRACE_CTOR(bind_scope_t, "scope_t&, scope_t&");
+ }
+ virtual ~bind_scope_t() {
+ TRACE_DTOR(bind_scope_t);
+ }
+
+ virtual expr_t::ptr_op_t lookup(const string& name) {
+ if (expr_t::ptr_op_t def = grandchild.lookup(name))
+ return def;
+ return child_scope_t::lookup(name);
+ }
+};
+
+/**
+ * @brief Brief
+ *
+ * Long.
+ */
+template <typename T>
+T * search_scope(scope_t * ptr)
+{
+ if (T * sought = dynamic_cast<T *>(ptr))
+ return sought;
+
+ if (bind_scope_t * scope = dynamic_cast<bind_scope_t *>(ptr)) {
+ if (T * sought = search_scope<T>(&scope->grandchild))
+ return sought;
+ return search_scope<T>(scope->parent);
+ }
+ else if (child_scope_t * scope = dynamic_cast<child_scope_t *>(ptr)) {
+ return search_scope<T>(scope->parent);
+ }
+ return NULL;
+}
+
+template <typename T>
+inline T& find_scope(child_scope_t& scope, bool skip_this = true)
+{
+ if (T * sought = search_scope<T>(skip_this ? scope.parent : &scope))
+ return *sought;
+
+ throw_(std::runtime_error, "Could not find scope");
+ return reinterpret_cast<T&>(scope); // never executed
+}
+
+/**
+ * @brief Brief
+ *
+ * Long.
+ */
template <typename T>
class ptr_t : public noncopyable
{
diff --git a/src/session.cc b/src/session.cc
index 075324ec..25acd821 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -38,36 +38,32 @@
namespace ledger {
-session_t * session_t::current = NULL;
-
#if 0
boost::mutex session_t::session_mutex;
#endif
void set_session_context(session_t * session)
{
+ if (session) {
#if 0
- session_t::session_mutex.lock();
+ session_t::session_mutex.lock();
#endif
+ amount_t::initialize(session->commodity_pool);
+
+ // jww (2009-02-04): Is amount_t the right place for parse_conversion to
+ // happen?
+ amount_t::parse_conversion("1.0m", "60s");
+ amount_t::parse_conversion("1.0h", "60m");
- if (session && ! session_t::current) {
- session_t::initialize();
+ value_t::initialize();
}
- else if (! session && session_t::current) {
- session_t::shutdown();
+ else if (! session) {
+ value_t::shutdown();
+ amount_t::shutdown();
#if 0
session_t::session_mutex.unlock();
#endif
}
-
- session_t::current = session;
-}
-
-void release_session_context()
-{
-#if 0
- session_t::session_mutex.unlock();
-#endif
}
session_t::session_t()
@@ -77,17 +73,17 @@ session_t::session_t()
saw_price_db_from_command_line(false),
register_format
- ("%-.9(date) %-.20(payee) %-.23(account(23)) %!12(print_balance(amount_expr, 12, 67)) "
- "%!12(print_balance(display_total, 12, 80, true))\n%/"
- "%31|%-.23(account(23)) %!12(print_balance(amount_expr, 12, 67)) "
- "%!12(print_balance(display_total, 12, 80, true))\n"),
+ ("%-.9(display_date) %-.20(payee) %-.23(truncate(account, 23, 2)) %!12(print_balance(strip(amount_expr), 12, 67)) "
+ "%!12(print_balance(strip(display_total), 12, 80, true))\n%/"
+ "%31|%-.23(truncate(account, 23, 2)) %!12(print_balance(strip(amount_expr), 12, 67)) "
+ "%!12(print_balance(strip(display_total), 12, 80, true))\n"),
wide_register_format
("%-.9D %-.35P %-.39A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n"),
print_format
- ("%(date)%(cleared ? \" *\" : (uncleared ? \"\" : \" !\"))%(code ? \" (\" + code + \")\" : \"\") %(payee)%(entry.comment | \"\")\n %-34(account) %12(amount)%(comment | \"\")\n%/ %-34(account) %12(amount)%(comment | \"\")\n%/\n"),
+ ("%(display_date)%(cleared ? \" *\" : (uncleared ? \"\" : \" !\"))%(code ? \" (\" + code + \")\" : \"\") %(payee)%(entry.comment | \"\")\n %-34(account) %12(amount)%(comment | \"\")\n%/ %-34(account) %12(amount)%(comment | \"\")\n%/\n"),
balance_format
- ("%20(display_total) %(depth_spacer)%-(partial_account)\n"),
+ ("%20(strip(display_total)) %(depth_spacer)%-(partial_account)\n"),
equity_format
("\n%D %Y%C%P\n%/ %-34W %12t\n"),
plot_amount_format
@@ -104,13 +100,12 @@ session_t::session_t()
("P %[%Y/%m/%d %H:%M:%S] %A %t\n"),
pricing_leeway(24 * 3600),
+ current_year(CURRENT_DATE().year()),
download_quotes(false),
use_cache(true),
cache_dirty(false),
- now(now),
-
#if 0
elision_style(ABBREVIATE),
#endif
@@ -119,6 +114,7 @@ session_t::session_t()
ansi_codes(false),
ansi_invert(false),
+ commodity_pool(new commodity_pool_t),
master(new account_t(NULL, ""))
{
TRACE_CTOR(session_t, "");
@@ -132,6 +128,14 @@ session_t::session_t()
cache_file = home ? *home / ".ledger-cache" : "./.ledger-cache";
register_parser(new textual_parser_t);
+
+ // Add time commodity conversions, so that timelog's may be parsed
+ // in terms of seconds, but reported as minutes or hours.
+ if (commodity_t * commodity = commodity_pool->create("s")) {
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ } else {
+ assert(false);
+ }
}
session_t::~session_t()
@@ -217,7 +221,7 @@ std::size_t session_t::read_data(journal_t& journal,
}
if (entry_count == 0) {
- account_t * acct = NULL;
+ account_t * acct = journal.master;
if (! master_account.empty())
acct = journal.find_account(master_account);
@@ -245,7 +249,7 @@ std::size_t session_t::read_data(journal_t& journal,
std::ostringstream buffer;
while (std::cin.good() && ! std::cin.eof()) {
- static char line[8192];
+ char line[8192];
std::cin.read(line, 8192);
std::streamsize count = std::cin.gcount();
buffer.write(line, count);
@@ -260,7 +264,6 @@ std::size_t session_t::read_data(journal_t& journal,
entry_count += read_journal(journal, pathname, acct);
if (journal.price_db)
journal.sources.push_back(*journal.price_db);
- clean_accounts();
}
else {
throw_(parse_error, "Could not open journal file '" << pathname << "'");
@@ -275,25 +278,6 @@ std::size_t session_t::read_data(journal_t& journal,
return entry_count;
}
-namespace {
- account_t * find_account_re_(account_t * account, const mask_t& regexp)
- {
- if (regexp.match(account->fullname()))
- return account;
-
- foreach (accounts_map::value_type& pair, account->accounts)
- if (account_t * a = find_account_re_(pair.second, regexp))
- return a;
-
- return NULL;
- }
-}
-
-account_t * session_t::find_account_re(const string& regexp)
-{
- return find_account_re_(master.get(), mask_t(regexp));
-}
-
void session_t::clean_xacts()
{
session_xacts_iterator walker(*this);
@@ -310,8 +294,7 @@ void session_t::clean_xacts(entry_t& entry)
void session_t::clean_accounts()
{
basic_accounts_iterator acct_walker(*master);
- pass_down_accounts(acct_handler_ptr(new clear_account_xdata),
- acct_walker);
+ pass_down_accounts(acct_handler_ptr(new clear_account_xdata), acct_walker);
}
#if 0
@@ -423,20 +406,4 @@ expr_t::ptr_op_t session_t::lookup(const string& name)
return expr_t::ptr_op_t();
}
-// jww (2007-04-26): All of Ledger should be accessed through a
-// session_t object
-void session_t::initialize()
-{
- amount_t::initialize();
- value_t::initialize();
- expr_t::initialize();
-}
-
-void session_t::shutdown()
-{
- expr_t::shutdown();
- value_t::shutdown();
- amount_t::shutdown();
-}
-
} // namespace ledger
diff --git a/src/session.h b/src/session.h
index ea5538c4..2b33cb8d 100644
--- a/src/session.h
+++ b/src/session.h
@@ -60,15 +60,9 @@ namespace ledger {
*/
class session_t : public noncopyable, public scope_t
{
- static void initialize();
- static void shutdown();
-
friend void set_session_context(session_t * session);
- friend void release_session_context();
public:
- static session_t * current;
-
scope_t * global_scope;
std::list<path> data_files;
@@ -93,25 +87,22 @@ public:
string pricesdb_format;
std::size_t pricing_leeway;
+ int current_year;
bool download_quotes;
bool use_cache;
bool cache_dirty;
- datetime_t now;
- date_t today;
-
format_t::elision_style_t elision_style;
int abbrev_length;
bool ansi_codes;
bool ansi_invert;
- ptr_list<journal_t> journals;
+ shared_ptr<commodity_pool_t> commodity_pool;
ptr_list<journal_t::parser_t> parsers;
- scoped_ptr<commodity_pool_t> commdity_pool;
+ ptr_list<journal_t> journals;
scoped_ptr<account_t> master;
- mutable accounts_map accounts_cache;
session_t();
virtual ~session_t();
@@ -122,7 +113,7 @@ public:
}
journal_t * create_journal() {
- journal_t * journal = new journal_t;
+ journal_t * journal = new journal_t(master.get());
journals.push_back(journal);
return journal;
}
@@ -177,17 +168,6 @@ public:
return master->remove_account(acct);
}
- account_t * find_account(const string& name, bool auto_create = true) {
- accounts_map::iterator c = accounts_cache.find(name);
- if (c != accounts_cache.end())
- return (*c).second;
-
- account_t * account = master->find_account(name, auto_create);
- accounts_cache.insert(accounts_map::value_type(name, account));
- return account;
- }
- account_t * find_account_re(const string& regexp);
-
void clean_accounts();
void clean_xacts();
@@ -213,12 +193,6 @@ public:
std::cout << "\n\nCopyright (c) 2003-2009, John Wiegley. All rights reserved.\n\n\
This program is made available under the terms of the BSD Public License.\n\
See LICENSE file included with the distribution for details and disclaimer.\n";
- std::cout << "\n(modules: gmp, pcre";
- std::cout << ", xml";
-#ifdef HAVE_LIBOFX
- std::cout << ", ofx";
-#endif
- std::cout << ")\n";
return NULL_VALUE;
}
diff --git a/src/textual.cc b/src/textual.cc
index 28d8c36e..9dd79ae0 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -92,6 +92,8 @@ std::size_t textual_parser_t::parse(std::istream& in,
original_file);
parsing_instance.parse();
+ session.clean_accounts(); // remove calculated totals
+
TRACE_STOP(parsing_total, 1);
TRACE_FINISH(instance_parse, 1); // report per-instance timers
@@ -107,7 +109,8 @@ namespace {
#else
void
#endif
- parse_amount_expr(std::istream& in,
+ parse_amount_expr(session_t& session,
+ std::istream& in,
amount_t& amount,
xact_t * xact,
uint_least8_t flags = 0)
@@ -126,7 +129,9 @@ namespace {
#endif
if (expr) {
- value_t result(expr.calc(*xact));
+ bind_scope_t bound_scope(session, *xact);
+
+ value_t result(expr.calc(bound_scope));
if (! result.is_amount())
throw_(parse_error, "Transactions may only specify simple amounts");
@@ -369,7 +374,7 @@ void textual_parser_t::instance_t::clock_in_directive(char * line,
char * p = skip_ws(line + 22);
char * n = next_element(p, true);
- timelog.clock_in(parse_datetime(date),
+ timelog.clock_in(parse_datetime(date, session.current_year),
account_stack.front()->find_account(p), n ? n : "");
}
@@ -381,7 +386,7 @@ void textual_parser_t::instance_t::clock_out_directive(char * line,
char * p = skip_ws(line + 22);
char * n = next_element(p, true);
- timelog.clock_out(parse_datetime(date),
+ timelog.clock_out(parse_datetime(date, session.current_year),
p ? account_stack.front()->find_account(p) : NULL, n);
count++;
}
@@ -445,10 +450,11 @@ void textual_parser_t::instance_t::price_entry_directive(char * line)
if (std::isdigit(time_field_ptr[0])) {
symbol_and_price = next_element(time_field_ptr);
if (! symbol_and_price) return;
- datetime = parse_datetime(date_field + " " + time_field_ptr);
+ datetime = parse_datetime(date_field + " " + time_field_ptr,
+ session.current_year);
} else {
symbol_and_price = time_field_ptr;
- datetime = parse_datetime(date_field);
+ datetime = parse_datetime(date_field, session.current_year);
}
string symbol;
@@ -474,7 +480,7 @@ void textual_parser_t::instance_t::nomarket_directive(char * line)
void textual_parser_t::instance_t::year_directive(char * line)
{
- current_year = std::atoi(skip_ws(line + 1));
+ session.current_year = std::atoi(skip_ws(line + 1));
}
void textual_parser_t::instance_t::option_directive(char * line)
@@ -498,7 +504,10 @@ void textual_parser_t::instance_t::automated_entry_directive(char * line)
istream_pos_type pos = curr_pos;
std::size_t lnum = linenum;
- std::auto_ptr<auto_entry_t> ae(new auto_entry_t(skip_ws(line + 1)));
+ std::auto_ptr<auto_entry_t>
+ ae(new auto_entry_t(item_predicate<xact_t>
+ (skip_ws(line + 1),
+ keep_details_t(true, true, true, true))));
if (parse_xacts(account_stack.front(), *ae.get(), "automated")) {
journal.auto_entries.push_back(ae.get());
@@ -700,7 +709,7 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
xact->beg_pos = line_beg_pos;
xact->beg_line = linenum;
- static char buf[MAX_LINE + 1];
+ char buf[MAX_LINE + 1];
std::strcpy(buf, line);
std::size_t beg = 0;
@@ -780,7 +789,7 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
if (*next != '(') // indicates a value expression
xact->amount.parse(stream, amount_t::PARSE_NO_REDUCE);
else
- parse_amount_expr(stream, xact->amount, xact.get(),
+ parse_amount_expr(session, stream, xact->amount, xact.get(),
static_cast<uint_least8_t>(expr_t::PARSE_NO_REDUCE) |
static_cast<uint_least8_t>(expr_t::PARSE_NO_ASSIGN));
@@ -821,7 +830,7 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
if (*p != '(') // indicates a value expression
xact->cost->parse(cstream, amount_t::PARSE_NO_MIGRATE);
else
- parse_amount_expr(cstream, *xact->cost, xact.get(),
+ parse_amount_expr(session, cstream, *xact->cost, xact.get(),
static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE) |
static_cast<uint_least8_t>(expr_t::PARSE_NO_ASSIGN));
@@ -835,7 +844,7 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
per_unit_cost /= xact->amount;
commodity_t::exchange(xact->amount.commodity(),
- per_unit_cost, datetime_t(*xact->date()));
+ per_unit_cost, datetime_t(xact->date()));
DEBUG("textual.parse", "line " << linenum << ": "
<< "Total cost is " << *xact->cost);
@@ -873,7 +882,7 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
if (*p != '(') // indicates a value expression
xact->assigned_amount->parse(stream, amount_t::PARSE_NO_MIGRATE);
else
- parse_amount_expr(stream, *xact->assigned_amount, xact.get(),
+ parse_amount_expr(session, stream, *xact->assigned_amount, xact.get(),
static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE));
if (xact->assigned_amount->is_null())
@@ -886,9 +895,9 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
amount_t& amt(*xact->assigned_amount);
DEBUG("xact.assign", "line " << linenum << ": "
- "account balance = " << xdata.value.strip_annotations());
+ "account balance = " << xdata.value);
DEBUG("xact.assign", "line " << linenum << ": "
- "xact amount = " << amt.strip_annotations());
+ "xact amount = " << amt);
amount_t diff;
@@ -919,9 +928,9 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
}
DEBUG("xact.assign", "line " << linenum << ": "
- << "diff = " << diff.strip_annotations());
+ << "diff = " << diff);
DEBUG("textual.parse", "line " << linenum << ": "
- << "XACT assign: diff = " << diff.strip_annotations());
+ << "XACT assign: diff = " << diff);
if (! diff.is_zero()) {
if (! xact->amount.is_null()) {
@@ -953,7 +962,7 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
// Parse the optional note
if (next && *next == ';') {
- xact->append_note(++next);
+ xact->append_note(++next, session.current_year);
next = line + len;
DEBUG("textual.parse", "line " << linenum << ": "
<< "Parsed a transaction note");
@@ -1022,9 +1031,9 @@ entry_t * textual_parser_t::instance_t::parse_entry(char * line,
if (char * p = std::strchr(line, '=')) {
*p++ = '\0';
- curr->_date_eff = parse_date(p);
+ curr->_date_eff = parse_date(p, session.current_year);
}
- curr->_date = parse_date(line);
+ curr->_date = parse_date(line, session.current_year);
// Parse the optional cleared flag: *
@@ -1064,7 +1073,7 @@ entry_t * textual_parser_t::instance_t::parse_entry(char * line,
// Parse the entry note
if (next && *next == ';')
- curr->append_note(next);
+ curr->append_note(next, session.current_year);
TRACE_STOP(entry_text, 1);
@@ -1089,7 +1098,7 @@ entry_t * textual_parser_t::instance_t::parse_entry(char * line,
item = curr.get();
// This is a trailing note, and possibly a metadata info tag
- item->append_note(p + 1);
+ item->append_note(p + 1, session.current_year);
item->end_pos = curr_pos;
item->end_line++;
}
diff --git a/src/timelog.cc b/src/timelog.cc
index b22b2e60..96b629c8 100644
--- a/src/timelog.cc
+++ b/src/timelog.cc
@@ -113,7 +113,7 @@ time_log_t::~time_log_t()
accounts.push_back(time_entry.account);
foreach (account_t * account, accounts)
- clock_out_from_timelog(time_entries, current_time, account, NULL,
+ clock_out_from_timelog(time_entries, CURRENT_TIME(), account, NULL,
journal);
assert(time_entries.empty());
diff --git a/src/times.cc b/src/times.cc
index ba0a19a3..f93759d1 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -34,19 +34,6 @@
namespace ledger {
namespace {
-#ifdef BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK
- const ptime time_now = boost::posix_time::microsec_clock::universal_time();
-#else
- const ptime time_now = boost::posix_time::second_clock::universal_time();
-#endif
- const date date_now = boost::gregorian::day_clock::universal_day();
-}
-
-const datetime_t& current_time(time_now);
-const date_t& current_date(date_now);
- int current_year(current_date.year());
-
-namespace {
const char * formats[] = {
"%y/%m/%d",
"%Y/%m/%d",
@@ -67,7 +54,6 @@ namespace {
}
optional<string> input_date_format;
-string output_date_format = "%y-%b-%d";
namespace {
bool parse_date_mask(const char * date_str, std::tm& result)
@@ -85,7 +71,7 @@ namespace {
return false;
}
- bool parse_date(const char * date_str, std::tm& result, const int year)
+ bool quick_parse_date(const char * date_str, std::tm& result, const int year)
{
if (! parse_date_mask(date_str, result))
return false;
@@ -95,7 +81,7 @@ namespace {
result.tm_sec = 0;
if (result.tm_year == -1)
- result.tm_year = ((year == -1) ? current_year : year) - 1900;
+ result.tm_year = (year == -1 ? int(CURRENT_DATE().year()) : year) - 1900;
if (result.tm_mon == -1)
result.tm_mon = 0;
@@ -105,25 +91,20 @@ namespace {
return true;
}
-
- bool quick_parse_date(const char * date_str, std::tm& result)
- {
- return parse_date(date_str, result, current_year);
- }
}
-datetime_t parse_datetime(const char * str)
+datetime_t parse_datetime(const char * str, int current_year)
{
std::tm when;
- // jww (2008-08-01): This needs to look for HH:MM:SS as well.
- quick_parse_date(str, when);
+ // jww (2008-08-01): Needs to look for HH:MM:SS as well.
+ quick_parse_date(str, when, current_year);
return posix_time::ptime_from_tm(when);
}
-date_t parse_date(const char * str)
+date_t parse_date(const char * str, int current_year)
{
std::tm when;
- quick_parse_date(str, when);
+ quick_parse_date(str, when, current_year);
return gregorian::date_from_tm(when);
}
@@ -168,7 +149,8 @@ date_t interval_t::increment(const date_t& moment) const
namespace {
void parse_inclusion_specifier(const string& word,
- date_t * begin, date_t * end)
+ date_t * begin,
+ date_t * end)
{
struct std::tm when;
@@ -185,7 +167,7 @@ namespace {
bool saw_day = true;
if (when.tm_year == -1) {
- when.tm_year = current_year - 1900;
+ when.tm_year = CURRENT_DATE().year() - 1900;
saw_year = false;
}
if (when.tm_mon == -1) {
@@ -238,13 +220,14 @@ namespace {
}
if (word == "month") {
- time_t now = to_time_t(current_time);
+ time_t now = to_time_t(CURRENT_TIME());
std::strftime(buf, 31, "%B", localtime(&now));
word = buf;
mon_spec = true;
}
else if (word == "year") {
- std::sprintf(buf, "%04d", current_year);
+ int year = CURRENT_DATE().year();
+ std::sprintf(buf, "%04d", year);
word = buf;
}
diff --git a/src/times.h b/src/times.h
index 375a2555..4bcdd9e2 100644
--- a/src/times.h
+++ b/src/times.h
@@ -63,22 +63,25 @@ inline bool is_valid(const date_t& moment) {
return ! moment.is_not_a_date();
}
-extern const datetime_t& current_time;
-extern const date_t& current_date;
-extern int current_year;
-extern optional<string> input_date_format;
-extern string output_date_format;
+#ifdef BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK
+#define CURRENT_TIME() boost::posix_time::microsec_clock::universal_time()
+#else
+#define CURRENT_TIME() boost::posix_time::second_clock::universal_time()
+#endif
+#define CURRENT_DATE() boost::gregorian::day_clock::universal_day()
-datetime_t parse_datetime(const char * str);
+extern optional<string> input_date_format;
-inline datetime_t parse_datetime(const string& str) {
- return parse_datetime(str.c_str());
+datetime_t parse_datetime(const char * str, int current_year = -1);
+
+inline datetime_t parse_datetime(const string& str, int current_year = -1) {
+ return parse_datetime(str.c_str(), current_year);
}
-date_t parse_date(const char * str);
+date_t parse_date(const char * str, int current_year = -1);
-inline date_t parse_date(const string& str) {
- return parse_date(str.c_str());
+inline date_t parse_date(const string& str, int current_year = -1) {
+ return parse_date(str.c_str(), current_year);
}
inline std::time_t to_time_t(const ptime& t)
@@ -91,27 +94,22 @@ inline std::time_t to_time_t(const ptime& t)
return (t-start).total_seconds();
}
-inline string format_datetime(const datetime_t& when)
+inline string format_datetime(const datetime_t& when,
+ const string format = "%Y-%m-%d %H:%M:%S")
{
char buf[256];
time_t moment = to_time_t(when);
- std::strftime(buf, 255, (output_date_format + " %H:%M:%S").c_str(),
- std::localtime(&moment));
+ std::strftime(buf, 255, format.c_str(), std::localtime(&moment));
return buf;
}
inline string format_date(const date_t& when,
- const optional<string>& format = none)
+ const string format = "%Y-%m-%d")
{
- if (format || ! output_date_format.empty()) {
- char buf[256];
- std::tm moment = gregorian::to_tm(when);
- std::strftime(buf, 255, format ?
- format->c_str() : output_date_format.c_str(), &moment);
- return buf;
- } else {
- return to_simple_string(when).substr(2);
- }
+ char buf[256];
+ std::tm moment = gregorian::to_tm(when);
+ std::strftime(buf, 255, format.c_str(), &moment);
+ return buf;
}
/**
diff --git a/src/utils.cc b/src/utils.cc
index 2cfc69db..74a8ea6c 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -435,12 +435,6 @@ std::ostringstream _log_buffer;
uint8_t _trace_level;
#endif
-#ifdef BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK
-#define CURRENT_TIME() boost::posix_time::microsec_clock::universal_time()
-#else
-#define CURRENT_TIME() boost::posix_time::second_clock::universal_time()
-#endif
-
static inline void stream_memory_size(std::ostream& out, std::size_t size)
{
if (size < 1024)
@@ -458,20 +452,16 @@ static ptime logger_start;
bool logger_func(log_level_t level)
{
- std::size_t appender = 0;
-
if (! logger_has_run) {
logger_has_run = true;
logger_start = CURRENT_TIME();
IF_VERIFY()
- *_log_stream << " TIME OBJSZ MEMSZ" << std::endl;
-
- appender = (logger_start - current_time).total_milliseconds();
+ *_log_stream << " TIME OBJSZ MEMSZ" << std::endl;
}
*_log_stream << std::right << std::setw(5)
- << (CURRENT_TIME() - logger_start).total_milliseconds();
+ << (CURRENT_TIME() - logger_start).total_milliseconds() << "ms";
IF_VERIFY() {
*_log_stream << std::right << std::setw(6) << std::setprecision(3);
@@ -500,13 +490,7 @@ bool logger_func(log_level_t level)
break;
}
- *_log_stream << ' ' << _log_buffer.str();
-
- if (appender)
- *_log_stream << " (" << appender << "ms startup)";
-
- *_log_stream << std::endl;
-
+ *_log_stream << ' ' << _log_buffer.str() << std::endl;
_log_buffer.str("");
return true;
diff --git a/src/value.cc b/src/value.cc
index e9eaf5cb..c7ef8617 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -130,7 +130,7 @@ void value_t::storage_t::destroy()
void value_t::initialize()
{
#if defined(DEBUG_ON)
- LOGGER("value.initialize");
+ LOGGER("value.init");
#endif
true_value = new storage_t;
@@ -1523,10 +1523,11 @@ value_t value_t::annotated_tag() const
}
#endif
-value_t value_t::strip_annotations(const bool keep_price,
- const bool keep_date,
- const bool keep_tag) const
+value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
{
+ if (what_to_keep.keep_all())
+ return *this;
+
switch (type()) {
case VOID:
case BOOLEAN:
@@ -1541,17 +1542,16 @@ value_t value_t::strip_annotations(const bool keep_price,
case SEQUENCE: {
sequence_t temp;
foreach (const value_t& value, as_sequence())
- temp.push_back(value.strip_annotations(keep_price, keep_date, keep_tag));
+ temp.push_back(value.strip_annotations(what_to_keep));
return temp;
}
case AMOUNT:
- return as_amount().strip_annotations(keep_price, keep_date, keep_tag);
+ return as_amount().strip_annotations(what_to_keep);
case BALANCE:
- return as_balance().strip_annotations(keep_price, keep_date, keep_tag);
+ return as_balance().strip_annotations(what_to_keep);
case BALANCE_PAIR:
- return as_balance_pair().quantity().strip_annotations(keep_price, keep_date,
- keep_tag);
+ return as_balance_pair().quantity().strip_annotations(what_to_keep);
default:
assert(false);
@@ -1623,24 +1623,35 @@ value_t& value_t::add(const amount_t& amount, const optional<amount_t>& tcost)
return *this;
}
-void value_t::dump(std::ostream& out, const int first_width,
- const int latter_width) const
+void value_t::print(std::ostream& out,
+ const int first_width,
+ const int latter_width,
+ const optional<string>& date_format) const
{
switch (type()) {
case VOID:
- out << "VOID";
+ out << "";
break;
case BOOLEAN:
- out << as_boolean();
+ if (as_boolean())
+ out << "true";
+ else
+ out << "false";
break;
case DATETIME:
- out << format_datetime(as_datetime());
+ if (date_format)
+ out << format_datetime(as_datetime(), *date_format);
+ else
+ out << format_datetime(as_datetime());
break;
case DATE:
- out << format_date(as_date());
+ if (date_format)
+ out << format_date(as_date(), *date_format);
+ else
+ out << format_date(as_date());
break;
case INTEGER:
@@ -1655,14 +1666,6 @@ void value_t::dump(std::ostream& out, const int first_width,
out << as_string();
break;
- case MASK:
- out << as_mask();
- break;
-
- case POINTER:
- out << boost::unsafe_any_cast<const void *>(&as_any_pointer());
- break;
-
case SEQUENCE: {
out << '(';
bool first = true;
@@ -1672,7 +1675,7 @@ void value_t::dump(std::ostream& out, const int first_width,
else
out << ", ";
- value.dump(out, first_width, latter_width);
+ value.print(out, first_width, latter_width, date_format);
}
out << ')';
break;
@@ -1684,13 +1687,13 @@ void value_t::dump(std::ostream& out, const int first_width,
case BALANCE_PAIR:
as_balance_pair().print(out, first_width, latter_width);
break;
+
default:
- assert(false);
- break;
+ throw_(value_error, "Cannot print " << label());
}
}
-void value_t::print(std::ostream& out, const bool relaxed) const
+void value_t::dump(std::ostream& out, const bool relaxed) const
{
switch (type()) {
case VOID:
@@ -1704,6 +1707,13 @@ void value_t::print(std::ostream& out, const bool relaxed) const
out << "false";
break;
+ case DATETIME:
+ out << '[' << format_datetime(as_datetime()) << ']';
+ break;
+ case DATE:
+ out << '[' << format_date(as_date()) << ']';
+ break;
+
case INTEGER:
out << as_long();
break;
@@ -1723,13 +1733,6 @@ void value_t::print(std::ostream& out, const bool relaxed) const
out << as_balance_pair();
break;
- case DATETIME:
- assert(false);
- break;
- case DATE:
- out << '[' << format_date(as_date()) << ']';
- break;
-
case STRING:
out << '"' << as_string() << '"';
break;
@@ -1739,7 +1742,7 @@ void value_t::print(std::ostream& out, const bool relaxed) const
break;
case POINTER:
- assert(false);
+ out << boost::unsafe_any_cast<const void *>(&as_any_pointer());
break;
case SEQUENCE: {
@@ -1751,11 +1754,15 @@ void value_t::print(std::ostream& out, const bool relaxed) const
else
out << ", ";
- value.print(out, relaxed);
+ value.dump(out, relaxed);
}
out << ')';
break;
}
+
+ default:
+ assert(false);
+ break;
}
}
diff --git a/src/value.h b/src/value.h
index 8ee00a10..17ac4378 100644
--- a/src/value.h
+++ b/src/value.h
@@ -802,9 +802,7 @@ public:
value_t annotated_tag() const;
#endif
- value_t strip_annotations(const bool keep_price = amount_t::keep_price,
- const bool keep_date = amount_t::keep_date,
- const bool keep_tag = amount_t::keep_tag) const;
+ value_t strip_annotations(const keep_details_t& what_to_keep) const;
/**
* Collection-style access methods for SEQUENCE values.
@@ -925,9 +923,11 @@ public:
/**
* Printing methods.
*/
- void dump(std::ostream& out, const int first_width,
- const int latter_width = -1) const;
- void print(std::ostream& out, const bool relaxed = true) const;
+ void print(std::ostream& out,
+ const int first_width,
+ const int latter_width = -1,
+ const optional<string>& date_format = none) const;
+ void dump(std::ostream& out, const bool relaxed = true) const;
/**
* Debugging methods.
@@ -954,7 +954,7 @@ inline string value_context(const value_t& val) {
std::ostringstream buf;
buf << std::right;
buf.width(20);
- val.print(buf);
+ val.dump(buf);
return buf.str();
}
diff --git a/src/work.cc b/src/work.cc
index 9bd75c9c..e4cee9e6 100644
--- a/src/work.cc
+++ b/src/work.cc
@@ -124,13 +124,9 @@ void normalize_session_options(session_t& session)
INFO("Initialization file is " << session.init_file->string());
INFO("Price database is " << session.price_db->string());
- INFO("Binary cache is " << session.cache_file->string());
foreach (const path& pathname, session.data_files)
INFO("Journal file is " << pathname.string());
-
- if (! session.use_cache)
- INFO("Binary cache mechanism will not be used");
}
function_t look_for_precommand(report_t& report, const string& verb)
@@ -200,7 +196,7 @@ void normalize_report_options(report_t& report, const string& verb)
}
if (verb[0] != 'b' && verb[0] != 'r')
- amount_t::keep_base = true;
+ report.what_to_keep.keep_base = true;
// Setup the default value for the display predicate
@@ -223,19 +219,6 @@ void normalize_report_options(report_t& report, const string& verb)
}
#endif
- // Now setup the various formatting strings
-
- // jww (2008-08-14): I hear a song, and it's sound is "HaAaaCcK"
-
-#if 0
- if (! date_output_format.empty())
- date_t::output_format = date_output_format;
-#endif
-
- amount_t::keep_price = report.keep_price;
- amount_t::keep_date = report.keep_date;
- amount_t::keep_tag = report.keep_tag;
-
if (! report.report_period.empty() && ! report.sort_all)
report.entry_sort = true;
}
@@ -265,21 +248,4 @@ void invoke_command_verb(report_t& report,
INFO_FINISH(command);
}
-void write_binary_cache(session_t& session, journal_t * journal)
-{
- // Write out the binary cache, if need be
-
- if (session.use_cache && session.cache_dirty && session.cache_file) {
- TRACE_START(binary_cache, 1, "Wrote binary journal file");
-
- ofstream stream(*session.cache_file);
-#if 0
- // jww (2009-01-31): NYI
- journal->write(stream);
-#endif
-
- TRACE_FINISH(binary_cache, 1);
- }
-}
-
} // namespace ledger
diff --git a/src/work.h b/src/work.h
index 935db18f..c09766fd 100644
--- a/src/work.h
+++ b/src/work.h
@@ -56,7 +56,6 @@ void invoke_command_verb(report_t& report,
function_t& command,
string_iterator args_begin,
string_iterator args_end);
-void write_binary_cache(session_t& session, journal_t * journal);
} // namespace ledger
diff --git a/src/xact.cc b/src/xact.cc
index fbd3e8bb..c154d31c 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -36,12 +36,13 @@
namespace ledger {
-optional<date_t> xact_t::actual_date() const
+date_t xact_t::date() const
{
- optional<date_t> date = item_t::actual_date();
- if (! date && entry)
- return entry->actual_date();
- return date;
+ if (! _date) {
+ assert(entry);
+ return entry->date();
+ }
+ return item_t::date();
}
optional<date_t> xact_t::effective_date() const
@@ -129,7 +130,7 @@ namespace {
value_t get_account(call_scope_t& scope)
{
- xact_t& xact(downcast<xact_t>(*scope.parent));
+ xact_t& xact(find_scope<xact_t>(scope));
var_t<long> max_width(scope, 0);
diff --git a/src/xact.h b/src/xact.h
index d7e87748..f06f2136 100644
--- a/src/xact.h
+++ b/src/xact.h
@@ -106,7 +106,7 @@ public:
TRACE_DTOR(xact_t);
}
- virtual optional<date_t> actual_date() const;
+ virtual date_t date() const;
virtual optional<date_t> effective_date() const;
virtual state_t state() const;
@@ -203,7 +203,7 @@ public:
date_t reported_date() const {
if (xdata_ && is_valid(xdata_->date))
return xdata_->date;
- return *date();
+ return date();
}
account_t * reported_account() {