Did more work on the utility code.

This commit is contained in:
John Wiegley 2007-04-30 11:22:08 +00:00
parent 3ba6c2572d
commit 21af83013f
42 changed files with 980 additions and 970 deletions

View file

@ -79,10 +79,11 @@ if USE_PCH
libledger_la_CXXFLAGS = $(WARNFLAGS) libledger_la_CXXFLAGS = $(WARNFLAGS)
nodist_libledger_la_SOURCES = system.hh.gch nodist_libledger_la_SOURCES = system.hh.gch
BUILT_SOURCES += system.hh.gch BUILT_SOURCES += system.hh.gch system.hh
CLEANFILES += system.hh.gch CLEANFILES += system.hh.gch system.hh
$(top_builddir)/system.hh.gch: $(srcdir)/src/system.hh acconf.h $(top_builddir)/system.hh.gch: $(srcdir)/src/system.hh acconf.h
echo "#include \"src/system.hh\"" > $(top_builddir)/system.hh
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(libledger_la_CPPFLAGS) \ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(libledger_la_CPPFLAGS) \
-o $@ $(srcdir)/src/system.hh -o $@ $(srcdir)/src/system.hh
endif endif
@ -103,7 +104,6 @@ pkginclude_HEADERS = \
src/csv.h \ src/csv.h \
src/derive.h \ src/derive.h \
src/emacs.h \ src/emacs.h \
src/error.h \
src/fdstream.hpp \ src/fdstream.hpp \
src/format.h \ src/format.h \
src/gnucash.h \ src/gnucash.h \
@ -168,7 +168,8 @@ clean-local:
ledger_so_SOURCES = src/pyledger.cc ledger_so_SOURCES = src/pyledger.cc
ledger_so_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la ledger_so_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la
PYLIBS = pyledger ledger gdtoa boost_date_time boost_regex boost_python gmp PYLIBS = pyledger ledger gdtoa gmp boost_date_time \
boost_filesystem boost_regex boost_python
if HAVE_EXPAT if HAVE_EXPAT
PYLIBS += expat PYLIBS += expat

View file

@ -45,8 +45,8 @@ host_triplet = @host@
@DEBUG_TRUE@am__append_8 = -DFULL_DEBUG @DEBUG_TRUE@am__append_8 = -DFULL_DEBUG
@HAVE_BOOST_PYTHON_TRUE@am__append_9 = -DUSE_BOOST_PYTHON=1 @HAVE_BOOST_PYTHON_TRUE@am__append_9 = -DUSE_BOOST_PYTHON=1
@HAVE_BOOST_PYTHON_TRUE@am__append_10 = src/pyinterp.cc @HAVE_BOOST_PYTHON_TRUE@am__append_10 = src/pyinterp.cc
@USE_PCH_TRUE@am__append_11 = system.hh.gch @USE_PCH_TRUE@am__append_11 = system.hh.gch system.hh
@USE_PCH_TRUE@am__append_12 = system.hh.gch @USE_PCH_TRUE@am__append_12 = system.hh.gch system.hh
bin_PROGRAMS = ledger$(EXEEXT) bin_PROGRAMS = ledger$(EXEEXT)
@HAVE_BOOST_PYTHON_TRUE@am__append_13 = libpyledger.la @HAVE_BOOST_PYTHON_TRUE@am__append_13 = libpyledger.la
@HAVE_BOOST_PYTHON_TRUE@noinst_PROGRAMS = ledger.so$(EXEEXT) @HAVE_BOOST_PYTHON_TRUE@noinst_PROGRAMS = ledger.so$(EXEEXT)
@ -382,7 +382,6 @@ pkginclude_HEADERS = \
src/csv.h \ src/csv.h \
src/derive.h \ src/derive.h \
src/emacs.h \ src/emacs.h \
src/error.h \
src/fdstream.hpp \ src/fdstream.hpp \
src/format.h \ src/format.h \
src/gnucash.h \ src/gnucash.h \
@ -425,8 +424,9 @@ info_TEXINFOS = docs/ledger.texi
dist_lisp_LISP = lisp/ledger.el lisp/timeclock.el dist_lisp_LISP = lisp/ledger.el lisp/timeclock.el
@HAVE_BOOST_PYTHON_TRUE@ledger_so_SOURCES = src/pyledger.cc @HAVE_BOOST_PYTHON_TRUE@ledger_so_SOURCES = src/pyledger.cc
@HAVE_BOOST_PYTHON_TRUE@ledger_so_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la @HAVE_BOOST_PYTHON_TRUE@ledger_so_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la
@HAVE_BOOST_PYTHON_TRUE@PYLIBS = pyledger ledger gdtoa boost_date_time \ @HAVE_BOOST_PYTHON_TRUE@PYLIBS = pyledger ledger gdtoa gmp \
@HAVE_BOOST_PYTHON_TRUE@ boost_regex boost_python gmp \ @HAVE_BOOST_PYTHON_TRUE@ boost_date_time boost_filesystem \
@HAVE_BOOST_PYTHON_TRUE@ boost_regex boost_python \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_15) $(am__append_16) \ @HAVE_BOOST_PYTHON_TRUE@ $(am__append_15) $(am__append_16) \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_17) @HAVE_BOOST_PYTHON_TRUE@ $(am__append_17)
nodist_UnitTests_SOURCES = tests/UnitTests.cc \ nodist_UnitTests_SOURCES = tests/UnitTests.cc \
@ -1737,6 +1737,7 @@ dist-hook:
rm -fr `find $(distdir) -name .svn` rm -fr `find $(distdir) -name .svn`
@USE_PCH_TRUE@$(top_builddir)/system.hh.gch: $(srcdir)/src/system.hh acconf.h @USE_PCH_TRUE@$(top_builddir)/system.hh.gch: $(srcdir)/src/system.hh acconf.h
@USE_PCH_TRUE@ echo "#include \"src/system.hh\"" > $(top_builddir)/system.hh
@USE_PCH_TRUE@ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(libledger_la_CPPFLAGS) \ @USE_PCH_TRUE@ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(libledger_la_CPPFLAGS) \
@USE_PCH_TRUE@ -o $@ $(srcdir)/src/system.hh @USE_PCH_TRUE@ -o $@ $(srcdir)/src/system.hh

78
configure vendored
View file

