First round of work to get the balance report working again.

This commit is contained in:
John Wiegley 2008-08-04 16:24:41 -04:00
parent 966b231f23
commit 9c9a34388a
11 changed files with 230 additions and 199 deletions

View file

@ -112,10 +112,33 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
return out;
}
namespace {
value_t get_total(account_t& account) {
assert(account.xdata_);
return account.xdata_->total;
}
template <value_t (*Func)(account_t&)>
value_t get_wrapper(call_scope_t& scope) {
return (*Func)(find_scope<account_t>(scope));
}
}
expr_t::ptr_op_t account_t::lookup(const string& name)
{
switch (name[0]) {
case 'a':
case 'f':
if (name.find("fmt_") == 0) {
switch (name[4]) {
case 'T':
return WRAP_FUNCTOR(get_wrapper<&get_total>);
}
}
break;
case 't':
if (name == "total")
return WRAP_FUNCTOR(get_wrapper<&get_total>);
break;
}
return expr_t::ptr_op_t();
@ -150,7 +173,11 @@ void account_t::calculate_sums()
foreach (accounts_map::value_type& pair, accounts) {
(*pair.second).calculate_sums();
xd.total += (*pair.second).xdata().total;
if (xd.total.is_null())
xd.total = (*pair.second).xdata().total;
else
xd.total += (*pair.second).xdata().total;
xd.total_count += ((*pair.second).xdata().total_count +
(*pair.second).xdata().count);
}
@ -159,8 +186,12 @@ void account_t::calculate_sums()
#if 0
compute_amount(result, details_t(account));
#endif
if (! result.is_realzero())
if (xd.total.is_null())
xd.total = result;
else
xd.total += result;
xd.total_count += xd.count;
}

View file

