diff options
-rwxr-xr-x | acprep | 4 | ||||
-rw-r--r-- | config.cc | 12 | ||||
-rw-r--r-- | format.cc | 15 | ||||
-rw-r--r-- | journal.cc | 5 | ||||
-rw-r--r-- | valexpr.cc | 35 | ||||
-rw-r--r-- | valexpr.h | 13 | ||||
-rw-r--r-- | walk.cc | 2 | ||||
-rw-r--r-- | walk.h | 11 |
8 files changed, 63 insertions, 34 deletions
@@ -3,7 +3,7 @@ glibtoolize --automake -f -c aclocal autoheader -touch AUTHORS ChangeLog COPYING +touch AUTHORS COPYING if [ "$1" = "--dist" ]; then automake -acfi @@ -30,4 +30,4 @@ elif [ "$1" = "--perf" ]; then ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g -pg" fi -rm AUTHORS ChangeLog COPYING +rm AUTHORS COPYING @@ -171,23 +171,17 @@ void config_t::process_options(const std::string& command, try { if (! format_t::amount_expr) format_t::amount_expr = parse_value_expr(amount_expr); - if (! format_t::amount_expr) - throw value_expr_error(std::string("Failed to parse '") + - amount_expr + "'"); } catch (const value_expr_error& err) { - throw error(std::string("In value expression to -t: ") + err.what()); + throw error(std::string("In amount expression (-t): ") + err.what()); } try { if (! format_t::total_expr) format_t::total_expr = parse_value_expr(total_expr); - if (! format_t::total_expr) - throw value_expr_error(std::string("Failed to parse '") + - total_expr + "'"); } catch (const value_expr_error& err) { - throw error(std::string("In value expression to -T: ") + err.what()); + throw error(std::string("In total expression (-T): ") + err.what()); } // If downloading is to be supported, configure the updater @@ -197,7 +191,7 @@ void config_t::process_options(const std::string& command, pricing_leeway, cache_dirty); - if (format_t::date_format.empty() && ! date_format.empty()) + if (! date_format.empty()) format_t::date_format = date_format; } @@ -14,7 +14,7 @@ std::string truncated(const std::string& str, unsigned int width) return buf; } -std::string partial_account_name(const account_t& account) +std::string partial_account_name(const account_t& account) { std::string name; @@ -135,8 +135,14 @@ element_t * format_t::parse_elements(const std::string& fmt) if (*p != ')') throw format_error("Missing ')'"); - current->type = element_t::VALUE_EXPR; - current->val_expr = parse_value_expr(std::string(b, p)); + current->type = element_t::VALUE_EXPR; + try { + current->val_expr = parse_value_expr(std::string(b, p)); + } + catch (value_expr_error& err) { + throw value_expr_error(std::string("In format expression '") + + std::string(b, p) + "': " + err.what()); + } break; } @@ -210,11 +216,12 @@ void format_t::format(std::ostream& out, const details_t& details) const case element_t::AMOUNT: expr = amount_expr; break; case element_t::TOTAL: expr = total_expr; break; case element_t::VALUE_EXPR: expr = elem->val_expr; break; - default: assert(0); break; } + if (! expr) + break; value_t value; expr->compute(value, details); switch (value.type) { @@ -631,12 +631,7 @@ void export_journal() .def_readonly("sources", &journal_t::sources) .def("__len__", entries_len) -#if 0 .def("__getitem__", entries_getitem, return_internal_reference<1>()) -#else - .def("__getitem__", entries_getitem, - return_value_policy<reference_existing_object>()) -#endif .def("add_account", &journal_t::add_account) .def("remove_account", &journal_t::remove_account) .def("find_account", py_find_account_1, return_internal_reference<1>()) @@ -474,10 +474,10 @@ value_expr_t * parse_value_term(std::istream& in) node.reset(new value_expr_t(value_expr_t::F_VALUE)); if (peek_next_nonws(in) == '(') { in.get(c); - node->left = parse_value_expr(in); + node->left = parse_value_expr(in, true); if (peek_next_nonws(in) == ',') { in.get(c); - node->right = parse_value_expr(in); + node->right = parse_value_expr(in, true); } if (peek_next_nonws(in) == ')') in.get(c); @@ -527,12 +527,12 @@ value_expr_t * parse_value_term(std::istream& in) in.get(c); node.reset(new value_expr_t(value_expr_t::F_INTERP_FUNC)); node->constant_s = buf; - node->right = parse_value_expr(in); + node->right = parse_value_expr(in, true); break; } case '(': - node.reset(parse_value_expr(in)); + node.reset(parse_value_expr(in, true)); if (peek_next_nonws(in) == ')') in.get(c); else @@ -687,7 +687,7 @@ value_expr_t * parse_logic_expr(std::istream& in) return node.release(); } -value_expr_t * parse_value_expr(std::istream& in) +value_expr_t * parse_value_expr(std::istream& in, const bool partial) { std::auto_ptr<value_expr_t> node(parse_logic_expr(in)); @@ -738,6 +738,20 @@ value_expr_t * parse_value_expr(std::istream& in) } } + if (! partial) { + char c; + in.get(c); + if (! node.get()) { + if (in.eof()) + throw value_expr_error(std::string("Failed to parse value expression")); + else + throw value_expr_error(std::string("Unexpected character '") + c + "'"); + } else if (! in.eof()) { + throw value_expr_error(std::string("Unexpected character '") + + c + "'"); + } + } + return node.release(); } @@ -915,11 +929,16 @@ value_t py_compute(value_expr_t& value_expr, const T& item) return result; } -value_expr_t * py_parse_value_expr(const std::string& str) +value_expr_t * py_parse_value_expr_1(const std::string& str) { return parse_value_expr(str); } +value_expr_t * py_parse_value_expr_2(const std::string& str, const bool partial) +{ + return parse_value_expr(str, partial); +} + void export_valexpr() { class_< details_t > ("Details", init<const entry_t&>()) @@ -943,7 +962,9 @@ void export_valexpr() .def("compute", py_compute<transaction_t>) ; - def("parse_value_expr", py_parse_value_expr, + def("parse_value_expr", py_parse_value_expr_1, + return_value_policy<manage_new_object>()); + def("parse_value_expr", py_parse_value_expr_2, return_value_policy<manage_new_object>()); class_< item_predicate<transaction_t> > @@ -120,15 +120,18 @@ struct value_expr_t void compute(value_t& result, const details_t& details) const; }; -value_expr_t * parse_value_expr(std::istream& in); +value_expr_t * parse_value_expr(std::istream& in, + const bool partial = false); -inline value_expr_t * parse_value_expr(const char * p) { +inline value_expr_t * parse_value_expr(const char * p, + const bool partial = false) { std::istringstream stream(p); - return parse_value_expr(stream); + return parse_value_expr(stream, partial); } -inline value_expr_t * parse_value_expr(const std::string& str) { - return parse_value_expr(str.c_str()); +inline value_expr_t * parse_value_expr(const std::string& str, + const bool partial = false) { + return parse_value_expr(str.c_str(), partial); } #ifdef DEBUG_ENABLED @@ -361,6 +361,8 @@ void walk_accounts(account_t& account, { if (! sort_string.empty()) { std::auto_ptr<value_expr_t> sort_order(parse_value_expr(sort_string)); + if (! sort_order.get()) + throw error(std::string("Sort string failed to parse: " + sort_string)); walk_accounts(account, handler, sort_order.get()); } else { walk_accounts(account, handler); @@ -182,8 +182,15 @@ class sort_transactions : public item_handler<transaction_t> sort_transactions(item_handler<transaction_t> * handler, const std::string& _sort_order) - : item_handler<transaction_t>(handler), - sort_order(parse_value_expr(_sort_order)), allocated(true) {} + : item_handler<transaction_t>(handler), allocated(true) { + try { + sort_order = parse_value_expr(_sort_order); + } + catch (value_expr_error& err) { + throw value_expr_error(std::string("In sort string '") + _sort_order + + "': " + err.what()); + } + } virtual ~sort_transactions() { assert(sort_order); |