@ -19613,6 +19613,84 @@ See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
fi fi
# check for boost_filesystem
{ echo "$as_me:$LINENO: checking if boost_filesystem is available" >&5
echo $ECHO_N "checking if boost_filesystem is available... $ECHO_C" >&6; }
if test "${boost_filesystem_cpplib_avail+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
boost_filesystem_save_libs=$LIBS
LIBS="-lboost_filesystem $LIBS"
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <boost/filesystem/path.hpp>
int
main ()
{
boost::filesystem::path this_path("Hello");
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
boost_filesystem_cpplib_avail=true
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
boost_filesystem_cpplib_avail=false
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
LIBS=$boost_filesystem_save_libs
fi
{ echo "$as_me:$LINENO: result: $boost_filesystem_cpplib_avail" >&5
echo "${ECHO_T}$boost_filesystem_cpplib_avail" >&6; }
if test x$boost_filesystem_cpplib_avail = xtrue ; then
LIBS="-lboost_filesystem $LIBS"
else
{ { echo "$as_me:$LINENO: error: \"Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&5
echo "$as_me: error: \"Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; }
fi
# check for gmp # check for gmp
{ echo "$as_me:$LINENO: checking if libgmp is available" >&5 { echo "$as_me:$LINENO: checking if libgmp is available" >&5
echo $ECHO_N "checking if libgmp is available... $ECHO_C" >&6; } echo $ECHO_N "checking if libgmp is available... $ECHO_C" >&6; }

View file

@ -127,6 +127,27 @@ else
AC_MSG_FAILURE("Could not find boost_date_time library (set CPPFLAGS and LDFLAGS?)") AC_MSG_FAILURE("Could not find boost_date_time library (set CPPFLAGS and LDFLAGS?)")
fi fi
# check for boost_filesystem
AC_CACHE_CHECK(
[if boost_filesystem is available],
[boost_filesystem_cpplib_avail],
[boost_filesystem_save_libs=$LIBS
LIBS="-lboost_filesystem $LIBS"
AC_LANG_PUSH(C++)
AC_TRY_LINK(
[#include <boost/filesystem/path.hpp>],
[boost::filesystem::path this_path("Hello");],
[boost_filesystem_cpplib_avail=true],
[boost_filesystem_cpplib_avail=false])
AC_LANG_POP
LIBS=$boost_filesystem_save_libs])
if [test x$boost_filesystem_cpplib_avail = xtrue ]; then
LIBS="-lboost_filesystem $LIBS"
else
AC_MSG_FAILURE("Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)")
fi
# check for gmp # check for gmp
AC_CACHE_CHECK( AC_CACHE_CHECK(
[if libgmp is available], [if libgmp is available],

View file

@ -487,13 +487,12 @@ void amount_t::_clear()
amount_t& amount_t::operator+=(const amount_t& amt) amount_t& amount_t::operator+=(const amount_t& amt)
{ {
if (commodity() != amt.commodity()) { if (commodity() != amt.commodity())
throw amount_exception throw_(amount_error,
(string("Adding amounts with different commodities: ") + "Adding amounts with different commodities: " <<
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " + (has_commodity() ? commodity_->qualified_symbol : "NONE") <<
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"), " != " <<
context()); (amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
}
if (! amt.quantity) if (! amt.quantity)
return *this; return *this;
@ -524,11 +523,11 @@ amount_t& amount_t::operator+=(const amount_t& amt)
amount_t& amount_t::operator-=(const amount_t& amt) amount_t& amount_t::operator-=(const amount_t& amt)
{ {
if (commodity() != amt.commodity()) if (commodity() != amt.commodity())
throw amount_exception throw_(amount_error,
(string("Subtracting amounts with different commodities: ") + "Subtracting amounts with different commodities: " <<
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " + (has_commodity() ? commodity_->qualified_symbol : "NONE") <<
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"), " != " <<
context()); (amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
if (! amt.quantity) if (! amt.quantity)
return *this; return *this;
@ -561,13 +560,12 @@ amount_t& amount_t::operator-=(const amount_t& amt)
amount_t& amount_t::operator*=(const amount_t& amt) amount_t& amount_t::operator*=(const amount_t& amt)
{ {
if (has_commodity() && amt.has_commodity() && if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity()) { commodity() != amt.commodity())
throw amount_exception throw_(amount_error,
(string("Multiplying amounts with different commodities: ") + "Multiplying amounts with different commodities: " <<
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " + (has_commodity() ? commodity_->qualified_symbol : "NONE") <<
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"), " != " <<
context()); (amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
}
if (! amt.quantity) { if (! amt.quantity) {
*this = *this - *this; // preserve our commodity *this = *this - *this; // preserve our commodity
@ -602,16 +600,15 @@ amount_t& amount_t::operator*=(const amount_t& amt)
amount_t& amount_t::operator/=(const amount_t& amt) amount_t& amount_t::operator/=(const amount_t& amt)
{ {
if (has_commodity() && amt.has_commodity() && if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity()) { commodity() != amt.commodity())
throw amount_exception throw_(amount_error,
(string("Dividing amounts with different commodities: ") + "Dividing amounts with different commodities: " <<
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " + (has_commodity() ? commodity_->qualified_symbol : "NONE") <<
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"), " != " <<
context()); (amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
}
if (! amt.quantity || ! amt) { if (! amt.quantity || ! amt) {
throw amount_exception("Divide by zero", context()); throw_(amount_error, "Divide by zero");
} }
else if (! quantity) { else if (! quantity) {
*this = amt; *this = amt;
@ -677,10 +674,9 @@ int amount_t::compare(const amount_t& amt) const
return sign(); return sign();
if (has_commodity() && amt.commodity() && commodity() != amt.commodity()) if (has_commodity() && amt.commodity() && commodity() != amt.commodity())
throw amount_exception throw_(amount_error,
(string("Cannot compare amounts with different commodities: ") + "Cannot compare amounts with different commodities: " <<
commodity().symbol() + " and " + amt.commodity().symbol(), commodity().symbol() << " and " << amt.commodity().symbol());
context());
if (quantity->prec == amt.quantity->prec) { if (quantity->prec == amt.quantity->prec) {
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)); return mpz_cmp(MPZ(quantity), MPZ(amt.quantity));
@ -1139,8 +1135,7 @@ static void parse_commodity(std::istream& in, string& symbol)
if (c == '"') if (c == '"')
in.get(c); in.get(c);
else else
throw amount_exception("Quoted commodity symbol lacks closing quote", throw_(amount_error, "Quoted commodity symbol lacks closing quote");
context());
} else { } else {
READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]); READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]);
} }
@ -1157,15 +1152,14 @@ bool parse_annotations(std::istream& in, amount_t& price,
char c = peek_next_nonws(in); char c = peek_next_nonws(in);
if (c == '{') { if (c == '{') {
if (price) if (price)
throw amount_exception("Commodity specifies more than one price", throw_(amount_error, "Commodity specifies more than one price");
context());
in.get(c); in.get(c);
READ_INTO(in, buf, 255, c, c != '}'); READ_INTO(in, buf, 255, c, c != '}');
if (c == '}') if (c == '}')
in.get(c); in.get(c);
else else
throw amount_exception("Commodity price lacks closing brace", context()); throw_(amount_error, "Commodity price lacks closing brace");
price.parse(buf, AMOUNT_PARSE_NO_MIGRATE); price.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
price.in_place_reduce(); price.in_place_reduce();
@ -1180,32 +1174,28 @@ bool parse_annotations(std::istream& in, amount_t& price,
} }
else if (c == '[') { else if (c == '[') {
if (is_valid_moment(date)) if (is_valid_moment(date))
throw amount_exception("Commodity specifies more than one date", throw_(amount_error, "Commodity specifies more than one date");
context());
in.get(c); in.get(c);
READ_INTO(in, buf, 255, c, c != ']'); READ_INTO(in, buf, 255, c, c != ']');
if (c == ']') if (c == ']')
in.get(c); in.get(c);
else else
throw amount_exception("Commodity date lacks closing bracket", throw_(amount_error, "Commodity date lacks closing bracket");
context());
date = parse_datetime(buf); date = parse_datetime(buf);
has_date = true; has_date = true;
} }
else if (c == '(') { else if (c == '(') {
if (! tag.empty()) if (! tag.empty())
throw amount_exception("Commodity specifies more than one tag", throw_(amount_error, "Commodity specifies more than one tag");
context());
in.get(c); in.get(c);
READ_INTO(in, buf, 255, c, c != ')'); READ_INTO(in, buf, 255, c, c != ')');
if (c == ')') if (c == ')')
in.get(c); in.get(c);
else else
throw amount_exception("Commodity tag lacks closing parenthesis", throw_(amount_error, "Commodity tag lacks closing parenthesis");
context());
tag = buf; tag = buf;
} }
@ -1277,8 +1267,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
} }
if (quant.empty()) if (quant.empty())
throw amount_exception("No quantity specified for amount", throw_(amount_error, "No quantity specified for amount");
context());
_init(); _init();
@ -1926,8 +1915,7 @@ namespace {
const string& tag) const string& tag)
{ {
if (price < 0) if (price < 0)
throw amount_exception("A commodity's price may not be negative", throw_(amount_error, "A commodity's price may not be negative");
context());
std::ostringstream name; std::ostringstream name;
@ -1935,10 +1923,10 @@ namespace {
annotated_commodity_t::write_annotations(name, price, date, tag); annotated_commodity_t::write_annotations(name, price, date, tag);
DEBUG("amounts.commodities", "make_qualified_name for " DEBUG("amounts.commodities", "make_qualified_name for "
<< comm.qualified_symbol << std::endl << comm.qualified_symbol << std::endl
<< " price " << price << " " << " price " << price << " "
<< " date " << date << " " << " date " << date << " "
<< " tag " << tag); << " tag " << tag);
DEBUG("amounts.commodities", "qualified_name is " << name.str()); DEBUG("amounts.commodities", "qualified_name is " << name.str());

View file

@ -749,7 +749,7 @@ inline commodity_t& amount_t::commodity() const {
void parse_conversion(const string& larger_str, void parse_conversion(const string& larger_str,
const string& smaller_str); const string& smaller_str);
DECLARE_EXCEPTION(amount_exception); DECLARE_EXCEPTION(amount_error);
struct compare_amount_commodities { struct compare_amount_commodities {
bool operator()(const amount_t * left, const amount_t * right) const; bool operator()(const amount_t * left, const amount_t * right) const;

View file

@ -15,7 +15,7 @@ amount_t balance_t::amount(const commodity_t& commodity) const
if (temp.amounts.size() == 1) if (temp.amounts.size() == 1)
return temp.amount(commodity); return temp.amount(commodity);
throw_(amount_exception, throw_(amount_error,
"Requested amount of a balance with multiple commodities: " << temp); "Requested amount of a balance with multiple commodities: " << temp);
} }
} }
@ -172,9 +172,7 @@ balance_t& balance_t::operator*=(const balance_t& bal)
if (temp.amounts.size() == 1) if (temp.amounts.size() == 1)
return *this = bal * temp; return *this = bal * temp;
std::ostringstream errmsg; throw_(amount_error, "Cannot multiply two balances: " << temp << " * " << bal);
errmsg << "Cannot multiply two balances: " << temp << " * " << bal;
throw amount_exception(errmsg.str(), context());
} }
} }
@ -209,11 +207,8 @@ balance_t& balance_t::operator*=(const amount_t& amt)
return *this = temp * amt; return *this = temp * amt;
} }
std::ostringstream errmsg; throw_(amount_error, "Attempt to multiply balance by a commodity" <<
errmsg << "Attempt to multiply balance by a commodity" " not found in that balance: " << temp << " * " << amt);
<< " not found in that balance: "
<< temp << " * " << amt;
throw amount_exception(errmsg.str(), context());
} }
} }
return *this; return *this;
@ -222,9 +217,7 @@ balance_t& balance_t::operator*=(const amount_t& amt)
balance_t& balance_t::operator/=(const balance_t& bal) balance_t& balance_t::operator/=(const balance_t& bal)
{ {
if (bal.realzero()) { if (bal.realzero()) {
std::ostringstream errmsg; throw_(amount_error, "Divide by zero: " << *this << " / " << bal);
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
throw amount_exception(errmsg.str(), context());
} }
else if (realzero()) { else if (realzero()) {
return *this = 0L; return *this = 0L;
@ -241,18 +234,15 @@ balance_t& balance_t::operator/=(const balance_t& bal)
if (temp.amounts.size() == 1) if (temp.amounts.size() == 1)
return *this /= temp; return *this /= temp;
std::ostringstream errmsg; throw_(amount_error,
errmsg << "Cannot divide between two balances: " << temp << " / " << bal; "Cannot divide two balances: " << temp << " / " << bal);
throw amount_exception(errmsg.str(), context());
} }
} }
balance_t& balance_t::operator/=(const amount_t& amt) balance_t& balance_t::operator/=(const amount_t& amt)
{ {
if (amt.realzero()) { if (amt.realzero()) {
std::ostringstream errmsg; throw_(amount_error, "Divide by zero: " << *this << " / " << amt);
errmsg << "Attempt to divide by zero: " << *this << " / " << amt;
throw amount_exception(errmsg.str(), context());
} }
else if (realzero()) { else if (realzero()) {
return *this = 0L; return *this = 0L;
@ -280,11 +270,8 @@ balance_t& balance_t::operator/=(const amount_t& amt)
(*temp.amounts.begin()).first == &amt.commodity()) (*temp.amounts.begin()).first == &amt.commodity())
return *this = temp / amt; return *this = temp / amt;
std::ostringstream errmsg; throw_(amount_error, "Attempt to divide balance by a commodity" <<
errmsg << "Attempt to divide balance by a commodity" " not found in that balance: " << temp << " * " << amt);
<< " not found in that balance: "
<< temp << " * " << amt;
throw amount_exception(errmsg.str(), context());
} }
} }
return *this; return *this;
@ -304,7 +291,7 @@ balance_t::operator amount_t() const
if (temp.amounts.size() == 1) if (temp.amounts.size() == 1)
return (*temp.amounts.begin()).second; return (*temp.amounts.begin()).second;
throw_(amount_exception, throw_(amount_error,
"Cannot convert a balance with " << "Cannot convert a balance with " <<
"multiple commodities to an amount: " << temp); "multiple commodities to an amount: " << temp);
} }

View file

@ -6,7 +6,12 @@ namespace ledger {
class context class context
{ {
public: public:
string context; // ex: 'While parsing file "%R" at line %L' string description; // ex: 'While parsing file "%R" at line %L'
explicit context(const string& _description) throw()
: description(_description) {}
virtual ~context() {}
}; };
class file_context : public context class file_context : public context
@ -14,12 +19,25 @@ class file_context : public context
public: public:
path pathname; // ex: ledger.dat path pathname; // ex: ledger.dat
optional<long> linenum_beg; // ex: 1010 uint_least32_t linenum_beg; // ex: 1010
optional<long> linenum_end; // ex: 1010 uint_least32_t linenum_end; // ex: 1010
optional<long> colnum_beg; // ex: 8 uint_least32_t position_beg;
optional<long> colnum_end; // ex: 8 uint_least32_t position_end;
optional<long> position_beg;
optional<long> position_end; optional<uint_least32_t> colnum_beg; // ex: 8
optional<uint_least32_t> colnum_end; // ex: 8
explicit file_context(const path& _pathname,
const uint_least32_t _linenum_beg,
const uint_least32_t _linenum_end,
const uint_least32_t _position_beg,
const uint_least32_t _position_end) throw()
: context(""),
pathname(_pathname),
linenum_beg(_linenum_beg),
linenum_end(_linenum_end),
position_beg(_position_beg),
position_end(_position_end) {}
}; };
class string_context : public context class string_context : public context
@ -27,12 +45,66 @@ class string_context : public context
public: public:
string text; // ex: (The multi-line text of an entry) string text; // ex: (The multi-line text of an entry)
optional<long> linenum_beg_off; // ex: 2 / none means start at beginning optional<uint_least32_t> linenum_beg_off; // ex: 2
optional<long> linenum_end_off; // ex: 2 / none means start at beginning optional<uint_least32_t> linenum_end_off; // ex: 2
optional<long> colnum_beg_off; // ex: 8 / none means start optional<uint_least32_t> colnum_beg_off; // ex: 8
optional<long> colnum_end_off; // ex: 8 / none means start optional<uint_least32_t> colnum_end_off; // ex: 8
}; };
#if 0
class file_context : public error_context
{
protected:
string file;
unsigned long line;
public:
file_context(const string& _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;
}
};
#endif
extern ptr_list<context> context_stack;
#define PUSH_CONTEXT() try {
#define POP_CONTEXT(ctxt) \
} catch (...) { \
context_stack.push_front(new ctxt); \
throw; \
}
} // namespace ledger } // namespace ledger
#endif // _CONTEXT_H #endif // _CONTEXT_H

View file

