summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exprbase.h15
-rw-r--r--src/format.cc80
-rw-r--r--src/format.h40
-rw-r--r--src/output.cc43
-rw-r--r--src/precmd.cc2
-rw-r--r--src/scope.h3
6 files changed, 97 insertions, 86 deletions
diff --git a/src/exprbase.h b/src/exprbase.h
index 605c30f7..d2bf5a6d 100644
--- a/src/exprbase.h
+++ b/src/exprbase.h
@@ -118,7 +118,8 @@ public:
return str;
}
void set_text(const string& txt) {
- str = txt;
+ str = txt;
+ compiled = false;
}
void parse(const string& str, const parse_flags_t& flags = PARSE_DEFAULT) {
@@ -128,9 +129,7 @@ public:
virtual void parse(std::istream&,
const parse_flags_t& = PARSE_DEFAULT,
const optional<string>& original_string = none) {
- str = original_string ? *original_string : "<stream>";
- context = NULL;
- compiled = false;
+ set_text(original_string ? *original_string : "<stream>");
}
void mark_uncompiled() {
@@ -185,7 +184,9 @@ public:
context = scope;
}
- virtual string context_to_str() const = 0;
+ virtual string context_to_str() const {
+ return empty_string;
+ }
string print_to_str() const {
std::ostringstream out;
@@ -203,8 +204,8 @@ public:
return out.str();
}
- virtual void print(std::ostream& out) const = 0;
- virtual void dump(std::ostream& out) const = 0;
+ virtual void print(std::ostream&) const {}
+ virtual void dump(std::ostream&) const {}
result_type preview(std::ostream& out, scope_t& scope) const {
out << _("--- Input expression ---") << std::endl;
diff --git a/src/format.cc b/src/format.cc
index f3f52f20..d949c350 100644
--- a/src/format.cc
+++ b/src/format.cc
@@ -61,8 +61,12 @@ void format_t::element_t::dump(std::ostream& out) const
out << std::dec << int(max_width);
switch (type) {
- case STRING: out << " str: '" << chars << "'" << std::endl; break;
- case EXPR: out << " expr: " << expr << std::endl; break;
+ case STRING:
+ out << " str: '" << boost::get<string>(data) << "'" << std::endl;
+ break;
+ case EXPR:
+ out << " expr: " << boost::get<expr_t>(data) << std::endl;
+ break;
}
}
@@ -117,7 +121,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
if (q != buf) {
current->type = element_t::STRING;
- current->chars = string(buf, q);
+ current->data = string(buf, q);
q = buf;
current->next.reset(new element_t);
@@ -128,14 +132,14 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
p++;
current->type = element_t::STRING;
switch (*p) {
- case 'b': current->chars = "\b"; break;
- case 'f': current->chars = "\f"; break;
- case 'n': current->chars = "\n"; break;
- case 'r': current->chars = "\r"; break;
- case 't': current->chars = "\t"; break;
- case 'v': current->chars = "\v"; break;
- case '\\': current->chars = "\\"; break;
- default: current->chars = string(1, *p); break;
+ case 'b': current->data = string("\b"); break;
+ case 'f': current->data = string("\f"); break;
+ case 'n': current->data = string("\n"); break;
+ case 'r': current->data = string("\r"); break;
+ case 't': current->data = string("\t"); break;
+ case 'v': current->data = string("\v"); break;
+ case '\\': current->data = string("\\"); break;
+ default: current->data = string(1, *p); break;
}
continue;
}
@@ -171,8 +175,8 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
switch (*p) {
case '%':
- current->type = element_t::STRING;
- current->chars = "%";
+ current->type = element_t::STRING;
+ current->data = string("%");
break;
case '$': {
@@ -207,7 +211,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
if (format_amount) p++;
current->type = element_t::EXPR;
- current->expr = parse_single_expression(p, ! format_amount);
+ current->data = parse_single_expression(p, ! format_amount);
// Wrap the subexpression in calls to justify and scrub
if (format_amount) {
@@ -216,7 +220,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
else
p++;
- expr_t::ptr_op_t op = current->expr.get_op();
+ expr_t::ptr_op_t op = boost::get<expr_t>(current->data).get_op();
expr_t::ptr_op_t amount_op;
expr_t::ptr_op_t colorize_op;
@@ -238,8 +242,10 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
expr_t::ptr_op_t arg2_node(new expr_t::op_t(expr_t::op_t::VALUE));
expr_t::ptr_op_t arg3_node(new expr_t::op_t(expr_t::op_t::VALUE));
- arg1_node->set_value(current->min_width > 0 ? long(current->min_width) : -1);
- arg2_node->set_value(current->max_width > 0 ? long(current->max_width) : -1);
+ arg1_node->set_value(current->min_width > 0 ?
+ long(current->min_width) : -1);
+ arg2_node->set_value(current->max_width > 0 ?
+ long(current->max_width) : -1);
arg3_node->set_value(! current->has_flags(ELEMENT_ALIGN_LEFT));
current->min_width = 0;
@@ -264,7 +270,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
call2_node->set_left(justify_node);
call2_node->set_right(args3_node);
- string prev_expr = current->expr.text();
+ string prev_expr = boost::get<expr_t>(current->data).text();
if (colorize_op) {
expr_t::ptr_op_t ansify_if_node(new expr_t::op_t(expr_t::op_t::IDENT));
@@ -278,21 +284,18 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
call3_node->set_left(ansify_if_node);
call3_node->set_right(args4_node);
- current->expr = expr_t(call3_node);
+ current->data = expr_t(call3_node);
} else {
- current->expr = expr_t(call2_node);
+ current->data = expr_t(call2_node);
}
- current->expr.set_text(prev_expr);
+ boost::get<expr_t>(current->data).set_text(prev_expr);
}
break;
}
default:
- current->type = element_t::EXPR;
- current->chars = string(FMT_PREFIX) + *p;
- current->expr.parse(current->chars);
- break;
+ throw_(format_error, _("Unrecognized formatting character: %1") << *p);
}
}
@@ -304,15 +307,17 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
current->next.reset(new element_t);
current = current->next.get();
}
- current->type = element_t::STRING;
- current->chars = string(buf, q);
+ current->type = element_t::STRING;
+ current->data = string(buf, q);
}
return result.release();
}
-void format_t::format(std::ostream& out_str, scope_t& scope)
+string format_t::real_calc(scope_t& scope)
{
+ std::ostringstream out_str;
+
for (element_t * elem = elements.get(); elem; elem = elem->next.get()) {
std::ostringstream out;
string name;
@@ -326,20 +331,22 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
case element_t::STRING:
if (elem->min_width > 0)
out.width(elem->min_width);
- out << elem->chars;
+ out << boost::get<string>(elem->data);
break;
- case element_t::EXPR:
+ case element_t::EXPR: {
+ expr_t& expr(boost::get<expr_t>(elem->data));
try {
- elem->expr.compile(scope);
+
+ expr.compile(scope);
value_t value;
- if (elem->expr.is_function()) {
+ if (expr.is_function()) {
call_scope_t args(scope);
args.push_back(long(elem->max_width));
- value = elem->expr.get_function()(args);
+ value = expr.get_function()(args);
} else {
- value = elem->expr.calc(scope);
+ value = expr.calc(scope);
}
DEBUG("format.expr", "value = (" << value << ")");
@@ -348,10 +355,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
}
catch (const calc_error&) {
add_error_context(_("While calculating format expression:"));
- add_error_context(elem->expr.context_to_str());
+ add_error_context(expr.context_to_str());
throw;
}
break;
+ }
default:
assert(false);
@@ -375,6 +383,8 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
out_str << out.str();
}
}
+
+ return out_str.str();
}
string format_t::truncate(const unistring& ustr,
diff --git a/src/format.h b/src/format.h
index 8043594b..516b6d7e 100644
--- a/src/format.h
+++ b/src/format.h
@@ -50,20 +50,20 @@ class unistring;
DECLARE_EXCEPTION(format_error, std::runtime_error);
-class format_t : public noncopyable
+class format_t : public expr_base_t<string>
{
+ typedef expr_base_t<string> base_type;
+
struct element_t : public supports_flags<>
{
#define ELEMENT_ALIGN_LEFT 0x01
enum kind_t { STRING, EXPR };
- kind_t type;
- std::size_t min_width;
- std::size_t max_width;
- string chars;
- expr_t expr;
-
+ kind_t type;
+ std::size_t min_width;
+ std::size_t max_width;
+ variant<string, expr_t> data;
scoped_ptr<struct element_t> next;
element_t() throw()
@@ -83,8 +83,7 @@ class format_t : public noncopyable
type = elem.type;
min_width = elem.min_width;
max_width = elem.max_width;
- chars = elem.chars;
- expr = elem.expr;
+ data = elem.data;
}
return *this;
}
@@ -124,25 +123,28 @@ private:
const optional<format_t&>& tmpl);
public:
- format_t() {
+ format_t() : base_type() {
TRACE_CTOR(format_t, "");
}
- format_t(const string& _format) {
+ format_t(const string& _str, scope_t * context = NULL)
+ : base_type(context) {
TRACE_CTOR(format_t, "const string&");
- parse(_format);
+ if (! _str.empty())
+ parse_format(_str);
}
~format_t() {
TRACE_DTOR(format_t);
}
- void parse(const string& _format, const optional<format_t&>& tmpl = none) {
+ void parse_format(const string& _format,
+ const optional<format_t&>& tmpl = none) {
elements.reset(parse_elements(_format, tmpl));
- format_string = _format;
+ set_text(_format);
}
- void format(std::ostream& out, scope_t& scope);
+ virtual result_type real_calc(scope_t& scope);
- void dump(std::ostream& out) const {
+ virtual void dump(std::ostream& out) const {
for (const element_t * elem = elements.get();
elem;
elem = elem->next.get())
@@ -154,12 +156,6 @@ public:
const std::size_t account_abbrev_length = 0);
};
-#define FMT_PREFIX "fmt_"
-#define FMT_PREFIX_LEN 4
-
-#define WANT_FMT() \
- (std::strncmp(p, FMT_PREFIX, FMT_PREFIX_LEN) == 0)
-
} // namespace ledger
#endif // _FORMAT_H
diff --git a/src/output.cc b/src/output.cc
index eee84553..2a6f0c20 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -51,17 +51,19 @@ format_posts::format_posts(report_t& _report,
const char * f = format.c_str();
if (const char * p = std::strstr(f, "%/")) {
- first_line_format.parse(string(f, 0, p - f));
+ first_line_format.parse_format(string(f, 0, p - f));
const char * n = p + 2;
if (const char * p = std::strstr(n, "%/")) {
- next_lines_format.parse(string(n, 0, p - n), first_line_format);
- between_format.parse(string(p + 2), first_line_format);
+ next_lines_format.parse_format(string(n, 0, p - n),
+ first_line_format);
+ between_format.parse_format(string(p + 2),
+ first_line_format);
} else {
- next_lines_format.parse(n, first_line_format);
+ next_lines_format.parse_format(string(n), first_line_format);
}
} else {
- first_line_format.parse(format);
- next_lines_format.parse(format);
+ first_line_format.parse_format(format);
+ next_lines_format.parse_format(format);
}
}
@@ -80,7 +82,7 @@ void format_posts::operator()(post_t& post)
if (last_xact != post.xact) {
if (last_xact) {
bind_scope_t xact_scope(report, *last_xact);
- between_format.format(out, xact_scope);
+ out << between_format(xact_scope);
}
print_item(out, *post.xact);
out << '\n';
@@ -96,16 +98,16 @@ void format_posts::operator()(post_t& post)
if (last_xact != post.xact) {
if (last_xact) {
bind_scope_t xact_scope(report, *last_xact);
- between_format.format(out, xact_scope);
+ out << between_format(xact_scope);
}
- first_line_format.format(out, bound_scope);
+ out << first_line_format(bound_scope);
last_xact = post.xact;
}
else if (last_post && last_post->date() != post.date()) {
- first_line_format.format(out, bound_scope);
+ out << first_line_format(bound_scope);
}
else {
- next_lines_format.format(out, bound_scope);
+ out << next_lines_format(bound_scope);
}
post.xdata().add_flags(POST_EXT_DISPLAYED);
@@ -122,17 +124,17 @@ format_accounts::format_accounts(report_t& _report,
const char * f = format.c_str();
if (const char * p = std::strstr(f, "%/")) {
- account_line_format.parse(string(f, 0, p - f));
+ account_line_format.parse_format(string(f, 0, p - f));
const char * n = p + 2;
if (const char * p = std::strstr(n, "%/")) {
- total_line_format.parse(string(n, 0, p - n), account_line_format);
- separator_format.parse(string(p + 2), account_line_format);
+ total_line_format.parse_format(string(n, 0, p - n), account_line_format);
+ separator_format.parse_format(string(p + 2), account_line_format);
} else {
- total_line_format.parse(n, account_line_format);
+ total_line_format.parse_format(n, account_line_format);
}
} else {
- account_line_format.parse(format);
- total_line_format.parse(format, account_line_format);
+ account_line_format.parse_format(format);
+ total_line_format.parse_format(format, account_line_format);
}
}
@@ -148,7 +150,8 @@ std::size_t format_accounts::post_account(account_t& account, const bool flat)
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
bind_scope_t bound_scope(report, account);
- account_line_format.format(report.output_stream, bound_scope);
+ static_cast<std::ostream&>(report.output_stream)
+ << account_line_format(bound_scope);
return 1;
}
@@ -213,8 +216,8 @@ void format_accounts::flush()
if (displayed > 1 &&
! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
bind_scope_t bound_scope(report, *report.session.journal->master);
- separator_format.format(out, bound_scope);
- total_line_format.format(out, bound_scope);
+ out << separator_format(bound_scope);
+ out << total_line_format(bound_scope);
}
out.flush();
diff --git a/src/precmd.cc b/src/precmd.cc
index 277e7b89..92483dc8 100644
--- a/src/precmd.cc
+++ b/src/precmd.cc
@@ -148,7 +148,7 @@ value_t format_command(call_scope_t& args)
out << std::endl << _("--- Formatted string ---") << std::endl;
bind_scope_t bound_scope(args, *post);
out << '"';
- fmt.format(out, bound_scope);
+ out << fmt(bound_scope);
out << "\"\n";
return NULL_VALUE;
diff --git a/src/scope.h b/src/scope.h
index cd7d93c7..44ca3229 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -54,7 +54,8 @@ struct symbol_t
OPTION,
PRECOMMAND,
COMMAND,
- DIRECTIVE
+ DIRECTIVE,
+ FORMAT
};
kind_t kind;