@ -52,9 +52,9 @@ class account_t : public scope_t
unsigned short depth;
accounts_map accounts;
mutable void * data;
mutable ident_t ident;
mutable string _fullname;
mutable void * data;
mutable ident_t ident;
mutable string _fullname;
account_t(account_t * _parent = NULL,
const string& _name = "",

139
main.cc
View file

@ -150,52 +150,37 @@ namespace ledger {
return final_value_expr;
}
template <class Formatter = format_xacts>
class xacts_report
template <class Formatter = format_xacts,
class handler_ptr = xact_handler_ptr,
void (report_t::*report_method)(handler_ptr) =
&report_t::xacts_report>
class reporter
{
string format_name;
public:
xacts_report(const string& _format_name)
reporter(const string& _format_name)
: format_name(_format_name) {}
value_t operator()(call_scope_t& args)
{
ptr_t<std::ostream> ostream(args, 0);
var_t<string> format(args, format_name);
report_t& report(find_scope<report_t>(args));
var_t<string> format(args, format_name);
if (! report.format_string.empty())
*format = report.format_string;
if (! report.predicate.empty())
report.predicate = string("(") + report.predicate + ")&";
report.predicate +=
args_to_predicate(++args.value().as_sequence().begin(),
args.value().as_sequence().end());
if (args.value().is_sequence() &&
args.value().size() > 1) {
if (! report.predicate.empty())
report.predicate = string("(") + report.predicate + ")&";
report.predicate +=
args_to_predicate(++args.value().as_sequence().begin(),
args.value().as_sequence().end());
}
report.xacts_report(xact_handler_ptr(new Formatter(*ostream,
*format)));
return true;
}
};
(report.*report_method)(handler_ptr(new Formatter(report, *format)));
template <class Formatter = format_accounts>
class accounts_report
{
string format_name;
public:
accounts_report(const string& _format_name)
: format_name(_format_name) {}
value_t operator()(call_scope_t& args)
{
ptr_t<std::ostream> ostream(args, 0);
var_t<string> format(args, format_name);
find_scope<report_t>(args).accounts_report
(acct_handler_ptr(new Formatter(*ostream, *format)));
return true;
}
};
@ -261,10 +246,10 @@ namespace ledger {
#ifdef HAVE_UNIX_PIPES
int status, pfd[2]; // Pipe file descriptors
#endif
std::ostream * out = &std::cout;
report.output_stream = &std::cout;
if (report.output_file) {
out = new ofstream(*report.output_file);
report.output_stream = new ofstream(*report.output_file);
}
#ifdef HAVE_UNIX_PIPES
else if (report.pager) {
@ -298,7 +283,7 @@ namespace ledger {
}
else { // parent
close(pfd[0]);
out = new boost::fdostream(pfd[1]);
report.output_stream = new boost::fdostream(pfd[1]);
}
}
#endif
@ -306,80 +291,82 @@ namespace ledger {
// Read the command word and see if it's any of the debugging commands
// that Ledger supports.
std::ostream& out(*report.output_stream);
string verb = *arg++;
if (verb == "parse") {
expr_t expr(*arg);
*out << "Value expression as input: " << *arg << std::endl;
out << "Value expression as input: " << *arg << std::endl;
*out << "Value expression as parsed: ";
expr.print(*out, report);
*out << std::endl;
out << "Value expression as parsed: ";
expr.print(out, report);
out << std::endl;
*out << std::endl;
*out << "--- Parsed tree ---" << std::endl;
expr.dump(*out);
out << std::endl;
out << "--- Parsed tree ---" << std::endl;
expr.dump(out);
*out << std::endl;
*out << "--- Calculated value ---" << std::endl;
expr.calc(report).print(*out);
*out << std::endl;
out << std::endl;
out << "--- Calculated value ---" << std::endl;
expr.calc(report).print(out);
out << std::endl;
return 0;
}
else if (verb == "compile") {
expr_t expr(*arg);
*out << "Value expression as input: " << *arg << std::endl;
*out << "Value expression as parsed: ";
expr.print(*out, report);
*out << std::endl;
out << "Value expression as input: " << *arg << std::endl;
out << "Value expression as parsed: ";
expr.print(out, report);
out << std::endl;
*out << std::endl;
*out << "--- Parsed tree ---" << std::endl;
expr.dump(*out);
out << std::endl;
out << "--- Parsed tree ---" << std::endl;
expr.dump(out);
expr.compile(report);
*out << std::endl;
*out << "--- Compiled tree ---" << std::endl;
expr.dump(*out);
out << std::endl;
out << "--- Compiled tree ---" << std::endl;
expr.dump(out);
*out << std::endl;
*out << "--- Calculated value ---" << std::endl;
expr.calc(report).print(*out);
*out << std::endl;
out << std::endl;
out << "--- Calculated value ---" << std::endl;
expr.calc(report).print(out);
out << std::endl;
return 0;
}
else if (verb == "eval") {
expr_t expr(*arg);
*out << expr.calc(report).strip_annotations() << std::endl;
out << expr.calc(report).strip_annotations() << std::endl;
return 0;
}
else if (verb == "format") {
format_t fmt(*arg);
fmt.dump(*out);
fmt.dump(out);
return 0;
}
else if (verb == "period") {
interval_t interval(*arg);
if (! is_valid(interval.begin)) {
*out << "Time period has no beginning." << std::endl;
out << "Time period has no beginning." << std::endl;
} else {
*out << "begin: " << format_date(interval.begin) << std::endl;
*out << " end: " << format_date(interval.end) << std::endl;
*out << std::endl;
out << "begin: " << format_date(interval.begin) << std::endl;
out << " end: " << format_date(interval.end) << std::endl;
out << std::endl;
date_t date = interval.first();
for (int i = 0; i < 20; i++) {
*out << std::right;
out->width(2);
out << std::right;
out.width(2);
*out << i << ": " << format_date(date) << std::endl;
out << i << ": " << format_date(date) << std::endl;
date = interval.increment(date);
if (is_valid(interval.end) && date >= interval.end)
@ -420,13 +407,15 @@ namespace ledger {
function_t command;
if (verb == "register" || verb == "reg" || verb == "r")
command = xacts_report<>("register_format");
command = reporter<>("register_format");
else if (verb == "print" || verb == "p")
command = xacts_report<>("print_format");
command = reporter<>("print_format");
else if (verb == "balance" || verb == "bal" || verb == "b")
command = accounts_report<>("balance_format");
command = reporter<format_accounts, acct_handler_ptr,
&report_t::accounts_report>("balance_format");
else if (verb == "equity")
command = accounts_report<format_equity>("print_format");
command = reporter<format_equity, acct_handler_ptr,
&report_t::accounts_report>("print_format");
#if 0
else if (verb == "entry")
command = entry_command();
@ -462,8 +451,6 @@ namespace ledger {
call_scope_t command_args(report);
command_args.push_back(value_t(out));
for (strings_list::iterator i = arg; i != args.end(); i++)
command_args.push_back(string_value(*i));
@ -490,7 +477,7 @@ namespace ledger {
#ifdef HAVE_UNIX_PIPES
if (! report.output_file && report.pager) {
checked_delete(out);
checked_delete(report.output_stream);
close(pfd[1]);
// Wait for child to finish
@ -500,7 +487,7 @@ namespace ledger {
}
#endif
else if (DO_VERIFY() && report.output_file) {
checked_delete(out);
checked_delete(report.output_stream);
}
return 0;

View file

@ -33,13 +33,13 @@
namespace ledger {
format_xacts::format_xacts(std::ostream& _output_stream,
const string& format)
: output_stream(_output_stream), last_entry(NULL), last_xact(NULL)
format_xacts::format_xacts(report_t& _report, const string& format)
: report(_report), last_entry(NULL), last_xact(NULL)
{
TRACE_CTOR(format_xacts, "std::ostream&, const string&");
TRACE_CTOR(format_xacts, "report&, const string&");
const char * f = format.c_str();
if (const char * p = std::strstr(f, "%/")) {
first_line_format.parse(string(f, 0, p - f));
next_lines_format.parse(string(p + 2));
@ -51,17 +51,19 @@ format_xacts::format_xacts(std::ostream& _output_stream,
void format_xacts::operator()(xact_t& xact)
{
std::ostream& out(*report.output_stream);
if (! xact.has_xdata() ||
! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
if (last_entry != xact.entry) {
first_line_format.format(output_stream, xact);
first_line_format.format(out, xact);
last_entry = xact.entry;
}
else if (last_xact && last_xact->date() != xact.date()) {
first_line_format.format(output_stream, xact);
first_line_format.format(out, xact);
}
else {
next_lines_format.format(output_stream, xact);
next_lines_format.format(out, xact);
}
xact.xdata().add_flags(XACT_EXT_DISPLAYED);
@ -71,16 +73,17 @@ void format_xacts::operator()(xact_t& xact)
void format_entries::format_last_entry()
{
bool first = true;
bool first = true;
std::ostream& out(*report.output_stream);
foreach (xact_t * xact, last_entry->xacts) {
if (xact->has_xdata() &&
xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
if (first) {
first_line_format.format(output_stream, *xact);
first_line_format.format(out, *xact);
first = false;
} else {
next_lines_format.format(output_stream, *xact);
next_lines_format.format(out, *xact);
}
xact->xdata().add_flags(XACT_EXT_DISPLAYED);
}
@ -131,13 +134,37 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base,
#endif
}
void format_accounts::flush()
{
std::ostream& out(*report.output_stream);
#if 0
// jww (2008-08-02): I need access to the output formatter before this is
// going to work.
if (print_final_total) {
assert(out);
assert(account_has_xdata(*session.master));
account_xdata_t& xdata(account_xdata(*session.master));
if (! show_collapsed && xdata.total) {
out << "--------------------\n";
xdata.value = xdata.total;
handler->format.format(out, *session.master);
}
}
#endif
out.flush();
}
void format_accounts::operator()(account_t& account)
{
if (display_account(account)) {
if (! account.parent) {
account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
} else {
format.format(output_stream, account);
format.format(*report.output_stream, account);
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
}
}
@ -159,13 +186,11 @@ bool format_accounts::disp_subaccounts_p(account_t& account,
if (! disp_pred(*pair.second))
continue;
#if 0
compute_total(result, *pair.second);
#endif
call_scope_t args(*pair.second);
result = report.get_total_expr(args);
if (! computed) {
#if 0
compute_total(acct_total, account);
#endif
call_scope_t args(account);
acct_total = report.get_total_expr(args);
computed = true;
}
@ -201,10 +226,10 @@ bool format_accounts::display_account(account_t& account)
return ! account_to_show && disp_pred(account);
}
format_equity::format_equity(std::ostream& _output_stream,
format_equity::format_equity(report_t& _report,
const string& _format,
const string& display_predicate)
: format_accounts(_output_stream, "", display_predicate)
: format_accounts(_report, "", display_predicate)
{
const char * f = _format.c_str();
@ -219,7 +244,7 @@ format_equity::format_equity(std::ostream& _output_stream,
entry_t header_entry;
header_entry.payee = "Opening Balances";
header_entry._date = current_date;
first_line_format.format(output_stream, header_entry);
first_line_format.format(*report.output_stream, header_entry);
}
void format_equity::flush()
@ -227,6 +252,7 @@ void format_equity::flush()
account_t summary(NULL, "Equity:Opening Balances");
account_t::xdata_t& xdata(summary.xdata());
std::ostream& out(*report.output_stream);
xdata.value = total.negate();
@ -242,16 +268,18 @@ 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(output_stream, summary);
next_lines_format.format(out, summary);
}
} else {
next_lines_format.format(output_stream, summary);
next_lines_format.format(out, summary);
}
output_stream.flush();
out.flush();
}
void format_equity::operator()(account_t& account)
{
std::ostream& out(*report.output_stream);
if (display_account(account)) {
if (account.has_xdata()) {
value_t val = account.xdata().value;
@ -267,11 +295,11 @@ 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(output_stream, account);
next_lines_format.format(out, account);
}
account.xdata().value = val;
} else {
next_lines_format.format(output_stream, account);
next_lines_format.format(out, account);
}
total += val;
}

View file

@ -32,7 +32,7 @@
#ifndef _OUTPUT_H
#define _OUTPUT_H
#include "session.h"
#include "report.h"
#include "handler.h"
#include "format.h"
@ -41,21 +41,20 @@ namespace ledger {
class format_xacts : public item_handler<xact_t>
{
protected:
std::ostream& output_stream;
format_t first_line_format;
format_t next_lines_format;
entry_t * last_entry;
xact_t * last_xact;
report_t& report;
format_t first_line_format;
format_t next_lines_format;
entry_t * last_entry;
xact_t * last_xact;
public:
format_xacts(std::ostream& _output_stream,
const string& format);
format_xacts(report_t& _report, const string& format);
virtual ~format_xacts() {
TRACE_DTOR(format_xacts);
}
virtual void flush() {
output_stream.flush();
report.output_stream->flush();
}
virtual void operator()(xact_t& xact);
};
@ -63,9 +62,9 @@ public:
class format_entries : public format_xacts
{
public:
format_entries(std::ostream& output_stream, const string& format)
: format_xacts(output_stream, format) {
TRACE_CTOR(format_entries, "std::ostream&, const string&");
format_entries(report_t& _report, const string& format)
: format_xacts(_report, format) {
TRACE_CTOR(format_entries, "report_t&, const string&");
}
virtual ~format_entries() {
TRACE_DTOR(format_entries);
@ -91,7 +90,7 @@ private:
class format_accounts : public item_handler<account_t>
{
protected:
std::ostream& output_stream;
report_t& report;
item_predicate<account_t> disp_pred;
@ -101,20 +100,18 @@ protected:
public:
format_t format;
format_accounts(std::ostream& _output_stream,
format_accounts(report_t& _report,
const string& _format,
const string& display_predicate = "")
: output_stream(_output_stream), disp_pred(display_predicate),
format(_format) {
TRACE_CTOR(format_accounts, "std::ostream&, const string&, const string&");
const string& display_predicate = "" /*,
const bool print_final_total = true */)
: report(_report), disp_pred(display_predicate), format(_format) {
TRACE_CTOR(format_accounts, "report&, const string&, const string&");
}
virtual ~format_accounts() {
TRACE_DTOR(format_accounts);
}
virtual void flush() {
output_stream.flush();
}
virtual void flush();
virtual void operator()(account_t& account);
};
@ -127,7 +124,7 @@ class format_equity : public format_accounts
mutable value_t total;
public:
format_equity(std::ostream& _output_stream,
format_equity(report_t& _report,
const string& _format,
const string& display_predicate = "");
virtual ~format_equity() {

View file

@ -331,9 +331,7 @@ void report_t::sum_all_accounts()
session.master->calculate_sums();
}
void report_t::accounts_report(acct_handler_ptr handler,
const bool print_final_total,
optional<std::ostream&> ostream)
void report_t::accounts_report(acct_handler_ptr handler)
{
sum_all_accounts();
@ -346,22 +344,6 @@ void report_t::accounts_report(acct_handler_ptr handler,
}
handler->flush();
#if 0
// jww (2008-08-02): I need access to the output formatter before this is
// going to work.
if (print_final_total) {
assert(ostream);
assert(account_has_xdata(*session.master));
account_xdata_t& xdata(account_xdata(*session.master));
if (! show_collapsed && xdata.total) {
*ostream << "--------------------\n";
xdata.value = xdata.total;
handler->format.format(*ostream, *session.master);
}
}
#endif
if (DO_VERIFY()) {
session.clean_xacts();
session.clean_accounts();

View file

@ -87,6 +87,7 @@ class report_t : public noncopyable, public scope_t
public:
optional<path> output_file;
std::ostream * output_stream;
string format_string;
string date_output_format;
@ -186,9 +187,7 @@ public:
void sum_all_accounts();
void accounts_report(acct_handler_ptr handler,
const bool print_final_total = true,
optional<std::ostream&> ostream = none);
void accounts_report(acct_handler_ptr handler);
void commodities_report(const string& format);

View file

@ -835,6 +835,9 @@ value_t& value_t::operator/=(const value_t& val)
bool value_t::operator==(const value_t& val) const
{
switch (type()) {
case VOID:
return val.type() == VOID;
case BOOLEAN:
if (val.is_boolean())
return as_boolean() == val.as_boolean();

View file

@ -266,6 +266,8 @@ void xact_t::add_to_value(value_t& value)
value += xdata_->value;
}
else if (cost || (! value.is_null() && ! value.is_realzero())) {
if (value.is_null())
value = amount_t();
value.add(amount, cost);
}
else {

88
xml.cc
View file

@ -387,28 +387,30 @@ void output_xml_string(std::ostream& out, const string& str)
void format_xml_entries::format_last_entry()
{
std::ostream& out(*report.output_stream);
#if 0
// jww (2008-05-08): Need to format these dates
output_stream << " <entry>\n"
<< " <en:date>" << last_entry->_date.to_string("%Y/%m/%d")
<< "</en:date>\n";
out << " <entry>\n"
<< " <en:date>" << last_entry->_date.to_string("%Y/%m/%d")
<< "</en:date>\n";
if (is_valid(last_entry->_date_eff))
output_stream << " <en:date_eff>"
<< last_entry->_date_eff.to_string("%Y/%m/%d")
<< "</en:date_eff>\n";
out << " <en:date_eff>"
<< last_entry->_date_eff.to_string("%Y/%m/%d")
<< "</en:date_eff>\n";
#endif
if (last_entry->code) {
output_stream << " <en:code>";
output_xml_string(output_stream, *last_entry->code);
output_stream << "</en:code>\n";
out << " <en:code>";
output_xml_string(out, *last_entry->code);
out << "</en:code>\n";
}
if (! last_entry->payee.empty()) {
output_stream << " <en:payee>";
output_xml_string(output_stream, last_entry->payee);
output_stream << "</en:payee>\n";
out << " <en:payee>";
output_xml_string(out, last_entry->payee);
out << "</en:payee>\n";
}
bool first = true;
@ -416,34 +418,34 @@ void format_xml_entries::format_last_entry()
if (xact->has_xdata() &&
xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
if (first) {
output_stream << " <en:xacts>\n";
out << " <en:xacts>\n";
first = false;
}
output_stream << " <xact>\n";
out << " <xact>\n";
#if 0
// jww (2008-05-08): Need to format these
if (xact->_date)
output_stream << " <tr:date>"
<< xact->_date.to_string("%Y/%m/%d")
<< "</tr:date>\n";
out << " <tr:date>"
<< xact->_date.to_string("%Y/%m/%d")
<< "</tr:date>\n";
if (is_valid(xact->_date_eff))
output_stream << " <tr:date_eff>"
<< xact->_date_eff.to_string("%Y/%m/%d")
<< "</tr:date_eff>\n";
out << " <tr:date_eff>"
<< xact->_date_eff.to_string("%Y/%m/%d")
<< "</tr:date_eff>\n";
#endif
if (xact->state == xact_t::CLEARED)
output_stream << " <tr:cleared/>\n";
out << " <tr:cleared/>\n";
else if (xact->state == xact_t::PENDING)
output_stream << " <tr:pending/>\n";
out << " <tr:pending/>\n";
if (xact->has_flags(XACT_VIRTUAL))
output_stream << " <tr:virtual/>\n";
out << " <tr:virtual/>\n";
if (xact->has_flags(XACT_AUTO))
output_stream << " <tr:generated/>\n";
out << " <tr:generated/>\n";
if (xact->account) {
string name = xact->account->fullname();
@ -452,46 +454,46 @@ void format_xml_entries::format_last_entry()
else if (name == "<Unknown>")
name = "[UNKNOWN]";
output_stream << " <tr:account>";
output_xml_string(output_stream, name);
output_stream << "</tr:account>\n";
out << " <tr:account>";
output_xml_string(out, name);
out << "</tr:account>\n";
}
output_stream << " <tr:amount>\n";
out << " <tr:amount>\n";
if (xact->xdata().has_flags(XACT_EXT_COMPOUND))
xml_write_value(output_stream, xact->xdata().value, 10);
xml_write_value(out, xact->xdata().value, 10);
else
xml_write_value(output_stream, value_t(xact->amount), 10);
output_stream << " </tr:amount>\n";
xml_write_value(out, value_t(xact->amount), 10);
out << " </tr:amount>\n";
if (xact->cost) {
output_stream << " <tr:cost>\n";
xml_write_value(output_stream, value_t(*xact->cost), 10);
output_stream << " </tr:cost>\n";
out << " <tr:cost>\n";
xml_write_value(out, value_t(*xact->cost), 10);
out << " </tr:cost>\n";
}
if (xact->note) {
output_stream << " <tr:note>";
output_xml_string(output_stream, *xact->note);
output_stream << "</tr:note>\n";
out << " <tr:note>";
output_xml_string(out, *xact->note);
out << "</tr:note>\n";
}
if (show_totals) {
output_stream << " <total>\n";
xml_write_value(output_stream, xact->xdata().total, 10);
output_stream << " </total>\n";
out << " <total>\n";
xml_write_value(out, xact->xdata().total, 10);
out << " </total>\n";
}
output_stream << " </xact>\n";
out << " </xact>\n";
xact->xdata().add_flags(XACT_EXT_DISPLAYED);
}
}
if (! first)
output_stream << " </en:xacts>\n";
out << " </en:xacts>\n";
output_stream << " </entry>\n";
out << " </entry>\n";
}
} // namespace ledger

10
xml.h
View file

@ -61,12 +61,12 @@ class format_xml_entries : public format_entries
format_xml_entries();
public:
format_xml_entries(std::ostream& output_stream,
format_xml_entries(report_t& _report,
const bool _show_totals = false)
: format_entries(output_stream, ""), show_totals(_show_totals) {
: format_entries(_report, ""), show_totals(_show_totals) {
TRACE_CTOR(format_xml_entries, "std::ostream&, const bool");
output_stream << "<?xml version=\"1.0\"?>\n"
<< "<ledger version=\"2.5\">\n";
*report.output_stream << "<?xml version=\"1.0\"?>\n"
<< "<ledger version=\"2.5\">\n";
}
virtual ~format_xml_entries() throw() {
TRACE_DTOR(format_xml_entries);
@ -74,7 +74,7 @@ public:
virtual void flush() {
format_entries::flush();
output_stream << "</ledger>" << std::endl;
*report.output_stream << "</ledger>" << std::endl;
}
virtual void format_last_entry();