@ -1,151 +0,0 @@
#ifndef _ERROR_H
#define _ERROR_H
#import "context.h"
namespace ledger {
class exception : public std::exception
{
protected:
string reason;
public:
std::list<context> context_stack;
exception(const string& _reason,
const context& immediate_ctxt) throw()
: reason(_reason) {
EXCEPTION(reason);
push(immediate_ctxt);
}
virtual ~exception() throw() {}
void push(const context& intermediate_ctxt) throw() {
context_stack.push_front(intermediate_ctxt);
}
void write(std::ostream& out) const throw() {
#if 0
for (std::list<context>::const_iterator
i = context_stack.begin();
i != context_stack.end();
i++)
(*i).write(out);
#endif
}
const char * what() const throw() {
return reason.c_str();
}
};
#define DECLARE_EXCEPTION(name) \
class name : public exception { \
public: \
name(const string& _reason, \
const context& immediate_ctxt) throw() \
: exception(_reason, immediate_ctxt) {} \
}
#if 0
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:
string file;
unsigned long line;
public:
file_context(const string& _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 error : public str_exception {
public:
error(const string& _reason, error_context * _ctxt = NULL) throw()
: str_exception(_reason, _ctxt) {}
virtual ~error() throw() {}
};
class fatal : public str_exception {
public:
fatal(const string& _reason, error_context * _ctxt = NULL) throw()
: str_exception(_reason, _ctxt) {}
virtual ~fatal() throw() {}
};
class fatal_assert : public fatal {
public:
fatal_assert(const string& _reason, error_context * _ctxt = NULL) throw()
: fatal(string("assertion failed '") + _reason + "'", _ctxt) {}
virtual ~fatal_assert() throw() {}
};
#endif // 0
inline void unexpected(char c, char wanted)
{
#if 0
if ((unsigned char) c == 0xff) {
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 + "'");
}
#endif
}
} // namespace ledger
#endif // _ERROR_H

View file

@ -1,5 +1,7 @@
#include "format.h" #include "format.h"
#if 0
#include "pyinterp.h" #include "pyinterp.h"
#endif
namespace ledger { namespace ledger {
@ -85,7 +87,7 @@ void format_t::parse(const string& fmt)
if (current->max_width != -1 && current->min_width != -1 && if (current->max_width != -1 && current->min_width != -1 &&
current->max_width < current->min_width) current->max_width < current->min_width)
throw_(format_exception, "Maximum width is less than the minimum width"); throw_(format_error, "Maximum width is less than the minimum width");
switch (*p) { switch (*p) {
case '|': case '|':
@ -107,7 +109,7 @@ void format_t::parse(const string& fmt)
p++; p++;
} }
if (*p != close) if (*p != close)
throw_(format_exception, "Missing '" << close << "'"); throw_(format_error, "Missing '" << close << "'");
if (open == '{') { if (open == '{') {
assert(! current->xpath); assert(! current->xpath);

View file

@ -101,7 +101,7 @@ class format_t
} }
}; };
DECLARE_EXCEPTION(format_exception); DECLARE_EXCEPTION(format_error);
} // namespace ledger } // namespace ledger

View file

