diff options
author | John Wiegley <johnw@newartisans.com> | 2008-07-31 06:24:45 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-07-31 06:24:45 -0400 |
commit | 99313ebc6c3779f692f9f1bd70cc69a236f5eb78 (patch) | |
tree | 44a553891a9aaa148084d8e011b2d326401343e9 | |
parent | 8afd926a27af55862ce360970e05d747f249a0da (diff) | |
download | fork-ledger-99313ebc6c3779f692f9f1bd70cc69a236f5eb78.tar.gz fork-ledger-99313ebc6c3779f692f9f1bd70cc69a236f5eb78.tar.bz2 fork-ledger-99313ebc6c3779f692f9f1bd70cc69a236f5eb78.zip |
Revised the way that exceptions are thrown around. Instead of context being a
complicated string of pointers, it's now just a global block of text that gets
appended to as the error is being thrown up, and can be displayed at the catch
point if desired. There are almost no cases where a thrown exception will not
result in an error message being displayed to the user.
-rw-r--r-- | amount.h | 2 | ||||
-rw-r--r-- | balance.h | 2 | ||||
-rw-r--r-- | cache.cc | 8 | ||||
-rw-r--r-- | cache.h | 2 | ||||
-rw-r--r-- | derive.cc | 4 | ||||
-rw-r--r-- | entry.cc | 6 | ||||
-rw-r--r-- | entry.h | 12 | ||||
-rw-r--r-- | error.h | 198 | ||||
-rw-r--r-- | expr.h | 6 | ||||
-rw-r--r-- | format.cc | 4 | ||||
-rw-r--r-- | format.h | 8 | ||||
-rw-r--r-- | gnucash.cc | 2 | ||||
-rw-r--r-- | journal.h | 8 | ||||
-rw-r--r-- | main.cc | 25 | ||||
-rw-r--r-- | op.cc | 57 | ||||
-rw-r--r-- | option.cc | 47 | ||||
-rw-r--r-- | option.h | 2 | ||||
-rw-r--r-- | parser.cc | 13 | ||||
-rw-r--r-- | qif.cc | 5 | ||||
-rw-r--r-- | quotes.cc | 6 | ||||
-rw-r--r-- | reconcile.cc | 9 | ||||
-rw-r--r-- | report.cc | 2 | ||||
-rw-r--r-- | session.cc | 4 | ||||
-rw-r--r-- | textual.cc | 82 | ||||
-rw-r--r-- | textual.h | 2 | ||||
-rw-r--r-- | times.cc | 2 | ||||
-rw-r--r-- | times.h | 2 | ||||
-rw-r--r-- | utils.cc | 12 | ||||
-rw-r--r-- | utils.h | 48 | ||||
-rw-r--r-- | value.cc | 13 | ||||
-rw-r--r-- | value.h | 22 | ||||
-rw-r--r-- | walk.cc | 8 | ||||
-rw-r--r-- | walk.h | 8 | ||||
-rw-r--r-- | xact.cc | 6 | ||||
-rw-r--r-- | xact.h | 9 | ||||
-rw-r--r-- | xml.cc | 4 |
36 files changed, 243 insertions, 407 deletions
@@ -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 @@ -48,7 +48,7 @@ namespace ledger { -DECLARE_EXCEPTION(error, balance_error); +DECLARE_EXCEPTION(balance_error, std::runtime_error); /** * @class balance_t @@ -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); @@ -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; @@ -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(); } @@ -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<entry_t>(*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) { @@ -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: @@ -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 <exception> -#include <stdexcept> -#include <string> -#include <cstring> -#include <sstream> -#include <list> - namespace ledger { -class error_context -{ -public: - string desc; - - 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; - } -}; - -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 << ": "; +extern std::ostringstream _desc_buffer; + +template <typename T> +inline void throw_func(const std::string& message) { + _desc_buffer.str(""); + throw T(message); +} + +#define throw_(cls, msg) \ + ((_desc_buffer << msg), throw_func<cls>(_desc_buffer.str())) + +extern std::ostringstream _ctxt_buffer; + +#define add_error_context(msg) \ + ((static_cast<unsigned long>(_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 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<error_context *> 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<error_context *>::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<error_context *>::const_reverse_iterator i = - context.rbegin(); - i != context.rend(); - i++) { - std::list<error_context *>::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 @@ -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; @@ -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); @@ -219,13 +219,7 @@ class format_equity : public item_handler<account_t> 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 @@ -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()) { @@ -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; }; @@ -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<ledger::xact_context *>(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<ledger::xact_context *>(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; @@ -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<op_t *>(this))); - if (! right()) - throw new compute_error("Comma operator missing right operand", - new valexpr_context(const_cast<op_t *>(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<valexpr_context *>(err->context.back())) - err->context.push_back(new valexpr_context(const_cast<op_t *>(this))); + catch (const std::exception& err) { + add_error_context(expr_context(*this)); throw err; } } @@ -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 += "&"; @@ -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<string>& args); -DECLARE_EXCEPTION(error, option_error); +DECLARE_EXCEPTION(option_error, std::runtime_error); } // namespace ledger @@ -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 @@ -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': @@ -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!"); } } @@ -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 @@ -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); @@ -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<unsigned long>(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<unsigned long>(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, "<?xml", 5) == 0) { #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) - throw new parse_error("Ledger file contains XML data, but format was not recognized"); + throw parse_error("Ledger file contains XML data, but format was not recognized"); #else - throw new parse_error("Ledger file contains XML data, but no XML support present"); + throw parse_error("Ledger file contains XML data, but no XML support present"); #endif } @@ -596,10 +594,10 @@ static void clock_out_from_timelog(std::list<time_entry_t>& 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_entry_t>& 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_entry_t>& 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_entry_t>& 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<std::pair<path, int> >::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(); @@ -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 @@ -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; @@ -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 { @@ -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> 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 } @@ -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 <typename T> -inline void throw_func(const std::string& message) { - _exc_buffer.str(""); - throw T(message); -} - -#define throw_(cls, msg) \ - ((_exc_buffer << msg), throw_func<cls>(_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" @@ -1378,7 +1378,7 @@ value_t value_t::annotated_tag() const optional<string> 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 @@ -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 @@ -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; } } @@ -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; @@ -72,7 +72,7 @@ namespace { value_t get_payee(call_scope_t& scope) { xact_t& xact(downcast<xact_t>(*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 @@ -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 @@ -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); } } |