From ab416f759f860ce25788bf618ff1538f5d523116 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 5 Mar 2010 22:08:40 -0500 Subject: Updated copyrights to 2003-2010 --- src/report.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/report.cc') diff --git a/src/report.cc b/src/report.cc index b882ca92..f4ebfb72 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are -- cgit v1.2.3 From fe95280492a35fb2e8ee8d43f63754defc3b56e7 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 5 Mar 2010 22:12:59 -0500 Subject: Added some preliminary code for convert CSV to Ledger --- src/convert.cc | 136 ++++++++++++++++++++++++++++++++++++++++ src/convert.h | 55 +++++++++++++++++ src/csv.cc | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/csv.h | 69 +++++++++++++++++++++ src/report.cc | 3 + src/system.hh.in | 3 +- tools/Makefile.am | 4 ++ 7 files changed, 449 insertions(+), 2 deletions(-) create mode 100644 src/convert.cc create mode 100644 src/convert.h create mode 100644 src/csv.cc create mode 100644 src/csv.h (limited to 'src/report.cc') diff --git a/src/convert.cc b/src/convert.cc new file mode 100644 index 00000000..e47fb6c0 --- /dev/null +++ b/src/convert.cc @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "convert.h" +#include "csv.h" +#include "scope.h" +#include "interactive.h" +#include "iterators.h" +#include "report.h" +#include "xact.h" +#include "output.h" + +namespace ledger { + +value_t convert_command(call_scope_t& scope) +{ + interactive_t args(scope, "s"); + report_t& report(find_scope(scope)); + journal_t& journal(*report.session.journal.get()); + + string bucket_name; + if (report.HANDLED(account_)) + bucket_name = report.HANDLER(account_).str(); + else + bucket_name = "Equity:Unknown"; + + account_t * bucket = journal.master->find_account(bucket_name); + + // Make an amounts mapping for the account under consideration + + typedef std::map > post_map_t; + post_map_t post_map; + + xacts_iterator journal_iter(journal); + while (xact_t * xact = journal_iter()) { + post_t * post = NULL; + xact_posts_iterator xact_iter(*xact); + while ((post = xact_iter()) != NULL) { + if (post->account == bucket) + break; + } + if (post) { + post_map_t::iterator i = post_map.find(post->amount); + if (i == post_map.end()) { + std::list post_list; + post_list.push_back(post); + post_map.insert(post_map_t::value_type(post->amount, post_list)); + } else { + (*i).second.push_back(post); + } + } + } + + // Read in the series of transactions from the CSV file + + format_posts formatter(report, + report.report_format(report.HANDLER(print_format_)), + false); + + ifstream data(path(args.get(0))); + csv_reader reader(data); + while (xact_t * xact = reader.read_xact(journal, bucket)) { + bool matched = false; + post_map_t::iterator i = post_map.find(- xact->posts.front()->amount); + if (i != post_map.end()) { + std::list& post_list((*i).second); + foreach (post_t * post, post_list) { + if (xact->code && post->xact->code && + *xact->code == *post->xact->code) { + matched = true; + break; + } + else if (xact->actual_date() == post->actual_date()) { + matched = true; + break; + } + } + } + + if (matched) { + DEBUG("convert.csv", "Ignored xact with code: " << *xact->code); + delete xact; // ignore it + } + else if (! journal.add_xact(xact)) { + delete xact; + throw_(std::runtime_error, + _("Failed to finalize derived transaction (check commodities)")); + } + else { + xact_posts_iterator xact_iter(*xact); + while (post_t * post = xact_iter()) + formatter(*post); + } + } + + // If not, transform the payee according to regexps + + // Set the account to a default vaule, then transform the account according + // to the payee + + // Print out the final form of the transaction + + return true; +} + +} // namespace ledger diff --git a/src/convert.h b/src/convert.h new file mode 100644 index 00000000..6d02f24a --- /dev/null +++ b/src/convert.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup data + */ + +/** + * @file convert.h + * @author John Wiegley + * + * @ingroup data + */ +#ifndef _CONVERT_H +#define _CONVERT_H + +#include "value.h" + +namespace ledger { + +class call_scope_t; + +value_t convert_command(call_scope_t& scope); + +} // namespace ledger + +#endif // _CONVERT_H diff --git a/src/csv.cc b/src/csv.cc new file mode 100644 index 00000000..c0f8cd0e --- /dev/null +++ b/src/csv.cc @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "csv.h" +#include "xact.h" +#include "post.h" +#include "account.h" +#include "journal.h" +#include "pool.h" + +namespace ledger { + +string csv_reader::read_field() +{ + string field; + + char c; + if (in.peek() == '"' || in.peek() == '|') { + in.get(c); + char x; + while (in.good() && ! in.eof()) { + in.get(x); + if (x == '\\') { + in.get(x); + } + else if (x == c) { + if (x == '|') + in.unget(); + else if (in.peek() == ',') + in.get(c); + break; + } + field += x; + } + } + else { + + } + return field; +} + +xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket) +{ + static char linebuf[MAX_LINE + 1]; + + if (! in.good() || in.eof()) + return NULL; + + std::auto_ptr xact; + + while (in.good() && ! in.eof() && in.peek() == '#') + in.getline(linebuf, MAX_LINE); + + xact.reset(new xact_t); + + xact->pos = position_t(); + xact->pos->pathname = "jww (2010-03-05): unknown"; + xact->pos->beg_pos = in.tellg(); + xact->pos->beg_line = 0; + xact->pos->sequence = 0; + + string date = read_field(); trim(date); + string code = read_field(); trim(code); + string payee = read_field(); trim(payee); + + if (date.empty()) + return NULL; + + xact->set_state(item_t::CLEARED); + xact->_date = parse_date(date); + if (! code.empty()) + xact->code = code; + + bool found = false; + foreach (payee_mapping_t& value, journal.payee_mappings) { + DEBUG("csv.mappings", "Looking for payee mapping: " << value.first); + if (value.first.match(payee)) { + xact->payee = value.second; + found = true; + break; + } + } + if (! found) + xact->payee = payee; + + string amount = read_field(); trim(amount); + string total = read_field(); trim(total); + in.getline(linebuf, MAX_LINE); // skip to the next line + + std::auto_ptr post(new post_t); + + post->xact = xact.get(); + +#if 0 + post->pos = position_t(); + post->pos->pathname = pathname; + post->pos->beg_pos = line_beg_pos; + post->pos->beg_line = linenum; + post->pos->sequence = context.sequence++; +#endif + + post->set_state(item_t::CLEARED); + post->account = journal.master->find_account(_("Expenses:Unknown")); + + foreach (account_mapping_t& value, journal.account_mappings) { + if (value.first.match(xact->payee)) { + post->account = value.second; + break; + } + } + + std::istringstream amount_str(amount); + amount_t amt; + amt.parse(amount_str, PARSE_NO_REDUCE); + if (! amt.has_commodity() && + commodity_pool_t::current_pool->default_commodity) + amt.set_commodity + (*commodity_pool_t::current_pool->default_commodity); + post->amount = amt; + + xact->add_post(post.release()); + + post.reset(new post_t); + + post->xact = xact.get(); + +#if 0 + post->pos = position_t(); + post->pos->pathname = pathname; + post->pos->beg_pos = line_beg_pos; + post->pos->beg_line = linenum; + post->pos->sequence = context.sequence++; +#endif + + post->set_state(item_t::CLEARED); + post->account = bucket; + post->amount = - amt; + + if (! total.empty()) { + std::istringstream assigned_amount_str(total); + amount_t assigned_amount; + assigned_amount.parse(assigned_amount_str, PARSE_NO_REDUCE); + post->assigned_amount = assigned_amount; + } + + xact->add_post(post.release()); + + return xact.release(); +} + +} // namespace ledger diff --git a/src/csv.h b/src/csv.h new file mode 100644 index 00000000..7029d482 --- /dev/null +++ b/src/csv.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup data + */ + +/** + * @file csv.h + * @author John Wiegley + * + * @ingroup data + */ +#ifndef _CSV_H +#define _CSV_H + +#include "value.h" + +namespace ledger { + +class xact_t; +class journal_t; +class account_t; + +class csv_reader +{ + static const std::size_t MAX_LINE = 1024; + + std::istream& in; + +public: + csv_reader(std::istream& _in) : in(_in) {} + + string read_field(); + + xact_t * read_xact(journal_t& journal, account_t * bucket); +}; + +} // namespace ledger + +#endif // _CSV_H diff --git a/src/report.cc b/src/report.cc index f4ebfb72..d3e24379 100644 --- a/src/report.cc +++ b/src/report.cc @@ -43,6 +43,7 @@ #include "stats.h" #include "generate.h" #include "draft.h" +#include "convert.h" #include "xml.h" #include "emacs.h" @@ -1206,6 +1207,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, maybe_format(HANDLER(prepend_format_))), *this, "#cleared")); } + else if (is_eq(p, "convert")) + return WRAP_FUNCTOR(convert_command); break; case 'e': diff --git a/src/system.hh.in b/src/system.hh.in index d68ac1a5..5de7150e 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -136,8 +136,7 @@ typedef std::ostream::pos_type ostream_pos_type; #include #endif -#include -#include +#include #include #include #include diff --git a/tools/Makefile.am b/tools/Makefile.am index 53caf565..88d84231 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -72,6 +72,8 @@ libledger_data_la_LDFLAGS = -release $(VERSION) libledger_report_la_SOURCES = \ src/stats.cc \ src/generate.cc \ + src/csv.cc \ + src/convert.cc \ src/draft.cc \ src/emacs.cc \ src/xml.cc \ @@ -133,6 +135,8 @@ pkginclude_HEADERS = \ src/temps.h \ src/chain.h \ src/precmd.h \ + src/csv.h \ + src/convert.h \ src/draft.h \ src/generate.h \ src/stats.h \ -- cgit v1.2.3 From b90ce7890647c3f7cfb1103222df011a4534a1c9 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 5 Mar 2010 22:13:11 -0500 Subject: Fixed a problem with the "quoted" valexpr function --- src/report.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/report.cc') diff --git a/src/report.cc b/src/report.cc index d3e24379..e6aa3ec8 100644 --- a/src/report.cc +++ b/src/report.cc @@ -470,11 +470,11 @@ value_t report_t::fn_justify(call_scope_t& scope) value_t report_t::fn_quoted(call_scope_t& scope) { - interactive_t args(scope, "s"); + interactive_t args(scope, "v"); std::ostringstream out; out << '"'; - foreach (const char ch, args.get(0)) { + foreach (const char ch, args.value_at(0).to_string()) { if (ch == '"') out << "\\\""; else -- cgit v1.2.3 From 75b7294a6db10e7f7b18b6aeef1aa0f568124a1d Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 7 Mar 2010 22:47:07 -0500 Subject: Rewrite the "print" command as a custom function There ended up being too many corner cases for the generalized formatter to handle. --- src/draft.cc | 7 +- src/item.cc | 36 ++++--- src/item.h | 7 +- src/output.cc | 24 +---- src/output.h | 2 - src/post.cc | 4 +- src/post.h | 9 +- src/print.cc | 208 ++++++++++++++++++++++++++++++++++++ src/print.h | 79 ++++++++++++++ src/report.cc | 36 ++++--- src/report.h | 21 +--- src/textual.cc | 1 + src/value.h | 10 +- src/xact.cc | 4 +- test/baseline/opt-print-format.test | 10 -- tools/Makefile.am | 6 +- 16 files changed, 362 insertions(+), 102 deletions(-) create mode 100644 src/print.cc create mode 100644 src/print.h delete mode 100644 test/baseline/opt-print-format.test (limited to 'src/report.cc') diff --git a/src/draft.cc b/src/draft.cc index 83a8012d..74e17dba 100644 --- a/src/draft.cc +++ b/src/draft.cc @@ -38,7 +38,7 @@ #include "journal.h" #include "session.h" #include "report.h" -#include "output.h" +#include "print.h" namespace ledger { @@ -520,10 +520,7 @@ value_t xact_command(call_scope_t& args) // Only consider actual postings for the "xact" command report.HANDLER(limit_).on(string("#xact"), "actual"); - report.xact_report(post_handler_ptr - (new format_posts(report, - report.HANDLER(print_format_).str())), - *new_xact); + report.xact_report(post_handler_ptr(new print_xacts(report)), *new_xact); return true; } diff --git a/src/item.cc b/src/item.cc index 4420d1a6..cb92c003 100644 --- a/src/item.cc +++ b/src/item.cc @@ -65,8 +65,8 @@ bool item_t::has_tag(const mask_t& tag_mask, if (tag_mask.match(data.first)) { if (! value_mask) return true; - else if (data.second) - return value_mask->match(*data.second); + else if (data.second.first) + return value_mask->match(*data.second.first); } } } @@ -81,7 +81,7 @@ optional item_t::get_tag(const string& tag) const string_map::const_iterator i = metadata->find(tag); if (i != metadata->end()) { DEBUG("item.meta", "Found the item!"); - return (*i).second; + return (*i).second.first; } } return none; @@ -94,25 +94,33 @@ optional item_t::get_tag(const mask_t& tag_mask, foreach (const string_map::value_type& data, *metadata) { if (tag_mask.match(data.first) && (! value_mask || - (data.second && value_mask->match(*data.second)))) - return data.second; + (data.second.first && value_mask->match(*data.second.first)))) + return data.second.first; } } return none; } -void item_t::set_tag(const string& tag, - const optional& value) +item_t::string_map::iterator item_t::set_tag(const string& tag, + const optional& value) { + assert(! tag.empty()); + if (! metadata) metadata = string_map(); DEBUG("item.meta", "Setting tag '" << tag << "' to value '" << (value ? *value : string("")) << "'"); + optional data = value; + if (data && data->empty()) + data = none; + std::pair result - = metadata->insert(string_map::value_type(tag, value)); + = metadata->insert(string_map::value_type(tag, tag_data_t(data, false))); assert(result.second); + + return result.first; } void item_t::parse_tags(const char * p, @@ -149,15 +157,19 @@ void item_t::parse_tags(const char * p, q = std::strtok(NULL, " \t")) { const string::size_type len = std::strlen(q); if (! tag.empty()) { - if (! has_tag(tag)) - set_tag(tag, string(p + (q - buf.get()))); + if (! has_tag(tag)) { + string_map::iterator i = set_tag(tag, string(p + (q - buf.get()))); + (*i).second.second = true; + } break; } else if (q[0] == ':' && q[len - 1] == ':') { // a series of tags for (char * r = std::strtok(q + 1, ":"); r; - r = std::strtok(NULL, ":")) - set_tag(r); + r = std::strtok(NULL, ":")) { + string_map::iterator i = set_tag(r); + (*i).second.second = true; + } } else if (q[len - 1] == ':') { // a metadata setting tag = string(q, len - 1); diff --git a/src/item.h b/src/item.h index 4cca9de4..f82e8da6 100644 --- a/src/item.h +++ b/src/item.h @@ -106,7 +106,8 @@ public: enum state_t { UNCLEARED = 0, CLEARED, PENDING }; - typedef std::map > string_map; + typedef std::pair, bool> tag_data_t; + typedef std::map string_map; state_t _state; optional _date; @@ -156,8 +157,8 @@ public: virtual optional get_tag(const mask_t& tag_mask, const optional& value_mask = none) const; - virtual void set_tag(const string& tag, - const optional& value = none); + virtual string_map::iterator set_tag(const string& tag, + const optional& value = none); virtual void parse_tags(const char * p, optional current_year = none); diff --git a/src/output.cc b/src/output.cc index c3afc9bc..30775310 100644 --- a/src/output.cc +++ b/src/output.cc @@ -42,10 +42,8 @@ namespace ledger { format_posts::format_posts(report_t& _report, const string& format, - bool _print_raw, const optional& _prepend_format) - : report(_report), last_xact(NULL), last_post(NULL), - print_raw(_print_raw) + : report(_report), last_xact(NULL), last_post(NULL) { TRACE_CTOR(format_posts, "report&, const string&, bool"); @@ -80,24 +78,8 @@ void format_posts::operator()(post_t& post) { std::ostream& out(report.output_stream); - if (print_raw) { - if (! post.has_xdata() || - ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { - if (last_xact != post.xact) { - if (last_xact) { - bind_scope_t xact_scope(report, *last_xact); - out << between_format(xact_scope); - } - print_item(out, *post.xact); - out << '\n'; - last_xact = post.xact; - } - post.xdata().add_flags(POST_EXT_DISPLAYED); - last_post = &post; - } - } - else if (! post.has_xdata() || - ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { + if (! post.has_xdata() || + ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { bind_scope_t bound_scope(report, post); if (prepend_format) diff --git a/src/output.h b/src/output.h index 7af88707..7618e567 100644 --- a/src/output.h +++ b/src/output.h @@ -63,11 +63,9 @@ protected: format_t prepend_format; xact_t * last_xact; post_t * last_post; - bool print_raw; public: format_posts(report_t& _report, const string& format, - bool _print_raw = false, const optional& _prepend_format = none); virtual ~format_posts() { TRACE_DTOR(format_posts); diff --git a/src/post.cc b/src/post.cc index 5850fc3e..41ae04dd 100644 --- a/src/post.cc +++ b/src/post.cc @@ -576,7 +576,7 @@ void to_xml(std::ostream& out, const post_t& post) if (post.metadata) { push_xml y(out, "metadata"); foreach (const item_t::string_map::value_type& pair, *post.metadata) { - if (pair.second) { + if (pair.second.first) { push_xml z(out, "variable"); { push_xml z(out, "key"); @@ -584,7 +584,7 @@ void to_xml(std::ostream& out, const post_t& post) } { push_xml z(out, "value"); - out << y.guard(*pair.second); + out << y.guard(*pair.second.first); } } else { push_xml z(out, "tag"); diff --git a/src/post.h b/src/post.h index 99fd841e..272cd9d8 100644 --- a/src/post.h +++ b/src/post.h @@ -52,10 +52,11 @@ class account_t; class post_t : public item_t { public: -#define POST_VIRTUAL 0x10 // the account was specified with (parens) -#define POST_MUST_BALANCE 0x20 // posting must balance in the transaction -#define POST_CALCULATED 0x40 // posting's amount was calculated -#define POST_COST_CALCULATED 0x80 // posting's cost was calculated +#define POST_VIRTUAL 0x08 // the account was specified with (parens) +#define POST_MUST_BALANCE 0x10 // posting must balance in the transaction +#define POST_CALCULATED 0x20 // posting's amount was calculated +#define POST_COST_CALCULATED 0x40 // posting's cost was calculated +#define POST_COST_IN_FULL 0x80 // cost specified using @@ xact_t * xact; // only set for posts of regular xacts account_t * account; diff --git a/src/print.cc b/src/print.cc new file mode 100644 index 00000000..e190ad31 --- /dev/null +++ b/src/print.cc @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "print.h" +#include "xact.h" +#include "post.h" +#include "account.h" +#include "session.h" +#include "report.h" + +namespace ledger { + +print_xacts::print_xacts(report_t& _report, + bool _print_raw) + : report(_report), print_raw(_print_raw) +{ + TRACE_CTOR(print_xacts, "report&, bool"); +} + +namespace { + void print_note(std::ostream& out, const string& note) + { + if (note.length() > 15) + out << "\n ;"; + else + out << " ;"; + + bool need_separator = false; + for (const char * p = note.c_str(); *p; p++) { + if (*p == '\n') { + need_separator = true; + } else { + if (need_separator) { + out << "\n ;"; + need_separator = false; + } + out << *p; + } + } + } + + void print_xact(report_t& report, std::ostream& out, xact_t& xact) + { + // jww (2010-03-07): Also add support for --raw + + out << format_date(item_t::use_effective_date ? + xact.date() : xact.actual_date(), + FMT_WRITTEN); + if (! item_t::use_effective_date && xact.effective_date()) + out << '=' << format_date(*xact.effective_date(), FMT_WRITTEN); + out << ' '; + + // jww (2010-03-06): Output posting state, if different + out << (xact.state() == item_t::CLEARED ? "* " : + (xact.state() == item_t::PENDING ? "! " : "")); + + if (xact.code) + out << '(' << *xact.code << ") "; + + out << xact.payee; + + if (xact.note) + print_note(out, *xact.note); + out << '\n'; + + if (xact.metadata) { + foreach (const item_t::string_map::value_type& data, *xact.metadata) { + if (! data.second.second) { + out << " ; "; + if (data.second.first) + out << data.first << ": " << *data.second.first; + else + out << ':' << data.first << ":"; + out << '\n'; + } + } + } + + foreach (post_t * post, xact.posts) { + if (post->has_flags(ITEM_TEMP | ITEM_GENERATED) && + ! report.HANDLED(print_virtual)) + continue; + + out << " "; + // jww (2010-03-06): Output posting state, if different + + std::ostringstream buf; + + if (post->has_flags(POST_VIRTUAL)) { + if (post->has_flags(POST_MUST_BALANCE)) + buf << '['; + else + buf << '('; + } + + buf << post->account->fullname(); + + if (post->has_flags(POST_VIRTUAL)) { + if (post->has_flags(POST_MUST_BALANCE)) + buf << ']'; + else + buf << ')'; + } + + if (! post->has_flags(POST_CALCULATED) || report.HANDLED(print_virtual)) { + unistring name(buf.str()); + + out << name.extract(); + int slip = 36 - static_cast(name.length()); + if (slip > 0) + out << string(slip, ' '); + + std::ostringstream amt_str; + report.scrub(post->amount).print(amt_str, 12, -1, true); + string amt = amt_str.str(); + string trimmed_amt(amt); + trim_left(trimmed_amt); + int amt_slip = (static_cast(amt.length()) - + static_cast(trimmed_amt.length())); + if (slip + amt_slip < 2) + out << string(2 - (slip + amt_slip), ' '); + out << amt; + + if (post->cost && ! post->has_flags(POST_CALCULATED)) { + if (post->has_flags(POST_COST_IN_FULL)) + out << " @@ " << report.scrub(post->cost->abs()); + else + out << " @ " << report.scrub((*post->cost / post->amount).abs()); + } + + if (post->assigned_amount) + out << " = " << report.scrub(*post->assigned_amount); + } else { + out << buf.str(); + } + + if (post->note) + print_note(out, *post->note); + out << '\n'; + } + } +} + +void print_xacts::flush() +{ + std::ostream& out(report.output_stream); + + bool first = true; + foreach (xact_t * xact, xacts) { + if (first) + first = false; + else + out << '\n'; + + if (print_raw) { + print_item(out, *xact); + out << '\n'; + } else { + print_xact(report, out, *xact); + } + } + + out.flush(); +} + +void print_xacts::operator()(post_t& post) +{ + if (! post.has_xdata() || + ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { + if (xacts_present.find(post.xact) == xacts_present.end()) { + xacts_present.insert(xacts_present_map::value_type(post.xact, true)); + xacts.push_back(post.xact); + } + post.xdata().add_flags(POST_EXT_DISPLAYED); + } +} + +} // namespace ledger diff --git a/src/print.h b/src/print.h new file mode 100644 index 00000000..f323b153 --- /dev/null +++ b/src/print.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup data + */ + +/** + * @file convert.h + * @author John Wiegley + * + * @ingroup data + */ +#ifndef _PRINT_H +#define _PRINT_H + +#include "chain.h" +#include "predicate.h" +#include "format.h" + +namespace ledger { + +class xact_t; +class post_t; +class report_t; + +class print_xacts : public item_handler +{ +protected: + typedef std::list xacts_list; + typedef std::map xacts_present_map; + + report_t& report; + xacts_present_map xacts_present; + xacts_list xacts; + bool print_raw; + +public: + print_xacts(report_t& _report, bool _print_raw = false); + virtual ~print_xacts() { + TRACE_DTOR(print_xacts); + } + + virtual void flush(); + virtual void operator()(post_t& post); +}; + + +} // namespace ledger + +#endif // _PRINT_H diff --git a/src/report.cc b/src/report.cc index e6aa3ec8..4a7b105f 100644 --- a/src/report.cc +++ b/src/report.cc @@ -37,6 +37,7 @@ #include "format.h" #include "query.h" #include "output.h" +#include "print.h" #include "iterators.h" #include "filters.h" #include "precmd.h" @@ -410,15 +411,20 @@ value_t report_t::fn_trim(call_scope_t& args) } } -value_t report_t::fn_scrub(call_scope_t& args) +value_t report_t::scrub(value_t val) { - value_t temp(args.value().strip_annotations(what_to_keep())); + value_t temp(val.strip_annotations(what_to_keep())); if (HANDLED(base)) return temp; else return temp.unreduced(); } +value_t report_t::fn_scrub(call_scope_t& args) +{ + return scrub(args.value()); +} + value_t report_t::fn_rounded(call_scope_t& args) { return args.value().rounded(); @@ -880,9 +886,9 @@ option_t * report_t::lookup_option(const char * p) else OPT(price); else OPT(prices_format_); else OPT(pricedb_format_); - else OPT(print_format_); else OPT(payee_width_); else OPT(prepend_format_); + else OPT(print_virtual); break; case 'q': OPT(quantity); @@ -1200,7 +1206,6 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, else if (is_eq(p, "cleared")) { HANDLER(amount_).set_expr(string("#cleared"), "(amount, cleared ? amount : 0)"); - return expr_t::op_t::wrap_functor (reporter (new format_accounts(*this, report_format(HANDLER(cleared_format_)), @@ -1212,11 +1217,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, break; case 'e': - if (is_eq(p, "equity")) - return WRAP_FUNCTOR - (reporter<> - (new format_posts(*this, report_format(HANDLER(print_format_))), - *this, "#equity")); + if (is_eq(p, "equity")) { + HANDLER(print_virtual).on_only(string("#equity")); + return WRAP_FUNCTOR(reporter<>(new print_xacts(*this), *this, "#equity")); + } else if (is_eq(p, "entry")) return WRAP_FUNCTOR(xact_command); else if (is_eq(p, "emacs")) @@ -1229,9 +1233,7 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case 'p': if (*(p + 1) == '\0' || is_eq(p, "print")) return WRAP_FUNCTOR - (reporter<> - (new format_posts(*this, report_format(HANDLER(print_format_)), - HANDLED(raw)), *this, "#print")); + (reporter<>(new print_xacts(*this, HANDLED(raw)), *this, "#print")); else if (is_eq(p, "prices")) return expr_t::op_t::wrap_functor (reporter @@ -1251,7 +1253,7 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR (reporter<> (new format_posts(*this, report_format(HANDLER(register_format_)), - false, maybe_format(HANDLER(prepend_format_))), + maybe_format(HANDLER(prepend_format_))), *this, "#register")); else if (is_eq(p, "reload")) return MAKE_FUNCTOR(report_t::reload_command); @@ -1286,11 +1288,13 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(format_command); break; case 'g': - if (is_eq(p, "generate")) + if (is_eq(p, "generate")) { + HANDLER(print_virtual).on_only(string("#generate")); return expr_t::op_t::wrap_functor (reporter - (new format_posts(*this, report_format(HANDLER(print_format_)), - false), *this, "#generate")); + (new print_xacts(*this), *this, "#generate")); + } + break; case 'p': if (is_eq(p, "parse")) return WRAP_FUNCTOR(parse_command); diff --git a/src/report.h b/src/report.h index 893ee3ae..682c2414 100644 --- a/src/report.h +++ b/src/report.h @@ -144,6 +144,7 @@ public: value_t fn_is_seq(call_scope_t& scope); value_t fn_strip(call_scope_t& scope); value_t fn_trim(call_scope_t& scope); + value_t scrub(value_t val); value_t fn_scrub(call_scope_t& scope); value_t fn_quantity(call_scope_t& scope); value_t fn_rounded(call_scope_t& scope); @@ -280,7 +281,7 @@ public: HANDLER(price).report(out); HANDLER(prices_format_).report(out); HANDLER(pricedb_format_).report(out); - HANDLER(print_format_).report(out); + HANDLER(print_virtual).report(out); HANDLER(quantity).report(out); HANDLER(quarterly).report(out); HANDLER(raw).report(out); @@ -748,23 +749,7 @@ public: "P %(datetime) %(account) %(scrub(display_amount))\n"); }); - OPTION__(report_t, print_format_, CTOR(report_t, print_format_) { - on(none, - "%(xact.date)" - "%(!effective & xact.effective_date ?" - " \"=\" + xact.effective_date : \"\")" - "%(xact.cleared ? \" *\" : (xact.pending ? \" !\" : \"\"))" - "%(code ? \" (\" + code + \")\" :" - " \"\") %(payee)%(xact.comment)\n" - " %(xact.uncleared ?" - " (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")" - "%(calculated ? account : justify(account, 34, -1, false))" - "%(calculated ? \"\" : \" \" + justify(scrub(amount), 12, -1, true))" - "%(has_cost & !cost_calculated ?" - " \" @ \" + justify(scrub(abs(cost / amount)), 0) : \"\")" - "%(comment)\n%/" - " %$7%$8%$9%$A%$B\n%/\n"); - }); + OPTION(report_t, print_virtual); OPTION_(report_t, quantity, DO() { // -O parent->HANDLER(revalued).off(); diff --git a/src/textual.cc b/src/textual.cc index 764d15e8..dae9c3c6 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -1031,6 +1031,7 @@ post_t * instance_t::parse_post(char * line, if (*++next == '@') { per_unit = false; + post->add_flags(POST_COST_IN_FULL); DEBUG("textual.parse", "line " << linenum << ": " << "And it's for a total price"); } diff --git a/src/value.h b/src/value.h index 2e59366e..1c1d8b6c 100644 --- a/src/value.h +++ b/src/value.h @@ -919,11 +919,11 @@ public: /** * Printing methods. */ - void print(std::ostream& out, - const int first_width = -1, - const int latter_width = -1, - const bool right_justify = false, - const bool colorize = false) const; + void print(std::ostream& out, + const int first_width = -1, + const int latter_width = -1, + const bool right_justify = false, + const bool colorize = false) const; void dump(std::ostream& out, const bool relaxed = true) const; /** diff --git a/src/xact.cc b/src/xact.cc index f78ea301..1a022387 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -755,7 +755,7 @@ void to_xml(std::ostream& out, const xact_t& xact) if (xact.metadata) { push_xml y(out, "metadata"); foreach (const item_t::string_map::value_type& pair, *xact.metadata) { - if (pair.second) { + if (pair.second.first) { push_xml z(out, "variable"); { push_xml w(out, "key"); @@ -763,7 +763,7 @@ void to_xml(std::ostream& out, const xact_t& xact) } { push_xml w(out, "value"); - out << y.guard(*pair.second); + out << y.guard(*pair.second.first); } } else { push_xml z(out, "tag"); diff --git a/test/baseline/opt-print-format.test b/test/baseline/opt-print-format.test deleted file mode 100644 index 103ceb1e..00000000 --- a/test/baseline/opt-print-format.test +++ /dev/null @@ -1,10 +0,0 @@ -print --print-format='%(amount)\n' -<<< -2007/02/02 RD VMMXX - Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00 - Income:Dividends:Vanguard:VMMXX $-0.35 ->>>1 -0.350 VMMXX {$1.00} [2007/02/02] -$-0.35 ->>>2 -=== 0 diff --git a/tools/Makefile.am b/tools/Makefile.am index 88d84231..7ae81ccf 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -75,8 +75,9 @@ libledger_report_la_SOURCES = \ src/csv.cc \ src/convert.cc \ src/draft.cc \ - src/emacs.cc \ - src/xml.cc \ + src/emacs.cc \ + src/xml.cc \ + src/print.cc \ src/output.cc \ src/precmd.cc \ src/chain.cc \ @@ -140,6 +141,7 @@ pkginclude_HEADERS = \ src/draft.h \ src/generate.h \ src/stats.h \ + src/print.h \ src/output.h \ src/xml.h \ src/emacs.h \ -- cgit v1.2.3 From 36b616da5e0e2b31138e05d347b0ff3599467c00 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 17 Mar 2010 02:20:08 -0400 Subject: Added new --meta and --meta-width options The usages are: --meta= prepend value of TAG before every line --meta-width= force the meta column to be NUM wide --meta=: shortcut that also applies --meta-width --- src/report.cc | 42 ++++++++++++++++++++++++++++++++++++++---- src/report.h | 19 ++++++++++++++----- 2 files changed, 52 insertions(+), 9 deletions(-) (limited to 'src/report.cc') diff --git a/src/report.cc b/src/report.cc index 4a7b105f..2189812b 100644 --- a/src/report.cc +++ b/src/report.cc @@ -93,6 +93,33 @@ void report_t::normalize_options(const string& verb) start_of_week = *weekday; } + long meta_width = -1; + + if (! HANDLED(prepend_format_) && HANDLED(meta_)) { + if (! HANDLED(meta_width_)) { + string::size_type i = HANDLER(meta_).str().find(':'); + if (i != string::npos) { + HANDLED(meta_width_).on_with + (string("?normalize"), + lexical_cast(string(HANDLER(meta_).str(), i + 1))); + HANDLED(meta_).on(string("?normalize"), + string(HANDLER(meta_).str(), 0, i)); + } + } + if (HANDLED(meta_width_)) { + HANDLER(prepend_format_).on + (string("?normalize"), + string("%(justify(truncated(tag(\"") + + HANDLER(meta_).str() + "\"), " + + HANDLED(meta_width_).value.to_string() + " - 1), " + + HANDLED(meta_width_).value.to_string() + "))"); + meta_width = HANDLED(meta_width_).value.to_long(); + } else { + HANDLER(prepend_format_).on(string("?normalize"), string("%(tag(\"") + + HANDLER(meta_).str() + "\"))"); + } + } + if (verb == "print" || verb == "xact" || verb == "dump") { HANDLER(related).on_only(string("?normalize")); HANDLER(related_all).on_only(string("?normalize")); @@ -165,6 +192,9 @@ void report_t::normalize_options(const string& verb) else cols = 80L; + if (meta_width > 0) + cols -= meta_width; + if (cols > 0) { DEBUG("auto.columns", "cols = " << cols); @@ -187,11 +217,11 @@ void report_t::normalize_options(const string& verb) HANDLER(total_width_).value.to_long() : amount_width); - DEBUG("auto.columns", "date_width = " << date_width); - DEBUG("auto.columns", "payee_width = " << payee_width); + DEBUG("auto.columns", "date_width = " << date_width); + DEBUG("auto.columns", "payee_width = " << payee_width); DEBUG("auto.columns", "account_width = " << account_width); - DEBUG("auto.columns", "amount_width = " << amount_width); - DEBUG("auto.columns", "total_width = " << total_width); + DEBUG("auto.columns", "amount_width = " << amount_width); + DEBUG("auto.columns", "total_width = " << total_width); if (! HANDLER(date_width_).specified && ! HANDLER(payee_width_).specified && @@ -207,6 +237,8 @@ void report_t::normalize_options(const string& verb) } } + if (! HANDLED(meta_width_)) + HANDLER(meta_width_).on_with(string("?normalize"), 0L); if (! HANDLER(date_width_).specified) HANDLER(date_width_).on_with(string("?normalize"), date_width); if (! HANDLER(payee_width_).specified) @@ -862,6 +894,8 @@ option_t * report_t::lookup_option(const char * p) case 'm': OPT(market); else OPT(monthly); + else OPT(meta_); + else OPT(meta_width_); break; case 'n': OPT_CH(collapse); diff --git a/src/report.h b/src/report.h index 682c2414..50071940 100644 --- a/src/report.h +++ b/src/report.h @@ -264,6 +264,7 @@ public: HANDLER(lots).report(out); HANDLER(lots_actual).report(out); HANDLER(market).report(out); + HANDLER(meta_).report(out); HANDLER(monthly).report(out); HANDLER(no_total).report(out); HANDLER(now_).report(out); @@ -312,6 +313,7 @@ public: HANDLER(weekly).report(out); HANDLER(wide).report(out); HANDLER(yearly).report(out); + HANDLER(meta_width_).report(out); HANDLER(date_width_).report(out); HANDLER(payee_width_).report(out); HANDLER(account_width_).report(out); @@ -619,6 +621,8 @@ public: .set_expr(string("--market"), "market(total_expr, date, exchange)"); }); + OPTION(report_t, meta_); + OPTION_(report_t, monthly, DO() { // -M parent->HANDLER(period_).on(string("--monthly"), "monthly"); }); @@ -776,12 +780,13 @@ public: " %(ansify_if(justify(truncated(account, account_width, abbrev_len), " " account_width), blue if color))" " %(justify(scrub(display_amount), amount_width, " - " 3 + date_width + payee_width + account_width + amount_width, " - " true, color))" + " 3 + meta_width + date_width + payee_width + account_width" + " + amount_width, true, color))" " %(justify(scrub(display_total), total_width, " - " 4 + date_width + payee_width + account_width + amount_width " - " + total_width, true, color))\n%/" - "%(justify(\" \", 2 + date_width + payee_width))%$3 %$4 %$5\n"); + " 4 + meta_width + date_width + payee_width + account_width" + " + amount_width + total_width, true, color))\n%/" + "%(justify(\" \", 2 + date_width + payee_width))" + "%$3 %$4 %$5\n"); }); OPTION(report_t, related); // -r @@ -891,6 +896,10 @@ public: parent->HANDLER(period_).on(string("--yearly"), "yearly"); }); + OPTION__(report_t, meta_width_, + bool specified; + CTOR(report_t, meta_width_) { specified = false; } + DO_(args) { value = args[1].to_long(); specified = true; }); OPTION__(report_t, date_width_, bool specified; CTOR(report_t, date_width_) { specified = false; } -- cgit v1.2.3