@ -341,7 +341,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * msg = XML_ErrorString(XML_GetErrorCode(parser)); const char * msg = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser); XML_ParserFree(parser);
throw_(parse_exception, msg); throw_(parse_error, msg);
} }
if (! have_error.empty()) { if (! have_error.empty()) {

View file

@ -199,7 +199,7 @@ bool entry_base_t::finalize()
continue; continue;
if (! empty_allowed) if (! empty_allowed)
throw_(exception, "Only one transaction with null amount allowed per entry"); throw_(std::logic_error, "Only one transaction with null amount allowed per entry");
empty_allowed = false; empty_allowed = false;
// If one transaction gives no value at all, its value will become // If one transaction gives no value at all, its value will become
@ -256,7 +256,7 @@ bool entry_base_t::finalize()
if (balance) { if (balance) {
#if 1 #if 1
throw_(balance_exception, "Entry does not balance"); throw_(balance_error, "Entry does not balance");
#else #else
error * err = error * err =
new balance_error("Entry does not balance", new balance_error("Entry does not balance",

View file

@ -212,7 +212,7 @@ class entry_context : public error_context {
}; };
#endif #endif
DECLARE_EXCEPTION(balance_exception); DECLARE_EXCEPTION(balance_error);
class auto_entry_t : public entry_base_t class auto_entry_t : public entry_base_t

View file

@ -168,7 +168,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
command.reset(def->functor_obj()); command.reset(def->functor_obj());
if (! command.get()) if (! command.get())
throw_(exception, string("Unrecognized command '") + verb + "'"); throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
} }
// Parse the initialization file, which can only be textual; then // Parse the initialization file, which can only be textual; then
@ -201,11 +201,11 @@ static int read_and_report(report_t * report, int argc, char * argv[],
else if (! report->pager.empty()) { else if (! report->pager.empty()) {
status = pipe(pfd); status = pipe(pfd);
if (status == -1) if (status == -1)
throw_(exception, "Failed to create pipe"); throw_(std::logic_error, "Failed to create pipe");
status = fork(); status = fork();
if (status < 0) { if (status < 0) {
throw_(exception, "Failed to fork child process"); throw_(std::logic_error, "Failed to fork child process");
} }
else if (status == 0) { // child else if (status == 0) { // child
const char *arg0; const char *arg0;
@ -378,7 +378,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
// Wait for child to finish // Wait for child to finish
wait(&status); wait(&status);
if (status & 0xffff != 0) if (status & 0xffff != 0)
throw_(exception, "Something went wrong in the pager"); throw_(std::logic_error, "Something went wrong in the pager");
} }
#endif #endif

View file

@ -153,21 +153,21 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
std::auto_ptr<xml::xpath_t::op_t> opt(find_option(scope, name)); std::auto_ptr<xml::xpath_t::op_t> opt(find_option(scope, name));
if (! opt.get()) if (! opt.get())
throw_(option_exception, "illegal option --" << name); throw_(option_error, "illegal option --" << name);
xml::xpath_t::functor_t * def = opt->functor_obj(); xml::xpath_t::functor_t * def = opt->functor_obj();
if (! def) if (! def)
throw_(option_exception, "illegal option --" << name); throw_(option_error, "illegal option --" << name);
if (def->wants_args && value == NULL) { if (def->wants_args && value == NULL) {
value = *++i; value = *++i;
if (value == NULL) if (value == NULL)
throw_(option_exception, "missing option argument for --" << name); throw_(option_error, "missing option argument for --" << name);
} }
process_option(def, scope, value); process_option(def, scope, value);
} }
else if ((*i)[1] == '\0') { else if ((*i)[1] == '\0') {
throw_(option_exception, "illegal option -"); throw_(option_error, "illegal option -");
} }
else { else {
std::list<xml::xpath_t::op_t *> option_queue; std::list<xml::xpath_t::op_t *> option_queue;
@ -176,11 +176,11 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) { for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) {
xml::xpath_t::op_t * opt = find_option(scope, c); xml::xpath_t::op_t * opt = find_option(scope, c);
if (! opt) if (! opt)
throw_(option_exception, "illegal option -" << c); throw_(option_error, "illegal option -" << c);
xml::xpath_t::functor_t * def = opt->functor_obj(); xml::xpath_t::functor_t * def = opt->functor_obj();
if (! def) if (! def)
throw_(option_exception, "illegal option -" << c); throw_(option_error, "illegal option -" << c);
option_queue.push_back(opt); option_queue.push_back(opt);
} }
@ -197,7 +197,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
if (def->wants_args) { if (def->wants_args) {
value = *++i; value = *++i;
if (value == NULL) if (value == NULL)
throw_(option_exception, "missing option argument for -" << throw_(option_error, "missing option argument for -" <<
#if 0 #if 0
def->short_opt def->short_opt
#else #else

View file

@ -15,7 +15,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
xml::xpath_t::scope_t * scope, xml::xpath_t::scope_t * scope,
std::list<string>& args); std::list<string>& args);
DECLARE_EXCEPTION(option_exception); DECLARE_EXCEPTION(option_error);
} // namespace ledger } // namespace ledger

View file

@ -21,7 +21,7 @@ class parser_t
const string * original_file = NULL) = 0; const string * original_file = NULL) = 0;
}; };
DECLARE_EXCEPTION(parse_exception); DECLARE_EXCEPTION(parse_error);
/************************************************************************ /************************************************************************
* *

View file

@ -1,10 +1,12 @@
#include "pyinterp.h" #include "pyinterp.h"
#include "amount.h" #include "amount.h"
using namespace boost::python; #include <boost/python/exception_translator.hpp>
namespace ledger { namespace ledger {
using namespace boost::python;
int py_amount_quantity(amount_t& amount) int py_amount_quantity(amount_t& amount)
{ {
std::ostringstream quant; std::ostringstream quant;
@ -51,7 +53,7 @@ commodity_t * py_find_commodity(const string& symbol)
PyErr_SetString(PyExc_ArithmeticError, err.what()); \ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
} }
EXC_TRANSLATOR(amount_exception) EXC_TRANSLATOR(amount_error)
void export_amount() void export_amount()
{ {
@ -236,10 +238,10 @@ void export_amount()
#endif #endif
; ;
#define EXC_TRANSLATE(type) \ #define EXC_TRANSLATE(type) \
register_exception_translator<type>(&exc_translate_ ## type); register_exception_translator<type>(&exc_translate_ ## type);
EXC_TRANSLATE(amount_exception); EXC_TRANSLATE(amount_error);
} }
} // namespace ledger } // namespace ledger

View file

@ -365,7 +365,7 @@ void export_journal()
; ;
#define EXC_TRANSLATE(type) \ #define EXC_TRANSLATE(type) \
register_exception_translator<type>(&exc_translate_ ## type); register_error_translator<type>(&exc_translate_ ## type);
EXC_TRANSLATE(balance_error); EXC_TRANSLATE(balance_error);
EXC_TRANSLATE(interval_expr_error); EXC_TRANSLATE(interval_expr_error);

View file

@ -48,13 +48,13 @@ amount_t value_getitem(value_t& val, int i)
switch (val.type) { switch (val.type) {
case value_t::BOOLEAN: case value_t::BOOLEAN:
throw_(value_exception, "Cannot cast a boolean to an amount"); throw_(value_error, "Cannot cast a boolean to an amount");
case value_t::INTEGER: case value_t::INTEGER:
return long(val); return long(val);
case value_t::DATETIME: case value_t::DATETIME:
throw_(value_exception, "Cannot cast a date/time to an amount"); throw_(value_error, "Cannot cast a date/time to an amount");
case value_t::AMOUNT: case value_t::AMOUNT:
return *((amount_t *) val.data); return *((amount_t *) val.data);
@ -66,13 +66,13 @@ amount_t value_getitem(value_t& val, int i)
return balance_pair_getitem(*((balance_pair_t *) val.data), i); return balance_pair_getitem(*((balance_pair_t *) val.data), i);
case value_t::STRING: case value_t::STRING:
throw_(value_exception, "Cannot cast a string to an amount"); throw_(value_error, "Cannot cast a string to an amount");
case value_t::XML_NODE: case value_t::XML_NODE:
return (*(xml::node_t **) data)->to_value(); return (*(xml::node_t **) data)->to_value();
case value_t::POINTER: case value_t::POINTER:
throw_(value_exception, "Cannot cast a pointer to an amount"); throw_(value_error, "Cannot cast a pointer to an amount");
case value_t::SEQUENCE: case value_t::SEQUENCE:
return (*(value_t::sequence_t **) val.data)[i]; return (*(value_t::sequence_t **) val.data)[i];

View file

@ -69,7 +69,7 @@ void export_xpath()
; ;
#define EXC_TRANSLATE(type) \ #define EXC_TRANSLATE(type) \
register_exception_translator<type>(&exc_translate_ ## type); register_error_translator<type>(&exc_translate_ ## type);
EXC_TRANSLATE(xpath_t_error); EXC_TRANSLATE(xpath_t_error);
EXC_TRANSLATE(calc_error); EXC_TRANSLATE(calc_error);

View file

@ -1,7 +1,6 @@
#include "pyinterp.h" #include "pyinterp.h"
#include <boost/python/module_init.hpp> #include <boost/python/module_init.hpp>
#include <boost/python/exception_translator.hpp>
namespace ledger { namespace ledger {
@ -37,7 +36,7 @@ object python_interpreter_t::import(const string& str)
try { try {
PyObject * mod = PyImport_Import(PyString_FromString(str.c_str())); PyObject * mod = PyImport_Import(PyString_FromString(str.c_str()));
if (! mod) if (! mod)
throw_(exception, "Failed to import Python module " << str); throw_(std::logic_error, "Failed to import Python module " << str);
object newmod(handle<>(borrowed(mod))); object newmod(handle<>(borrowed(mod)));
@ -52,7 +51,7 @@ object python_interpreter_t::import(const string& str)
} }
catch (const error_already_set&) { catch (const error_already_set&) {
PyErr_Print(); PyErr_Print();
throw_(exception, "Importing Python module " << str); throw_(std::logic_error, "Importing Python module " << str);
} }
} }
@ -86,7 +85,7 @@ object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
} }
catch (const error_already_set&) { catch (const error_already_set&) {
PyErr_Print(); PyErr_Print();
throw_(exception, "Evaluating Python code"); throw_(std::logic_error, "Evaluating Python code");
} }
} }
@ -104,7 +103,7 @@ object python_interpreter_t::eval(const string& str, py_eval_mode_t mode)
} }
catch (const error_already_set&) { catch (const error_already_set&) {
PyErr_Print(); PyErr_Print();
throw_(exception, "Evaluating Python code"); throw_(std::logic_error, "Evaluating Python code");
} }
} }
@ -132,7 +131,7 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
} }
else if (PyObject * err = PyErr_Occurred()) { else if (PyObject * err = PyErr_Occurred()) {
PyErr_Print(); PyErr_Print();
throw_(xml::xpath_t::calc_exception, throw_(xml::xpath_t::calc_error,
"While calling Python function '" << name() << "'"); "While calling Python function '" << name() << "'");
} else { } else {
assert(0); assert(0);
@ -144,7 +143,7 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
} }
catch (const error_already_set&) { catch (const error_already_set&) {
PyErr_Print(); PyErr_Print();
throw_(xml::xpath_t::calc_exception, throw_(xml::xpath_t::calc_error,
"While calling Python function '" << name() << "'"); "While calling Python function '" << name() << "'");
} }
} }
@ -161,7 +160,7 @@ void python_interpreter_t::lambda_t::operator()(value_t& result,
} }
catch (const error_already_set&) { catch (const error_already_set&) {
PyErr_Print(); PyErr_Print();
throw_(xml::xpath_t::calc_exception, throw_(xml::xpath_t::calc_error,
"While evaluating Python lambda expression"); "While evaluating Python lambda expression");
} }
} }

View file

@ -73,7 +73,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
case '\t': case '\t':
if (peek_next_nonws(in) != '\n') { if (peek_next_nonws(in) != '\n') {
get_line(in); get_line(in);
throw_(parse_exception, "Line begins with whitespace"); throw_(parse_error, "Line begins with whitespace");
} }
// fall through... // fall through...
@ -90,7 +90,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
std::strcmp(line, "Type:Cat") == 0 || std::strcmp(line, "Type:Cat") == 0 ||
std::strcmp(line, "Type:Class") == 0 || std::strcmp(line, "Type:Class") == 0 ||
std::strcmp(line, "Type:Memorized") == 0) std::strcmp(line, "Type:Memorized") == 0)
throw_(parse_exception, throw_(parse_error,
"QIF files of type " << line << " are not supported."); "QIF files of type " << line << " are not supported.");
break; break;

View file

@ -55,12 +55,13 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
commodity.history->last_lookup = time_now; commodity.history->last_lookup = time_now;
cache_dirty = true; cache_dirty = true;
if (price && ! price_db.empty()) { if (price) {
assert(! price_db.empty());
#if defined(__GNUG__) && __GNUG__ < 3 #if defined(__GNUG__) && __GNUG__ < 3
std::ofstream database(price_db.c_str(), ios::out | ios::app); ofstream database(price_db, ios::out | ios::app);
#else #else
std::ofstream database(price_db.c_str(), ofstream database(price_db, std::ios_base::out | std::ios_base::app);
std::ios_base::out | std::ios_base::app);
#endif #endif
#if 0 #if 0
// jww (2007-04-18): Need to convert to local time and print // jww (2007-04-18): Need to convert to local time and print
@ -70,10 +71,9 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
#endif #endif
} }
} else { } else {
throw exception(string("Failed to download price for '") + throw_(download_error,
commodity.symbol + "' (command: \"getquote " + "Failed to download price for '" << commodity.symbol <<
commodity.symbol + "\")", "' (command: \"getquote " << commodity.symbol << "\")");
context());
} }
} }

View file

@ -7,12 +7,12 @@ namespace ledger {
class quotes_by_script : public commodity_base_t::updater_t class quotes_by_script : public commodity_base_t::updater_t
{ {
string price_db; path price_db;
time_duration pricing_leeway; time_duration pricing_leeway;
bool& cache_dirty; bool& cache_dirty;
public: public:
quotes_by_script(string _price_db, quotes_by_script(path _price_db,
time_duration _pricing_leeway, time_duration _pricing_leeway,
bool& _cache_dirty) bool& _cache_dirty)
: price_db(_price_db), pricing_leeway(_pricing_leeway), : price_db(_price_db), pricing_leeway(_pricing_leeway),
@ -25,6 +25,8 @@ class quotes_by_script : public commodity_base_t::updater_t
amount_t& price); amount_t& price);
}; };
DECLARE_EXCEPTION(download_error);
} // namespace ledger } // namespace ledger
#endif // _QUOTES_H #endif // _QUOTES_H

View file

@ -22,7 +22,7 @@ void report_t::apply_transforms(xml::document_t * document)
void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals) void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals)
{ {
if (locals->args.size() < 2) if (locals->args.size() < 2)
throw_(exception, "usage: abbrev(STRING, WIDTH [, STYLE, ABBREV_LEN])"); throw_(std::logic_error, "usage: abbrev(STRING, WIDTH [, STYLE, ABBREV_LEN])");
string str = locals->args[0].to_string(); string str = locals->args[0].to_string();
long wid = locals->args[1]; long wid = locals->args[1];
@ -41,7 +41,7 @@ void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals)
void report_t::ftime(value_t&, xml::xpath_t::scope_t * locals) void report_t::ftime(value_t&, xml::xpath_t::scope_t * locals)
{ {
if (locals->args.size() < 1) if (locals->args.size() < 1)
throw_(exception, "usage: ftime(DATE [, DATE_FORMAT])"); throw_(std::logic_error, "usage: ftime(DATE [, DATE_FORMAT])");
moment_t date = locals->args[0].to_datetime(); moment_t date = locals->args[0].to_datetime();

View file

@ -19,20 +19,21 @@ unsigned int session_t::read_journal(std::istream& in,
return 0; return 0;
} }
unsigned int session_t::read_journal(const string& path, unsigned int session_t::read_journal(const string& pathname,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string * original_file) const string * original_file)
{ {
journal->sources.push_back(path); journal->sources.push_back(pathname);
if (access(path.c_str(), R_OK) == -1) if (access(pathname.c_str(), R_OK) == -1)
throw_(exception, "Cannot read file '" << path << "'"); throw filesystem_error(BOOST_CURRENT_FUNCTION, pathname,
"Cannot read file");
if (! original_file) if (! original_file)
original_file = &path; original_file = &pathname;
std::ifstream stream(path.c_str()); std::ifstream stream(pathname.c_str());
return read_journal(stream, journal, master, original_file); return read_journal(stream, journal, master, original_file);
} }
@ -42,7 +43,8 @@ void session_t::read_init()
return; return;
if (access(init_file.c_str(), R_OK) == -1) if (access(init_file.c_str(), R_OK) == -1)
throw_(exception, "Cannot read init file '" << init_file << "'"); throw filesystem_error(BOOST_CURRENT_FUNCTION, init_file,
"Cannot read init file");
std::ifstream init(init_file.c_str()); std::ifstream init(init_file.c_str());
@ -88,7 +90,7 @@ journal_t * session_t::read_data(const string& master_account)
if (! journal->price_db.empty() && if (! journal->price_db.empty() &&
access(journal->price_db.c_str(), R_OK) != -1) { access(journal->price_db.c_str(), R_OK) != -1) {
if (read_journal(journal->price_db, journal)) { if (read_journal(journal->price_db, journal)) {
throw_(exception, "Entries not allowed in price history file"); throw_(parse_error, "Entries not allowed in price history file");
} else { } else {
DEBUG("ledger.cache", "read price database " << journal->price_db); DEBUG("ledger.cache", "read price database " << journal->price_db);
journal->sources.pop_back(); journal->sources.pop_back();
@ -111,7 +113,7 @@ journal_t * session_t::read_data(const string& master_account)
VERIFY(journal->valid()); VERIFY(journal->valid());
if (entry_count == 0) if (entry_count == 0)
throw_(exception, "Failed to locate any journal entries; " throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?"); "did you specify a valid file with -f?");
TRACE_STOP(parser, 1); TRACE_STOP(parser, 1);

View file

@ -21,6 +21,7 @@
#include <algorithm> #include <algorithm>
#include <exception> #include <exception>
#include <stdexcept>
#include <iostream> #include <iostream>
#include <streambuf> #include <streambuf>
#include <iomanip> #include <iomanip>
@ -96,4 +97,16 @@ extern "C" {
#include <libofx.h> #include <libofx.h>
#endif #endif
#include <boost/algorithm/string/predicate.hpp>
#include <boost/any.hpp>
#include <boost/current_function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/optional.hpp>
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/regex.hpp>
#endif // _SYSTEM_HH #endif // _SYSTEM_HH

View file

@ -167,47 +167,47 @@ transaction_t * parse_transaction(char * line,
if (amount && *amount) { if (amount && *amount) {
std::istringstream in(amount); std::istringstream in(amount);
try { PUSH_CONTEXT();
// jww (2006-09-15): Make sure it doesn't gobble up the upcoming @ symbol
unsigned long beg = (long)in.tellg(); // jww (2006-09-15): Make sure it doesn't gobble up the upcoming @ symbol
xact->amount.parse(in, AMOUNT_PARSE_NO_REDUCE); unsigned long beg = (long)in.tellg();
char c; xact->amount.parse(in, AMOUNT_PARSE_NO_REDUCE);
if (! in.eof() && (c = peek_next_nonws(in)) != '@' &&
c != ';' && ! in.eof()) {
in.seekg(beg, std::ios::beg);
if (xact->entry) { char c;
// Create a report item for this entry, so the transaction if (! in.eof() && (c = peek_next_nonws(in)) != '@' &&
// below may refer to it c != ';' && ! in.eof()) {
in.seekg(beg, std::ios::beg);
if (! xact->entry->data) if (xact->entry) {
xact->entry->data = xml::wrap_node(journal->document, xact->entry, // Create a report item for this entry, so the transaction
journal->document->top); // below may refer to it
xact->data = xml::wrap_node(journal->document, xact.get(), if (! xact->entry->data)
xact->entry->data); xact->entry->data = xml::wrap_node(journal->document, xact->entry,
} journal->document->top);
parse_amount_expr(in, journal, *xact, xact->amount, xact->data = xml::wrap_node(journal->document, xact.get(),
XPATH_PARSE_NO_REDUCE); xact->entry->data);
if (xact->entry) {
delete static_cast<xml::transaction_node_t *>(xact->data);
xact->data = NULL;
}
unsigned long end = (long)in.tellg();
xact->amount_expr = string(line, beg, end - beg);
} }
parse_amount_expr(in, journal, *xact, xact->amount,
XPATH_PARSE_NO_REDUCE);
if (xact->entry) {
delete static_cast<xml::transaction_node_t *>(xact->data);
xact->data = NULL;
}
unsigned long end = (long)in.tellg();
xact->amount_expr = string(line, beg, end - beg);
} }
catch (exception& err) {
err_desc = "While parsing transaction amount:"; // jww (2007-04-30): This should be a string context, or perhaps a
throw; // file context
} POP_CONTEXT(context("While parsing transaction amount"));
// Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST) // Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST)
@ -228,27 +228,25 @@ transaction_t * parse_transaction(char * line,
if (in.good() && ! in.eof()) { if (in.good() && ! in.eof()) {
xact->cost = new amount_t; xact->cost = new amount_t;
try { PUSH_CONTEXT();
unsigned long beg = (long)in.tellg();
xact->cost->parse(in); unsigned long beg = (long)in.tellg();
unsigned long end = (long)in.tellg(); xact->cost->parse(in);
if (per_unit) unsigned long end = (long)in.tellg();
xact->cost_expr = (string("@") +
string(amount, beg, end - beg)); if (per_unit)
else xact->cost_expr = (string("@") +
xact->cost_expr = (string("@@") + string(amount, beg, end - beg));
string(amount, beg, end - beg)); else
} xact->cost_expr = (string("@@") +
catch (exception& err) { string(amount, beg, end - beg));
err_desc = "While parsing transaction cost:";
throw; POP_CONTEXT(context("While parsing transaction cost"));
}
if (*xact->cost < 0) if (*xact->cost < 0)
throw_(parse_exception, "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); amount_t per_unit_cost(*xact->cost);
if (per_unit) if (per_unit)
@ -514,7 +512,7 @@ static inline void parse_symbol(char *& p, string& symbol)
if (*p == '"') { if (*p == '"') {
char * q = std::strchr(p + 1, '"'); char * q = std::strchr(p + 1, '"');
if (! q) if (! q)
throw_(parse_exception, "Quoted commodity symbol lacks closing quote"); throw_(parse_error, "Quoted commodity symbol lacks closing quote");
symbol = string(p + 1, 0, q - p - 1); symbol = string(p + 1, 0, q - p - 1);
p = q + 2; p = q + 2;
} else { } else {
@ -526,7 +524,7 @@ static inline void parse_symbol(char *& p, string& symbol)
p += symbol.length(); p += symbol.length();
} }
if (symbol.empty()) if (symbol.empty())
throw_(parse_exception, "Failed to parse commodity"); throw_(parse_error, "Failed to parse commodity");
} }
bool textual_parser_t::test(std::istream& in) const bool textual_parser_t::test(std::istream& in) const
@ -536,9 +534,9 @@ bool textual_parser_t::test(std::istream& in) const
in.read(buf, 5); in.read(buf, 5);
if (std::strncmp(buf, "<?xml", 5) == 0) { if (std::strncmp(buf, "<?xml", 5) == 0) {
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
throw_(parse_exception, "Ledger file contains XML data, but format was not recognized"); throw_(parse_error, "Ledger file contains XML data, but format was not recognized");
#else #else
throw_(parse_exception, "Ledger file contains XML data, but no XML support present"); throw_(parse_error, "Ledger file contains XML data, but no XML support present");
#endif #endif
} }
@ -560,10 +558,10 @@ static void clock_out_from_timelog(const moment_t& when,
time_entries.clear(); time_entries.clear();
} }
else if (time_entries.empty()) { else if (time_entries.empty()) {
throw_(parse_exception, "Timelog check-out event without a check-in"); throw_(parse_error, "Timelog check-out event without a check-in");
} }
else if (! account) { else if (! account) {
throw_(parse_exception, throw_(parse_error,
"When multiple check-ins are active, checking out requires an account"); "When multiple check-ins are active, checking out requires an account");
} }
else { else {
@ -580,7 +578,7 @@ static void clock_out_from_timelog(const moment_t& when,
} }
if (! found) if (! found)
throw_(parse_exception, throw_(parse_error,
"Timelog check-out event does not match any current check-ins"); "Timelog check-out event does not match any current check-ins");
} }
@ -595,7 +593,7 @@ static void clock_out_from_timelog(const moment_t& when,
curr->payee = event.desc; curr->payee = event.desc;
if (curr->_date < event.checkin) if (curr->_date < event.checkin)
throw_(parse_exception, throw_(parse_error,
"Timelog check-out date less than corresponding check-in"); "Timelog check-out date less than corresponding check-in");
char buf[32]; char buf[32];
@ -609,7 +607,7 @@ static void clock_out_from_timelog(const moment_t& when,
curr->add_transaction(xact); curr->add_transaction(xact);
if (! journal->add_entry(curr.get())) if (! journal->add_entry(curr.get()))
throw_(parse_exception, "Failed to record 'out' timelog entry"); throw_(parse_error, "Failed to record 'out' timelog entry");
else else
curr.release(); curr.release();
} }
@ -622,7 +620,6 @@ unsigned int textual_parser_t::parse(std::istream& in,
static bool added_auto_entry_hook = false; static bool added_auto_entry_hook = false;
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
unsigned int count = 0; unsigned int count = 0;
unsigned int errors = 0;
TRACE_START(parsing_total, 1, "Total time spent parsing text:"); TRACE_START(parsing_total, 1, "Total time spent parsing text:");
@ -646,303 +643,290 @@ unsigned int textual_parser_t::parse(std::istream& in,
unsigned long beg_line = linenum; unsigned long beg_line = linenum;
while (in.good() && ! in.eof()) { while (in.good() && ! in.eof()) {
#if 0 in.getline(line, MAX_LINE);
try { if (in.eof())
#endif break;
in.getline(line, MAX_LINE); end_pos = beg_pos + std::strlen(line) + 1;
if (in.eof()) linenum++;
break;
end_pos = beg_pos + std::strlen(line) + 1;
linenum++;
switch (line[0]) { PUSH_CONTEXT();
case '\0':
case '\r':
break;
case ' ': switch (line[0]) {
case '\t': { case '\0':
char * p = skip_ws(line); case '\r':
if (*p && *p != '\r') break;
throw_(parse_exception, "Line begins with whitespace");
break; case ' ':
} case '\t': {
char * p = skip_ws(line);
if (*p && *p != '\r')
throw_(parse_error, "Line begins with whitespace");
break;
}
#ifdef TIMELOG_SUPPORT #ifdef TIMELOG_SUPPORT
case 'i': case 'i':
case 'I': { case 'I': {
string date(line, 2, 19);
char * p = skip_ws(line + 22);
char * n = next_element(p, true);
time_entry_t event;
event.desc = n ? n : "";
event.checkin = parse_datetime(date);
event.account = account_stack.front()->find_account(p);
if (! time_entries.empty())
for (std::list<time_entry_t>::iterator i = time_entries.begin();
i != time_entries.end();
i++)
if (event.account == (*i).account)
throw_(parse_error,
"Cannot double check-in to the same account");
time_entries.push_back(event);
break;
}
case 'o':
case 'O':
if (time_entries.empty()) {
throw_(parse_error, "Timelog check-out event without a check-in");
} else {
string date(line, 2, 19); string date(line, 2, 19);
char * p = skip_ws(line + 22); char * p = skip_ws(line + 22);
char * n = next_element(p, true); char * n = next_element(p, true);
time_entry_t event; clock_out_from_timelog
event.desc = n ? n : ""; (parse_datetime(date),
event.checkin = parse_datetime(date); p ? account_stack.front()->find_account(p) : NULL, n, journal);
event.account = account_stack.front()->find_account(p); count++;
if (! time_entries.empty())
for (std::list<time_entry_t>::iterator i = time_entries.begin();
i != time_entries.end();
i++)
if (event.account == (*i).account)
throw_(parse_exception,
"Cannot double check-in to the same account");
time_entries.push_back(event);
break;
} }
break;
case 'o':
case 'O':
if (time_entries.empty()) {
throw_(parse_exception, "Timelog check-out event without a check-in");
} else {
string date(line, 2, 19);
char * p = skip_ws(line + 22);
char * n = next_element(p, true);
clock_out_from_timelog
(parse_datetime(date),
p ? account_stack.front()->find_account(p) : NULL, n, journal);
count++;
}
break;
#endif // TIMELOG_SUPPORT #endif // TIMELOG_SUPPORT
case 'D': { // a default commodity for "entry" case 'D': { // a default commodity for "entry"
amount_t amt(skip_ws(line + 1)); amount_t amt(skip_ws(line + 1));
commodity_t::default_commodity = &amt.commodity(); commodity_t::default_commodity = &amt.commodity();
break; break;
}
case 'A': // a default account for unbalanced xacts
journal->basket =
account_stack.front()->find_account(skip_ws(line + 1));
break;
case 'C': // a set of conversions
if (char * p = std::strchr(line + 1, '=')) {
*p++ = '\0';
parse_conversion(line + 1, p);
}
break;
case 'P': { // a pricing entry
char * date_field_ptr = skip_ws(line + 1);
char * time_field_ptr = next_element(date_field_ptr);
if (! time_field_ptr) break;
string date_field = date_field_ptr;
char * symbol_and_price;
moment_t datetime;
if (std::isdigit(time_field_ptr[0])) {
symbol_and_price = next_element(time_field_ptr);
if (! symbol_and_price) break;
datetime = parse_datetime(date_field + " " + time_field_ptr);
} else {
symbol_and_price = time_field_ptr;
datetime = parse_datetime(date_field);
} }
case 'A': // a default account for unbalanced xacts string symbol;
journal->basket = parse_symbol(symbol_and_price, symbol);
account_stack.front()->find_account(skip_ws(line + 1)); amount_t price(symbol_and_price);
break;
case 'C': // a set of conversions if (commodity_t * commodity = commodity_t::find_or_create(symbol))
if (char * p = std::strchr(line + 1, '=')) { commodity->add_price(datetime, price);
*p++ = '\0'; break;
parse_conversion(line + 1, p); }
}
break;
case 'P': { // a pricing entry case 'N': { // don't download prices
char * date_field_ptr = skip_ws(line + 1); char * p = skip_ws(line + 1);
char * time_field_ptr = next_element(date_field_ptr); string symbol;
if (! time_field_ptr) break; parse_symbol(p, symbol);
string date_field = date_field_ptr;
char * symbol_and_price; if (commodity_t * commodity = commodity_t::find_or_create(symbol))
moment_t datetime; commodity->add_flags(COMMODITY_STYLE_NOMARKET);
break;
}
if (std::isdigit(time_field_ptr[0])) { case 'Y': // set current year
symbol_and_price = next_element(time_field_ptr);
if (! symbol_and_price) break;
datetime = parse_datetime(date_field + " " + time_field_ptr);
} else {
symbol_and_price = time_field_ptr;
datetime = parse_datetime(date_field);
}
string symbol;
parse_symbol(symbol_and_price, symbol);
amount_t price(symbol_and_price);
if (commodity_t * commodity = commodity_t::find_or_create(symbol))
commodity->add_price(datetime, price);
break;
}
case 'N': { // don't download prices
char * p = skip_ws(line + 1);
string symbol;
parse_symbol(p, symbol);
if (commodity_t * commodity = commodity_t::find_or_create(symbol))
commodity->add_flags(COMMODITY_STYLE_NOMARKET);
break;
}
case 'Y': // set current year
#if 0 #if 0
// jww (2007-04-18): Need to set this up again // jww (2007-04-18): Need to set this up again
date_t::current_year = std::atoi(skip_ws(line + 1)); date_t::current_year = std::atoi(skip_ws(line + 1));
#endif #endif
break; break;
#ifdef TIMELOG_SUPPORT #ifdef TIMELOG_SUPPORT
case 'h': case 'h':
case 'b': case 'b':
#endif #endif
case ';': // comment case ';': // comment
break; break;
case '-': // option setting case '-': // option setting
throw_(parse_exception, "Option settings are not allowed in journal files"); throw_(parse_error, "Option settings are not allowed in journal files");
case '=': { // automated entry case '=': { // automated entry
if (! added_auto_entry_hook) { if (! added_auto_entry_hook) {
journal->add_entry_finalizer(&auto_entry_finalizer); journal->add_entry_finalizer(&auto_entry_finalizer);
added_auto_entry_hook = true; added_auto_entry_hook = true;
}
auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1));
if (parse_transactions(in, journal, account_stack.front(), *ae,
"automated", end_pos)) {
journal->auto_entries.push_back(ae);
ae->src_idx = src_idx;
ae->beg_pos = beg_pos;
ae->beg_line = beg_line;
ae->end_pos = end_pos;
ae->end_line = linenum;
}
break;
} }
case '~': { // period entry std::auto_ptr<auto_entry_t> ae(new auto_entry_t(skip_ws(line + 1)));
period_entry_t * pe = new period_entry_t(skip_ws(line + 1)); if (parse_transactions(in, journal, account_stack.front(), *ae,
if (! pe->period) "automated", end_pos)) {
throw_(parse_exception, string("Parsing time period '") + skip_ws(line + 1) + "'"); ae->src_idx = src_idx;
ae->beg_pos = beg_pos;
if (parse_transactions(in, journal, account_stack.front(), *pe, ae->beg_line = beg_line;
"period", end_pos)) { ae->end_pos = end_pos;
if (pe->finalize()) { ae->end_line = linenum;
extend_entry_base(journal, *pe, true); journal->auto_entries.push_back(ae.release());
journal->period_entries.push_back(pe);
pe->src_idx = src_idx;
pe->beg_pos = beg_pos;
pe->beg_line = beg_line;
pe->end_pos = end_pos;
pe->end_line = linenum;
} else {
throw_(parse_exception, "Period entry failed to balance");
}
}
break;
} }
break;
}
case '@': case '~': { // period entry
case '!': { // directive std::auto_ptr<period_entry_t> pe(new period_entry_t(skip_ws(line + 1)));
char * p = next_element(line); if (! pe->period)
string word(line + 1); throw_(parse_error, string("Parsing time period '") + skip_ws(line + 1) + "'");
if (word == "include") {
push_var<string> save_path(pathname);
push_var<unsigned int> save_src_idx(src_idx);
push_var<unsigned long> save_beg_pos(beg_pos);
push_var<unsigned long> save_end_pos(end_pos);
push_var<unsigned int> save_linenum(linenum);
pathname = p; if (parse_transactions(in, journal, account_stack.front(), *pe,
if (pathname[0] != '/' && pathname[0] != '\\' && "period", end_pos)) {
pathname[0] != '~') { if (pe->finalize()) {
string::size_type pos = save_path.prev.rfind('/'); extend_entry_base(journal, *pe, true);
if (pos == string::npos) pe->src_idx = src_idx;
pos = save_path.prev.rfind('\\'); pe->beg_pos = beg_pos;
if (pos != string::npos) pe->beg_line = beg_line;
pathname = string(save_path.prev, 0, pos + 1) + pathname; pe->end_pos = end_pos;
} pe->end_line = linenum;
pathname = resolve_path(pathname); journal->period_entries.push_back(pe.release());
} else {
DEBUG("ledger.textual.include", "line " << linenum << ": " << throw_(parse_error, "Period entry failed to balance");
"Including path '" << pathname << "'");
include_stack.push_back(std::pair<string, int>
(journal->sources.back(), linenum - 1));
count += journal->session->read_journal(pathname, journal,
account_stack.front());
include_stack.pop_back();
} }
else if (word == "account") { }
account_t * acct; break;
acct = account_stack.front()->find_account(p); }
case '@':
case '!': { // directive
char * p = next_element(line);
string word(line + 1);
if (word == "include") {
push_var<string> save_path(pathname);
push_var<unsigned int> save_src_idx(src_idx);
push_var<unsigned long> save_beg_pos(beg_pos);
push_var<unsigned long> save_end_pos(end_pos);
push_var<unsigned int> save_linenum(linenum);
pathname = p;
if (pathname[0] != '/' && pathname[0] != '\\' &&
pathname[0] != '~') {
string::size_type pos = save_path.prev.rfind('/');
if (pos == string::npos)
pos = save_path.prev.rfind('\\');
if (pos != string::npos)
pathname = string(save_path.prev, 0, pos + 1) + pathname;
}
pathname = resolve_path(pathname);
DEBUG("ledger.textual.include", "line " << linenum << ": " <<
"Including path '" << pathname << "'");
include_stack.push_back(std::pair<string, int>
(journal->sources.back(), linenum - 1));
count += journal->session->read_journal(pathname, journal,
account_stack.front());
include_stack.pop_back();
}
else if (word == "account") {
if (account_t * acct = account_stack.front()->find_account(p))
account_stack.push_front(acct); account_stack.push_front(acct);
} else
else if (word == "end") { ; // jww (2007-04-30): throw an error here
account_stack.pop_front(); }
} else if (word == "end") {
else if (word == "alias") { account_stack.pop_front();
char * b = p; }
if (char * e = std::strchr(b, '=')) { else if (word == "alias") {
char * z = e - 1; char * b = p;
while (std::isspace(*z)) if (char * e = std::strchr(b, '=')) {
*z-- = '\0'; char * z = e - 1;
*e++ = '\0'; while (std::isspace(*z))
e = skip_ws(e); *z-- = '\0';
*e++ = '\0';
e = skip_ws(e);
// Once we have an alias name (b) and the target account // Once we have an alias name (b) and the target account
// name (e), add a reference to the account in the // name (e), add a reference to the account in the
// `account_aliases' map, which is used by the transaction // `account_aliases' map, which is used by the transaction
// parser to resolve alias references. // parser to resolve alias references.
account_t * acct = account_stack.front()->find_account(e); if (account_t * acct = account_stack.front()->find_account(e)) {
std::pair<accounts_map::iterator, bool> result std::pair<accounts_map::iterator, bool> result
= account_aliases.insert(accounts_pair(b, acct)); = account_aliases.insert(accounts_pair(b, acct));
assert(result.second); assert(result.second);
}
}
else if (word == "def" || word == "eval") {
// jww (2006-09-13): Read the string after and evaluate it.
// But also keep a list of these value expressions, and a
// way to know where they fall in the transaction sequence.
// This will be necessary so that binary file reading can
// re-evaluate them at the appopriate time.
// compile(&journal->defs);
}
break;
}
default: {
//unsigned int first_line = linenum;
unsigned long pos = end_pos;
TRACE_START(entries, 1, "Time spent handling entries:");
if (entry_t * entry = parse_entry(in, line, journal,
account_stack.front(),
*this, pos)) {
if (journal->add_entry(entry)) {
entry->src_idx = src_idx;
entry->beg_pos = beg_pos;
entry->beg_line = beg_line;
entry->end_pos = end_pos;
entry->end_line = linenum;
count++;
} else { } else {
delete entry; ; // jww (2007-04-30): throw an error here
throw_(parse_exception, "Entry does not balance");
} }
} else {
throw_(parse_exception, "Failed to parse entry");
} }
TRACE_STOP(entries, 1);
end_pos = pos;
break;
} }
} else if (word == "def" || word == "eval") {
#if 0 // jww (2006-09-13): Read the string after and evaluate it.
} // But also keep a list of these value expressions, and a
catch (error * err) { // way to know where they fall in the transaction sequence.
for (std::list<std::pair<string, int> >::reverse_iterator i = // This will be necessary so that binary file reading can
include_stack.rbegin(); // re-evaluate them at the appopriate time.
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));
std::cout.flush(); // compile(&journal->defs);
if (errors > 0 && err->context.size() > 1) }
std::cerr << std::endl; break;
err->reveal_context(std::cerr, "Error");
std::cerr << err->what() << std::endl;
delete err;
errors++;
} }
#endif
beg_pos = end_pos; default: {
TRACE_START(entries, 1, "Time spent handling entries:");
std::auto_ptr<entry_t> entry
(parse_entry(in, line, journal, account_stack.front(),
*this, end_pos));
if (entry.get()) {
entry->src_idx = src_idx;
entry->beg_pos = beg_pos;
entry->beg_line = beg_line;
entry->end_pos = end_pos;
entry->end_line = linenum;
if (journal->add_entry(entry.get())) {
entry.release();
count++;
} else {
throw_(parse_error, "Entry does not balance");
}
} else {
throw_(parse_error, "Failed to parse entry");
}
TRACE_STOP(entries, 1);
break;
}
}
POP_CONTEXT(file_context(pathname, beg_line, linenum,
beg_pos, end_pos));
beg_pos = end_pos;
beg_line = linenum;
} }
if (! time_entries.empty()) { if (! time_entries.empty()) {
@ -956,9 +940,6 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (added_auto_entry_hook) if (added_auto_entry_hook)
journal->remove_entry_finalizer(&auto_entry_finalizer); journal->remove_entry_finalizer(&auto_entry_finalizer);
if (errors > 0)
throw (int)errors;
TRACE_STOP(parsing_total, 1); TRACE_STOP(parsing_total, 1);
return count; return count;

View file

@ -28,7 +28,7 @@ inline bool is_valid_moment(const moment_t& moment) {
extern const moment_t& now; extern const moment_t& now;
DECLARE_EXCEPTION(datetime_exception); DECLARE_EXCEPTION(datetime_error);
class interval_t class interval_t
{ {

View file

@ -10,6 +10,8 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(assertion_failed);
void debug_assert(const string& reason, void debug_assert(const string& reason,
const string& func, const string& func,
const string& file, const string& file,
@ -18,7 +20,7 @@ void debug_assert(const string& reason,
std::ostringstream buf; std::ostringstream buf;
buf << "Assertion failed in \"" << file << "\", line " << line buf << "Assertion failed in \"" << file << "\", line " << line
<< ": " << reason; << ": " << reason;
throw exception(buf.str(), context()); throw assertion_failed(buf.str());
} }
} // namespace ledger } // namespace ledger
@ -618,6 +620,7 @@ void finish_timer(const char * name)
namespace ledger { namespace ledger {
std::ostringstream _exc_buffer; std::ostringstream _exc_buffer;
ptr_list<context> context_stack;
} // namespace ledger } // namespace ledger

View file

@ -9,24 +9,13 @@
*/ */
namespace ledger { namespace ledger {
#if ! defined(USE_BOOST_PYTHON) using namespace boost;
#if defined(VERIFY_ON) && ! defined(USE_BOOST_PYTHON)
class string; class string;
#else #else
typedef std::string string; typedef std::string string;
#endif #endif
}
// jww (2007-04-30): These Boost includes can go into system.hh as
// soon as GCC fixes it's problem with pre-compiled headers and global
// variables defined in unnamed namespaces.
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/optional.hpp>
#include <boost/regex.hpp>
namespace ledger {
using namespace boost;
typedef posix_time::ptime ptime; typedef posix_time::ptime ptime;
typedef ptime::time_duration_type time_duration; typedef ptime::time_duration_type time_duration;
@ -35,6 +24,9 @@ namespace ledger {
typedef posix_time::seconds seconds; typedef posix_time::seconds seconds;
typedef filesystem::path path; typedef filesystem::path path;
typedef boost::filesystem::ifstream ifstream;
typedef boost::filesystem::ofstream ofstream;
typedef boost::filesystem::filesystem_error filesystem_error;
} }
/********************************************************************** /**********************************************************************
@ -71,8 +63,6 @@ namespace ledger {
#endif #endif
#if defined(ASSERTS_ON) #if defined(ASSERTS_ON)
#include <boost/current_function.hpp>
namespace ledger { namespace ledger {
void debug_assert(const string& reason, const string& func, void debug_assert(const string& reason, const string& func,
const string& file, unsigned long line); const string& file, unsigned long line);
@ -247,11 +237,7 @@ extern unsigned int _trace_level;
extern std::string _log_category; extern std::string _log_category;
inline bool category_matches(const char * cat) { inline bool category_matches(const char * cat) {
return (_log_category == cat || return starts_with(_log_category, cat);
(std::strlen(cat) > _log_category.size() + 1 &&
std::strncmp(cat, _log_category.c_str(),
_log_category.size()) == 0 &&
cat[_log_category.size()] == '.'));
} }
#define SHOW_DEBUG(cat) \ #define SHOW_DEBUG(cat) \
@ -403,21 +389,44 @@ void finish_timer(const char * name);
* Exception handling * Exception handling
*/ */
#include "error.h" #include "context.h"
namespace ledger { namespace ledger {
#define DECLARE_EXCEPTION(name) \
class name : public std::logic_error { \
public: \
name(const string& why) throw() : std::logic_error(why) {} \
}
extern std::ostringstream _exc_buffer; extern std::ostringstream _exc_buffer;
template <typename T> template <typename T>
inline void throw_func(const std::string& message) { inline void throw_func(const std::string& message) {
_exc_buffer.str(""); _exc_buffer.str("");
throw T(message, context()); throw T(message);
} }
#define throw_(cls, msg) \ #define throw_(cls, msg) \
((_exc_buffer << msg), throw_func<cls>(_exc_buffer.str())) ((_exc_buffer << msg), throw_func<cls>(_exc_buffer.str()))
inline void throw_unexpected_error(char c, char wanted) {
#if 0
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 + "'");
}
#endif
}
} // namespace ledger } // namespace ledger
/********************************************************************** /**********************************************************************

File diff suppressed because it is too large Load diff

View file

@ -573,7 +573,7 @@ class value_context : public error_context
}; };
#endif #endif
DECLARE_EXCEPTION(value_exception); DECLARE_EXCEPTION(value_error);
} // namespace ledger } // namespace ledger

View file

@ -382,14 +382,14 @@ document_t * document_t::parser_t::parse(std::istream& in)
catch (const std::exception& err) { catch (const std::exception& err) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
XML_ParserFree(parser); XML_ParserFree(parser);
throw_(parse_exception, err.what()); throw_(parse_error, err.what());
} }
if (! have_error.empty()) { if (! have_error.empty()) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
#if 0 #if 0
// jww (2007-04-26): What is this doing?? // jww (2007-04-26): What is this doing??
parse_exception err(have_error); parse_error err(have_error);
std::cerr << "Error: " << err.what() << std::endl; std::cerr << "Error: " << err.what() << std::endl;
#endif #endif
have_error = ""; have_error = "";
@ -399,7 +399,7 @@ document_t * document_t::parser_t::parse(std::istream& in)
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * err = XML_ErrorString(XML_GetErrorCode(parser)); const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser); XML_ParserFree(parser);
throw_(parse_exception, err); throw_(parse_error, err);
} }
} }

View file

@ -15,7 +15,7 @@ namespace xml {
#define XML_NODE_IS_PARENT 0x1 #define XML_NODE_IS_PARENT 0x1
DECLARE_EXCEPTION(conversion_exception); DECLARE_EXCEPTION(conversion_error);
class parent_node_t; class parent_node_t;
class document_t; class document_t;
@ -85,7 +85,7 @@ public:
} }
virtual value_t to_value() const { virtual value_t to_value() const {
throw_(conversion_exception, "Cannot convert node to a value"); throw_(conversion_error, "Cannot convert node to a value");
} }
virtual void write(std::ostream& out, int depth = 0) const = 0; virtual void write(std::ostream& out, int depth = 0) const = 0;
@ -255,7 +255,7 @@ class xml_parser_t : public parser_t
const string * original_file = NULL); const string * original_file = NULL);
}; };
DECLARE_EXCEPTION(parse_exception); DECLARE_EXCEPTION(parse_error);
#endif #endif

View file

@ -208,7 +208,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
catch (const std::exception& err) { catch (const std::exception& err) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
XML_ParserFree(parser); XML_ParserFree(parser);
throw_(parse_exception, err.what()); throw_(parse_error, err.what());
} }
if (! have_error.empty()) { if (! have_error.empty()) {
@ -225,7 +225,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * err = XML_ErrorString(XML_GetErrorCode(parser)); const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser); XML_ParserFree(parser);
throw_(parse_exception, err); throw_(parse_error, err);
} }
} }

View file

@ -382,7 +382,7 @@ void xpath_t::token_t::next(std::istream& in, unsigned short flags)
kind = VALUE; kind = VALUE;
value = temp; value = temp;
} }
catch (amount_exception& err) { catch (amount_error& err) {
// If the amount had no commodity, it must be an unambiguous // If the amount had no commodity, it must be an unambiguous
// variable reference // variable reference
@ -414,13 +414,13 @@ void xpath_t::token_t::unexpected()
{ {
switch (kind) { switch (kind) {
case TOK_EOF: case TOK_EOF:
throw_(parse_exception, "Unexpected end of expression"); throw_(parse_error, "Unexpected end of expression");
case IDENT: case IDENT:
throw_(parse_exception, "Unexpected symbol '" << value << "'"); throw_(parse_error, "Unexpected symbol '" << value << "'");
case VALUE: case VALUE:
throw_(parse_exception, "Unexpected value '" << value << "'"); throw_(parse_error, "Unexpected value '" << value << "'");
default: default:
throw_(parse_exception, "Unexpected operator '" << symbol << "'"); throw_(parse_error, "Unexpected operator '" << symbol << "'");
} }
} }
@ -428,15 +428,15 @@ void xpath_t::token_t::unexpected(char c, char wanted)
{ {
if ((unsigned char) c == 0xff) { if ((unsigned char) c == 0xff) {
if (wanted) if (wanted)
throw_(parse_exception, "Missing '" << wanted << "'"); throw_(parse_error, "Missing '" << wanted << "'");
else else
throw_(parse_exception, "Unexpected end"); throw_(parse_error, "Unexpected end");
} else { } else {
if (wanted) if (wanted)
throw_(parse_exception, "Invalid char '" << c << throw_(parse_error, "Invalid char '" << c <<
"' (wanted '" << wanted << "')"); "' (wanted '" << wanted << "')");
else else
throw_(parse_exception, "Invalid char '" << c << "'"); throw_(parse_error, "Invalid char '" << c << "'");
} }
} }
@ -488,7 +488,7 @@ void xpath_t::scope_t::define(const string& name, op_t * def)
std::pair<symbol_map::iterator, bool> result2 std::pair<symbol_map::iterator, bool> result2
= symbols.insert(symbol_pair(name, def)); = symbols.insert(symbol_pair(name, def));
if (! result2.second) if (! result2.second)
throw_(compile_exception, throw_(compile_error,
"Redefinition of '" << name << "' in same scope"); "Redefinition of '" << name << "' in same scope");
} }
def->acquire(); def->acquire();
@ -536,7 +536,7 @@ bool xpath_t::function_scope_t::resolve(const string& name,
if (value->type == value_t::XML_NODE) if (value->type == value_t::XML_NODE)
result.set_string(value->to_xml_node()->text()); result.set_string(value->to_xml_node()->text());
else else
throw_(calc_exception, "Attempt to call text() on a non-node value"); throw_(calc_error, "Attempt to call text() on a non-node value");
return true; return true;
} }
break; break;
@ -604,7 +604,7 @@ void xpath_t::op_t::get_value(value_t& result) const
result = (long)arg_index; result = (long)arg_index;
break; break;
default: default:
throw_(calc_exception, throw_(calc_error,
"Cannot determine value of expression symbol '" << *this << "'"); "Cannot determine value of expression symbol '" << *this << "'");
} }
} }
@ -645,7 +645,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
goto done; goto done;
} }
catch(const boost::python::error_already_set&) { catch(const boost::python::error_already_set&) {
throw_(parse_exception, "Error parsing lambda expression"); throw_(parse_error, "Error parsing lambda expression");
} }
#endif /* USE_BOOST_PYTHON */ #endif /* USE_BOOST_PYTHON */
#endif #endif
@ -689,7 +689,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
case token_t::AT_SYM: case token_t::AT_SYM:
tok = next_token(in, tflags); tok = next_token(in, tflags);
if (tok.kind != token_t::IDENT) if (tok.kind != token_t::IDENT)
throw_(parse_exception, "@ symbol must be followed by attribute name"); throw_(parse_error, "@ symbol must be followed by attribute name");
node.reset(new op_t(op_t::ATTR_NAME)); node.reset(new op_t(op_t::ATTR_NAME));
node->name = new string(tok.value.to_string()); node->name = new string(tok.value.to_string());
@ -727,7 +727,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
case token_t::LPAREN: case token_t::LPAREN:
node.reset(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL)); node.reset(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL));
if (! node.get()) if (! node.get())
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags); tok = next_token(in, tflags);
if (tok.kind != token_t::RPAREN) if (tok.kind != token_t::RPAREN)
@ -766,7 +766,7 @@ xpath_t::parse_predicate_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL)); node->set_right(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL));
if (! node->right) if (! node->right)
throw_(parse_exception, "[ operator not followed by valid expression"); throw_(parse_error, "[ operator not followed by valid expression");
tok = next_token(in, tflags); tok = next_token(in, tflags);
if (tok.kind != token_t::RBRACKET) if (tok.kind != token_t::RBRACKET)
@ -800,7 +800,7 @@ xpath_t::parse_path_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_predicate_expr(in, tflags)); node->set_right(parse_predicate_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, "/ operator not followed by a valid term"); throw_(parse_error, "/ operator not followed by a valid term");
tok = next_token(in, tflags); tok = next_token(in, tflags);
} }
@ -822,7 +822,7 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
case token_t::EXCLAM: { case token_t::EXCLAM: {
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags)); std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
if (! texpr.get()) if (! texpr.get())
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
// A very quick optimization // A very quick optimization
if (texpr->kind == op_t::VALUE) { if (texpr->kind == op_t::VALUE) {
@ -838,7 +838,7 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
case token_t::MINUS: { case token_t::MINUS: {
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags)); std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
if (! texpr.get()) if (! texpr.get())
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
// A very quick optimization // A very quick optimization
if (texpr->kind == op_t::VALUE) { if (texpr->kind == op_t::VALUE) {
@ -855,7 +855,7 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
case token_t::PERCENT: { case token_t::PERCENT: {
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags)); std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
if (! texpr.get()) if (! texpr.get())
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
// A very quick optimization // A very quick optimization
if (texpr->kind == op_t::VALUE) { if (texpr->kind == op_t::VALUE) {
@ -892,7 +892,7 @@ xpath_t::parse_union_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_union_expr(in, tflags)); node->set_right(parse_union_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
} else { } else {
push_token(tok); push_token(tok);
@ -915,7 +915,7 @@ xpath_t::parse_mul_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_mul_expr(in, tflags)); node->set_right(parse_mul_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags); tok = next_token(in, tflags);
@ -941,7 +941,7 @@ xpath_t::parse_add_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_add_expr(in, tflags)); node->set_right(parse_add_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags); tok = next_token(in, tflags);
@ -1011,10 +1011,10 @@ xpath_t::parse_logic_expr(std::istream& in, unsigned short tflags) const
if (! node->right) { if (! node->right) {
if (tok.kind == token_t::PLUS) if (tok.kind == token_t::PLUS)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
else else
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
} }
} }
@ -1036,7 +1036,7 @@ xpath_t::parse_and_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_and_expr(in, tflags)); node->set_right(parse_and_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
} else { } else {
push_token(tok); push_token(tok);
@ -1058,7 +1058,7 @@ xpath_t::parse_or_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_or_expr(in, tflags)); node->set_right(parse_or_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
} else { } else {
push_token(tok); push_token(tok);
@ -1081,14 +1081,14 @@ xpath_t::parse_querycolon_expr(std::istream& in, unsigned short tflags) const
node->set_right(new op_t(op_t::O_COLON)); node->set_right(new op_t(op_t::O_COLON));
node->right->set_left(parse_querycolon_expr(in, tflags)); node->right->set_left(parse_querycolon_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags); tok = next_token(in, tflags);
if (tok.kind != token_t::COLON) if (tok.kind != token_t::COLON)
tok.unexpected(); // jww (2006-09-09): wanted : tok.unexpected(); // jww (2006-09-09): wanted :
node->right->set_right(parse_querycolon_expr(in, tflags)); node->right->set_right(parse_querycolon_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
} else { } else {
push_token(tok); push_token(tok);
@ -1110,7 +1110,7 @@ xpath_t::parse_value_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release()); node->set_left(prev.release());
node->set_right(parse_value_expr(in, tflags)); node->set_right(parse_value_expr(in, tflags));
if (! node->right) if (! node->right)
throw_(parse_exception, throw_(parse_error,
tok.symbol << " operator not followed by argument"); tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags); tok = next_token(in, tflags);
} }
@ -1123,7 +1123,7 @@ xpath_t::parse_value_expr(std::istream& in, unsigned short tflags) const
} }
} }
else if (! (tflags & XPATH_PARSE_PARTIAL)) { else if (! (tflags & XPATH_PARSE_PARTIAL)) {
throw_(parse_exception, "Failed to parse value expression"); throw_(parse_error, "Failed to parse value expression");
} }
return node.release(); return node.release();
@ -1195,7 +1195,7 @@ void xpath_t::op_t::find_values(value_t * context, scope_t * scope,
} }
} }
} else { } else {
throw_(calc_exception, "Recursive path selection on a non-node value"); throw_(calc_error, "Recursive path selection on a non-node value");
} }
} }
} }
@ -1206,7 +1206,7 @@ bool xpath_t::op_t::test_value(value_t * context, scope_t * scope,
xpath_t expr(compile(context, scope, true)); xpath_t expr(compile(context, scope, true));
if (expr->kind != VALUE) if (expr->kind != VALUE)
throw_(calc_exception, "Predicate expression does not yield a constant value"); throw_(calc_error, "Predicate expression does not yield a constant value");
switch (expr->valuep->type) { switch (expr->valuep->type) {
case value_t::INTEGER: case value_t::INTEGER:
@ -1283,25 +1283,25 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
case document_t::PARENT: case document_t::PARENT:
if (context->type != value_t::XML_NODE) if (context->type != value_t::XML_NODE)
throw_(compile_exception, "Referencing parent node from a non-node value"); throw_(compile_error, "Referencing parent node from a non-node value");
else if (context->to_xml_node()->parent) else if (context->to_xml_node()->parent)
return wrap_value(context->to_xml_node()->parent)->acquire(); return wrap_value(context->to_xml_node()->parent)->acquire();
else else
throw_(compile_exception, "Referencing parent node from the root node"); throw_(compile_error, "Referencing parent node from the root node");
case document_t::ROOT: case document_t::ROOT:
if (context->type != value_t::XML_NODE) if (context->type != value_t::XML_NODE)
throw_(compile_exception, "Referencing root node from a non-node value"); throw_(compile_error, "Referencing root node from a non-node value");
else else
return wrap_value(context->to_xml_node()->document->top)->acquire(); return wrap_value(context->to_xml_node()->document->top)->acquire();
case document_t::ALL: { case document_t::ALL: {
if (context->type != value_t::XML_NODE) if (context->type != value_t::XML_NODE)
throw_(compile_exception, "Referencing child nodes from a non-node value"); throw_(compile_error, "Referencing child nodes from a non-node value");
node_t * ptr = context->to_xml_node(); node_t * ptr = context->to_xml_node();
if (! (ptr->flags & XML_NODE_IS_PARENT)) if (! (ptr->flags & XML_NODE_IS_PARENT))
throw_(compile_exception, "Request for child nodes of a leaf node"); throw_(compile_error, "Request for child nodes of a leaf node");
parent_node_t * parent = static_cast<parent_node_t *>(ptr); parent_node_t * parent = static_cast<parent_node_t *>(ptr);
@ -1375,7 +1375,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
if (arg_index < scope->args.to_sequence()->size()) if (arg_index < scope->args.to_sequence()->size())
return wrap_value((*scope->args.to_sequence())[arg_index])->acquire(); return wrap_value((*scope->args.to_sequence())[arg_index])->acquire();
else else
throw_(compile_exception, "Reference to non-existing argument"); throw_(compile_error, "Reference to non-existing argument");
} else { } else {
return acquire(); return acquire();
} }
@ -1659,7 +1659,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
} }
if (lexpr->valuep->type != value_t::STRING) if (lexpr->valuep->type != value_t::STRING)
throw_(compile_exception, "Left operand of mask operator is not a string"); throw_(compile_error, "Left operand of mask operator is not a string");
assert(rexpr->mask); assert(rexpr->mask);
@ -1768,7 +1768,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
return func->compile(context, call_args.get(), resolve); return func->compile(context, call_args.get(), resolve);
} }
else { else {
throw_(calc_exception, "Unknown function name '" << *left->name << "'"); throw_(calc_error, "Unknown function name '" << *left->name << "'");
} }
} }
else if (left->kind == FUNCTOR) { else if (left->kind == FUNCTOR) {
@ -1823,7 +1823,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
i++, index++) { i++, index++) {
assert((*i).type != value_t::SEQUENCE); assert((*i).type != value_t::SEQUENCE);
if ((*i).type != value_t::XML_NODE) if ((*i).type != value_t::XML_NODE)
throw_(compile_exception, "Attempting to apply path selection " throw_(compile_error, "Attempting to apply path selection "
"to non-node(s)"); "to non-node(s)");
function_scope_t xpath_fscope(seq, &(*i), index, scope); function_scope_t xpath_fscope(seq, &(*i), index, scope);
@ -1839,7 +1839,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
} }
default: default:
throw_(compile_exception, "Attempting to apply path selection " throw_(compile_error, "Attempting to apply path selection "
"to non-node(s)"); "to non-node(s)");
} }

