diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-07 04:26:30 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-07 04:26:30 -0400 |
commit | eb98e0da8b095634ae779b5b1f3c234d24cccde2 (patch) | |
tree | 0ae0bc269b90f47f0e74432c6363dd84baf41d50 /src | |
parent | 17c7037da9ee345c02ad8db89d976fb6c122a7d7 (diff) | |
download | fork-ledger-eb98e0da8b095634ae779b5b1f3c234d24cccde2.tar.gz fork-ledger-eb98e0da8b095634ae779b5b1f3c234d24cccde2.tar.bz2 fork-ledger-eb98e0da8b095634ae779b5b1f3c234d24cccde2.zip |
More revision to the way options are handled; reworked CSV command.
Diffstat (limited to 'src')
-rw-r--r-- | src/csv.cc | 135 | ||||
-rw-r--r-- | src/csv.h | 81 | ||||
-rw-r--r-- | src/global.cc | 12 | ||||
-rw-r--r-- | src/handler.h | 300 | ||||
-rw-r--r-- | src/ledger.h | 1 | ||||
-rw-r--r-- | src/option.h | 185 | ||||
-rw-r--r-- | src/report.cc | 498 | ||||
-rw-r--r-- | src/report.h | 10 | ||||
-rw-r--r-- | src/session.cc | 2 | ||||
-rw-r--r-- | src/session.h | 3 | ||||
-rw-r--r-- | src/textual.cc | 4 | ||||
-rw-r--r-- | src/utils.h | 3 |
12 files changed, 507 insertions, 727 deletions
diff --git a/src/csv.cc b/src/csv.cc deleted file mode 100644 index baaf2775..00000000 --- a/src/csv.cc +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2003-2009, 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 "csv.h" - -namespace ledger { - -namespace { - inline void write_escaped_string(std::ostream& out, const string& xact) - { - out << "\""; - foreach (char ch, xact) - if (ch == '"') { - out << "\\"; - out << "\""; - } else { - out << ch; - } - out << "\""; - } -} - -void format_csv_xacts::operator()(xact_t& xact) -{ - if (! xact.has_xdata() || - ! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) { - { - format_t fmt("%D"); - std::ostringstream str; -#if 0 - fmt.format(str, details_t(xact)); -#endif - write_escaped_string(out, str.str()); - } - out << ','; - - { - format_t fmt("%P"); - std::ostringstream str; -#if 0 - fmt.format(str, details_t(xact)); -#endif - write_escaped_string(out, str.str()); - } - out << ','; - - { - format_t fmt("%A"); - std::ostringstream str; -#if 0 - fmt.format(str, details_t(xact)); -#endif - write_escaped_string(out, str.str()); - } - out << ','; - - { - format_t fmt("%t"); - std::ostringstream str; -#if 0 - fmt.format(str, details_t(xact)); -#endif - write_escaped_string(out, str.str()); - } - out << ','; - - { - format_t fmt("%T"); - std::ostringstream str; -#if 0 - fmt.format(str, details_t(xact)); -#endif - write_escaped_string(out, str.str()); - } - out << ','; - - switch (xact.state()) { - case item_t::CLEARED: - write_escaped_string(out, "*"); - break; - case item_t::PENDING: - write_escaped_string(out, "!"); - break; - default: - break; - } - out << ','; - - if (xact.entry->code) - write_escaped_string(out, *xact.entry->code); - out << ','; - - { - format_t fmt("%N"); - std::ostringstream str; -#if 0 - fmt.format(str, details_t(xact)); -#endif - write_escaped_string(out, str.str()); - } - out << '\n'; - - xact.xdata().add_flags(XACT_EXT_DISPLAYED); - } -} - -} // namespace ledger diff --git a/src/csv.h b/src/csv.h deleted file mode 100644 index cc565400..00000000 --- a/src/csv.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2003-2009, 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 parse - */ - -/** - * @file csv.h - * @author John Wiegley - * - * @ingroup parse - * - * @brief Brief - * - * Long. - */ -#ifndef _CSV_H -#define _CSV_H - -#include "output.h" - -namespace ledger { - -/** - * @brief Brief - * - * Long. - */ -class format_csv_xacts : public item_handler<xact_t> -{ - format_csv_xacts(); - -protected: - std::ostream& out; - -public: - format_csv_xacts(std::ostream& _out) : out(_out) { - TRACE_CTOR(format_csv_xacts, "std::ostream&"); - } - ~format_csv_xacts() { - TRACE_DTOR(format_csv_xacts); - } - - virtual void flush() { - out.flush(); - } - virtual void operator()(xact_t& xact); -}; - -} // namespace ledger - -#endif // _REPORT_H diff --git a/src/global.cc b/src/global.cc index 14fb3c29..497dc397 100644 --- a/src/global.cc +++ b/src/global.cc @@ -102,8 +102,8 @@ void global_scope_t::read_journal_files() INFO_START(journal, "Read journal file"); string master_account; - if (report().HANDLED(account_)) - master_account = report().HANDLER(account_).str(); + if (session().HANDLED(account_)) + master_account = session().HANDLER(account_).str(); std::size_t count = session().read_data(*session().create_journal(), master_account); @@ -269,8 +269,10 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name) if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN; switch (*p) { case 'p': - M_COMMAND(global_scope_t, push); - else M_COMMAND(global_scope_t, pop); + if (is_eq(p, "push")) + MAKE_FUNCTOR(global_scope_t::push_command); + else if (is_eq(p, "pop")) + MAKE_FUNCTOR(global_scope_t::pop_command); break; } } @@ -279,7 +281,7 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name) // If you're wondering how symbols from report() will be found, it's // because of the bind_scope_t object in execute_command() below. - return expr_t::ptr_op_t(); + return NULL; } void global_scope_t::read_environment_settings(char * envp[]) diff --git a/src/handler.h b/src/handler.h deleted file mode 100644 index 7d420ee4..00000000 --- a/src/handler.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 2003-2009, 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 report - */ - -/** - * @file handler.h - * @author John Wiegley - * - * @ingroup report - * - * @brief Defines a scheme for more easily handling commands and options via - * value expressions. - * - * The OPTION and OPTION_ macros are used to define an option handler within a - * scope_t derived class. The _ variant can specify a body in order to - * provide HELP(out) and DO() or DO_(args) methods. - * - * The other macros are used for looking up and referring to handlers, - * commands and functions. Typically they occur in the object's lookup - * method, for example: - * - * expr_t::ptr_op_t some_class_t::lookup(const string& name) - * { - * const char * p = name.c_str(); - * switch (*p) { - * case 'a': - * METHOD(some_class_t, my_method); // looks up a method by name - * break; - * - * case 'c': - * if (WANT_CMD()) { p += CMD_PREFIX_LEN; - * switch (*p) { - * case 'a': - * COMMAND(args); // looks up global func named "args_command" - * break; - * } - * } - * break; - * - * case 'o': - * if (WANT_OPT()) { p += OPT_PREFIX_LEN; - * switch (*p) { - * case 'f': - * OPT(foo); // look for a handler named "foo" - * else OPT(foo2_); // same, but foo2 wants an argument - * else OPT_(foo3); // match on "foo3" or 'f' - * else OPT_CH(foo4_); // match only on 'f' - * break; - * } - * } - * break; - * } - * - * return expr_t::ptr_op_t(); - * } - */ -#ifndef _HANDLER_H -#define _HANDLER_H - -#include "scope.h" - -namespace ledger { - -template <typename T> -class handler_t -{ - const char * name; - std::size_t name_len; - const char ch; - bool handled; - -public: - T * parent; - value_t value; - bool wants_arg; - - handler_t(const char * _name, const char _ch = '\0') - : name(_name), name_len(std::strlen(name)), ch(_ch), - handled(false), parent(NULL), value(), - wants_arg(name[name_len - 1] == '_') { - TRACE_CTOR(handler_t, "const char *, const char"); - } - handler_t(const handler_t& other) - : name(other.name), - name_len(other.name_len), - ch(other.ch), - handled(other.handled), - parent(NULL), - value(other.value) - { - TRACE_CTOR(handler_t, "copy"); - } - - virtual ~handler_t() { - TRACE_DTOR(handler_t); - } - - string desc() const { - std::ostringstream out; - if (ch) - out << "--" << name << " (-" << ch << ")"; - else - out << "--" << name; - return out.str(); - } - - virtual void help(std::ostream& out) { - out << "No help for " << desc() << "\n"; - } - - operator bool() const { - return handled; - } - - string& str() { - assert(handled); - return value.as_string_lval(); - } - - void on() { - handled = true; - } - void on(const char * str) { - handled = true; - value = string_value(str); - } - void on(const string& str) { - handled = true; - value = string_value(str); - } - void on(const value_t& val) { - handled = true; - value = val; - } - - void off() { - handled = false; - value = value_t(); - } - - virtual void handler(call_scope_t& args) { - if (wants_arg) - value = args[0]; - } - - virtual value_t operator()(call_scope_t& args) { - handled = true; - handler(args); - return true; - } -}; - -#define BEGIN(type, name) \ - struct name ## _handler_t : public handler_t<type> - -#define CTOR(type, name) \ - name ## _handler_t() : handler_t<type>(#name) -#define DECL1(type, name, vartype, var, value) \ - vartype var ; \ - name ## _handler_t() : handler_t<type>(#name), var(value) - -#define HELP(var) virtual void help(std::ostream& var) -#define DO() virtual void handler(call_scope_t&) -#define DO_(var) virtual void handler(call_scope_t& var) - -#define END(name) name ## _handler - -#define COPY_OPT(name, other) name ## _handler(other.name ## _handler) - -#define CALL_FUNCTOR(x) \ - expr_t::op_t::wrap_functor(bind(&x ## _t::operator(), &x, _1)) - -inline bool optcmp(const char * p, const char * n) { - // Test whether p matches n, substituting - in p for _ in n. - for (; *p && *n; p++, n++) { - if (! (*p == '-' && *n == '_' ) && *p != *n) - return false; - } - return *p == *n; -} - -#define OPT(name) \ - if (optcmp(p, #name)) \ - return ((name ## _handler).parent = this, \ - CALL_FUNCTOR(name ## _handler)) - -#define OPT_(name) \ - if (! *(p + 1) || \ - ((name ## _handler).wants_arg && \ - *(p + 1) == '_' && ! *(p + 2)) || \ - optcmp(p, #name)) \ - return ((name ## _handler).parent = this, \ - CALL_FUNCTOR(name ## _handler)) - -#define OPT_CH(name) \ - if (! *(p + 1) || \ - ((name ## _handler).wants_arg && \ - *(p + 1) == '_' && ! *(p + 2))) \ - return ((name ## _handler).parent = this, \ - CALL_FUNCTOR(name ## _handler)) - -#define FUNCTION(name) \ - if (std::strcmp(p, #name) == 0) \ - return WRAP_FUNCTOR(fn_ ## name) - -#define METHOD(type, name) \ - if (std::strcmp(p, #name) == 0) \ - return MAKE_FUNCTOR(type::fn_ ## name) - -#define M_COMMAND(type, name) \ - if (std::strcmp(p, #name) == 0) \ - return MAKE_FUNCTOR(type::name ## _command) - -#define COMMAND(name) \ - if (std::strcmp(p, #name) == 0) \ - return WRAP_FUNCTOR(name ## _command) - -#define HANDLER(name) name ## _handler -#define HANDLED(name) HANDLER(name) - -#define OPTION(type, name) \ - BEGIN(type, name) \ - { \ - CTOR(type, name) {} \ - } \ - END(name) - -#define OPTION_(type, name, body) \ - BEGIN(type, name) \ - { \ - CTOR(type, name) {} \ - body \ - } \ - END(name) - -#define OPTION__(type, name, body) \ - BEGIN(type, name) \ - { \ - body \ - } \ - END(name) - -#define OPT_PREFIX "opt_" -#define OPT_PREFIX_LEN 4 - -#define WANT_OPT() \ - (std::strncmp(p, OPT_PREFIX, OPT_PREFIX_LEN) == 0) - -#define PRECMD_PREFIX "precmd_" -#define PRECMD_PREFIX_LEN 7 - -#define WANT_PRECMD() \ - (std::strncmp(p, PRECMD_PREFIX, PRECMD_PREFIX_LEN) == 0) - -#define CMD_PREFIX "cmd_" -#define CMD_PREFIX_LEN 4 - -#define WANT_CMD() \ - (std::strncmp(p, CMD_PREFIX, CMD_PREFIX_LEN) == 0) - -#define DIR_PREFIX "dir_" -#define DIR_PREFIX_LEN 4 - -#define WANT_DIR() \ - (std::strncmp(p, DIR_PREFIX, DIR_PREFIX_LEN) == 0) - -} // namespace ledger - -#endif // _HANDLER_H diff --git a/src/ledger.h b/src/ledger.h index 70e15c5a..bb8ce488 100644 --- a/src/ledger.h +++ b/src/ledger.h @@ -86,7 +86,6 @@ #include <derive.h> #include <quotes.h> #include <emacs.h> -#include <csv.h> #if defined(HAVE_BOOST_PYTHON) #include <pyinterp.h> diff --git a/src/option.h b/src/option.h index 14b85c50..2bb9e342 100644 --- a/src/option.h +++ b/src/option.h @@ -50,6 +50,191 @@ namespace ledger { +template <typename T> +class option_t +{ + const char * name; + std::size_t name_len; + const char ch; + bool handled; + +public: + T * parent; + value_t value; + bool wants_arg; + + option_t(const char * _name, const char _ch = '\0') + : name(_name), name_len(std::strlen(name)), ch(_ch), + handled(false), parent(NULL), value(), + wants_arg(name[name_len - 1] == '_') { + TRACE_CTOR(option_t, "const char *, const char"); + } + option_t(const option_t& other) + : name(other.name), + name_len(other.name_len), + ch(other.ch), + handled(other.handled), + parent(NULL), + value(other.value) + { + TRACE_CTOR(option_t, "copy"); + } + + virtual ~option_t() { + TRACE_DTOR(option_t); + } + + string desc() const { + std::ostringstream out; + if (ch) + out << "--" << name << " (-" << ch << ")"; + else + out << "--" << name; + return out.str(); + } + + virtual void help(std::ostream& out) { + out << "No help for " << desc() << "\n"; + } + + operator bool() const { + return handled; + } + + string& str() { + assert(handled); + return value.as_string_lval(); + } + + void on() { + handled = true; + } + void on(const char * str) { + handled = true; + value = string_value(str); + } + void on(const string& str) { + handled = true; + value = string_value(str); + } + void on(const value_t& val) { + handled = true; + value = val; + } + + void off() { + handled = false; + value = value_t(); + } + + virtual void handler(call_scope_t& args) { + if (wants_arg) + value = args[0]; + } + + virtual value_t operator()(call_scope_t& args) { + handled = true; + handler(args); + return true; + } +}; + +#define BEGIN(type, name) \ + struct name ## _option_t : public option_t<type> + +#define CTOR(type, name) \ + name ## _option_t() : option_t<type>(#name) +#define DECL1(type, name, vartype, var, value) \ + vartype var ; \ + name ## _option_t() : option_t<type>(#name), var(value) + +#define HELP(var) virtual void help(std::ostream& var) +#define DO() virtual void handler(call_scope_t&) +#define DO_(var) virtual void handler(call_scope_t& var) + +#define END(name) name ## _handler + +#define COPY_OPT(name, other) name ## _handler(other.name ## _handler) + +#define MAKE_OPT_FUNCTOR(x) \ + expr_t::op_t::wrap_functor(bind(&x ## _option_t::operator(), \ + &x ## _handler, _1)) + +inline bool is_eq(const char * p, const char * n) { + // Test whether p matches n, substituting - in p for _ in n. + for (; *p && *n; p++, n++) { + if (! (*p == '-' && *n == '_' ) && *p != *n) + return false; + } + return *p == *n; +} + +#define OPT(name) \ + if (is_eq(p, #name)) \ + return ((name ## _handler).parent = this, MAKE_OPT_FUNCTOR(name)) + +#define OPT_(name) \ + if (! *(p + 1) || \ + ((name ## _handler).wants_arg && \ + *(p + 1) == '_' && ! *(p + 2)) || \ + is_eq(p, #name)) \ + return ((name ## _handler).parent = this, MAKE_OPT_FUNCTOR(name)) + +#define OPT_CH(name) \ + if (! *(p + 1) || \ + ((name ## _handler).wants_arg && \ + *(p + 1) == '_' && ! *(p + 2))) \ + return ((name ## _handler).parent = this, MAKE_OPT_FUNCTOR(name)) + +#define HANDLER(name) name ## _handler +#define HANDLED(name) HANDLER(name) + +#define OPTION(type, name) \ + BEGIN(type, name) \ + { \ + CTOR(type, name) {} \ + } \ + END(name) + +#define OPTION_(type, name, body) \ + BEGIN(type, name) \ + { \ + CTOR(type, name) {} \ + body \ + } \ + END(name) + +#define OPTION__(type, name, body) \ + BEGIN(type, name) \ + { \ + body \ + } \ + END(name) + +#define OPT_PREFIX "opt_" +#define OPT_PREFIX_LEN 4 + +#define WANT_OPT() \ + (std::strncmp(p, OPT_PREFIX, OPT_PREFIX_LEN) == 0) + +#define PRECMD_PREFIX "precmd_" +#define PRECMD_PREFIX_LEN 7 + +#define WANT_PRECMD() \ + (std::strncmp(p, PRECMD_PREFIX, PRECMD_PREFIX_LEN) == 0) + +#define CMD_PREFIX "cmd_" +#define CMD_PREFIX_LEN 4 + +#define WANT_CMD() \ + (std::strncmp(p, CMD_PREFIX, CMD_PREFIX_LEN) == 0) + +#define DIR_PREFIX "dir_" +#define DIR_PREFIX_LEN 4 + +#define WANT_DIR() \ + (std::strncmp(p, DIR_PREFIX, DIR_PREFIX_LEN) == 0) + void process_option(const string& name, scope_t& scope, const char * arg, const string& varname); diff --git a/src/report.cc b/src/report.cc index 6d8a0b88..5caad47c 100644 --- a/src/report.cc +++ b/src/report.cc @@ -69,12 +69,25 @@ report_t::report_t(session_t& _session) : session(_session) "%20(strip(display_total)) %(depth_spacer)%-(partial_account)\n"); HANDLER(equity_format_).on("\n%D %Y%C%P\n%/ %-34W %12t\n"); + HANDLER(plot_amount_format_).on("%D %(S(t))\n"); HANDLER(plot_total_format_).on("%D %(S(T))\n"); + HANDLER(write_hdr_format_).on("%d %Y%C%P\n"); HANDLER(write_xact_format_).on(" %-34W %12o%n\n"); + HANDLER(prices_format_).on("%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n"); HANDLER(pricesdb_format_).on("P %[%Y/%m/%d %H:%M:%S] %A %t\n"); + + HANDLER(csv_format_).on( + "%(escape(display_date))," + "%(escape(payee))," + "%(escape(account))," + "%(escape(display_amount))," + "%(escape(display_total))," + "%(escape(cleared ? \"*\" : (uncleared ? \"\" : \"!\")))," + "%(escape(code)," + "%(squash(escape(note))\n"); } void report_t::xacts_report(xact_handler_ptr handler) @@ -133,6 +146,28 @@ value_t report_t::fn_total_expr(call_scope_t& scope) return HANDLER(total_).expr.calc(scope); } +value_t report_t::fn_display_date(call_scope_t& args) +{ + item_t& item(find_scope<item_t>(args)); + + // jww (2009-02-06): Should we be calling reported_date here? + + date_t when; + if (HANDLED(effective)) { + if (optional<date_t> date = item.effective_date()) + when = *date; + else + when = item.date(); + } else { + when = item.date(); + } + + if (HANDLED(date_format_)) + return string_value(format_date(when, HANDLER(date_format_).str())); + else + return string_value(format_date(when)); +} + value_t report_t::fn_display_amount(call_scope_t& scope) { return HANDLER(display_amount_).expr.calc(scope); @@ -143,87 +178,85 @@ value_t report_t::fn_display_total(call_scope_t& scope) return HANDLER(display_total_).expr.calc(scope); } -namespace { - value_t fn_market_value(call_scope_t& args) - { - var_t<datetime_t> date(args, 1); - var_t<string> in_terms_of(args, 2); - - commodity_t * commodity = NULL; - if (in_terms_of) - commodity = amount_t::current_pool->find_or_create(*in_terms_of); +value_t report_t::fn_market_value(call_scope_t& args) +{ + var_t<datetime_t> date(args, 1); + var_t<string> in_terms_of(args, 2); - DEBUG("report.market", "getting market value of: " << args[0]); + commodity_t * commodity = NULL; + if (in_terms_of) + commodity = amount_t::current_pool->find_or_create(*in_terms_of); - value_t result = - args[0].value(date ? optional<datetime_t>(*date) : optional<datetime_t>(), - commodity ? optional<commodity_t&>(*commodity) : - optional<commodity_t&>()); + DEBUG("report.market", "getting market value of: " << args[0]); - DEBUG("report.market", "result is: " << result); - return result; - } + value_t result = + args[0].value(date ? optional<datetime_t>(*date) : optional<datetime_t>(), + commodity ? optional<commodity_t&>(*commodity) : + optional<commodity_t&>()); - value_t fn_print_balance(call_scope_t& args) - { - report_t& report(find_scope<report_t>(args)); + DEBUG("report.market", "result is: " << result); + return result; +} - var_t<long> first_width(args, 1); - var_t<long> latter_width(args, 2); +value_t report_t::fn_print_balance(call_scope_t& args) +{ + var_t<long> first_width(args, 1); + var_t<long> latter_width(args, 2); #if 0 - var_t<bool> bold_negative(args, 3); + var_t<bool> bold_negative(args, 3); #endif - std::ostringstream out; - args[0].strip_annotations(report.what_to_keep()) - .print(out, *first_width, *latter_width, - report.HANDLED(date_format_) ? - report.HANDLER(date_format_).str() : optional<string>()); - - return string_value(out.str()); - } + std::ostringstream out; + args[0].strip_annotations(what_to_keep()) + .print(out, *first_width, *latter_width, + HANDLED(date_format_) ? + HANDLER(date_format_).str() : optional<string>()); - value_t fn_strip(call_scope_t& args) - { - report_t& report(find_scope<report_t>(args)); - return args[0].strip_annotations(report.what_to_keep()); - } + return string_value(out.str()); +} - value_t fn_truncate(call_scope_t& args) - { - report_t& report(find_scope<report_t>(args)); +value_t report_t::fn_strip(call_scope_t& args) +{ + return args[0].strip_annotations(what_to_keep()); +} - var_t<long> width(args, 1); - var_t<long> account_abbrev(args, 2); +value_t report_t::fn_truncate(call_scope_t& args) +{ + var_t<long> width(args, 1); + var_t<long> account_abbrev(args, 2); - return string_value(format_t::truncate(args[0].as_string(), *width, - account_abbrev ? *account_abbrev : -1)); - } + return string_value(format_t::truncate(args[0].as_string(), *width, + account_abbrev ? *account_abbrev : -1)); +} - value_t fn_display_date(call_scope_t& args) - { - report_t& report(find_scope<report_t>(args)); - item_t& item(find_scope<item_t>(args)); - - // jww (2009-02-06): Should we be calling reported_date here? - - date_t when; - if (report.HANDLED(effective)) { - if (optional<date_t> date = item.effective_date()) - when = *date; - else - when = item.date(); - } else { - when = item.date(); - } +value_t report_t::fn_escape(call_scope_t& args) +{ + std::ostringstream out; - if (report.HANDLED(date_format_)) - return string_value(format_date(when, - report.HANDLER(date_format_).str())); + out << '"'; + foreach (const char ch, args[0].to_string()) { + if (ch == '"') + out << "\\\""; else - return string_value(format_date(when)); + out << ch; } + out << '"'; + + return string_value(out.str()); +} + +value_t report_t::fn_join(call_scope_t& args) +{ + std::ostringstream out; + + foreach (const char ch, args[0].to_string()) + if (ch != '\n') + out << ch; + return string_value(out.str()); +} + +namespace { template <class Type = xact_t, class handler_ptr = xact_handler_ptr, void (report_t::*report_method)(handler_ptr) = @@ -232,14 +265,14 @@ namespace { { shared_ptr<item_handler<Type> > handler; + report_t& report; + public: - reporter(item_handler<Type> * _handler) - : handler(_handler) {} + reporter(item_handler<Type> * _handler, report_t& _report) + : handler(_handler), report(_report) {} value_t operator()(call_scope_t& args) { - report_t& report(find_scope<report_t>(args)); - if (args.value().size() > 0) report.append_predicate (args_to_predicate_expr(args.value().as_sequence().begin(), @@ -255,233 +288,297 @@ namespace { }; } -#if 0 -// Commands yet to implement: -// -// entry -// prices -// pricesdb -// csv -// emacs | lisp -#endif - expr_t::ptr_op_t report_t::lookup(const string& name) { const char * p = name.c_str(); switch (*p) { case 'a': - METHOD(report_t, amount_expr); + if (is_eq(p, "amount_expr")) + MAKE_FUNCTOR(report_t::fn_amount_expr); break; case 'c': if (WANT_CMD()) { p += CMD_PREFIX_LEN; switch (*p) { case 'b': - if (*(p + 1) == '\0' || - std::strcmp(p, "bal") == 0 || - std::strcmp(p, "balance") == 0) + if (*(p + 1) == '\0' || is_eq(p, "bal") || is_eq(p, "balance")) return expr_t::op_t::wrap_functor (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> - (new format_accounts(*this, HANDLER(balance_format_).str()))); + (new format_accounts(*this, HANDLER(balance_format_).str()), + *this)); + break; + + case 'c': + if (is_eq(p, "csv")) + return WRAP_FUNCTOR + (reporter<>(new format_xacts(*this, HANDLER(csv_format_).str()), + *this)); break; case 'e': - if (std::strcmp(p, "equity") == 0) + if (is_eq(p, "equity")) return expr_t::op_t::wrap_functor (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> - (new format_equity(*this, HANDLER(print_format_).str()))); + (new format_equity(*this, HANDLER(print_format_).str()), *this)); + else if (is_eq(p, "entry")) + return NULL; // jww (2009-02-07): NYI + else if (is_eq(p, "emacs")) + return NULL; // jww (2009-02-07): NYI break; case 'p': - if (*(p + 1) == '\0' || std::strcmp(p, "print") == 0) + if (*(p + 1) == '\0' || is_eq(p, "print")) return WRAP_FUNCTOR - (reporter<>(new format_xacts(*this, HANDLER(print_format_).str()))); + (reporter<>(new format_xacts(*this, HANDLER(print_format_).str()), + *this)); + else if (is_eq(p, "prices")) + return NULL; // jww (2009-02-07): NYI + else if (is_eq(p, "pricesdb")) + return NULL; // jww (2009-02-07): NYI break; case 'r': - if (*(p + 1) == '\0' || - std::strcmp(p, "reg") == 0 || - std::strcmp(p, "register") == 0) + if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) return WRAP_FUNCTOR - (reporter<>(new format_xacts(*this, HANDLER(register_format_).str()))); + (reporter<>(new format_xacts(*this, HANDLER(register_format_).str()), + *this)); break; } } break; case 'd': - METHOD(report_t, display_total); - else METHOD(report_t, display_amount); - else FUNCTION(display_date); + if (is_eq(p, "display_total")) + return MAKE_FUNCTOR(report_t::fn_display_total); + else if (is_eq(p, "display_total")) + return MAKE_FUNCTOR(report_t::fn_display_amount); + else if (is_eq(p, "display_total")) + return MAKE_FUNCTOR(report_t::fn_display_date); + break; + + case 'e': + if (is_eq(p, "escape")) + return MAKE_FUNCTOR(report_t::fn_escape); + break; + + case 'j': + if (is_eq(p, "join")) + return MAKE_FUNCTOR(report_t::fn_join); break; case 'm': - FUNCTION(market_value); + if (is_eq(p, "market")) + return MAKE_FUNCTOR(report_t::fn_market_value); break; case 'o': if (WANT_OPT()) { p += OPT_PREFIX_LEN; switch (*p) { + case '%': + OPT_CH(percentage); + break; + case 'A': + OPT_CH(average); + break; + case 'B': + OPT_CH(basis); + break; + case 'C': + OPT_CH(cleared); + break; + case 'D': + OPT_CH(deviation); + break; + case 'E': + OPT_CH(empty); + break; + case 'F': + OPT_CH(format_); + break; + case 'G': + OPT_CH(gain); + break; + case 'I': + OPT_CH(price); + break; + case 'J': + OPT_CH(total_data); + break; + case 'L': + OPT_CH(actual); + break; + case 'M': + OPT_CH(monthly); + break; + case 'O': + OPT_CH(quantity); + break; + case 'P': + OPT_CH(by_payee); + break; + case 'R': + OPT_CH(real); + break; + case 'S': + OPT_CH(sort_); + break; + case 'T': + OPT_CH(total_); + break; + case 'U': + OPT_CH(uncleared); + break; + case 'V': + OPT_CH(market); + break; + case 'W': + OPT_CH(weekly); + break; + case 'Y': + OPT_CH(yearly); + break; + case 'Z': + OPT_CH(price_exp_); + break; case 'a': - OPT(amount_); - else OPT(anon); + OPT(abbrev_len_); else OPT(account_); - else OPT(abbrev_len_); + else OPT(actual); + else OPT(add_budget); + else OPT(amount_); + else OPT(amount_data); + else OPT(anon); + else OPT(ansi); + else OPT(ansi_invert); + else OPT(average); break; - case 'b': - OPT_(begin_); + OPT(balance_format_); else OPT(base); + else OPT(basis); + else OPT_(begin_); + else OPT(budget); else OPT(by_payee); break; - case 'c': - OPT_(current); - else OPT(collapse); + OPT(cache_); + else OPT(csv_format_); else OPT(cleared); - else OPT(cost); - else OPT(comm_as_payee); else OPT(code_as_payee); + else OPT(collapse); + else OPT(comm_as_payee); + else OPT(cost); + else OPT_(current); break; - case 'd': OPT(daily); - else OPT(dow); else OPT(date_format_); + else OPT(deviation); + else OPT_(display_); + else OPT(display_amount_); + else OPT(display_total_); + else OPT(dow); break; - case 'e': - OPT_(end_); + OPT(effective); else OPT(empty); - else OPT(effective); + else OPT_(end_); + else OPT(equity_format_); break; - case 'f': - OPT(format_); + OPT(forecast_); + else OPT(format_); + break; + case 'g': + OPT_CH(performance); + else OPT(gain); break; - case 'h': OPT(head_); break; - case 'i': OPT(invert); break; - case 'j': OPT_CH(amount_data); break; - case 'l': OPT_(limit_); + else OPT(lot_dates); + else OPT(lot_prices); + else OPT(lot_tags); + else OPT(lots); break; - case 'm': - OPT(monthly); - else OPT(market); + OPT(market); + else OPT(monthly); break; - case 'n': OPT_CH(collapse); break; - case 'o': - OPT_(output_); + OPT(only_); + else OPT_(output_); break; - case 'p': - OPT_(period_); + OPT(pager_); + else OPT(percentage); + else OPT(performance); + else OPT_(period_); else OPT(period_sort_); + else OPT(plot_amount_format_); + else OPT(plot_total_format_); else OPT(price); - else OPT(pager_); + else OPT(price_exp_); + else OPT(prices_format_); + else OPT(pricesdb_format_); + else OPT(print_format_); break; - case 'q': - OPT(quarterly); - else OPT(quantity); + OPT(quantity); + else OPT(quarterly); break; - case 'r': - OPT_(related); - else OPT_(related_all); + OPT(real); + else OPT(register_format_); + else OPT_(related); + else OPT(related_all); + else OPT(revalued); + else OPT(revalued_only); break; - case 's': - OPT_(subtotal); + OPT(set_price_); else OPT(sort_); else OPT(sort_all_); else OPT(sort_entries_); + else OPT_(subtotal); break; - case 't': OPT_CH(amount_); + else OPT(tail_); else OPT(total_); + else OPT(total_data); else OPT(totals); - else OPT(tail_); + else OPT(truncate_); break; - case 'u': - OPT(uncleared); + OPT(unbudgeted); + else OPT(uncleared); break; - case 'w': OPT(weekly); + else OPT_(wide); + else OPT(wide_register_format_); + else OPT(write_hdr_format_); + else OPT(write_xact_format_); break; - case 'x': - OPT_CH(comm_as_payee); // jww (2009-02-05): ??? + OPT_CH(comm_as_payee); break; - case 'y': OPT_CH(date_format_); else OPT(yearly); break; - - case 'B': - OPT_CH(cost); - break; - case 'C': - OPT_CH(cleared); - break; - case 'E': - OPT_CH(empty); - break; - case 'F': - OPT_CH(format_); - break; - case 'I': - OPT_CH(price); - break; - case 'J': - OPT_CH(total_data); - break; - case 'M': - OPT_CH(monthly); - break; - case 'O': - OPT_CH(quantity); - break; - case 'P': - OPT_CH(by_payee); - break; - case 'S': - OPT_CH(sort_); - break; - case 'T': - OPT_CH(total_); - break; - case 'U': - OPT_CH(uncleared); - break; - case 'V': - OPT_CH(market); - break; - case 'W': - OPT_CH(weekly); - break; - case 'Y': - OPT_CH(yearly); - break; } } break; @@ -490,30 +587,39 @@ expr_t::ptr_op_t report_t::lookup(const string& name) if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN; switch (*p) { case 'a': - COMMAND(args); + if (is_eq(p, "args")) + return WRAP_FUNCTOR(args_command); break; case 'p': - COMMAND(parse); - else COMMAND(period); + if (is_eq(p, "parse")) + return WRAP_FUNCTOR(parse_command); + else if (is_eq(p, "period")) + return WRAP_FUNCTOR(period_command); break; case 'e': - COMMAND(eval); + if (is_eq(p, "eval")) + return WRAP_FUNCTOR(eval_command); break; case 'f': - COMMAND(format); + if (is_eq(p, "format")) + return WRAP_FUNCTOR(format_command); break; } } - else FUNCTION(print_balance); + else if (is_eq(p, "print_balance")) + return MAKE_FUNCTOR(report_t::fn_print_balance); break; case 's': - FUNCTION(strip); + if (is_eq(p, "strip")) + return MAKE_FUNCTOR(report_t::fn_strip); break; case 't': - FUNCTION(truncate); - else METHOD(report_t, total_expr); + if (is_eq(p, "truncate")) + return MAKE_FUNCTOR(report_t::fn_truncate); + else if (is_eq(p, "total_expr")) + return MAKE_FUNCTOR(report_t::fn_total_expr); break; } diff --git a/src/report.h b/src/report.h index 6b252446..d3ee6ea2 100644 --- a/src/report.h +++ b/src/report.h @@ -122,8 +122,15 @@ public: value_t fn_amount_expr(call_scope_t& scope); value_t fn_total_expr(call_scope_t& scope); + value_t fn_display_date(call_scope_t& scope); value_t fn_display_amount(call_scope_t& scope); value_t fn_display_total(call_scope_t& scope); + value_t fn_market_value(call_scope_t& scope); + value_t fn_print_balance(call_scope_t& scope); + value_t fn_strip(call_scope_t& scope); + value_t fn_truncate(call_scope_t& scope); + value_t fn_escape(call_scope_t& scope); + value_t fn_join(call_scope_t& scope); void append_predicate(const string& str) { if (HANDLED(limit_)) @@ -193,6 +200,7 @@ public: OPTION(report_t, collapse); // -n OPTION(report_t, comm_as_payee); // -x OPTION(report_t, cost); + OPTION(report_t, csv_format_); OPTION(report_t, current); // -c OPTION(report_t, daily); OPTION(report_t, date_format_); // -y @@ -270,7 +278,7 @@ public: OPTION(report_t, set_price_); OPTION_(report_t, sort_, DO_(args) { // -S - on(args[0].to_string()); + on(args[0].to_string()); parent->HANDLER(sort_entries_).off(); parent->HANDLER(sort_all_).off(); }); diff --git a/src/session.cc b/src/session.cc index 4afe2e51..d84c79a3 100644 --- a/src/session.cc +++ b/src/session.cc @@ -284,7 +284,7 @@ expr_t::ptr_op_t session_t::lookup(const string& name) } break; } - return expr_t::ptr_op_t(); + return NULL; } } // namespace ledger diff --git a/src/session.h b/src/session.h index 0b36b1c6..89530cf1 100644 --- a/src/session.h +++ b/src/session.h @@ -46,8 +46,7 @@ #ifndef _SESSION_H #define _SESSION_H -#include "scope.h" -#include "handler.h" +#include "option.h" #include "journal.h" #include "account.h" #include "format.h" diff --git a/src/textual.cc b/src/textual.cc index d6fd966b..d3a829d3 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -37,12 +37,8 @@ #if defined(TIMELOG_SUPPORT) #include "timelog.h" #endif -#include "expr.h" #include "parser.h" #include "session.h" -#include "option.h" -#include "acconf.h" -#include "pstream.h" namespace ledger { diff --git a/src/utils.h b/src/utils.h index a292ccf6..ddc83882 100644 --- a/src/utils.h +++ b/src/utils.h @@ -472,7 +472,8 @@ void finish_timer(const char * name); #include "error.h" #include "times.h" #include "flags.h" -#include "stream.h" +#include "stream.h" // output_stream_t +#include "pstream.h" // pstristream enum caught_signal_t { NONE_CAUGHT, |