Move handling of all commands to the value expression subsystem, rather than
handling them explicitly in main.cc.
This commit is contained in:
parent
b9182bccdc
commit
1fcf7b5fc1
2 changed files with 189 additions and 195 deletions
200
src/main.cc
200
src/main.cc
|
|
@ -32,7 +32,6 @@
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "report.h"
|
#include "report.h"
|
||||||
#include "option.h"
|
#include "option.h"
|
||||||
#include "output.h"
|
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
|
||||||
#include "textual.h"
|
#include "textual.h"
|
||||||
|
|
@ -52,131 +51,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
string args_to_predicate(value_t::sequence_t::const_iterator begin,
|
|
||||||
value_t::sequence_t::const_iterator end)
|
|
||||||
{
|
|
||||||
string acct_value_expr;
|
|
||||||
string payee_value_expr;
|
|
||||||
string note_value_expr;
|
|
||||||
|
|
||||||
string * value_expr;
|
|
||||||
|
|
||||||
enum regexp_kind_t {
|
|
||||||
ACCOUNT_REGEXP,
|
|
||||||
PAYEE_REGEXP,
|
|
||||||
NOTE_REGEXP
|
|
||||||
}
|
|
||||||
kind = ACCOUNT_REGEXP;
|
|
||||||
|
|
||||||
value_expr = &acct_value_expr;
|
|
||||||
|
|
||||||
for ( ; begin != end; begin++) {
|
|
||||||
const string& arg((*begin).as_string());
|
|
||||||
|
|
||||||
if (arg == "--") {
|
|
||||||
kind = PAYEE_REGEXP;
|
|
||||||
value_expr = &payee_value_expr;
|
|
||||||
}
|
|
||||||
else if (arg == "/") {
|
|
||||||
kind = NOTE_REGEXP;
|
|
||||||
value_expr = ¬e_value_expr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (! value_expr->empty())
|
|
||||||
*value_expr += "|";
|
|
||||||
|
|
||||||
switch (kind) {
|
|
||||||
case ACCOUNT_REGEXP:
|
|
||||||
*value_expr += "account =~ ";
|
|
||||||
break;
|
|
||||||
case PAYEE_REGEXP:
|
|
||||||
*value_expr += "payee =~ ";
|
|
||||||
break;
|
|
||||||
case NOTE_REGEXP:
|
|
||||||
*value_expr += "note =~ ";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * p = arg.c_str();
|
|
||||||
if (*p == '-') {
|
|
||||||
*value_expr += "!";
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*value_expr += "/";
|
|
||||||
if (kind == NOTE_REGEXP) *value_expr += ":";
|
|
||||||
while (*p) {
|
|
||||||
if (*p == '/')
|
|
||||||
*value_expr += "\\";
|
|
||||||
*value_expr += *p;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (kind == NOTE_REGEXP) *value_expr += ":";
|
|
||||||
*value_expr += "/";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string final_value_expr;
|
|
||||||
|
|
||||||
if (! acct_value_expr.empty()) {
|
|
||||||
if (! payee_value_expr.empty() ||
|
|
||||||
! note_value_expr.empty())
|
|
||||||
final_value_expr = string("(") + acct_value_expr + ")";
|
|
||||||
else
|
|
||||||
final_value_expr = acct_value_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! payee_value_expr.empty()) {
|
|
||||||
if (! acct_value_expr.empty())
|
|
||||||
final_value_expr += string("&(") + payee_value_expr + ")";
|
|
||||||
else if (! note_value_expr.empty())
|
|
||||||
final_value_expr = string("(") + payee_value_expr + ")";
|
|
||||||
else
|
|
||||||
final_value_expr = payee_value_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! note_value_expr.empty()) {
|
|
||||||
if (! acct_value_expr.empty() ||
|
|
||||||
! payee_value_expr.empty())
|
|
||||||
final_value_expr += string("&(") + note_value_expr + ")";
|
|
||||||
else if (acct_value_expr.empty() &&
|
|
||||||
payee_value_expr.empty())
|
|
||||||
final_value_expr = note_value_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("report.predicate",
|
|
||||||
"Regexp predicate expression = " << final_value_expr);
|
|
||||||
|
|
||||||
return final_value_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Type = xact_t,
|
|
||||||
class handler_ptr = xact_handler_ptr,
|
|
||||||
void (report_t::*report_method)(handler_ptr) =
|
|
||||||
&report_t::xacts_report>
|
|
||||||
class reporter
|
|
||||||
{
|
|
||||||
shared_ptr<item_handler<Type> > handler;
|
|
||||||
|
|
||||||
public:
|
|
||||||
reporter(item_handler<Type> * _handler)
|
|
||||||
: handler(_handler) {}
|
|
||||||
|
|
||||||
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(args.value().as_sequence().begin(),
|
|
||||||
args.value().as_sequence().end()));
|
|
||||||
|
|
||||||
(report.*report_method)(handler_ptr(handler));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int read_and_report(ledger::report_t& report,
|
int read_and_report(ledger::report_t& report,
|
||||||
int argc, char * argv[], char * envp[])
|
int argc, char * argv[], char * envp[])
|
||||||
{
|
{
|
||||||
|
|
@ -393,66 +267,14 @@ namespace ledger {
|
||||||
TRACE_FINISH(entries, 1);
|
TRACE_FINISH(entries, 1);
|
||||||
TRACE_FINISH(parsing_total, 1);
|
TRACE_FINISH(parsing_total, 1);
|
||||||
|
|
||||||
// Create a command object based on the command verb that was seen
|
// Lookup the command object corresponding to the command verb.
|
||||||
// above.
|
|
||||||
|
|
||||||
function_t command;
|
function_t command;
|
||||||
|
if (expr_t::ptr_op_t def = report.lookup(string("cmd_") + verb))
|
||||||
|
command = def->as_function();
|
||||||
|
|
||||||
if (verb == "register" || verb == "reg" || verb == "r") {
|
if (! command)
|
||||||
verb = "register";
|
throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
|
||||||
command = reporter<>(new format_xacts(report,
|
|
||||||
report.format_string.empty() ?
|
|
||||||
session.register_format :
|
|
||||||
report.format_string));
|
|
||||||
}
|
|
||||||
else if (verb == "print" || verb == "p") {
|
|
||||||
verb = "print";
|
|
||||||
command = reporter<>(new format_xacts(report,
|
|
||||||
report.format_string.empty() ?
|
|
||||||
session.print_format :
|
|
||||||
report.format_string));
|
|
||||||
}
|
|
||||||
else if (verb == "balance" || verb == "bal" || verb == "b") {
|
|
||||||
verb = "balance";
|
|
||||||
command = reporter<account_t, acct_handler_ptr,
|
|
||||||
&report_t::accounts_report>
|
|
||||||
(new format_accounts(report, session.balance_format));
|
|
||||||
}
|
|
||||||
else if (verb == "equity") {
|
|
||||||
verb = "equity";
|
|
||||||
command = reporter<account_t, acct_handler_ptr,
|
|
||||||
&report_t::accounts_report>
|
|
||||||
(new format_equity(report, session.print_format));
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
else if (verb == "entry")
|
|
||||||
command = entry_command();
|
|
||||||
else if (verb == "dump")
|
|
||||||
command = dump_command();
|
|
||||||
else if (verb == "output")
|
|
||||||
command = output_command();
|
|
||||||
else if (verb == "prices")
|
|
||||||
command = prices_command();
|
|
||||||
else if (verb == "pricesdb")
|
|
||||||
command = pricesdb_command();
|
|
||||||
else if (verb == "csv")
|
|
||||||
command = csv_command();
|
|
||||||
else if (verb == "emacs" || verb == "lisp")
|
|
||||||
command = emacs_command();
|
|
||||||
else if (verb == "xml")
|
|
||||||
command = xml_command();
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
char buf[128];
|
|
||||||
std::strcpy(buf, "cmd_");
|
|
||||||
std::strcat(buf, verb.c_str());
|
|
||||||
|
|
||||||
if (expr_t::ptr_op_t def = report.lookup(buf))
|
|
||||||
command = def->as_function();
|
|
||||||
|
|
||||||
if (! command)
|
|
||||||
throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patch up some of the reporting options based on what kind of
|
// Patch up some of the reporting options based on what kind of
|
||||||
// command it was.
|
// command it was.
|
||||||
|
|
@ -460,7 +282,7 @@ namespace ledger {
|
||||||
// jww (2008-08-14): This code really needs to be rationalized away
|
// jww (2008-08-14): This code really needs to be rationalized away
|
||||||
// for 3.0.
|
// for 3.0.
|
||||||
|
|
||||||
if (verb == "print" || verb == "entry" || verb == "dump") {
|
if (verb[0] == 'p' || verb == "entry" || verb == "dump") {
|
||||||
report.show_related = true;
|
report.show_related = true;
|
||||||
report.show_all_related = true;
|
report.show_all_related = true;
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +290,7 @@ namespace ledger {
|
||||||
report.show_subtotal = true;
|
report.show_subtotal = true;
|
||||||
}
|
}
|
||||||
else if (report.show_related) {
|
else if (report.show_related) {
|
||||||
if (verb == "register") {
|
if (verb[0] == 'r') {
|
||||||
report.show_inverted = true;
|
report.show_inverted = true;
|
||||||
} else {
|
} else {
|
||||||
report.show_subtotal = true;
|
report.show_subtotal = true;
|
||||||
|
|
@ -476,13 +298,13 @@ namespace ledger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verb != "balance" && verb != "register")
|
if (verb[0] != 'b' && verb[0] != 'r')
|
||||||
amount_t::keep_base = true;
|
amount_t::keep_base = true;
|
||||||
|
|
||||||
// Setup the default value for the display predicate
|
// Setup the default value for the display predicate
|
||||||
|
|
||||||
if (report.display_predicate.empty()) {
|
if (report.display_predicate.empty()) {
|
||||||
if (verb == "balance") {
|
if (verb[0] == 'b') {
|
||||||
if (! report.show_empty)
|
if (! report.show_empty)
|
||||||
report.display_predicate = "total";
|
report.display_predicate = "total";
|
||||||
if (! report.show_subtotal) {
|
if (! report.show_subtotal) {
|
||||||
|
|
@ -492,9 +314,9 @@ namespace ledger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (verb == "equity") {
|
else if (verb == "equity") {
|
||||||
report.display_predicate = "fmt_t"; // jww (2008-08-14): ???
|
report.display_predicate = "amount_expr"; // jww (2008-08-14): ???
|
||||||
}
|
}
|
||||||
else if (verb == "register" && ! report.show_empty) {
|
else if (verb[0] == 'r' && ! report.show_empty) {
|
||||||
report.display_predicate = "amount";
|
report.display_predicate = "amount";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
184
src/report.cc
184
src/report.cc
|
|
@ -30,6 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "report.h"
|
#include "report.h"
|
||||||
|
#include "output.h"
|
||||||
#include "reconcile.h"
|
#include "reconcile.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
@ -284,20 +285,191 @@ namespace {
|
||||||
args[0].strip_annotations().dump(out, *first_width, *latter_width);
|
args[0].strip_annotations().dump(out, *first_width, *latter_width);
|
||||||
return string_value(out.str());
|
return string_value(out.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string args_to_predicate(value_t::sequence_t::const_iterator begin,
|
||||||
|
value_t::sequence_t::const_iterator end)
|
||||||
|
{
|
||||||
|
string acct_value_expr;
|
||||||
|
string payee_value_expr;
|
||||||
|
string note_value_expr;
|
||||||
|
|
||||||
|
string * value_expr;
|
||||||
|
|
||||||
|
enum regexp_kind_t {
|
||||||
|
ACCOUNT_REGEXP,
|
||||||
|
PAYEE_REGEXP,
|
||||||
|
NOTE_REGEXP
|
||||||
|
}
|
||||||
|
kind = ACCOUNT_REGEXP;
|
||||||
|
|
||||||
|
value_expr = &acct_value_expr;
|
||||||
|
|
||||||
|
for ( ; begin != end; begin++) {
|
||||||
|
const string& arg((*begin).as_string());
|
||||||
|
|
||||||
|
if (arg == "--") {
|
||||||
|
kind = PAYEE_REGEXP;
|
||||||
|
value_expr = &payee_value_expr;
|
||||||
|
}
|
||||||
|
else if (arg == "/") {
|
||||||
|
kind = NOTE_REGEXP;
|
||||||
|
value_expr = ¬e_value_expr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (! value_expr->empty())
|
||||||
|
*value_expr += "|";
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case ACCOUNT_REGEXP:
|
||||||
|
*value_expr += "account =~ ";
|
||||||
|
break;
|
||||||
|
case PAYEE_REGEXP:
|
||||||
|
*value_expr += "payee =~ ";
|
||||||
|
break;
|
||||||
|
case NOTE_REGEXP:
|
||||||
|
*value_expr += "note =~ ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * p = arg.c_str();
|
||||||
|
if (*p == '-') {
|
||||||
|
*value_expr += "!";
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*value_expr += "/";
|
||||||
|
if (kind == NOTE_REGEXP) *value_expr += ":";
|
||||||
|
while (*p) {
|
||||||
|
if (*p == '/')
|
||||||
|
*value_expr += "\\";
|
||||||
|
*value_expr += *p;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (kind == NOTE_REGEXP) *value_expr += ":";
|
||||||
|
*value_expr += "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string final_value_expr;
|
||||||
|
|
||||||
|
if (! acct_value_expr.empty()) {
|
||||||
|
if (! payee_value_expr.empty() ||
|
||||||
|
! note_value_expr.empty())
|
||||||
|
final_value_expr = string("(") + acct_value_expr + ")";
|
||||||
|
else
|
||||||
|
final_value_expr = acct_value_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! payee_value_expr.empty()) {
|
||||||
|
if (! acct_value_expr.empty())
|
||||||
|
final_value_expr += string("&(") + payee_value_expr + ")";
|
||||||
|
else if (! note_value_expr.empty())
|
||||||
|
final_value_expr = string("(") + payee_value_expr + ")";
|
||||||
|
else
|
||||||
|
final_value_expr = payee_value_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! note_value_expr.empty()) {
|
||||||
|
if (! acct_value_expr.empty() ||
|
||||||
|
! payee_value_expr.empty())
|
||||||
|
final_value_expr += string("&(") + note_value_expr + ")";
|
||||||
|
else if (acct_value_expr.empty() &&
|
||||||
|
payee_value_expr.empty())
|
||||||
|
final_value_expr = note_value_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("report.predicate",
|
||||||
|
"Regexp predicate expression = " << final_value_expr);
|
||||||
|
|
||||||
|
return final_value_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Type = xact_t,
|
||||||
|
class handler_ptr = xact_handler_ptr,
|
||||||
|
void (report_t::*report_method)(handler_ptr) =
|
||||||
|
&report_t::xacts_report>
|
||||||
|
class reporter
|
||||||
|
{
|
||||||
|
shared_ptr<item_handler<Type> > handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
reporter(item_handler<Type> * _handler)
|
||||||
|
: handler(_handler) {}
|
||||||
|
|
||||||
|
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(args.value().as_sequence().begin(),
|
||||||
|
args.value().as_sequence().end()));
|
||||||
|
|
||||||
|
(report.*report_method)(handler_ptr(handler));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_t::ptr_op_t report_t::lookup(const string& name)
|
expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
{
|
{
|
||||||
const char * p = name.c_str();
|
const char * p = name.c_str();
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case 'f':
|
case 'a':
|
||||||
if (std::strncmp(p, "fmt_", 4) == 0) {
|
if (std::strcmp(p, "amount_expr") == 0)
|
||||||
|
return MAKE_FUNCTOR(report_t::get_amount_expr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
if (std::strncmp(p, "cmd_", 4) == 0) {
|
||||||
|
|
||||||
|
#define FORMAT(str) \
|
||||||
|
(format_string.empty() ? session. str : format_string)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Commands yet to implement:
|
||||||
|
//
|
||||||
|
// entry
|
||||||
|
// dump
|
||||||
|
// output
|
||||||
|
// prices
|
||||||
|
// pricesdb
|
||||||
|
// csv
|
||||||
|
// emacs | lisp
|
||||||
|
// xml
|
||||||
|
#endif
|
||||||
|
|
||||||
p = p + 4;
|
p = p + 4;
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case 't':
|
case 'b':
|
||||||
return MAKE_FUNCTOR(report_t::get_amount_expr);
|
if (*(p + 1) == '\0' ||
|
||||||
case 'T':
|
std::strcmp(p, "bal") == 0 ||
|
||||||
return MAKE_FUNCTOR(report_t::get_total_expr);
|
std::strcmp(p, "balance") == 0)
|
||||||
|
return expr_t::op_t::wrap_functor
|
||||||
|
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
||||||
|
(new format_accounts(*this, FORMAT(balance_format))));
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
if (std::strcmp(p, "equity") == 0)
|
||||||
|
return expr_t::op_t::wrap_functor
|
||||||
|
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
||||||
|
(new format_equity(*this, FORMAT(print_format))));
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (*(p + 1) == '\0' ||
|
||||||
|
std::strcmp(p, "print") == 0)
|
||||||
|
return WRAP_FUNCTOR
|
||||||
|
(reporter<>(new format_xacts(*this, FORMAT(print_format))));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
if (*(p + 1) == '\0' ||
|
||||||
|
std::strcmp(p, "reg") == 0 ||
|
||||||
|
std::strcmp(p, "register") == 0)
|
||||||
|
return WRAP_FUNCTOR
|
||||||
|
(reporter<>(new format_xacts(*this, FORMAT(register_format))));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue