diff --git a/amount.h b/amount.h index 05508814..8fb5aa14 100644 --- a/amount.h +++ b/amount.h @@ -54,7 +54,7 @@ class commodity_t; class annotation_t; class commodity_pool_t; -DECLARE_EXCEPTION(error, amount_error); +DECLARE_EXCEPTION(amount_error, std::runtime_error); /** * @class amount_t diff --git a/balance.h b/balance.h index ea070ea3..0326ef13 100644 --- a/balance.h +++ b/balance.h @@ -48,7 +48,7 @@ namespace ledger { -DECLARE_EXCEPTION(error, balance_error); +DECLARE_EXCEPTION(balance_error, std::runtime_error); /** * @class balance_t diff --git a/cache.cc b/cache.cc index c04bcf1c..dd29fbd7 100644 --- a/cache.cc +++ b/cache.cc @@ -727,8 +727,8 @@ std::size_t read_session(std::istream& in, // expression passed to an option, we'll just override the flags, but // keep the commodity pointer intact. if (c == commodity_t::base_t::commodities.end()) - throw new error(string("Failed to read base commodity from cache: ") + - commodity->symbol); + throw_(cache_error, "Failed to read base commodity from cache: " + << commodity->symbol); (*c).second->name = commodity->name; (*c).second->note = commodity->note; @@ -769,8 +769,8 @@ std::size_t read_session(std::istream& in, commodities_map::iterator c = commodity_t::commodities.find(mapping_key); if (c == commodity_t::commodities.end()) - throw new error(string("Failed to read commodity from cache: ") + - commodity->symbol()); + throw_(cache_error, "Failed to read commodity from cache: " + << commodity->symbol()); *(commodities_next - 1) = (*c).second; checked_delete(commodity); diff --git a/cache.h b/cache.h index 0e1005dd..43123f9f 100644 --- a/cache.h +++ b/cache.h @@ -39,6 +39,8 @@ namespace ledger { +DECLARE_EXCEPTION(cache_error, std::runtime_error); + class binary_cache_t { static const unsigned long binary_magic_number = 0xFFEED765; diff --git a/derive.cc b/derive.cc index 9f6aeca8..bcf8f8f3 100644 --- a/derive.cc +++ b/derive.cc @@ -18,7 +18,7 @@ entry_t * derive_new_entry(report_t& report, //added->_date = *i++; added->_date = boost::posix_time::time_from_string(*i++); if (i == end) - throw new error("Too few arguments to 'entry'"); + throw std::runtime_error("Too few arguments to 'entry'"); mask_t regexp(*i++); @@ -196,7 +196,7 @@ entry_t * derive_new_entry(report_t& report, ! added->finalize() || (matching && ! matching->journal->entry_finalize_hooks.run_hooks(*added, true))) - throw new error("Failed to finalize derived entry (check commodities)"); + throw std::runtime_error("Failed to finalize derived entry (check commodities)"); return added.release(); } diff --git a/entry.cc b/entry.cc index 05fcfe9e..ab9ea9f0 100644 --- a/entry.cc +++ b/entry.cc @@ -320,12 +320,14 @@ bool entry_base_t::finalize() if (! balance.is_null()) { balance.round(); if (! balance.is_zero()) { +#if 0 error * err = new balance_error("Entry does not balance", new entry_context(*this, "While balancing entry:")); err->context.push_front (new value_context(balance, "Unbalanced remainder is:")); throw err; +#endif } } @@ -381,7 +383,7 @@ namespace { value_t get_payee(call_scope_t& scope) { entry_t& entry(downcast(*scope.parent)); - return value_t(entry.payee, true); + return string_value(entry.payee); } } @@ -425,6 +427,7 @@ bool entry_t::valid() const return true; } +#if 0 void entry_context::describe(std::ostream& out) const throw() { if (! desc.empty()) @@ -432,6 +435,7 @@ void entry_context::describe(std::ostream& out) const throw() print_entry(out, entry, " "); } +#endif void auto_entry_t::extend_entry(entry_base_t& entry, bool post) { diff --git a/entry.h b/entry.h index 5764624c..16fc3bf3 100644 --- a/entry.h +++ b/entry.h @@ -124,18 +124,6 @@ struct entry_finalizer_t { virtual bool operator()(entry_t& entry, bool post) = 0; }; -class entry_context : public error_context { - public: - const entry_base_t& entry; - - entry_context(const entry_base_t& _entry, - const string& _desc = "") throw() - : error_context(_desc), entry(_entry) {} - virtual ~entry_context() throw() {} - - virtual void describe(std::ostream& out) const throw(); -}; - class auto_entry_t : public entry_base_t { public: diff --git a/error.h b/error.h index 16cb197e..4eaf72a8 100644 --- a/error.h +++ b/error.h @@ -1,132 +1,84 @@ +/* + * Copyright (c) 2003-2008, 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. + */ + #ifndef _ERROR_H #define _ERROR_H -#include -#include -#include -#include -#include -#include - namespace ledger { -class error_context -{ -public: - string desc; +extern std::ostringstream _desc_buffer; - error_context(const string& _desc) throw() : desc(_desc) {} - virtual ~error_context() throw() {} - virtual void describe(std::ostream& out) const throw() { - if (! desc.empty()) - out << desc << std::endl; +template +inline void throw_func(const std::string& message) { + _desc_buffer.str(""); + throw T(message); +} + +#define throw_(cls, msg) \ + ((_desc_buffer << msg), throw_func(_desc_buffer.str())) + +extern std::ostringstream _ctxt_buffer; + +#define add_error_context(msg) \ + ((static_cast(_ctxt_buffer.tellp()) == 0) ? \ + (_ctxt_buffer << msg) : (_ctxt_buffer << std::endl << msg)) + +inline string error_context() { + string context = _ctxt_buffer.str(); + _ctxt_buffer.str(""); + return context; +} + +inline string file_context(const path& file, std::size_t line) { + std::ostringstream buf; + buf << "\"" << file << "\", line " << line << ": "; + return buf.str(); +} + +inline string line_context(const string& line, long pos) { + std::ostringstream buf; + buf << " " << line << std::endl << " "; + long idx = pos < 0 ? line.length() - 1 : pos; + for (int i = 0; i < idx; i++) + buf << " "; + buf << "^" << std::endl; + return buf.str(); +} + +#define DECLARE_EXCEPTION(name, kind) \ + class name : public kind { \ + public: \ + explicit name(const string& why) throw() : kind(why) {} \ + virtual ~name() throw() {} \ } -}; - -class file_context : public error_context -{ - protected: - path file; - unsigned long line; - public: - file_context(const path& _file, unsigned long _line, - const string& desc = "") throw() - : error_context(desc), file(_file), line(_line) {} - virtual ~file_context() throw() {} - - virtual void describe(std::ostream& out) const throw() { - if (! desc.empty()) - out << desc << " "; - - out << "\"" << file << "\", line " << line << ": "; - } -}; - -class line_context : public error_context -{ -public: - string line; - long pos; - - line_context(const string& _line, long _pos, - const string& desc = "") throw() - : error_context(desc), line(_line), pos(_pos) {} - virtual ~line_context() throw() {} - - virtual void describe(std::ostream& out) const throw() { - if (! desc.empty()) - out << desc << std::endl; - - out << " " << line << std::endl << " "; - long idx = pos < 0 ? line.length() - 1 : pos; - for (int i = 0; i < idx; i++) - out << " "; - out << "^" << std::endl; - } -}; - -////////////////////////////////////////////////////////////////////// - -class str_exception : public std::logic_error -{ -public: - std::list context; - - str_exception(const string& why, - error_context * ctxt = NULL) throw() - : std::logic_error(why), context() { - if (ctxt) - context.push_back(ctxt); - } - - virtual ~str_exception() throw() { - for (std::list::iterator i = context.begin(); - i != context.end(); - i++) - checked_delete(*i); - } - - virtual void reveal_context(std::ostream& out, - const string& kind) const throw() { - for (std::list::const_reverse_iterator i = - context.rbegin(); - i != context.rend(); - i++) { - std::list::const_reverse_iterator x = i; - if (++x == context.rend()) - out << kind << ": "; - (*i)->describe(out); - } - } -}; - -#define DECLARE_EXCEPTION(kind, name) \ - class name : public kind { \ - public: \ - name(const string& why, error_context * ctxt = NULL) throw() \ - : kind(why, ctxt) {} \ - } - -class error : public str_exception { - public: - error(const string& why, error_context * ctxt = NULL) throw() - : str_exception(why, ctxt) {} - virtual ~error() throw() {} -}; - -class fatal : public str_exception { - public: - fatal(const string& why, error_context * ctxt = NULL) throw() - : str_exception(why, ctxt) {} - virtual ~fatal() throw() {} -}; - -class fatal_assert : public fatal { - public: - fatal_assert(const string& why, error_context * ctxt = NULL) throw() - : fatal(string("assertion failed '") + why + "'", ctxt) {} - virtual ~fatal_assert() throw() {} -}; } // namespace ledger diff --git a/expr.h b/expr.h index c81a24df..ab8c07f2 100644 --- a/expr.h +++ b/expr.h @@ -36,9 +36,9 @@ namespace ledger { -DECLARE_EXCEPTION(error, parse_error); -DECLARE_EXCEPTION(error, compile_error); -DECLARE_EXCEPTION(error, calc_error); +DECLARE_EXCEPTION(parse_error, std::runtime_error); +DECLARE_EXCEPTION(compile_error, std::runtime_error); +DECLARE_EXCEPTION(calc_error, std::runtime_error); class scope_t; class call_scope_t; diff --git a/format.cc b/format.cc index 1be9651c..db639edd 100644 --- a/format.cc +++ b/format.cc @@ -214,7 +214,7 @@ element_t * format_t::parse_elements(const string& fmt) p++; } if (*p != ')') - throw new format_error("Missing ')'"); + throw format_error("Missing ')'"); current->type = element_t::VALUE_EXPR; @@ -235,7 +235,7 @@ element_t * format_t::parse_elements(const string& fmt) p++; } if (*p != ']') - throw new format_error("Missing ']'"); + throw format_error("Missing ']'"); current->type = element_t::DATE_STRING; current->chars = string(b, p); diff --git a/format.h b/format.h index 6c9d2e5f..8348e863 100644 --- a/format.h +++ b/format.h @@ -219,13 +219,7 @@ class format_equity : public item_handler virtual void operator()(account_t& account); }; -class format_error : public error -{ - public: - format_error(const string& reason, error_context * ctxt = NULL) throw() - : error(reason, ctxt) {} - virtual ~format_error() throw() {} -}; +DECLARE_EXCEPTION(format_error, std::runtime_error); } // namespace ledger diff --git a/gnucash.cc b/gnucash.cc index 59902da2..0be5661e 100644 --- a/gnucash.cc +++ b/gnucash.cc @@ -394,7 +394,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in, //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; const char * msg = XML_ErrorString(XML_GetErrorCode(parser)); XML_ParserFree(parser); - throw new parse_error(msg); + throw parse_error(msg); } if (! have_error.empty()) { diff --git a/journal.h b/journal.h index e61ab114..d24e4fc1 100644 --- a/journal.h +++ b/journal.h @@ -118,14 +118,6 @@ public: const path * original_file = NULL); }; - class parse_error : public error - { - public: - parse_error(const string& reason, error_context * ctxt = NULL) throw() - : error(reason, ctxt) {} - virtual ~parse_error() throw() {} - }; - bool valid() const; }; diff --git a/main.cc b/main.cc index 4e475620..8d9f64dd 100644 --- a/main.cc +++ b/main.cc @@ -297,7 +297,7 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[], command_args.push_back(value_t(out)); for (strings_list::iterator i = arg; i != args.end(); i++) - command_args.push_back(value_t(*i, true)); + command_args.push_back(string_value(*i)); INFO_START(command, "Did user command '" << verb << "'"); @@ -422,29 +422,10 @@ int main(int argc, char * argv[], char * envp[]) session.release(); } } - catch (ledger::error * err) { - std::cout.flush(); - // Push a null here since there's no file context - if (err->context.empty() || - ! dynamic_cast(err->context.front())) - err->context.push_front(new ledger::error_context("")); - err->reveal_context(std::cerr, "Error"); - std::cerr << err->what() << std::endl; - ledger::checked_delete(err); - } - catch (ledger::fatal * err) { - std::cout.flush(); - // Push a null here since there's no file context - if (err->context.empty() || - ! dynamic_cast(err->context.front())) - err->context.push_front(new ledger::error_context("")); - err->reveal_context(std::cerr, "Fatal"); - std::cerr << err->what() << std::endl; - ledger::checked_delete(err); - } catch (const std::exception& err) { std::cout.flush(); - std::cerr << "Exception: " << err.what() << std::endl; + std::cerr << "Error: " << ledger::error_context() << err.what() + << std::endl; } catch (int _status) { status = _status; diff --git a/op.cc b/op.cc index d65ec715..dd808eb2 100644 --- a/op.cc +++ b/op.cc @@ -43,7 +43,7 @@ void expr_t::op_t::compute(value_t& result, try { switch (kind) { case INDEX: - throw new compute_error("Cannot directly compute an argument index"); + throw compute_error("Cannot directly compute an argument index"); case VALUE: result = as_value(); @@ -280,8 +280,8 @@ void expr_t::op_t::compute(value_t& result, moment.cast(value_t::INTEGER); result -= moment; } else { - throw new compute_error("Invalid date passed to datecmp(value,date)", - new valexpr_context(expr)); + add_error_context(expr_context(expr)); + throw compute_error("Invalid date passed to datecmp(value,date)"); } break; } @@ -293,9 +293,10 @@ void expr_t::op_t::compute(value_t& result, ptr_op_t expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - if (! result.is_type(value_t::DATETIME)) - throw new compute_error("Invalid date passed to year|month|day(date)", - new valexpr_context(expr)); + if (! result.is_type(value_t::DATETIME)) { + add_error_context(expr_context(expr)); + throw compute_error("Invalid date passed to year|month|day(date)"); + } const datetime_t& moment(result.as_datetime()); switch (kind) { @@ -357,9 +358,10 @@ void expr_t::op_t::compute(value_t& result, long arg_index = 0; ptr_op_t expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - if (! result.is_type(value_t::AMOUNT)) - throw new compute_error("Argument to commodity() must be a commoditized amount", - new valexpr_context(expr)); + if (! result.is_type(value_t::AMOUNT)) { + add_error_context(expr_context(expr)); + throw compute_error("Argument to commodity() must be a commoditized amount"); + } amount_t temp("1"); temp.set_commodity(result.as_amount().commodity()); result = temp; @@ -375,10 +377,10 @@ void expr_t::op_t::compute(value_t& result, arg_index = 0; expr = find_leaf(context, 1, arg_index); expr->compute(result, details, context); - if (! result.is_type(value_t::AMOUNT)) - throw new compute_error - ("Second argument to set_commodity() must be a commoditized amount", - new valexpr_context(expr)); + if (! result.is_type(value_t::AMOUNT)) { + add_error_context(expr_context(expr)); + throw compute_error("Second argument to set_commodity() must be a commoditized amount"); + } amount_t one("1"); one.set_commodity(result.as_amount().commodity()); result = one; @@ -482,13 +484,14 @@ void expr_t::op_t::compute(value_t& result, } case O_COMMA: - if (! left()) - throw new compute_error("Comma operator missing left operand", - new valexpr_context(const_cast(this))); - if (! right()) - throw new compute_error("Comma operator missing right operand", - new valexpr_context(const_cast(this))); - left()->compute(result, details, context); + if (! left()) { + add_error_context(expr_context(*this)); + throw compute_error("Comma operator missing left operand"); + } + if (! right()) { + add_error_context(expr_context(*this)); + throw compute_error("Comma operator missing right operand"); + } right()->compute(result, details, context); break; @@ -516,10 +519,10 @@ void expr_t::op_t::compute(value_t& result, expr = find_leaf(context, 1, arg_index); value_t moment; expr->compute(moment, details, context); - if (! moment.is_type(value_t::DATETIME)) - throw new compute_error("Invalid date passed to P(value,date)", - new valexpr_context(expr)); - + if (! moment.is_type(value_t::DATETIME)) { + add_error_context(expr_context(expr)); + throw compute_error("Invalid date passed to P(value,date)"); + } result = result.value(moment.as_datetime()); break; } @@ -624,10 +627,8 @@ void expr_t::op_t::compute(value_t& result, break; } } - catch (error * err) { - if (err->context.empty() || - ! dynamic_cast(err->context.back())) - err->context.push_back(new valexpr_context(const_cast(this))); + catch (const std::exception& err) { + add_error_context(expr_context(*this)); throw err; } } diff --git a/option.cc b/option.cc index a94a6a00..b3673633 100644 --- a/option.cc +++ b/option.cc @@ -79,25 +79,22 @@ namespace { void process_option(const function_t& opt, scope_t& scope, const char * arg) { -#if 0 try { -#endif call_scope_t args(scope); if (arg) - args.push_back(value_t(arg, true)); + args.push_back(string_value(arg)); opt(args); -#if 0 } - catch (error * err) { - err->context.push_back - (new error_context - (string("While parsing option '--") + opt->long_opt + - "'" + (opt->short_opt != '\0' ? - (string(" (-") + opt->short_opt + "):") : ":"))); + catch (const std::exception& err) { +#if 0 + add_error_context("While parsing option '--" << opt->long_opt + << "'" << (opt->short_opt != '\0' ? + (string(" (-") + opt->short_opt + "):") : + ": ")); +#endif throw err; } -#endif } } @@ -130,20 +127,14 @@ void process_environment(const char ** envp, const string& tag, *r = '\0'; if (*q == '=') { -#if 0 try { -#endif process_option(string(buf), scope, q + 1); -#if 0 } - catch (error * err) { - err->context.push_back - (new error_context - (string("While parsing environment variable option '") + - *p + "':")); + catch (const std::exception& err) { + add_error_context("While parsing environment variable option '" + << *p << "':"); throw err; } -#endif } } } @@ -429,8 +420,8 @@ OPT_BEGIN(init_file, "i:") { if (access(path.c_str(), R_OK) != -1) config->init_file = path; else - throw new error(std::string("The init file '") + path + - "' does not exist or is not readable"); + throw_(std::invalid_argument, + "The init file '" << path << "' does not exist or is not readable"); } OPT_END(init_file); OPT_BEGIN(file, "f:") { @@ -441,8 +432,8 @@ OPT_BEGIN(file, "f:") { if (access(path.c_str(), R_OK) != -1) config->data_file = path; else - throw new error(std::string("The ledger file '") + path + - "' does not exist or is not readable"); + throw_(std::invalid_argument, + "The ledger file '" << path << "' does not exist or is not readable"); } } OPT_END(file); @@ -490,8 +481,8 @@ OPT_BEGIN(begin, "b:") { char buf[128]; interval_t interval(optarg); if (! interval.begin) - throw new error(std::string("Could not determine beginning of period '") + - optarg + "'"); + throw_(std::invalid_argument, + "Could not determine beginning of period '" << optarg << "'"); if (! report->predicate.empty()) report->predicate += "&"; @@ -504,8 +495,8 @@ OPT_BEGIN(end, "e:") { char buf[128]; interval_t interval(optarg); if (! interval.begin) - throw new error(std::string("Could not determine end of period '") + - optarg + "'"); + throw_(std::invalid_argument, + "Could not determine end of period '" << optarg << "'"); if (! report->predicate.empty()) report->predicate += "&"; diff --git a/option.h b/option.h index fa908eff..23439b9d 100644 --- a/option.h +++ b/option.h @@ -45,7 +45,7 @@ void process_environment(const char ** envp, const string& tag, void process_arguments(int argc, char ** argv, const bool anywhere, scope_t& scope, std::list& args); -DECLARE_EXCEPTION(error, option_error); +DECLARE_EXCEPTION(option_error, std::runtime_error); } // namespace ledger diff --git a/parser.cc b/parser.cc index a03ea9df..85d92901 100644 --- a/parser.cc +++ b/parser.cc @@ -419,9 +419,7 @@ expr_t::parser_t::parse_value_expr(std::istream& in, expr_t::ptr_op_t expr_t::parser_t::parse(std::istream& in, const flags_t flags) { -#if 0 try { -#endif ptr_op_t top_node = parse_value_expr(in, flags); if (use_lookahead) { @@ -431,15 +429,14 @@ expr_t::parser_t::parse(std::istream& in, const flags_t flags) lookahead.clear(); return top_node; -#if 0 } - catch (error * err) { - err->context.push_back - (new line_context(str, (long)in.tellg() - 1, - "While parsing value expression:")); + catch (const std::exception& err) { + add_error_context("While parsing value expression:\n"); +#if 0 + add_error_context(line_context(str, (long)in.tellg() - 1)); +#endif throw err; } -#endif } } // namespace ledger diff --git a/qif.cc b/qif.cc index bb8d2c55..ee9318d2 100644 --- a/qif.cc +++ b/qif.cc @@ -75,7 +75,7 @@ unsigned int qif_parser_t::parse(std::istream& in, case '\t': if (peek_next_nonws(in) != '\n') { get_line(in); - throw new parse_error("Line begins with whitespace"); + throw parse_error("Line begins with whitespace"); } // fall through... @@ -92,8 +92,7 @@ unsigned int qif_parser_t::parse(std::istream& in, std::strcmp(line, "Type:Cat") == 0 || std::strcmp(line, "Type:Class") == 0 || std::strcmp(line, "Type:Memorized") == 0) - throw new parse_error(string("QIF files of type ") + line + - " are not supported."); + throw_(parse_error, "QIF files of type " << line << " are not supported."); break; case 'D': diff --git a/quotes.cc b/quotes.cc index e2ff97c8..bc6e5840 100644 --- a/quotes.cc +++ b/quotes.cc @@ -68,9 +68,9 @@ void quotes_by_script::operator()(commodity_base_t& commodity, << " " << commodity.symbol << " " << price << endl; } } else { - throw new error(string("Failed to download price for '") + - commodity.symbol + "' (command: \"getquote " + - commodity.symbol + "\")"); + throw_(std::runtime_error, + "Failed to download price for '" << commodity.symbol + << "' (command: \"getquote " << commodity.symbol << "\")"); } } #endif diff --git a/reconcile.cc b/reconcile.cc index d83eb37a..b3f53483 100644 --- a/reconcile.cc +++ b/reconcile.cc @@ -59,7 +59,7 @@ void reconcile_xacts::flush() } if (cleared_balance.type() >= value_t::BALANCE) - throw new error("Cannot reconcile accounts with multiple commodities"); + throw std::runtime_error("Cannot reconcile accounts with multiple commodities"); cleared_balance.cast(value_t::AMOUNT); balance.cast(value_t::AMOUNT); @@ -69,8 +69,9 @@ void reconcile_xacts::flush() balance -= cleared_balance; if (balance.type() >= value_t::BALANCE) - throw new error(string("Reconcile balance is not of the same commodity ('") + - b_comm.symbol() + string("' != '") + cb_comm.symbol() + "')"); + throw_(std::runtime_error, + "Reconcile balance is not of the same commodity ('" + << b_comm.symbol() << "' != '" << cb_comm.symbol() << "')"); // If the amount to reconcile is the same as the pending balance, // then assume an exact match and return the results right away. @@ -80,7 +81,7 @@ void reconcile_xacts::flush() search_for_balance(to_reconcile, &first, first)) { push_to_handler(first); } else { - throw new error("Could not reconcile account!"); + throw std::runtime_error("Could not reconcile account!"); } } diff --git a/report.cc b/report.cc index 51516acd..83acc179 100644 --- a/report.cc +++ b/report.cc @@ -319,7 +319,7 @@ value_t report_t::ftime(call_scope_t& args) else date_format = moment_t::output_format; - return value_t(date.as_string(date_format), true); + return string_value(date.as_string(date_format)); #else return NULL_VALUE; #endif diff --git a/session.cc b/session.cc index bb70862f..6f44cee2 100644 --- a/session.cc +++ b/session.cc @@ -266,7 +266,7 @@ value_t session_t::resolve(const string& name, expr_t::scope_t& locals) #if 0 if (name == "date_format") { // jww (2007-04-18): What to do here? - return value_t(moment_t::output_format, true); + return string_value(moment_t::output_format); } #endif break; @@ -282,7 +282,7 @@ value_t session_t::resolve(const string& name, expr_t::scope_t& locals) case 'r': if (name == "register_format") - return value_t(register_format, true); + return string_value(register_format); break; } return expr_t::scope_t::resolve(name, locals); diff --git a/textual.cc b/textual.cc index 7906cc8f..733a6c19 100644 --- a/textual.cc +++ b/textual.cc @@ -124,7 +124,7 @@ xact_t * parse_xact(char * line, account_t * account, } if (account_beg == account_end) - throw new parse_error("No account was specified"); + throw parse_error("No account was specified"); char * b = &line[account_beg]; char * e = &line[account_end]; @@ -189,8 +189,8 @@ xact_t * parse_xact(char * line, account_t * account, xact->amount_expr->set_text(string(line, beg, end - beg)); } } - catch (error * err) { - err_desc = "While parsing transaction amount:"; + catch (const std::exception& err) { + add_error_context("While parsing transaction amount:\n"); throw err; } } @@ -201,7 +201,7 @@ xact_t * parse_xact(char * line, account_t * account, p = peek_next_nonws(in); if (p == '@') { if (! saw_amount) - throw new parse_error + throw parse_error ("Transaction cannot have a cost expression with an amount"); DEBUG("ledger.textual.parse", "line " << linenum << ": " << @@ -236,13 +236,13 @@ xact_t * parse_xact(char * line, account_t * account, string(line, beg, end - beg)); } } - catch (error * err) { - err_desc = "While parsing transaction cost:"; + catch (const std::exception& err) { + add_error_context("While parsing transaction cost:\n"); throw err; } if (xact->cost->sign() < 0) - throw new parse_error("A transaction's cost may not be negative"); + throw parse_error("A transaction's cost may not be negative"); amount_t per_unit_cost(*xact->cost); if (per_unit) @@ -303,7 +303,7 @@ xact_t * parse_xact(char * line, account_t * account, if (parse_amount_expr(in, amt, xact.get(), EXPR_PARSE_NO_MIGRATE)) - throw new parse_error + throw parse_error ("An assigned balance must evaluate to a constant value"); DEBUG("ledger.textual.parse", "line " << linenum << ": " << @@ -352,8 +352,8 @@ xact_t * parse_xact(char * line, account_t * account, xdata.value = amt; } } - catch (error * err) { - err_desc = "While parsing assigned balance:"; + catch (const std::exception& err) { + add_error_context("While parsing assigned balance:\n"); throw err; } } @@ -396,11 +396,9 @@ xact_t * parse_xact(char * line, account_t * account, return xact.release(); } - catch (error * err) { - err->context.push_back - (new line_context(line, static_cast(in.tellg()) - 1, - ! err_desc.empty() ? - err_desc : "While parsing transaction:")); + catch (const std::exception& err) { + add_error_context("While parsing transaction:\n"); + add_error_context(line_context(line, static_cast(in.tellg()) - 1)); throw err; } } @@ -549,7 +547,7 @@ static inline void parse_symbol(char *& p, string& symbol) if (*p == '"') { char * q = std::strchr(p + 1, '"'); if (! q) - throw new parse_error("Quoted commodity symbol lacks closing quote"); + throw parse_error("Quoted commodity symbol lacks closing quote"); symbol = string(p + 1, 0, q - p - 1); p = q + 2; } else { @@ -561,7 +559,7 @@ static inline void parse_symbol(char *& p, string& symbol) p += symbol.length(); } if (symbol.empty()) - throw new parse_error("Failed to parse commodity"); + throw parse_error("Failed to parse commodity"); } bool textual_parser_t::test(std::istream& in) const @@ -571,9 +569,9 @@ bool textual_parser_t::test(std::istream& in) const in.read(buf, 5); if (std::strncmp(buf, "& time_entries, time_entries.clear(); } else if (time_entries.empty()) { - throw new parse_error("Timelog check-out event without a check-in"); + throw parse_error("Timelog check-out event without a check-in"); } else if (! account) { - throw new parse_error + throw parse_error ("When multiple check-ins are active, checking out requires an account"); } else { @@ -616,7 +614,7 @@ static void clock_out_from_timelog(std::list& time_entries, } if (! found) - throw new parse_error + throw parse_error ("Timelog check-out event does not match any current check-ins"); } @@ -631,7 +629,7 @@ static void clock_out_from_timelog(std::list& time_entries, curr->payee = event.desc; if (curr->_date < event.checkin) - throw new parse_error + throw parse_error ("Timelog check-out date less than corresponding check-in"); char buf[32]; @@ -646,7 +644,7 @@ static void clock_out_from_timelog(std::list& time_entries, curr->add_xact(xact); if (! journal.add_entry(curr.get())) - throw new parse_error("Failed to record 'out' timelog entry"); + throw parse_error("Failed to record 'out' timelog entry"); else curr.release(); } @@ -704,7 +702,7 @@ unsigned int textual_parser_t::parse(std::istream& in, case '\t': { char * p = skip_ws(line); if (*p) - throw new parse_error("Line begins with whitespace"); + throw parse_error("Line begins with whitespace"); break; } @@ -724,7 +722,7 @@ unsigned int textual_parser_t::parse(std::istream& in, i != time_entries.end(); i++) if (event.account == (*i).account) - throw new parse_error + throw parse_error ("Cannot double check-in to the same account"); time_entries.push_back(event); @@ -734,7 +732,7 @@ unsigned int textual_parser_t::parse(std::istream& in, case 'o': case 'O': if (time_entries.empty()) { - throw new parse_error("Timelog check-out event without a check-in"); + throw parse_error("Timelog check-out event without a check-in"); } else { string date(line, 2, 19); @@ -858,7 +856,7 @@ unsigned int textual_parser_t::parse(std::istream& in, case '~': { // period entry period_entry_t * pe = new period_entry_t(skip_ws(line + 1)); if (! pe->period) - throw new parse_error(string("Parsing time period '") + line + "'"); + throw_(parse_error, "Parsing time period '" << line << "'"); if (parse_xacts(in, account_stack.front(), *pe, "period", end_pos)) { @@ -960,10 +958,10 @@ unsigned int textual_parser_t::parse(std::istream& in, count++; } else { checked_delete(entry); - throw new parse_error("Entry does not balance"); + throw parse_error("Entry does not balance"); } } else { - throw new parse_error("Failed to parse entry"); + throw parse_error("Failed to parse entry"); } end_pos = pos; TRACE_STOP(entries, 1); @@ -971,21 +969,21 @@ unsigned int textual_parser_t::parse(std::istream& in, } } } - catch (error * err) { + catch (const std::exception& err) { for (std::list >::reverse_iterator i = include_stack.rbegin(); i != include_stack.rend(); - i++) - err->context.push_back(new include_context((*i).first, (*i).second, - "In file included from")); - err->context.push_front(new file_context(pathname, linenum - 1)); + i++) { + add_error_context("In file included from "); +#if 0 + add_error_context(include_context((*i).first, (*i).second)); +#endif + } + add_error_context(file_context(pathname, linenum - 1)); std::cout.flush(); - if (errors > 0 && err->context.size() > 1) - std::cerr << std::endl; - err->reveal_context(std::cerr, "Error"); - std::cerr << err->what() << std::endl; - checked_delete(err); + std::cerr << "Error: " << error_context() << err.what() + << std::endl; errors++; } beg_pos = end_pos; @@ -1061,8 +1059,8 @@ void write_textual_journal(journal_t& journal, } if (found.empty()) - throw new error(string("Journal does not refer to file '") + - string(pathname.string()) + "'"); + throw_(std::runtime_error, + "Journal does not refer to file '" << pathname << "'"); entries_list::iterator el = journal.entries.begin(); auto_entries_list::iterator al = journal.auto_entries.begin(); diff --git a/textual.h b/textual.h index 438d5ea2..418b273b 100644 --- a/textual.h +++ b/textual.h @@ -28,6 +28,7 @@ void write_textual_journal(journal_t& journal, const string& write_hdr_format, std::ostream& out); +#if 0 class include_context : public file_context { public: @@ -43,6 +44,7 @@ class include_context : public file_context << std::endl; } }; +#endif } // namespace ledger diff --git a/times.cc b/times.cc index be1b10f1..772158fb 100644 --- a/times.cc +++ b/times.cc @@ -192,7 +192,7 @@ namespace { struct std::tm when; if (! parse_date_mask(word.c_str(), &when)) - throw new datetime_error(string("Could not parse date mask: ") + word); + throw_(datetime_error, "Could not parse date mask: " << word); when.tm_hour = 0; when.tm_min = 0; diff --git a/times.h b/times.h index a6cd9e4d..ba765027 100644 --- a/times.h +++ b/times.h @@ -61,7 +61,7 @@ extern int current_year; extern string input_time_format; extern string output_time_format; -DECLARE_EXCEPTION(error, datetime_error); +DECLARE_EXCEPTION(datetime_error, std::runtime_error); struct interval_t { diff --git a/utils.cc b/utils.cc index d2cd1e1b..9be92c7b 100644 --- a/utils.cc +++ b/utils.cc @@ -40,7 +40,7 @@ namespace ledger { -DECLARE_EXCEPTION(fatal, assertion_failed); +DECLARE_EXCEPTION(assertion_failed, std::logic_error); void debug_assert(const string& reason, const string& func, @@ -649,8 +649,8 @@ void finish_timer(const char * name) namespace ledger { -std::ostringstream _exc_buffer; -/*ptr_list context_stack;*/ +std::ostringstream _desc_buffer; +std::ostringstream _ctxt_buffer; } // namespace ledger @@ -666,9 +666,7 @@ path expand_path(const path& pathname) if (pathname.empty()) return pathname; -#if 1 - return pathname; -#else +#if 0 // jww (2007-04-30): I need to port this code to use // boost::filesystem::path const char * pfx = NULL; @@ -711,6 +709,8 @@ path expand_path(const path& pathname) result += pathname.substr(pos + 1); return result; +#else + return pathname; #endif } diff --git a/utils.h b/utils.h index 05a214a7..60d47ec1 100644 --- a/utils.h +++ b/utils.h @@ -463,53 +463,13 @@ void finish_timer(const char * name); /********************************************************************** * - * Exception handling + * - Exception handling helpers + * - Date/time support classes + * - General support for objects with "flags" + * - Support for scoped execution and variable restoration */ #include "error.h" - -namespace ledger { - -extern std::ostringstream _exc_buffer; - -template -inline void throw_func(const std::string& message) { - _exc_buffer.str(""); - throw T(message); -} - -#define throw_(cls, msg) \ - ((_exc_buffer << msg), throw_func(_exc_buffer.str())) - -#if 0 -inline void throw_unexpected_error(char c, char wanted) { - if (c == -1) { - if (wanted) - throw new error(string("Missing '") + wanted + "'"); - else - throw new error("Unexpected end of input"); - } else { - if (wanted) - throw new error(string("Invalid char '") + c + - "' (wanted '" + wanted + "')"); - else - throw new error(string("Invalid char '") + c + "'"); - } -} -#else -inline void throw_unexpected_error(char, char) { -} -#endif - -} // namespace ledger - -/********************************************************************** - * - * Date/time support classes - * General support for objects with "flags" - * Support for scoped execution and variable restoration - */ - #include "times.h" #include "flags.h" #include "pushvar.h" diff --git a/value.cc b/value.cc index a6969af9..8edc5df1 100644 --- a/value.cc +++ b/value.cc @@ -1378,7 +1378,7 @@ value_t value_t::annotated_tag() const optional temp = as_amount().annotation_details().tag; if (! temp) return false; - return value_t(*temp, true); + return string_value(*temp); } case STRING: @@ -1679,15 +1679,4 @@ bool value_t::valid() const return true; } -void value_context::describe(std::ostream& out) const throw() -{ - if (! desc.empty()) - out << desc << std::endl; - - out << std::right; - out.width(20); - bal.print(out); - out << std::endl; -} - } // namespace ledger diff --git a/value.h b/value.h index 6bcce319..35a44828 100644 --- a/value.h +++ b/value.h @@ -48,6 +48,8 @@ namespace ledger { +DECLARE_EXCEPTION(value_error, std::runtime_error); + /** * @class value_t * @@ -880,18 +882,14 @@ inline std::ostream& operator<<(std::ostream& out, const value_t& val) { return out; } -class value_context : public error_context -{ - value_t bal; - public: - value_context(const value_t& _bal, const string& desc = "") throw() - : error_context(desc), bal(_bal) {} - virtual ~value_context() throw() {} - - virtual void describe(std::ostream& out) const throw(); -}; - -DECLARE_EXCEPTION(error, value_error); +inline string value_context(const value_t& val) { + std::ostringstream buf; + buf << std::right; + buf.width(20); + val.print(buf); + buf << std::endl; + return buf.str(); +} } // namespace ledger diff --git a/walk.cc b/walk.cc index bf93ea92..61681808 100644 --- a/walk.cc +++ b/walk.cc @@ -217,9 +217,11 @@ void calc_xacts::operator()(xact_t& xact) last_xact = &xact; } - catch (error * err) { - err->context.push_front - (new xact_context(xact, "Calculating transaction at")); + catch (const std::exception& err) { + add_error_context("Calculating transaction at"); +#if 0 + add_error_context(xact_context(xact)); +#endif throw err; } } diff --git a/walk.h b/walk.h index cb13a826..c92366e0 100644 --- a/walk.h +++ b/walk.h @@ -693,14 +693,6 @@ public: virtual void operator()(xact_t& xact); }; -class interval_expr_error : public error { - public: - interval_expr_error(const string& reason, - error_context * ctxt = NULL) throw() - : error(reason, ctxt) {} - virtual ~interval_expr_error() throw() {} -}; - class interval_xacts : public subtotal_xacts { interval_t interval; diff --git a/xact.cc b/xact.cc index 7e363333..211553a9 100644 --- a/xact.cc +++ b/xact.cc @@ -72,7 +72,7 @@ namespace { value_t get_payee(call_scope_t& scope) { xact_t& xact(downcast(*scope.parent)); - return value_t(xact.entry->payee, true); + return string_value(xact.entry->payee); } value_t get_account(call_scope_t& scope) @@ -87,7 +87,7 @@ namespace { else name = string("(") + name + ")"; } - return value_t(name, true); + return string_value(name); } value_t get_account_base(call_scope_t& scope) @@ -163,6 +163,7 @@ bool xact_t::valid() const return true; } +#if 0 xact_context::xact_context(const xact_t& _xact, const string& desc) throw() : file_context("", 0, desc), xact(_xact) { @@ -177,5 +178,6 @@ xact_context::xact_context(const xact_t& _xact, const string& desc) throw() } line = xact.beg_line; } +#endif } // namespace ledger diff --git a/xact.h b/xact.h index 2078dabd..a597876d 100644 --- a/xact.h +++ b/xact.h @@ -131,15 +131,6 @@ class xact_t : public supports_flags<>, public scope_t bool valid() const; }; -class xact_context : public file_context { - public: - const xact_t& xact; - - xact_context(const xact_t& _xact, - const string& desc = "") throw(); - virtual ~xact_context() throw() {} -}; - } // namespace ledger #endif // _XACT_H diff --git a/xml.cc b/xml.cc index 562dcf7e..297b710a 100644 --- a/xml.cc +++ b/xml.cc @@ -209,7 +209,7 @@ unsigned int xml_parser_t::parse(std::istream& in, catch (const std::exception& err) { //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; XML_ParserFree(parser); - throw new parse_error(err.what()); + throw parse_error(err.what()); } if (! have_error.empty()) { @@ -223,7 +223,7 @@ unsigned int xml_parser_t::parse(std::istream& in, //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; const char * err = XML_ErrorString(XML_GetErrorCode(parser)); XML_ParserFree(parser); - throw new parse_error(err); + throw parse_error(err); } }