diff options
-rw-r--r-- | account.cc | 37 | ||||
-rw-r--r-- | account.h | 6 | ||||
-rw-r--r-- | main.cc | 139 | ||||
-rw-r--r-- | output.cc | 78 | ||||
-rw-r--r-- | output.h | 41 | ||||
-rw-r--r-- | report.cc | 20 | ||||
-rw-r--r-- | report.h | 5 | ||||
-rw-r--r-- | value.cc | 3 | ||||
-rw-r--r-- | xact.cc | 2 | ||||
-rw-r--r-- | xml.cc | 88 | ||||
-rw-r--r-- | xml.h | 10 |
11 files changed, 230 insertions, 199 deletions
@@ -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; } @@ -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 = "", @@ -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()); - - report.xacts_report(xact_handler_ptr(new Formatter(*ostream, - *format))); - return true; - } - }; - - template <class Formatter = format_accounts> - class accounts_report - { - string format_name; - - public: - accounts_report(const string& _format_name) - : format_name(_format_name) {} + 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()); + } - value_t operator()(call_scope_t& args) - { - ptr_t<std::ostream> ostream(args, 0); - var_t<string> format(args, format_name); + (report.*report_method)(handler_ptr(new Formatter(report, *format))); - 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; @@ -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; } @@ -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() { @@ -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(); @@ -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); @@ -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(); @@ -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 { @@ -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 @@ -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(); |