Merge branch 'next'

This commit is contained in:
John Wiegley 2009-11-19 03:37:16 -05:00
commit cc9110a43a
20 changed files with 1750 additions and 613 deletions

View file

@ -55,9 +55,10 @@ typedef std::map<const string, account_t *> accounts_map;
class account_t : public supports_flags<>, public scope_t
{
#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
#define ACCOUNT_KNOWN 0x01
#define ACCOUNT_TEMP 0x02 // account is a temporary object
#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
#define ACCOUNT_KNOWN 0x01
#define ACCOUNT_TEMP 0x02 // account is a temporary object
#define ACCOUNT_GENERATED 0x04 // account never actually existed
public:
account_t * parent;

View file

@ -43,7 +43,7 @@
#include "xact.h"
#define LEDGER_MAGIC 0x4c454447
#define ARCHIVE_VERSION 0x03000005
#define ARCHIVE_VERSION 0x03000006
//BOOST_IS_ABSTRACT(ledger::scope_t)
BOOST_CLASS_EXPORT(ledger::scope_t)

View file

@ -41,7 +41,7 @@ namespace ledger {
post_handler_ptr chain_post_handlers(report_t& report,
post_handler_ptr base_handler,
bool only_preliminaries)
bool for_accounts_report)
{
post_handler_ptr handler(base_handler);
predicate_t display_predicate;
@ -51,7 +51,7 @@ post_handler_ptr chain_post_handlers(report_t& report,
expr_t& expr(report.HANDLER(amount_).expr);
expr.set_context(&report);
if (! only_preliminaries) {
if (! for_accounts_report) {
// Make sure only forecast postings which match are allowed through
if (report.HANDLED(forecast_while_)) {
handler.reset(new filter_posts
@ -77,25 +77,23 @@ post_handler_ptr chain_post_handlers(report_t& report,
report.what_to_keep());
handler.reset(new filter_posts(handler, display_predicate, report));
}
// changed_value_posts adds virtual posts to the list to account for
// changes in market value of commodities, which otherwise would affect
// the running total unpredictably.
if (report.HANDLED(revalued))
handler.reset(new changed_value_posts
(handler,
report.HANDLER(display_amount_).expr,
report.HANDLED(revalued_total_) ?
report.HANDLER(revalued_total_).expr :
report.HANDLER(display_total_).expr,
report.HANDLER(display_total_).expr,
report, report.HANDLED(revalued_only)));
}
// changed_value_posts adds virtual posts to the list to account for changes
// in market value of commodities, which otherwise would affect the running
// total unpredictably.
if (report.HANDLED(revalued) && (! for_accounts_report ||
report.HANDLED(unrealized)))
handler.reset(new changed_value_posts(handler, report,
for_accounts_report,
report.HANDLED(unrealized)));
// calc_posts computes the running total. When this appears will determine,
// for example, whether filtered posts are included or excluded from the
// running total.
handler.reset(new calc_posts(handler, expr, only_preliminaries));
handler.reset(new calc_posts(handler, expr, (! for_accounts_report ||
(report.HANDLED(revalued) &&
report.HANDLED(unrealized)))));
// filter_posts will only pass through posts matching the
// `secondary_predicate'.
@ -105,7 +103,7 @@ post_handler_ptr chain_post_handlers(report_t& report,
handler.reset(new filter_posts(handler, only_predicate, report));
}
if (! only_preliminaries) {
if (! for_accounts_report) {
// sort_posts will sort all the posts it sees, based on the `sort_order'
// value expression.
if (report.HANDLED(sort_)) {
@ -139,10 +137,6 @@ post_handler_ptr chain_post_handlers(report_t& report,
else if (report.HANDLED(subtotal))
handler.reset(new subtotal_posts(handler, expr));
}
else if (! report.HANDLED(period_) &&
! report.HANDLED(unsorted)) {
handler.reset(new sort_posts(handler, "date"));
}
if (report.HANDLED(dow))
handler.reset(new dow_posts(handler, expr));

View file

@ -84,7 +84,7 @@ class report_t;
post_handler_ptr
chain_post_handlers(report_t& report,
post_handler_ptr base_handler,
bool only_preliminaries = false);
bool for_accounts_report = false);
} // namespace ledger

View file

@ -637,7 +637,8 @@ bool compare_amount_commodities::operator()(const amount_t * left,
return false;
if (aleftcomm.details.date && arightcomm.details.date) {
date_duration_t diff = *aleftcomm.details.date - *arightcomm.details.date;
gregorian::date_duration diff =
*aleftcomm.details.date - *arightcomm.details.date;
return diff.is_negative();
}

View file

@ -217,7 +217,7 @@ void calc_posts::operator()(post_t& post)
if (last_post) {
assert(last_post->has_xdata());
if (! account_wise)
if (calc_running_total)
xdata.total = last_post->xdata().total;
xdata.count = last_post->xdata().count + 1;
} else {
@ -230,7 +230,7 @@ void calc_posts::operator()(post_t& post)
account_t * acct = post.reported_account();
acct->xdata().add_flags(ACCOUNT_EXT_VISITED);
if (! account_wise)
if (calc_running_total)
add_or_set_value(xdata.total, xdata.visited_value);
item_handler<post_t>::operator()(post);
@ -239,19 +239,21 @@ void calc_posts::operator()(post_t& post)
}
namespace {
typedef function<void (post_t *)> post_functor_t;
typedef function<void (post_t&)> post_functor_t;
void handle_value(const value_t& value,
account_t * account,
account_t * account,
xact_t * xact,
temporaries_t& temps,
item_handler<post_t>& handler,
const date_t& date = date_t(),
const value_t& total = value_t(),
post_handler_ptr handler,
const date_t& date = date_t(),
const value_t& total = value_t(),
const bool direct_amount = false,
const bool mark_visited = false,
const optional<post_functor_t>& functor = none)
{
post_t& post = temps.create_post(*xact, account);
post.add_flags(ITEM_GENERATED);
// If the account for this post is all virtual, then report the post as
// such. This allows subtotal reports to show "(Account)" for accounts
@ -302,11 +304,16 @@ namespace {
xdata.add_flags(POST_EXT_DIRECT_AMT);
if (functor)
(*functor)(&post);
(*functor)(post);
DEBUG("filter.changed_value.rounding", "post.amount = " << post.amount);
handler(post);
(*handler)(post);
if (mark_visited) {
post.xdata().add_flags(POST_EXT_VISITED);
post.account->xdata().add_flags(ACCOUNT_EXT_VISITED);
}
}
}
@ -344,7 +351,7 @@ void collapse_posts::report_subtotal()
earliest_date : last_xact->_date);
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
handle_value(subtotal, &totals_account, &xact, temps, *handler);
handle_value(subtotal, &totals_account, &xact, temps, handler);
}
component_posts.clear();
@ -404,30 +411,58 @@ void related_posts::flush()
item_handler<post_t>::flush();
}
changed_value_posts::changed_value_posts(post_handler_ptr handler,
report_t& _report,
bool _for_accounts_report,
bool _show_unrealized)
: item_handler<post_t>(handler), report(_report),
for_accounts_report(_for_accounts_report),
show_unrealized(_show_unrealized), last_post(NULL),
revalued_account(temps.create_account(_("<Revalued>"))),
rounding_account(temps.create_account(_("<Rounding>")))
{
TRACE_CTOR(changed_value_posts, "post_handler_ptr, report_t&, bool");
display_amount_expr = report.HANDLER(display_amount_).expr;
total_expr = (report.HANDLED(revalued_total_) ?
report.HANDLER(revalued_total_).expr :
report.HANDLER(display_total_).expr);
display_total_expr = report.HANDLER(display_total_).expr;
changed_values_only = report.HANDLED(revalued_only);
gains_equity_account =
report.session.journal->master->find_account(_("Equity:Unrealized Gains"));
gains_equity_account->add_flags(ACCOUNT_GENERATED);
losses_equity_account =
report.session.journal->master->find_account(_("Equity:Unrealized Losses"));
losses_equity_account->add_flags(ACCOUNT_GENERATED);
}
void changed_value_posts::flush()
{
if (last_post && last_post->date() <= report.terminus.date()) {
output_revaluation(last_post, report.terminus.date());
output_revaluation(*last_post, report.terminus.date());
last_post = NULL;
}
item_handler<post_t>::flush();
}
void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
{
if (is_valid(date))
post->xdata().date = date;
post.xdata().date = date;
value_t repriced_total;
try {
bind_scope_t bound_scope(report, *post);
bind_scope_t bound_scope(report, post);
repriced_total = total_expr.calc(bound_scope);
}
catch (...) {
post->xdata().date = date_t();
post.xdata().date = date_t();
throw;
}
post->xdata().date = date_t();
post.xdata().date = date_t();
DEBUG("filter.changed_value",
"output_revaluation(last_balance) = " << last_total);
@ -441,19 +476,44 @@ void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
xact_t& xact = temps.create_xact();
xact.payee = _("Commodities revalued");
xact._date = is_valid(date) ? date : post->date();
xact._date = is_valid(date) ? date : post.date();
handle_value(diff, &revalued_account, &xact, temps, *handler,
*xact._date, repriced_total, false,
optional<post_functor_t>
(bind(&changed_value_posts::output_rounding, this, _1)));
if (! for_accounts_report) {
handle_value
(/* value= */ diff,
/* account= */ &revalued_account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler,
/* date= */ *xact._date,
/* total= */ repriced_total,
/* direct_amount= */ false,
/* mark_visited= */ false,
/* functor= */ (optional<post_functor_t>
(bind(&changed_value_posts::output_rounding,
this, _1))));
}
else if (show_unrealized) {
handle_value
(/* value= */ - diff,
/* account= */ (diff < 0L ?
losses_equity_account :
gains_equity_account),
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler,
/* date= */ *xact._date,
/* total= */ value_t(),
/* direct_amount= */ false,
/* mark_visited= */ true);
}
}
}
}
void changed_value_posts::output_rounding(post_t * post)
void changed_value_posts::output_rounding(post_t& post)
{
bind_scope_t bound_scope(report, *post);
bind_scope_t bound_scope(report, post);
value_t new_display_total(display_total_expr.calc(bound_scope));
DEBUG("filter.changed_value.rounding",
@ -478,9 +538,9 @@ void changed_value_posts::output_rounding(post_t * post)
xact_t& xact = temps.create_xact();
xact.payee = _("Commodity rounding");
xact._date = post->date();
xact._date = post.date();
handle_value(diff, &rounding_account, &xact, temps, *handler,
handle_value(diff, &rounding_account, &xact, temps, handler,
*xact._date, precise_display_total, true);
}
}
@ -491,19 +551,19 @@ void changed_value_posts::output_rounding(post_t * post)
void changed_value_posts::operator()(post_t& post)
{
if (last_post)
output_revaluation(last_post, post.date());
output_revaluation(*last_post, post.date());
if (changed_values_only)
post.xdata().add_flags(POST_EXT_DISPLAYED);
output_rounding(&post);
if (! for_accounts_report)
output_rounding(post);
item_handler<post_t>::operator()(post);
bind_scope_t bound_scope(report, post);
last_total = total_expr.calc(bound_scope);
last_post = &post;
last_post = &post;
}
void subtotal_posts::report_subtotal(const char * spec_fmt,
@ -515,12 +575,14 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
optional<date_t> range_start = interval ? interval->start : none;
optional<date_t> range_finish = interval ? interval->inclusive_end() : none;
foreach (post_t * post, component_posts) {
date_t date = post->date();
if (! range_start || date < *range_start)
range_start = date;
if (! range_finish || date > *range_finish)
range_finish = date;
if (! range_start || ! range_finish) {
foreach (post_t * post, component_posts) {
date_t date = post->date();
if (! range_start || date < *range_start)
range_start = date;
if (! range_finish || date > *range_finish)
range_finish = date;
}
}
component_posts.clear();
@ -542,7 +604,7 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
foreach (values_map::value_type& pair, values)
handle_value(pair.second.value, pair.second.account, &xact, temps,
*handler);
handler);
values.clear();
}
@ -652,10 +714,10 @@ void posts_as_equity::report_subtotal()
foreach (balance_t::amounts_map::value_type amount_pair,
pair.second.value.as_balance().amounts)
handle_value(amount_pair.second, pair.second.account, &xact, temps,
*handler);
handler);
} else {
handle_value(pair.second.value, pair.second.account, &xact, temps,
*handler);
handler);
}
total += pair.second.value;
}
@ -784,7 +846,7 @@ void budget_posts::report_budget_items(const date_t& date)
assert(begin);
if (*begin <= date &&
(! pair.first.end || *begin < *pair.first.end)) {
(! pair.first.finish || *begin < *pair.first.finish)) {
post_t& post = *pair.second;
DEBUG("budget.generate", "Reporting budget for "
@ -905,8 +967,8 @@ void forecast_posts::flush()
}
date_t& begin = *(*least).first.start;
if ((*least).first.end)
assert(begin < *(*least).first.end);
if ((*least).first.finish)
assert(begin < *(*least).first.finish);
// If the next date in the series for this periodic posting is more than 5
// years beyond the last valid post we generated, drop it from further

View file

@ -241,8 +241,7 @@ public:
const predicate_t& predicate,
scope_t& _context)
: item_handler<post_t>(handler), pred(predicate), context(_context) {
TRACE_CTOR(filter_posts,
"post_handler_ptr, const predicate_t&, scope_t&");
TRACE_CTOR(filter_posts, "post_handler_ptr, predicate_t, scope_t&");
}
virtual ~filter_posts() {
TRACE_DTOR(filter_posts);
@ -280,16 +279,16 @@ class calc_posts : public item_handler<post_t>
{
post_t * last_post;
expr_t& amount_expr;
bool account_wise;
bool calc_running_total;
calc_posts();
public:
calc_posts(post_handler_ptr handler,
expr_t& _amount_expr,
bool _account_wise = false)
bool _calc_running_total = false)
: item_handler<post_t>(handler), last_post(NULL),
amount_expr(_amount_expr), account_wise(_account_wise) {
amount_expr(_amount_expr), calc_running_total(_calc_running_total) {
TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&, bool");
}
virtual ~calc_posts() {
@ -379,39 +378,33 @@ class changed_value_posts : public item_handler<post_t>
expr_t display_total_expr;
report_t& report;
bool changed_values_only;
bool for_accounts_report;
bool show_unrealized;
post_t * last_post;
value_t last_total;
value_t last_display_total;
temporaries_t temps;
temporaries_t temps;
account_t& revalued_account;
account_t& rounding_account;
account_t * gains_equity_account;
account_t * losses_equity_account;
changed_value_posts();
public:
changed_value_posts(post_handler_ptr handler,
const expr_t& _display_amount_expr,
const expr_t& _total_expr,
const expr_t& _display_total_expr,
report_t& _report,
bool _changed_values_only)
: item_handler<post_t>(handler),
display_amount_expr(_display_amount_expr), total_expr(_total_expr),
display_total_expr(_display_total_expr), report(_report),
changed_values_only(_changed_values_only), last_post(NULL),
revalued_account(temps.create_account(_("<Revalued>"))),
rounding_account(temps.create_account(_("<Rounding>"))) {
TRACE_CTOR(changed_value_posts,
"post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
}
report_t& _report,
bool _for_accounts_report,
bool _show_unrealized);
virtual ~changed_value_posts() {
TRACE_DTOR(changed_value_posts);
}
virtual void flush();
void output_revaluation(post_t * post, const date_t& current);
void output_rounding(post_t * post);
void output_revaluation(post_t& post, const date_t& current);
void output_rounding(post_t& post);
virtual void operator()(post_t& post);
};

View file

@ -165,57 +165,12 @@ value_t period_command(call_scope_t& args)
report_t& report(find_scope<report_t>(args));
std::ostream& out(report.output_stream);
show_period_tokens(out, arg);
out << std::endl;
date_interval_t interval(arg);
interval.dump(out, report.session.current_year);
out << _("global details => ") << std::endl << std::endl;
if (interval.start)
out << _(" start: ") << format_date(*interval.start) << std::endl;
else
out << _(" start: TODAY: ") << format_date(CURRENT_DATE()) << std::endl;
if (interval.end)
out << _(" end: ") << format_date(*interval.end) << std::endl;
if (interval.skip_duration)
out << _(" skip: ") << *interval.skip_duration << std::endl;
if (interval.factor)
out << _(" factor: ") << interval.factor << std::endl;
if (interval.duration)
out << _("duration: ") << *interval.duration << std::endl;
if (interval.find_period(interval.start ?
*interval.start : CURRENT_DATE())) {
out << std::endl
<< _("after finding first period => ") << std::endl
<< std::endl;
if (interval.start)
out << _(" start: ") << format_date(*interval.start) << std::endl;
if (interval.end)
out << _(" end: ") << format_date(*interval.end) << std::endl;
if (interval.skip_duration)
out << _(" skip: ") << *interval.skip_duration << std::endl;
if (interval.factor)
out << _(" factor: ") << interval.factor << std::endl;
if (interval.duration)
out << _("duration: ") << *interval.duration << std::endl;
out << std::endl;
for (int i = 0; i < 20 && interval; i++, ++interval) {
out << std::right;
out.width(2);
out << i << "): " << format_date(*interval.start);
if (interval.end_of_duration)
out << " -- " << format_date(*interval.inclusive_end());
out << std::endl;
if (! interval.skip_duration)
break;
}
}
return NULL_VALUE;
}
@ -229,14 +184,12 @@ value_t args_command(call_scope_t& args)
out << std::endl << std::endl;
query_t query(args.value(), report.what_to_keep());
if (! query)
throw_(std::runtime_error,
_("Invalid query predicate: %1") << join_args(args));
if (query) {
call_scope_t sub_args(static_cast<scope_t&>(args));
sub_args.push_back(string_value(query.text()));
call_scope_t sub_args(static_cast<scope_t&>(args));
sub_args.push_back(string_value(query.text()));
parse_command(sub_args);
parse_command(sub_args);
}
if (query.tokens_remaining()) {
out << std::endl << _("====== Display predicate ======")
@ -244,14 +197,12 @@ value_t args_command(call_scope_t& args)
query.parse_again();
if (! query)
throw_(std::runtime_error,
_("Invalid display predicate: %1") << join_args(args));
if (query) {
call_scope_t disp_sub_args(static_cast<scope_t&>(args));
disp_sub_args.push_back(string_value(query.text()));
call_scope_t disp_sub_args(static_cast<scope_t&>(args));
disp_sub_args.push_back(string_value(query.text()));
parse_command(disp_sub_args);
parse_command(disp_sub_args);
}
}
return NULL_VALUE;

View file

@ -263,12 +263,12 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
node->set_right(arg1);
}
if (interval.end) {
if (interval.finish) {
expr_t::ptr_op_t lt = new expr_t::op_t(expr_t::op_t::O_LT);
lt->set_left(ident);
expr_t::ptr_op_t arg1 = new expr_t::op_t(expr_t::op_t::VALUE);
arg1->set_value(*interval.end);
arg1->set_value(*interval.finish);
lt->set_right(arg1);
if (node) {

View file

@ -96,14 +96,14 @@ public:
explicit token_t(kind_t _kind = UNKNOWN,
const optional<string>& _value = none)
: kind(_kind), value(_value) {
TRACE_CTOR(lexer_t::token_t, "");
TRACE_CTOR(query_t::lexer_t::token_t, "");
}
token_t(const token_t& tok)
: kind(tok.kind), value(tok.value) {
TRACE_CTOR(lexer_t::token_t, "copy");
TRACE_CTOR(query_t::lexer_t::token_t, "copy");
}
~token_t() throw() {
TRACE_DTOR(lexer_t::token_t);
TRACE_DTOR(query_t::lexer_t::token_t);
}
token_t& operator=(const token_t& tok) {
@ -120,40 +120,42 @@ public:
string to_string() const {
switch (kind) {
case UNKNOWN: return "UNKNOWN";
case LPAREN: return "LPAREN";
case RPAREN: return "RPAREN";
case TOK_NOT: return "TOK_NOT";
case TOK_AND: return "TOK_AND";
case TOK_OR: return "TOK_OR";
case TOK_EQ: return "TOK_EQ";
case TOK_DATE: return "TOK_DATE";
case TOK_CODE: return "TOK_CODE";
case TOK_PAYEE: return "TOK_PAYEE";
case TOK_NOTE: return "TOK_NOTE";
case UNKNOWN: return "UNKNOWN";
case LPAREN: return "LPAREN";
case RPAREN: return "RPAREN";
case TOK_NOT: return "TOK_NOT";
case TOK_AND: return "TOK_AND";
case TOK_OR: return "TOK_OR";
case TOK_EQ: return "TOK_EQ";
case TOK_DATE: return "TOK_DATE";
case TOK_CODE: return "TOK_CODE";
case TOK_PAYEE: return "TOK_PAYEE";
case TOK_NOTE: return "TOK_NOTE";
case TOK_ACCOUNT: return "TOK_ACCOUNT";
case TOK_META: return "TOK_META";
case TOK_EXPR: return "TOK_EXPR";
case TERM: return string("TERM(") + *value + ")";
case TOK_META: return "TOK_META";
case TOK_EXPR: return "TOK_EXPR";
case TERM: return string("TERM(") + *value + ")";
case END_REACHED: return "END_REACHED";
}
assert(false);
return empty_string;
}
string symbol() const {
switch (kind) {
case LPAREN: return "(";
case RPAREN: return ")";
case TOK_NOT: return "not";
case TOK_AND: return "and";
case TOK_OR: return "or";
case TOK_EQ: return "=";
case TOK_DATE: return "date";
case TOK_CODE: return "code";
case TOK_PAYEE: return "payee";
case TOK_NOTE: return "note";
case LPAREN: return "(";
case RPAREN: return ")";
case TOK_NOT: return "not";
case TOK_AND: return "and";
case TOK_OR: return "or";
case TOK_EQ: return "=";
case TOK_DATE: return "date";
case TOK_CODE: return "code";
case TOK_PAYEE: return "payee";
case TOK_NOTE: return "note";
case TOK_ACCOUNT: return "account";
case TOK_META: return "meta";
case TOK_EXPR: return "expr";
case TOK_META: return "meta";
case TOK_EXPR: return "expr";
case END_REACHED: return "<EOF>";
@ -180,7 +182,7 @@ public:
consume_whitespace(false),
consume_next_arg(false)
{
TRACE_CTOR(lexer_t, "");
TRACE_CTOR(query_t::lexer_t, "");
assert(begin != end);
arg_i = (*begin).as_string().begin();
arg_end = (*begin).as_string().end();
@ -192,10 +194,10 @@ public:
consume_next_arg(lexer.consume_next_arg),
token_cache(lexer.token_cache)
{
TRACE_CTOR(lexer_t, "copy");
TRACE_CTOR(query_t::lexer_t, "copy");
}
~lexer_t() throw() {
TRACE_DTOR(lexer_t);
TRACE_DTOR(query_t::lexer_t);
}
token_t next_token();
@ -227,14 +229,14 @@ protected:
public:
parser_t(const value_t& _args)
: args(_args), lexer(args.begin(), args.end()) {
TRACE_CTOR(parser_t, "");
TRACE_CTOR(query_t::parser_t, "");
}
parser_t(const parser_t& parser)
: args(parser.args), lexer(parser.lexer) {
TRACE_CTOR(parser_t, "copy");
TRACE_CTOR(query_t::parser_t, "copy");
}
~parser_t() throw() {
TRACE_DTOR(parser_t);
TRACE_DTOR(query_t::parser_t);
}
expr_t::ptr_op_t parse() {

View file

@ -120,14 +120,15 @@ void report_t::normalize_options(const string& verb)
date_interval_t interval(HANDLER(period_).str());
if (! HANDLED(begin_) && interval.start) {
string predicate =
"date>=[" + to_iso_extended_string(*interval.start) + "]";
optional<date_t> begin = interval.begin(session.current_year);
optional<date_t> end = interval.end(session.current_year);
if (! HANDLED(begin_) && begin) {
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
HANDLER(limit_).on(string("?normalize"), predicate);
}
if (! HANDLED(end_) && interval.end) {
string predicate =
"date<[" + to_iso_extended_string(*interval.end) + "]";
if (! HANDLED(end_) && end) {
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
HANDLER(limit_).on(string("?normalize"), predicate);
}
@ -221,25 +222,21 @@ void report_t::normalize_options(const string& verb)
void report_t::parse_query_args(const value_t& args, const string& whence)
{
query_t query(args, what_to_keep());
if (! query)
throw_(std::runtime_error,
_("Invalid query predicate: %1") << query.text());
if (query) {
HANDLER(limit_).on(whence, query.text());
HANDLER(limit_).on(whence, query.text());
DEBUG("report.predicate",
"Predicate = " << HANDLER(limit_).str());
DEBUG("report.predicate",
"Predicate = " << HANDLER(limit_).str());
}
if (query.tokens_remaining()) {
query.parse_again();
if (! query)
throw_(std::runtime_error,
_("Invalid display predicate: %1") << query.text());
if (query) {
HANDLER(display_).on(whence, query.text());
HANDLER(display_).on(whence, query.text());
DEBUG("report.predicate",
"Display predicate = " << HANDLER(display_).str());
DEBUG("report.predicate",
"Display predicate = " << HANDLER(display_).str());
}
}
}
@ -281,6 +278,12 @@ void report_t::accounts_report(acct_handler_ptr handler)
chain_post_handlers(*this, post_handler_ptr(new ignore_posts), true);
pass_down_posts(chain, walker);
HANDLER(amount_).expr.mark_uncompiled();
HANDLER(total_).expr.mark_uncompiled();
HANDLER(display_amount_).expr.mark_uncompiled();
HANDLER(display_total_).expr.mark_uncompiled();
HANDLER(revalued_total_).expr.mark_uncompiled();
scoped_ptr<accounts_iterator> iter;
if (! HANDLED(sort_)) {
iter.reset(new basic_accounts_iterator(*session.journal->master));
@ -884,6 +887,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
case 'u':
OPT(unbudgeted);
else OPT(uncleared);
else OPT(unrealized);
else OPT(unround);
else OPT(unsorted);
break;

View file

@ -50,6 +50,7 @@
#include "option.h"
#include "commodity.h"
#include "annotate.h"
#include "session.h"
#include "format.h"
namespace ledger {
@ -300,6 +301,7 @@ public:
HANDLER(truncate_).report(out);
HANDLER(unbudgeted).report(out);
HANDLER(uncleared).report(out);
HANDLER(unrealized).report(out);
HANDLER(unround).report(out);
HANDLER(unsorted).report(out);
HANDLER(weekly).report(out);
@ -352,7 +354,7 @@ public:
set_expr(args[0].to_string(), args[1].to_string());
});
OPTION(report_t, amount_data);
OPTION(report_t, amount_data); // -j
OPTION(report_t, anon);
OPTION_(report_t, average, DO() { // -A
@ -377,14 +379,14 @@ public:
});
OPTION_(report_t, begin_, DO_(args) { // -b
date_interval_t interval(args[1].to_string());
if (! interval.start)
date_interval_t interval(args[1].to_string());
optional<date_t> begin = interval.begin(parent->session.current_year);
if (! begin)
throw_(std::invalid_argument,
_("Could not determine beginning of period '%1'")
<< args[1].to_string());
string predicate =
"date>=[" + to_iso_extended_string(*interval.start) + "]";
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
parent->HANDLER(limit_).on(string("--begin"), predicate);
});
@ -524,17 +526,19 @@ public:
OPTION(report_t, empty); // -E
OPTION_(report_t, end_, DO_(args) { // -e
date_interval_t interval(args[1].to_string());
if (! interval.start)
date_interval_t interval(args[1].to_string());
// Use begin() here so that if the user says --end=2008, we end on
// 2008/01/01 instead of 2009/01/01 (which is what end() would return).
optional<date_t> end = interval.begin(parent->session.current_year);
if (! end)
throw_(std::invalid_argument,
_("Could not determine end of period '%1'")
<< args[1].to_string());
string predicate =
"date<[" + to_iso_extended_string(*interval.start) + "]";
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
parent->HANDLER(limit_).on(string("--end"), predicate);
parent->terminus = datetime_t(*interval.start);
parent->terminus = datetime_t(*end);
});
OPTION(report_t, equity);
@ -622,11 +626,13 @@ public:
OPTION_(report_t, now_, DO_(args) {
date_interval_t interval(args[1].to_string());
if (! interval.start)
optional<date_t> begin = interval.begin(parent->session.current_year);
if (! begin)
throw_(std::invalid_argument,
_("Could not determine beginning of period '%1'")
<< args[1].to_string());
ledger::epoch = datetime_t(*interval.start);
ledger::epoch = parent->terminus = datetime_t(*begin);
parent->session.current_year = ledger::epoch->date().year();
});
OPTION__
@ -844,7 +850,7 @@ public:
set_expr(args[0].to_string(), args[1].to_string());
});
OPTION(report_t, total_data);
OPTION(report_t, total_data); // -J
OPTION_(report_t, truncate_, DO_(args) {
string style(args[1].to_string());
@ -868,6 +874,8 @@ public:
parent->HANDLER(limit_).on(string("--uncleared"), "uncleared|pending");
});
OPTION(report_t, unrealized);
OPTION_(report_t, unround, DO() {
parent->HANDLER(display_amount_)
.set_expr(string("--unround"), "unrounded(amount_expr)");

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,6 @@ inline bool is_valid(const datetime_t& moment) {
}
typedef boost::gregorian::date date_t;
typedef boost::gregorian::date_duration date_duration_t;
typedef boost::gregorian::date_iterator date_iterator_t;
inline bool is_valid(const date_t& moment) {
@ -85,19 +84,19 @@ string_to_day_of_week(const std::string& str);
optional<date_time::months_of_year>
string_to_month_of_year(const std::string& str);
datetime_t parse_datetime(const char * str,
optional<date_t::year_type> current_year = none);
typedef optional<date_t::year_type> optional_year;
datetime_t parse_datetime(const char * str, optional_year current_year = none);
inline datetime_t parse_datetime(const std::string& str,
optional<date_t::year_type> current_year = none) {
optional_year current_year = none) {
return parse_datetime(str.c_str(), current_year);
}
date_t parse_date(const char * str,
optional<date_t::year_type> current_year = none);
date_t parse_date(const char * str, optional_year current_year = none);
inline date_t parse_date(const std::string& str,
optional<date_t::year_type> current_year = none) {
optional_year current_year = none) {
return parse_date(str.c_str(), current_year);
}
@ -138,105 +137,423 @@ inline void to_xml(std::ostream& out, const date_t& when,
}
}
struct date_traits_t
{
bool has_year;
bool has_month;
bool has_day;
date_traits_t(bool _has_year = false,
bool _has_month = false,
bool _has_day = false)
: has_year(_has_year), has_month(_has_month), has_day(_has_day) {
TRACE_CTOR(date_traits_t, "bool, bool, bool");
}
date_traits_t(const date_traits_t& traits)
: has_year(traits.has_year),
has_month(traits.has_month),
has_day(traits.has_day) {
TRACE_CTOR(date_traits_t, "copy");
}
~date_traits_t() throw() {
TRACE_DTOR(date_traits_t);
}
date_traits_t& operator=(const date_traits_t& traits) {
has_year = traits.has_year;
has_month = traits.has_month;
has_day = traits.has_day;
return *this;
}
bool operator==(const date_traits_t& traits) const {
return (has_year == traits.has_year &&
has_month == traits.has_month &&
has_day == traits.has_day);
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & has_year;
ar & has_month;
ar & has_day;
}
#endif // HAVE_BOOST_SERIALIZATION
};
struct date_duration_t
{
enum skip_quantum_t {
DAYS, WEEKS, MONTHS, QUARTERS, YEARS
} quantum;
int length;
date_duration_t() : quantum(DAYS), length(0) {
TRACE_CTOR(date_duration_t, "");
}
date_duration_t(skip_quantum_t _quantum, int _length)
: quantum(_quantum), length(_length) {
TRACE_CTOR(date_duration_t, "skip_quantum_t, int");
}
date_duration_t(const date_duration_t& dur)
: quantum(dur.quantum), length(dur.length) {
TRACE_CTOR(date_duration_t, "copy");
}
~date_duration_t() throw() {
TRACE_DTOR(date_duration_t);
}
date_t add(const date_t& date) const {
switch (quantum) {
case DAYS:
return date + gregorian::days(length);
case WEEKS:
return date + gregorian::weeks(length);
case MONTHS:
return date + gregorian::months(length);
case QUARTERS:
return date + gregorian::months(length * 3);
case YEARS:
return date + gregorian::years(length);
default:
assert(false); return date_t();
}
}
date_t subtract(const date_t& date) const {
switch (quantum) {
case DAYS:
return date - gregorian::days(length);
case WEEKS:
return date - gregorian::weeks(length);
case MONTHS:
return date - gregorian::months(length);
case QUARTERS:
return date - gregorian::months(length * 3);
case YEARS:
return date - gregorian::years(length);
default:
assert(false); return date_t();
}
}
string to_string() const {
std::ostringstream out;
out << length << ' ';
switch (quantum) {
case DAYS: out << "day"; break;
case WEEKS: out << "week"; break;
case MONTHS: out << "month"; break;
case QUARTERS: out << "quarter"; break;
case YEARS: out << "year"; break;
default:
assert(false);
break;
}
if (length > 1)
out << 's';
return out.str();
}
static date_t find_nearest(const date_t& date, skip_quantum_t skip);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & quantum;
ar & length;
}
#endif // HAVE_BOOST_SERIALIZATION
};
class date_specifier_t
{
friend class date_parser_t;
#if 0
typedef date_t::year_type year_type;
#else
typedef unsigned short year_type;
#endif
typedef date_t::month_type month_type;
typedef date_t::day_type day_type;
typedef date_t::day_of_week_type day_of_week_type;
optional<year_type> year;
optional<month_type> month;
optional<day_type> day;
optional<day_of_week_type> wday;
public:
date_specifier_t(const optional<year_type>& _year = none,
const optional<month_type>& _month = none,
const optional<day_type>& _day = none,
const optional<day_of_week_type>& _wday = none)
: year(_year), month(_month), day(_day), wday(_wday) {
TRACE_CTOR(date_specifier_t,
"year_type, month_type, day_type, day_of_week_type");
}
date_specifier_t(const date_t& date,
const optional<date_traits_t>& traits = none) {
TRACE_CTOR(date_specifier_t, "date_t, date_traits_t");
if (! traits || traits->has_year)
year = date.year();
if (! traits || traits->has_month)
month = date.month();
if (! traits || traits->has_day)
day = date.day();
}
date_specifier_t(const date_specifier_t& other)
: year(other.year), month(other.month),
day(other.day), wday(other.wday) {
TRACE_CTOR(date_specifier_t, "copy");
}
~date_specifier_t() throw() {
TRACE_DTOR(date_specifier_t);
}
date_t begin(const optional_year& current_year = none) const;
date_t end(const optional_year& current_year = none) const;
bool is_within(const date_t& date,
const optional_year& current_year = none) const {
return date >= begin(current_year) && date < end(current_year);
}
optional<date_duration_t> implied_duration() const {
if (day || wday)
return date_duration_t(date_duration_t::DAYS, 1);
else if (month)
return date_duration_t(date_duration_t::MONTHS, 1);
else if (year)
return date_duration_t(date_duration_t::YEARS, 1);
else
return none;
}
string to_string() const {
std::ostringstream out;
if (year)
out << " year " << *year;
if (month)
out << " month " << *month;
if (day)
out << " day " << *day;
if (wday)
out << " wday " << *wday;
return out.str();
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & year;
ar & month;
ar & day;
ar & wday;
}
#endif // HAVE_BOOST_SERIALIZATION
};
class date_range_t
{
friend class date_parser_t;
optional<date_specifier_t> range_begin;
optional<date_specifier_t> range_end;
bool end_inclusive;
public:
date_range_t(const optional<date_specifier_t>& _range_begin = none,
const optional<date_specifier_t>& _range_end = none)
: range_begin(_range_begin), range_end(_range_end),
end_inclusive(false) {
TRACE_CTOR(date_range_t, "date_specifier_t, date_specifier_t");
}
date_range_t(const date_range_t& other)
: range_begin(other.range_begin), range_end(other.range_end),
end_inclusive(other.end_inclusive) {
TRACE_CTOR(date_range_t, "date_range_t");
}
~date_range_t() throw() {
TRACE_DTOR(date_range_t);
}
optional<date_t> begin(const optional_year& current_year = none) const {
if (range_begin)
return range_begin->begin(current_year);
else
return none;
}
optional<date_t> end(const optional_year& current_year = none) const {
if (range_end) {
if (end_inclusive)
return range_end->end(current_year);
else
return range_end->begin(current_year);
} else {
return none;
}
}
bool is_within(const date_t& date,
const optional_year& current_year = none) const {
optional<date_t> b = begin(current_year);
optional<date_t> e = end(current_year);
bool after_begin = b ? date >= *b : true;
bool before_end = e ? date < *e : true;
return after_begin && before_end;
}
string to_string() const {
std::ostringstream out;
if (range_begin)
out << "from" << range_begin->to_string();
if (range_end)
out << " to" << range_end->to_string();
return out.str();
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & range_begin;
ar & range_end;
ar & end_inclusive;
}
#endif // HAVE_BOOST_SERIALIZATION
};
class date_specifier_or_range_t
{
typedef variant<int, date_specifier_t, date_range_t> value_type;
value_type specifier_or_range;
public:
date_specifier_or_range_t() {
TRACE_CTOR(date_specifier_or_range_t, "");
}
date_specifier_or_range_t(const date_specifier_or_range_t& other)
: specifier_or_range(other.specifier_or_range) {
TRACE_CTOR(date_specifier_or_range_t, "copy");
}
date_specifier_or_range_t(const date_specifier_t& specifier)
: specifier_or_range(specifier) {
TRACE_CTOR(date_specifier_or_range_t, "date_specifier_t");
}
date_specifier_or_range_t(const date_range_t& range)
: specifier_or_range(range) {
TRACE_CTOR(date_specifier_or_range_t, "date_range_t");
}
~date_specifier_or_range_t() throw() {
TRACE_DTOR(date_specifier_or_range_t);
}
optional<date_t> begin(const optional_year& current_year = none) const {
if (specifier_or_range.type() == typeid(date_specifier_t))
return boost::get<date_specifier_t>(specifier_or_range).begin(current_year);
else if (specifier_or_range.type() == typeid(date_range_t))
return boost::get<date_range_t>(specifier_or_range).begin(current_year);
else
return none;
}
optional<date_t> end(const optional_year& current_year = none) const {
if (specifier_or_range.type() == typeid(date_specifier_t))
return boost::get<date_specifier_t>(specifier_or_range).end(current_year);
else if (specifier_or_range.type() == typeid(date_range_t))
return boost::get<date_range_t>(specifier_or_range).end(current_year);
else
return none;
}
string to_string() const {
std::ostringstream out;
if (specifier_or_range.type() == typeid(date_specifier_t))
out << "in" << boost::get<date_specifier_t>(specifier_or_range).to_string();
else if (specifier_or_range.type() == typeid(date_range_t))
out << boost::get<date_range_t>(specifier_or_range).to_string();
return out.str();
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & specifier_or_range;
}
#endif // HAVE_BOOST_SERIALIZATION
};
class date_interval_t : public equality_comparable<date_interval_t>
{
public:
struct duration_t
{
enum skip_quantum_t {
DAYS, WEEKS, MONTHS, YEARS
} quantum;
int length;
static date_t add_duration(const date_t& date,
const date_duration_t& duration);
static date_t subtract_duration(const date_t& date,
const date_duration_t& duration);
duration_t() : quantum(DAYS), length(0) {
TRACE_CTOR(date_interval_t::duration_t, "");
}
duration_t(skip_quantum_t _quantum, int _length)
: quantum(_quantum), length(_length) {
TRACE_CTOR(date_interval_t::duration_t, "skip_quantum_t, int");
}
duration_t(const duration_t& dur)
: quantum(dur.quantum), length(dur.length) {
TRACE_CTOR(date_interval_t::duration_t, "copy");
}
~duration_t() throw() {
TRACE_DTOR(date_interval_t::duration_t);
}
optional<date_specifier_or_range_t> range;
date_t add(const date_t& date) const {
switch (quantum) {
case DAYS:
return date + gregorian::days(length);
case WEEKS:
return date + gregorian::weeks(length);
case MONTHS:
return date + gregorian::months(length);
case YEARS:
return date + gregorian::years(length);
default:
assert(false); return date_t();
}
}
optional<date_t> start; // the real start, after adjustment
optional<date_t> finish; // the real end, likewise
bool aligned;
optional<date_t> next;
optional<date_duration_t> duration;
optional<date_t> end_of_duration;
date_t subtract(const date_t& date) const {
switch (quantum) {
case DAYS:
return date - gregorian::days(length);
case WEEKS:
return date - gregorian::weeks(length);
case MONTHS:
return date - gregorian::months(length);
case YEARS:
return date - gregorian::years(length);
default:
assert(false); return date_t();
}
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & quantum;
ar & length;
}
#endif // HAVE_BOOST_SERIALIZATION
};
static date_t add_duration(const date_t& date,
const duration_t& duration);
static date_t subtract_duration(const date_t& date,
const duration_t& duration);
optional<date_t> start;
bool aligned;
optional<duration_t> skip_duration;
std::size_t factor;
optional<date_t> next;
optional<duration_t> duration;
optional<date_t> end_of_duration;
optional<date_t> end;
explicit date_interval_t() : aligned(false), factor(1) {
explicit date_interval_t() : aligned(false) {
TRACE_CTOR(date_interval_t, "");
}
date_interval_t(const string& str) : aligned(false), factor(1) {
date_interval_t(const string& str) : aligned(false) {
TRACE_CTOR(date_interval_t, "const string&");
parse(str);
}
date_interval_t(const date_interval_t& other)
: start(other.start),
: range(other.range),
start(other.start),
finish(other.finish),
aligned(other.aligned),
skip_duration(other.skip_duration),
factor(other.factor),
next(other.next),
duration(other.duration),
end_of_duration(other.end_of_duration),
end(other.end) {
end_of_duration(other.end_of_duration) {
TRACE_CTOR(date_interval_t, "copy");
}
~date_interval_t() throw() {
@ -252,17 +569,19 @@ public:
return is_valid();
}
void parse(std::istream& in);
void parse(const string& str) {
std::istringstream in(str);
parse(in);
optional<date_t> begin(const optional_year& current_year = none) const {
return start ? start : (range ? range->begin(current_year) : none);
}
optional<date_t> end(const optional_year& current_year = none) const {
return finish ? finish : (range ? range->end(current_year) : none);
}
void resolve_end();
void stabilize(const optional<date_t>& date = none);
void parse(const string& str);
bool is_valid() const {
void resolve_end();
void stabilize(const optional<date_t>& date = none);
bool is_valid() const {
return start;
}
@ -280,6 +599,8 @@ public:
date_interval_t& operator++();
void dump(std::ostream& out, optional_year current_year = none);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
@ -288,14 +609,13 @@ private:
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
ar & range;
ar & start;
ar & finish;
ar & aligned;
ar & skip_duration;
ar & factor;
ar & next;
ar & duration;
ar & end_of_duration;
ar & end;
}
#endif // HAVE_BOOST_SERIALIZATION
};
@ -303,8 +623,9 @@ private:
void times_initialize();
void times_shutdown();
std::ostream& operator<<(std::ostream& out,
const date_interval_t::duration_t& duration);
void show_period_tokens(std::ostream& out, const string& arg);
std::ostream& operator<<(std::ostream& out, const date_duration_t& duration);
} // namespace ledger

View file

@ -206,11 +206,12 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
length++;
date_interval_t timespan(buf);
if (! timespan)
optional<date_t> begin = timespan.begin();
if (! begin)
throw_(parse_error,
_("Date specifier does not refer to a starting date"));
kind = VALUE;
value = *timespan.start;
value = *begin;
break;
}

View file

@ -194,6 +194,11 @@ public:
string(const string& str);
string(const std::string& str);
string(size_type len, char x);
template<class _InputIterator>
string(_InputIterator __beg, _InputIterator __end)
: std::string(__beg, __end) {
TRACE_CTOR(string, "InputIterator, InputIterator");
}
string(const char * str);
string(const char * str, const char * end);
string(const string& str, size_type x);

View file

@ -338,10 +338,13 @@ value_t& value_t::operator+=(const value_t& val)
case DATETIME:
switch (val.type()) {
case INTEGER:
as_datetime_lval() += date_duration(val.as_long());
as_datetime_lval() +=
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
return *this;
case AMOUNT:
as_datetime_lval() += date_duration(val.as_amount().to_long());
as_datetime_lval() +=
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
(val.as_amount().to_long()));
return *this;
default:
break;
@ -351,10 +354,10 @@ value_t& value_t::operator+=(const value_t& val)
case DATE:
switch (val.type()) {
case INTEGER:
as_date_lval() += date_duration_t(val.as_long());
as_date_lval() += gregorian::date_duration(val.as_long());
return *this;
case AMOUNT:
as_date_lval() += date_duration_t(val.as_amount().to_long());
as_date_lval() += gregorian::date_duration(val.as_amount().to_long());
return *this;
default:
break;
@ -466,10 +469,13 @@ value_t& value_t::operator-=(const value_t& val)
case DATETIME:
switch (val.type()) {
case INTEGER:
as_datetime_lval() -= date_duration(val.as_long());
as_datetime_lval() -=
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
return *this;
case AMOUNT:
as_datetime_lval() -= date_duration(val.as_amount().to_long());
as_datetime_lval() -=
time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
(val.as_amount().to_long()));
return *this;
default:
break;
@ -479,10 +485,10 @@ value_t& value_t::operator-=(const value_t& val)
case DATE:
switch (val.type()) {
case INTEGER:
as_date_lval() -= date_duration_t(val.as_long());
as_date_lval() -= gregorian::date_duration(val.as_long());
return *this;
case AMOUNT:
as_date_lval() -= date_duration_t(val.as_amount().to_long());
as_date_lval() -= gregorian::date_duration(val.as_amount().to_long());
return *this;
default:
break;
@ -1187,6 +1193,13 @@ void value_t::in_place_negate()
case BALANCE:
as_balance_lval().in_place_negate();
return;
case SEQUENCE: {
value_t temp;
foreach (const value_t& value, as_sequence())
temp.push_back(- value);
*this = temp;
return;
}
default:
break;
}
@ -1216,6 +1229,13 @@ void value_t::in_place_not()
case STRING:
set_boolean(as_string().empty());
return;
case SEQUENCE: {
value_t temp;
foreach (const value_t& value, as_sequence())
temp.push_back(! value);
*this = temp;
return;
}
default:
break;
}

View file

@ -0,0 +1,20 @@
bal -V --unrealized
<<<
2008/10/01 Sample
Assets:Brokerage 10 AAPL
Assets:Checking $-200.00
P 2008/10/20 12:00:00 AAPL $30.00
; 2008/10/20 <Generated Transaction>
; Assets:Brokerage $100
; Equity:Unrealized Gains
>>>1
$100.00 Assets
$300.00 Brokerage
$-200.00 Checking
$-100.00 Equity:Unrealized Gains
--------------------
0
>>>2
=== 0

View file

@ -1,50 +1,95 @@
period --now=2010/11/01 12/01
<<<
>>>1
global details =>
--- Period expression tokens ---
TOK_DATE: month Dec day 1
END_REACHED: <EOF>
start: 09-Dec-01
end: 09-Dec-02
factor: 1
--- Before stabilization ---
range: in month Dec day 1
--- After stabilization ---
range: in month Dec day 1
start: 10-Dec-01
finish: 10-Dec-02
--- Sample dates in range (max. 20) ---
1: 10-Dec-01
>>>2
=== 0
period --now=2010/11/01 10/01
<<<
>>>1
global details =>
--- Period expression tokens ---
TOK_DATE: month Oct day 1
END_REACHED: <EOF>
--- Before stabilization ---
range: in month Oct day 1
--- After stabilization ---
range: in month Oct day 1
start: 10-Oct-01
end: 10-Oct-02
factor: 1
finish: 10-Oct-02
--- Sample dates in range (max. 20) ---
1: 10-Oct-01
>>>2
=== 0
period --now=2010/11/01 2009/10
<<<
>>>1
global details =>
--- Period expression tokens ---
TOK_DATE: year 2009 month Oct
END_REACHED: <EOF>
--- Before stabilization ---
range: in year 2009 month Oct
--- After stabilization ---
range: in year 2009 month Oct
start: 09-Oct-01
end: 09-Nov-01
factor: 1
finish: 09-Nov-01
--- Sample dates in range (max. 20) ---
1: 09-Oct-01
>>>2
=== 0
period --now=2010/11/01 2009/10/01
<<<
>>>1
global details =>
--- Period expression tokens ---
TOK_DATE: year 2009 month Oct day 1
END_REACHED: <EOF>
--- Before stabilization ---
range: in year 2009 month Oct day 1
--- After stabilization ---
range: in year 2009 month Oct day 1
start: 09-Oct-01
end: 09-Oct-02
factor: 1
finish: 09-Oct-02
--- Sample dates in range (max. 20) ---
1: 09-Oct-01
>>>2
=== 0
period --now=2010/11/01 2009
<<<
>>>1
global details =>
--- Period expression tokens ---
TOK_A_YEAR: 2009
END_REACHED: <EOF>
--- Before stabilization ---
range: in year 2009
--- After stabilization ---
range: in year 2009
start: 09-Jan-01
end: 10-Jan-01
factor: 1
finish: 10-Jan-01
--- Sample dates in range (max. 20) ---
1: 09-Jan-01
>>>2
=== 0

View file

@ -1,10 +1,20 @@
period june 2008
<<<
>>>1
global details =>
--- Period expression tokens ---
TOK_A_MONTH: Jun
TOK_A_YEAR: 2008
END_REACHED: <EOF>
--- Before stabilization ---
range: in year 2008 month Jun
--- After stabilization ---
range: in year 2008 month Jun
start: 08-Jun-01
end: 08-Jul-01
factor: 1
finish: 08-Jul-01
--- Sample dates in range (max. 20) ---
1: 08-Jun-01
>>>2
=== 0