View file

@ -14,9 +14,9 @@ public:
static void initialize(); static void initialize();
static void shutdown(); static void shutdown();
DECLARE_EXCEPTION(parse_exception); DECLARE_EXCEPTION(parse_error);
DECLARE_EXCEPTION(compile_exception); DECLARE_EXCEPTION(compile_error);
DECLARE_EXCEPTION(calc_exception); DECLARE_EXCEPTION(calc_error);
#if 0 #if 0
class context : public error_context { class context : public error_context {

View file

@ -339,7 +339,7 @@ void BasicAmountTestCase::testIntegerDivision()
amount_t x1(123L); amount_t x1(123L);
amount_t y1(456L); amount_t y1(456L);
assertThrow(x1 / 0L, amount_exception); assertThrow(x1 / 0L, amount_error);
assertEqual(amount_t(0L), amount_t(0L) / x1); assertEqual(amount_t(0L), amount_t(0L) / x1);
assertEqual(amount_t(0L), 0L / x1); assertEqual(amount_t(0L), 0L / x1);
assertEqual(x1, x1 / 1L); assertEqual(x1, x1 / 1L);
@ -376,7 +376,7 @@ void BasicAmountTestCase::testFractionalDivision()
amount_t x1(123.123); amount_t x1(123.123);
amount_t y1(456.456); amount_t y1(456.456);
assertThrow(x1 / 0L, amount_exception); assertThrow(x1 / 0L, amount_error);
assertEqual(amount_t("0.008121959"), amount_t(1.0) / x1); assertEqual(amount_t("0.008121959"), amount_t(1.0) / x1);
assertEqual(amount_t("0.008121959"), 1.0 / x1); assertEqual(amount_t("0.008121959"), 1.0 / x1);
assertEqual(x1, x1 / 1.0); assertEqual(x1, x1 / 1.0);

View file

@ -232,13 +232,13 @@ void CommodityAmountTestCase::testAddition()
assertEqual(string("$246.90"), (x1 + x1).to_string()); assertEqual(string("$246.90"), (x1 + x1).to_string());
assertEqual(string("$246.91"), (x1 + x2).to_string()); assertEqual(string("$246.91"), (x1 + x2).to_string());
assertThrow(x1 + x0, amount_exception); assertThrow(x1 + x0, amount_error);
assertThrow(x1 + x3, amount_exception); assertThrow(x1 + x3, amount_error);
assertThrow(x1 + x4, amount_exception); assertThrow(x1 + x4, amount_error);
assertThrow(x1 + x5, amount_exception); assertThrow(x1 + x5, amount_error);
assertThrow(x1 + x6, amount_exception); assertThrow(x1 + x6, amount_error);
assertThrow(x1 + 123.45, amount_exception); assertThrow(x1 + 123.45, amount_error);
assertThrow(x1 + 123L, amount_exception); assertThrow(x1 + 123L, amount_error);
assertEqual(amount_t("DM 246.90"), x3 + x3); assertEqual(amount_t("DM 246.90"), x3 + x3);
assertEqual(amount_t("246.90 euro"), x4 + x4); assertEqual(amount_t("246.90 euro"), x4 + x4);
@ -290,13 +290,13 @@ void CommodityAmountTestCase::testSubtraction()
assertEqual(string("$0.00"), (x1 - x1).to_string()); assertEqual(string("$0.00"), (x1 - x1).to_string());
assertEqual(string("$-0.01"), (x1 - x2).to_string()); assertEqual(string("$-0.01"), (x1 - x2).to_string());
assertThrow(x1 - x0, amount_exception); assertThrow(x1 - x0, amount_error);
assertThrow(x1 - x3, amount_exception); assertThrow(x1 - x3, amount_error);
assertThrow(x1 - x4, amount_exception); assertThrow(x1 - x4, amount_error);
assertThrow(x1 - x5, amount_exception); assertThrow(x1 - x5, amount_error);
assertThrow(x1 - x6, amount_exception); assertThrow(x1 - x6, amount_error);
assertThrow(x1 - 123.45, amount_exception); assertThrow(x1 - 123.45, amount_error);
assertThrow(x1 - 123L, amount_exception); assertThrow(x1 - 123L, amount_error);
assertEqual(amount_t("DM 0.00"), x3 - x3); assertEqual(amount_t("DM 0.00"), x3 - x3);
assertEqual(amount_t("DM 23.45"), x3 - amount_t("DM 100.00")); assertEqual(amount_t("DM 23.45"), x3 - amount_t("DM 100.00"));
@ -374,9 +374,9 @@ void CommodityAmountTestCase::testMultiplication()
assertEqual(string("$15200.00"), (x1 * x2).to_string()); assertEqual(string("$15200.00"), (x1 * x2).to_string());
assertEqual(string("$15199.99986168"), (x2 * x1).to_string()); assertEqual(string("$15199.99986168"), (x2 * x1).to_string());
assertThrow(x1 * x3, amount_exception); assertThrow(x1 * x3, amount_error);
assertThrow(x1 * x4, amount_exception); assertThrow(x1 * x4, amount_error);
assertThrow(x1 * x5, amount_exception); assertThrow(x1 * x5, amount_error);
x1 *= amount_t("123.12"); x1 *= amount_t("123.12");
assertEqual(internalAmount("$15158.5344"), x1); assertEqual(internalAmount("$15158.5344"), x1);
@ -410,7 +410,7 @@ void CommodityAmountTestCase::testDivision()
amount_t x4("123.45 euro"); amount_t x4("123.45 euro");
amount_t x5("123.45€"); amount_t x5("123.45€");
assertThrow(x1 / 0L, amount_exception); assertThrow(x1 / 0L, amount_error);
assertEqual(amount_t("$0.00"), 0L / x1); assertEqual(amount_t("$0.00"), 0L / x1);
assertEqual(x1, x1 / 1L); assertEqual(x1, x1 / 1L);
assertEqual(internalAmount("$0.00812216"), 1L / x1); assertEqual(internalAmount("$0.00812216"), 1L / x1);
@ -428,9 +428,9 @@ void CommodityAmountTestCase::testDivision()
assertEqual(string("$1.00"), (x1 / x2).to_string()); assertEqual(string("$1.00"), (x1 / x2).to_string());
assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_string()); assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_string());
assertThrow(x1 / x3, amount_exception); assertThrow(x1 / x3, amount_error);
assertThrow(x1 / x4, amount_exception); assertThrow(x1 / x4, amount_error);
assertThrow(x1 / x5, amount_exception); assertThrow(x1 / x5, amount_error);
x1 /= amount_t("123.12"); x1 /= amount_t("123.12");
assertEqual(internalAmount("$1.00"), x1); assertEqual(internalAmount("$1.00"), x1);