Did more work on the utility code.
This commit is contained in:
parent
3ba6c2572d
commit
21af83013f
42 changed files with 980 additions and 970 deletions
|
|
@ -79,10 +79,11 @@ if USE_PCH
|
|||
libledger_la_CXXFLAGS = $(WARNFLAGS)
|
||||
nodist_libledger_la_SOURCES = system.hh.gch
|
||||
|
||||
BUILT_SOURCES += system.hh.gch
|
||||
CLEANFILES += system.hh.gch
|
||||
BUILT_SOURCES += system.hh.gch system.hh
|
||||
CLEANFILES += system.hh.gch system.hh
|
||||
|
||||
$(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) \
|
||||
-o $@ $(srcdir)/src/system.hh
|
||||
endif
|
||||
|
|
@ -103,7 +104,6 @@ pkginclude_HEADERS = \
|
|||
src/csv.h \
|
||||
src/derive.h \
|
||||
src/emacs.h \
|
||||
src/error.h \
|
||||
src/fdstream.hpp \
|
||||
src/format.h \
|
||||
src/gnucash.h \
|
||||
|
|
@ -168,7 +168,8 @@ clean-local:
|
|||
ledger_so_SOURCES = src/pyledger.cc
|
||||
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
|
||||
PYLIBS += expat
|
||||
|
|
|
|||
11
Makefile.in
11
Makefile.in
|
|
@ -45,8 +45,8 @@ host_triplet = @host@
|
|||
@DEBUG_TRUE@am__append_8 = -DFULL_DEBUG
|
||||
@HAVE_BOOST_PYTHON_TRUE@am__append_9 = -DUSE_BOOST_PYTHON=1
|
||||
@HAVE_BOOST_PYTHON_TRUE@am__append_10 = src/pyinterp.cc
|
||||
@USE_PCH_TRUE@am__append_11 = system.hh.gch
|
||||
@USE_PCH_TRUE@am__append_12 = system.hh.gch
|
||||
@USE_PCH_TRUE@am__append_11 = system.hh.gch system.hh
|
||||
@USE_PCH_TRUE@am__append_12 = system.hh.gch system.hh
|
||||
bin_PROGRAMS = ledger$(EXEEXT)
|
||||
@HAVE_BOOST_PYTHON_TRUE@am__append_13 = libpyledger.la
|
||||
@HAVE_BOOST_PYTHON_TRUE@noinst_PROGRAMS = ledger.so$(EXEEXT)
|
||||
|
|
@ -382,7 +382,6 @@ pkginclude_HEADERS = \
|
|||
src/csv.h \
|
||||
src/derive.h \
|
||||
src/emacs.h \
|
||||
src/error.h \
|
||||
src/fdstream.hpp \
|
||||
src/format.h \
|
||||
src/gnucash.h \
|
||||
|
|
@ -425,8 +424,9 @@ info_TEXINFOS = docs/ledger.texi
|
|||
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_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la
|
||||
@HAVE_BOOST_PYTHON_TRUE@PYLIBS = pyledger ledger gdtoa boost_date_time \
|
||||
@HAVE_BOOST_PYTHON_TRUE@ boost_regex boost_python gmp \
|
||||
@HAVE_BOOST_PYTHON_TRUE@PYLIBS = pyledger ledger gdtoa 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_17)
|
||||
nodist_UnitTests_SOURCES = tests/UnitTests.cc \
|
||||
|
|
@ -1737,6 +1737,7 @@ dist-hook:
|
|||
rm -fr `find $(distdir) -name .svn`
|
||||
|
||||
@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@ -o $@ $(srcdir)/src/system.hh
|
||||
|
||||
|
|
|
|||
78
configure
vendored
78
configure
vendored
|
|
@ -19613,6 +19613,84 @@ See \`config.log' for more details." >&2;}
|
|||
{ (exit 1); exit 1; }; }
|
||||
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
|
||||
{ echo "$as_me:$LINENO: checking if libgmp is available" >&5
|
||||
echo $ECHO_N "checking if libgmp is available... $ECHO_C" >&6; }
|
||||
|
|
|
|||
21
configure.in
21
configure.in
|
|
@ -127,6 +127,27 @@ else
|
|||
AC_MSG_FAILURE("Could not find boost_date_time library (set CPPFLAGS and LDFLAGS?)")
|
||||
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
|
||||
AC_CACHE_CHECK(
|
||||
[if libgmp is available],
|
||||
|
|
|
|||
|
|
@ -487,13 +487,12 @@ void amount_t::_clear()
|
|||
|
||||
amount_t& amount_t::operator+=(const amount_t& amt)
|
||||
{
|
||||
if (commodity() != amt.commodity()) {
|
||||
throw amount_exception
|
||||
(string("Adding amounts with different commodities: ") +
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
|
||||
context());
|
||||
}
|
||||
if (commodity() != amt.commodity())
|
||||
throw_(amount_error,
|
||||
"Adding amounts with different commodities: " <<
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") <<
|
||||
" != " <<
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
|
||||
|
||||
if (! amt.quantity)
|
||||
return *this;
|
||||
|
|
@ -524,11 +523,11 @@ amount_t& amount_t::operator+=(const amount_t& amt)
|
|||
amount_t& amount_t::operator-=(const amount_t& amt)
|
||||
{
|
||||
if (commodity() != amt.commodity())
|
||||
throw amount_exception
|
||||
(string("Subtracting amounts with different commodities: ") +
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
|
||||
context());
|
||||
throw_(amount_error,
|
||||
"Subtracting amounts with different commodities: " <<
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") <<
|
||||
" != " <<
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
|
||||
|
||||
if (! amt.quantity)
|
||||
return *this;
|
||||
|
|
@ -561,13 +560,12 @@ amount_t& amount_t::operator-=(const amount_t& amt)
|
|||
amount_t& amount_t::operator*=(const amount_t& amt)
|
||||
{
|
||||
if (has_commodity() && amt.has_commodity() &&
|
||||
commodity() != amt.commodity()) {
|
||||
throw amount_exception
|
||||
(string("Multiplying amounts with different commodities: ") +
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
|
||||
context());
|
||||
}
|
||||
commodity() != amt.commodity())
|
||||
throw_(amount_error,
|
||||
"Multiplying amounts with different commodities: " <<
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") <<
|
||||
" != " <<
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
|
||||
|
||||
if (! amt.quantity) {
|
||||
*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)
|
||||
{
|
||||
if (has_commodity() && amt.has_commodity() &&
|
||||
commodity() != amt.commodity()) {
|
||||
throw amount_exception
|
||||
(string("Dividing amounts with different commodities: ") +
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
|
||||
context());
|
||||
}
|
||||
commodity() != amt.commodity())
|
||||
throw_(amount_error,
|
||||
"Dividing amounts with different commodities: " <<
|
||||
(has_commodity() ? commodity_->qualified_symbol : "NONE") <<
|
||||
" != " <<
|
||||
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
|
||||
|
||||
if (! amt.quantity || ! amt) {
|
||||
throw amount_exception("Divide by zero", context());
|
||||
throw_(amount_error, "Divide by zero");
|
||||
}
|
||||
else if (! quantity) {
|
||||
*this = amt;
|
||||
|
|
@ -677,10 +674,9 @@ int amount_t::compare(const amount_t& amt) const
|
|||
return sign();
|
||||
|
||||
if (has_commodity() && amt.commodity() && commodity() != amt.commodity())
|
||||
throw amount_exception
|
||||
(string("Cannot compare amounts with different commodities: ") +
|
||||
commodity().symbol() + " and " + amt.commodity().symbol(),
|
||||
context());
|
||||
throw_(amount_error,
|
||||
"Cannot compare amounts with different commodities: " <<
|
||||
commodity().symbol() << " and " << amt.commodity().symbol());
|
||||
|
||||
if (quantity->prec == amt.quantity->prec) {
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity));
|
||||
|
|
@ -1139,8 +1135,7 @@ static void parse_commodity(std::istream& in, string& symbol)
|
|||
if (c == '"')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_exception("Quoted commodity symbol lacks closing quote",
|
||||
context());
|
||||
throw_(amount_error, "Quoted commodity symbol lacks closing quote");
|
||||
} else {
|
||||
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);
|
||||
if (c == '{') {
|
||||
if (price)
|
||||
throw amount_exception("Commodity specifies more than one price",
|
||||
context());
|
||||
throw_(amount_error, "Commodity specifies more than one price");
|
||||
|
||||
in.get(c);
|
||||
READ_INTO(in, buf, 255, c, c != '}');
|
||||
if (c == '}')
|
||||
in.get(c);
|
||||
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.in_place_reduce();
|
||||
|
|
@ -1180,32 +1174,28 @@ bool parse_annotations(std::istream& in, amount_t& price,
|
|||
}
|
||||
else if (c == '[') {
|
||||
if (is_valid_moment(date))
|
||||
throw amount_exception("Commodity specifies more than one date",
|
||||
context());
|
||||
throw_(amount_error, "Commodity specifies more than one date");
|
||||
|
||||
in.get(c);
|
||||
READ_INTO(in, buf, 255, c, c != ']');
|
||||
if (c == ']')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_exception("Commodity date lacks closing bracket",
|
||||
context());
|
||||
throw_(amount_error, "Commodity date lacks closing bracket");
|
||||
|
||||
date = parse_datetime(buf);
|
||||
has_date = true;
|
||||
}
|
||||
else if (c == '(') {
|
||||
if (! tag.empty())
|
||||
throw amount_exception("Commodity specifies more than one tag",
|
||||
context());
|
||||
throw_(amount_error, "Commodity specifies more than one tag");
|
||||
|
||||
in.get(c);
|
||||
READ_INTO(in, buf, 255, c, c != ')');
|
||||
if (c == ')')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_exception("Commodity tag lacks closing parenthesis",
|
||||
context());
|
||||
throw_(amount_error, "Commodity tag lacks closing parenthesis");
|
||||
|
||||
tag = buf;
|
||||
}
|
||||
|
|
@ -1277,8 +1267,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
|||
}
|
||||
|
||||
if (quant.empty())
|
||||
throw amount_exception("No quantity specified for amount",
|
||||
context());
|
||||
throw_(amount_error, "No quantity specified for amount");
|
||||
|
||||
_init();
|
||||
|
||||
|
|
@ -1926,8 +1915,7 @@ namespace {
|
|||
const string& tag)
|
||||
{
|
||||
if (price < 0)
|
||||
throw amount_exception("A commodity's price may not be negative",
|
||||
context());
|
||||
throw_(amount_error, "A commodity's price may not be negative");
|
||||
|
||||
std::ostringstream name;
|
||||
|
||||
|
|
@ -1935,10 +1923,10 @@ namespace {
|
|||
annotated_commodity_t::write_annotations(name, price, date, tag);
|
||||
|
||||
DEBUG("amounts.commodities", "make_qualified_name for "
|
||||
<< comm.qualified_symbol << std::endl
|
||||
<< " price " << price << " "
|
||||
<< " date " << date << " "
|
||||
<< " tag " << tag);
|
||||
<< comm.qualified_symbol << std::endl
|
||||
<< " price " << price << " "
|
||||
<< " date " << date << " "
|
||||
<< " tag " << tag);
|
||||
|
||||
DEBUG("amounts.commodities", "qualified_name is " << name.str());
|
||||
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ inline commodity_t& amount_t::commodity() const {
|
|||
void parse_conversion(const string& larger_str,
|
||||
const string& smaller_str);
|
||||
|
||||
DECLARE_EXCEPTION(amount_exception);
|
||||
DECLARE_EXCEPTION(amount_error);
|
||||
|
||||
struct compare_amount_commodities {
|
||||
bool operator()(const amount_t * left, const amount_t * right) const;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ amount_t balance_t::amount(const commodity_t& commodity) const
|
|||
if (temp.amounts.size() == 1)
|
||||
return temp.amount(commodity);
|
||||
|
||||
throw_(amount_exception,
|
||||
throw_(amount_error,
|
||||
"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)
|
||||
return *this = bal * temp;
|
||||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Cannot multiply two balances: " << temp << " * " << bal;
|
||||
throw amount_exception(errmsg.str(), context());
|
||||
throw_(amount_error, "Cannot multiply two balances: " << temp << " * " << bal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,11 +207,8 @@ balance_t& balance_t::operator*=(const amount_t& amt)
|
|||
return *this = temp * amt;
|
||||
}
|
||||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Attempt to multiply balance by a commodity"
|
||||
<< " not found in that balance: "
|
||||
<< temp << " * " << amt;
|
||||
throw amount_exception(errmsg.str(), context());
|
||||
throw_(amount_error, "Attempt to multiply balance by a commodity" <<
|
||||
" not found in that balance: " << temp << " * " << amt);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -222,9 +217,7 @@ balance_t& balance_t::operator*=(const amount_t& amt)
|
|||
balance_t& balance_t::operator/=(const balance_t& bal)
|
||||
{
|
||||
if (bal.realzero()) {
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
|
||||
throw amount_exception(errmsg.str(), context());
|
||||
throw_(amount_error, "Divide by zero: " << *this << " / " << bal);
|
||||
}
|
||||
else if (realzero()) {
|
||||
return *this = 0L;
|
||||
|
|
@ -241,18 +234,15 @@ balance_t& balance_t::operator/=(const balance_t& bal)
|
|||
if (temp.amounts.size() == 1)
|
||||
return *this /= temp;
|
||||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Cannot divide between two balances: " << temp << " / " << bal;
|
||||
throw amount_exception(errmsg.str(), context());
|
||||
throw_(amount_error,
|
||||
"Cannot divide two balances: " << temp << " / " << bal);
|
||||
}
|
||||
}
|
||||
|
||||
balance_t& balance_t::operator/=(const amount_t& amt)
|
||||
{
|
||||
if (amt.realzero()) {
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Attempt to divide by zero: " << *this << " / " << amt;
|
||||
throw amount_exception(errmsg.str(), context());
|
||||
throw_(amount_error, "Divide by zero: " << *this << " / " << amt);
|
||||
}
|
||||
else if (realzero()) {
|
||||
return *this = 0L;
|
||||
|
|
@ -280,11 +270,8 @@ balance_t& balance_t::operator/=(const amount_t& amt)
|
|||
(*temp.amounts.begin()).first == &amt.commodity())
|
||||
return *this = temp / amt;
|
||||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Attempt to divide balance by a commodity"
|
||||
<< " not found in that balance: "
|
||||
<< temp << " * " << amt;
|
||||
throw amount_exception(errmsg.str(), context());
|
||||
throw_(amount_error, "Attempt to divide balance by a commodity" <<
|
||||
" not found in that balance: " << temp << " * " << amt);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -304,7 +291,7 @@ balance_t::operator amount_t() const
|
|||
if (temp.amounts.size() == 1)
|
||||
return (*temp.amounts.begin()).second;
|
||||
|
||||
throw_(amount_exception,
|
||||
throw_(amount_error,
|
||||
"Cannot convert a balance with " <<
|
||||
"multiple commodities to an amount: " << temp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ namespace ledger {
|
|||
class context
|
||||
{
|
||||
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
|
||||
|
|
@ -14,12 +19,25 @@ class file_context : public context
|
|||
public:
|
||||
path pathname; // ex: ledger.dat
|
||||
|
||||
optional<long> linenum_beg; // ex: 1010
|
||||
optional<long> linenum_end; // ex: 1010
|
||||
optional<long> colnum_beg; // ex: 8
|
||||
optional<long> colnum_end; // ex: 8
|
||||
optional<long> position_beg;
|
||||
optional<long> position_end;
|
||||
uint_least32_t linenum_beg; // ex: 1010
|
||||
uint_least32_t linenum_end; // ex: 1010
|
||||
uint_least32_t position_beg;
|
||||
uint_least32_t 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
|
||||
|
|
@ -27,12 +45,66 @@ class string_context : public context
|
|||
public:
|
||||
string text; // ex: (The multi-line text of an entry)
|
||||
|
||||
optional<long> linenum_beg_off; // ex: 2 / none means start at beginning
|
||||
optional<long> linenum_end_off; // ex: 2 / none means start at beginning
|
||||
optional<long> colnum_beg_off; // ex: 8 / none means start
|
||||
optional<long> colnum_end_off; // ex: 8 / none means start
|
||||
optional<uint_least32_t> linenum_beg_off; // ex: 2
|
||||
optional<uint_least32_t> linenum_end_off; // ex: 2
|
||||
optional<uint_least32_t> colnum_beg_off; // ex: 8
|
||||
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
|
||||
|
||||
#endif // _CONTEXT_H
|
||||
|
|
|
|||
151
src/error.h
151
src/error.h
|
|
@ -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
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#include "format.h"
|
||||
#if 0
|
||||
#include "pyinterp.h"
|
||||
#endif
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -85,7 +87,7 @@ void format_t::parse(const string& fmt)
|
|||
|
||||
if (current->max_width != -1 && current->min_width != -1 &&
|
||||
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) {
|
||||
case '|':
|
||||
|
|
@ -107,7 +109,7 @@ void format_t::parse(const string& fmt)
|
|||
p++;
|
||||
}
|
||||
if (*p != close)
|
||||
throw_(format_exception, "Missing '" << close << "'");
|
||||
throw_(format_error, "Missing '" << close << "'");
|
||||
|
||||
if (open == '{') {
|
||||
assert(! current->xpath);
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class format_t
|
|||
}
|
||||
};
|
||||
|
||||
DECLARE_EXCEPTION(format_exception);
|
||||
DECLARE_EXCEPTION(format_error);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
|
|||
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
const char * msg = XML_ErrorString(XML_GetErrorCode(parser));
|
||||
XML_ParserFree(parser);
|
||||
throw_(parse_exception, msg);
|
||||
throw_(parse_error, msg);
|
||||
}
|
||||
|
||||
if (! have_error.empty()) {
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ bool entry_base_t::finalize()
|
|||
continue;
|
||||
|
||||
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;
|
||||
|
||||
// If one transaction gives no value at all, its value will become
|
||||
|
|
@ -256,7 +256,7 @@ bool entry_base_t::finalize()
|
|||
|
||||
if (balance) {
|
||||
#if 1
|
||||
throw_(balance_exception, "Entry does not balance");
|
||||
throw_(balance_error, "Entry does not balance");
|
||||
#else
|
||||
error * err =
|
||||
new balance_error("Entry does not balance",
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ class entry_context : public error_context {
|
|||
};
|
||||
#endif
|
||||
|
||||
DECLARE_EXCEPTION(balance_exception);
|
||||
DECLARE_EXCEPTION(balance_error);
|
||||
|
||||
|
||||
class auto_entry_t : public entry_base_t
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
|
|||
command.reset(def->functor_obj());
|
||||
|
||||
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
|
||||
|
|
@ -201,11 +201,11 @@ static int read_and_report(report_t * report, int argc, char * argv[],
|
|||
else if (! report->pager.empty()) {
|
||||
status = pipe(pfd);
|
||||
if (status == -1)
|
||||
throw_(exception, "Failed to create pipe");
|
||||
throw_(std::logic_error, "Failed to create pipe");
|
||||
|
||||
status = fork();
|
||||
if (status < 0) {
|
||||
throw_(exception, "Failed to fork child process");
|
||||
throw_(std::logic_error, "Failed to fork child process");
|
||||
}
|
||||
else if (status == 0) { // child
|
||||
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(&status);
|
||||
if (status & 0xffff != 0)
|
||||
throw_(exception, "Something went wrong in the pager");
|
||||
throw_(std::logic_error, "Something went wrong in the pager");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
if (! opt.get())
|
||||
throw_(option_exception, "illegal option --" << name);
|
||||
throw_(option_error, "illegal option --" << name);
|
||||
|
||||
xml::xpath_t::functor_t * def = opt->functor_obj();
|
||||
if (! def)
|
||||
throw_(option_exception, "illegal option --" << name);
|
||||
throw_(option_error, "illegal option --" << name);
|
||||
|
||||
if (def->wants_args && value == NULL) {
|
||||
value = *++i;
|
||||
if (value == NULL)
|
||||
throw_(option_exception, "missing option argument for --" << name);
|
||||
throw_(option_error, "missing option argument for --" << name);
|
||||
}
|
||||
process_option(def, scope, value);
|
||||
}
|
||||
else if ((*i)[1] == '\0') {
|
||||
throw_(option_exception, "illegal option -");
|
||||
throw_(option_error, "illegal option -");
|
||||
}
|
||||
else {
|
||||
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]) {
|
||||
xml::xpath_t::op_t * opt = find_option(scope, c);
|
||||
if (! opt)
|
||||
throw_(option_exception, "illegal option -" << c);
|
||||
throw_(option_error, "illegal option -" << c);
|
||||
|
||||
xml::xpath_t::functor_t * def = opt->functor_obj();
|
||||
if (! def)
|
||||
throw_(option_exception, "illegal option -" << c);
|
||||
throw_(option_error, "illegal option -" << c);
|
||||
|
||||
option_queue.push_back(opt);
|
||||
}
|
||||
|
|
@ -197,7 +197,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
|
|||
if (def->wants_args) {
|
||||
value = *++i;
|
||||
if (value == NULL)
|
||||
throw_(option_exception, "missing option argument for -" <<
|
||||
throw_(option_error, "missing option argument for -" <<
|
||||
#if 0
|
||||
def->short_opt
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
|
|||
xml::xpath_t::scope_t * scope,
|
||||
std::list<string>& args);
|
||||
|
||||
DECLARE_EXCEPTION(option_exception);
|
||||
DECLARE_EXCEPTION(option_error);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class parser_t
|
|||
const string * original_file = NULL) = 0;
|
||||
};
|
||||
|
||||
DECLARE_EXCEPTION(parse_exception);
|
||||
DECLARE_EXCEPTION(parse_error);
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#include "pyinterp.h"
|
||||
#include "amount.h"
|
||||
|
||||
using namespace boost::python;
|
||||
#include <boost/python/exception_translator.hpp>
|
||||
|
||||
namespace ledger {
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
int py_amount_quantity(amount_t& amount)
|
||||
{
|
||||
std::ostringstream quant;
|
||||
|
|
@ -51,7 +53,7 @@ commodity_t * py_find_commodity(const string& symbol)
|
|||
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
|
||||
}
|
||||
|
||||
EXC_TRANSLATOR(amount_exception)
|
||||
EXC_TRANSLATOR(amount_error)
|
||||
|
||||
void export_amount()
|
||||
{
|
||||
|
|
@ -236,10 +238,10 @@ void export_amount()
|
|||
#endif
|
||||
;
|
||||
|
||||
#define EXC_TRANSLATE(type) \
|
||||
#define EXC_TRANSLATE(type) \
|
||||
register_exception_translator<type>(&exc_translate_ ## type);
|
||||
|
||||
EXC_TRANSLATE(amount_exception);
|
||||
EXC_TRANSLATE(amount_error);
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ void export_journal()
|
|||
;
|
||||
|
||||
#define EXC_TRANSLATE(type) \
|
||||
register_exception_translator<type>(&exc_translate_ ## type);
|
||||
register_error_translator<type>(&exc_translate_ ## type);
|
||||
|
||||
EXC_TRANSLATE(balance_error);
|
||||
EXC_TRANSLATE(interval_expr_error);
|
||||
|
|
|
|||
|
|
@ -48,13 +48,13 @@ amount_t value_getitem(value_t& val, int i)
|
|||
|
||||
switch (val.type) {
|
||||
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:
|
||||
return long(val);
|
||||
|
||||
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:
|
||||
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);
|
||||
|
||||
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:
|
||||
return (*(xml::node_t **) data)->to_value();
|
||||
|
||||
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:
|
||||
return (*(value_t::sequence_t **) val.data)[i];
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ void export_xpath()
|
|||
;
|
||||
|
||||
#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(calc_error);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "pyinterp.h"
|
||||
|
||||
#include <boost/python/module_init.hpp>
|
||||
#include <boost/python/exception_translator.hpp>
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -37,7 +36,7 @@ object python_interpreter_t::import(const string& str)
|
|||
try {
|
||||
PyObject * mod = PyImport_Import(PyString_FromString(str.c_str()));
|
||||
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)));
|
||||
|
||||
|
|
@ -52,7 +51,7 @@ object python_interpreter_t::import(const string& str)
|
|||
}
|
||||
catch (const error_already_set&) {
|
||||
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&) {
|
||||
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&) {
|
||||
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()) {
|
||||
PyErr_Print();
|
||||
throw_(xml::xpath_t::calc_exception,
|
||||
throw_(xml::xpath_t::calc_error,
|
||||
"While calling Python function '" << name() << "'");
|
||||
} else {
|
||||
assert(0);
|
||||
|
|
@ -144,7 +143,7 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
|
|||
}
|
||||
catch (const error_already_set&) {
|
||||
PyErr_Print();
|
||||
throw_(xml::xpath_t::calc_exception,
|
||||
throw_(xml::xpath_t::calc_error,
|
||||
"While calling Python function '" << name() << "'");
|
||||
}
|
||||
}
|
||||
|
|
@ -161,7 +160,7 @@ void python_interpreter_t::lambda_t::operator()(value_t& result,
|
|||
}
|
||||
catch (const error_already_set&) {
|
||||
PyErr_Print();
|
||||
throw_(xml::xpath_t::calc_exception,
|
||||
throw_(xml::xpath_t::calc_error,
|
||||
"While evaluating Python lambda expression");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
|
|||
case '\t':
|
||||
if (peek_next_nonws(in) != '\n') {
|
||||
get_line(in);
|
||||
throw_(parse_exception, "Line begins with whitespace");
|
||||
throw_(parse_error, "Line begins with whitespace");
|
||||
}
|
||||
// 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:Class") == 0 ||
|
||||
std::strcmp(line, "Type:Memorized") == 0)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
"QIF files of type " << line << " are not supported.");
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,12 +55,13 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
|
|||
commodity.history->last_lookup = time_now;
|
||||
cache_dirty = true;
|
||||
|
||||
if (price && ! price_db.empty()) {
|
||||
if (price) {
|
||||
assert(! price_db.empty());
|
||||
|
||||
#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
|
||||
std::ofstream database(price_db.c_str(),
|
||||
std::ios_base::out | std::ios_base::app);
|
||||
ofstream database(price_db, std::ios_base::out | std::ios_base::app);
|
||||
#endif
|
||||
#if 0
|
||||
// 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
|
||||
}
|
||||
} else {
|
||||
throw exception(string("Failed to download price for '") +
|
||||
commodity.symbol + "' (command: \"getquote " +
|
||||
commodity.symbol + "\")",
|
||||
context());
|
||||
throw_(download_error,
|
||||
"Failed to download price for '" << commodity.symbol <<
|
||||
"' (command: \"getquote " << commodity.symbol << "\")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ namespace ledger {
|
|||
|
||||
class quotes_by_script : public commodity_base_t::updater_t
|
||||
{
|
||||
string price_db;
|
||||
path price_db;
|
||||
time_duration pricing_leeway;
|
||||
bool& cache_dirty;
|
||||
|
||||
public:
|
||||
quotes_by_script(string _price_db,
|
||||
quotes_by_script(path _price_db,
|
||||
time_duration _pricing_leeway,
|
||||
bool& _cache_dirty)
|
||||
: 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);
|
||||
};
|
||||
|
||||
DECLARE_EXCEPTION(download_error);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#endif // _QUOTES_H
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
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();
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -19,20 +19,21 @@ unsigned int session_t::read_journal(std::istream& in,
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned int session_t::read_journal(const string& path,
|
||||
journal_t * journal,
|
||||
account_t * master,
|
||||
unsigned int session_t::read_journal(const string& pathname,
|
||||
journal_t * journal,
|
||||
account_t * master,
|
||||
const string * original_file)
|
||||
{
|
||||
journal->sources.push_back(path);
|
||||
journal->sources.push_back(pathname);
|
||||
|
||||
if (access(path.c_str(), R_OK) == -1)
|
||||
throw_(exception, "Cannot read file '" << path << "'");
|
||||
if (access(pathname.c_str(), R_OK) == -1)
|
||||
throw filesystem_error(BOOST_CURRENT_FUNCTION, pathname,
|
||||
"Cannot read 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);
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +43,8 @@ void session_t::read_init()
|
|||
return;
|
||||
|
||||
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());
|
||||
|
||||
|
|
@ -88,7 +90,7 @@ journal_t * session_t::read_data(const string& master_account)
|
|||
if (! journal->price_db.empty() &&
|
||||
access(journal->price_db.c_str(), R_OK) != -1) {
|
||||
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 {
|
||||
DEBUG("ledger.cache", "read price database " << journal->price_db);
|
||||
journal->sources.pop_back();
|
||||
|
|
@ -111,7 +113,7 @@ journal_t * session_t::read_data(const string& master_account)
|
|||
VERIFY(journal->valid());
|
||||
|
||||
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?");
|
||||
|
||||
TRACE_STOP(parser, 1);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
#include <iomanip>
|
||||
|
|
@ -96,4 +97,16 @@ extern "C" {
|
|||
#include <libofx.h>
|
||||
#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
|
||||
|
|
|
|||
613
src/textual.cc
613
src/textual.cc
|
|
@ -167,47 +167,47 @@ transaction_t * parse_transaction(char * line,
|
|||
if (amount && *amount) {
|
||||
std::istringstream in(amount);
|
||||
|
||||
try {
|
||||
// jww (2006-09-15): Make sure it doesn't gobble up the upcoming @ symbol
|
||||
PUSH_CONTEXT();
|
||||
|
||||
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;
|
||||
if (! in.eof() && (c = peek_next_nonws(in)) != '@' &&
|
||||
c != ';' && ! in.eof()) {
|
||||
in.seekg(beg, std::ios::beg);
|
||||
xact->amount.parse(in, AMOUNT_PARSE_NO_REDUCE);
|
||||
|
||||
if (xact->entry) {
|
||||
// Create a report item for this entry, so the transaction
|
||||
// below may refer to it
|
||||
char c;
|
||||
if (! in.eof() && (c = peek_next_nonws(in)) != '@' &&
|
||||
c != ';' && ! in.eof()) {
|
||||
in.seekg(beg, std::ios::beg);
|
||||
|
||||
if (! xact->entry->data)
|
||||
xact->entry->data = xml::wrap_node(journal->document, xact->entry,
|
||||
journal->document->top);
|
||||
if (xact->entry) {
|
||||
// Create a report item for this entry, so the transaction
|
||||
// below may refer to it
|
||||
|
||||
xact->data = xml::wrap_node(journal->document, xact.get(),
|
||||
xact->entry->data);
|
||||
}
|
||||
if (! xact->entry->data)
|
||||
xact->entry->data = xml::wrap_node(journal->document, xact->entry,
|
||||
journal->document->top);
|
||||
|
||||
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);
|
||||
xact->data = xml::wrap_node(journal->document, xact.get(),
|
||||
xact->entry->data);
|
||||
}
|
||||
|
||||
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:";
|
||||
throw;
|
||||
}
|
||||
|
||||
// jww (2007-04-30): This should be a string context, or perhaps a
|
||||
// file context
|
||||
POP_CONTEXT(context("While parsing transaction amount"));
|
||||
|
||||
// Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST)
|
||||
|
||||
|
|
@ -228,27 +228,25 @@ transaction_t * parse_transaction(char * line,
|
|||
if (in.good() && ! in.eof()) {
|
||||
xact->cost = new amount_t;
|
||||
|
||||
try {
|
||||
unsigned long beg = (long)in.tellg();
|
||||
PUSH_CONTEXT();
|
||||
|
||||
xact->cost->parse(in);
|
||||
unsigned long beg = (long)in.tellg();
|
||||
|
||||
unsigned long end = (long)in.tellg();
|
||||
xact->cost->parse(in);
|
||||
|
||||
if (per_unit)
|
||||
xact->cost_expr = (string("@") +
|
||||
string(amount, beg, end - beg));
|
||||
else
|
||||
xact->cost_expr = (string("@@") +
|
||||
string(amount, beg, end - beg));
|
||||
}
|
||||
catch (exception& err) {
|
||||
err_desc = "While parsing transaction cost:";
|
||||
throw;
|
||||
}
|
||||
unsigned long end = (long)in.tellg();
|
||||
|
||||
if (per_unit)
|
||||
xact->cost_expr = (string("@") +
|
||||
string(amount, beg, end - beg));
|
||||
else
|
||||
xact->cost_expr = (string("@@") +
|
||||
string(amount, beg, end - beg));
|
||||
|
||||
POP_CONTEXT(context("While parsing transaction cost"));
|
||||
|
||||
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);
|
||||
if (per_unit)
|
||||
|
|
@ -514,7 +512,7 @@ static inline void parse_symbol(char *& p, string& symbol)
|
|||
if (*p == '"') {
|
||||
char * q = std::strchr(p + 1, '"');
|
||||
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);
|
||||
p = q + 2;
|
||||
} else {
|
||||
|
|
@ -526,7 +524,7 @@ static inline void parse_symbol(char *& p, string& symbol)
|
|||
p += symbol.length();
|
||||
}
|
||||
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
|
||||
|
|
@ -536,9 +534,9 @@ bool textual_parser_t::test(std::istream& in) const
|
|||
in.read(buf, 5);
|
||||
if (std::strncmp(buf, "<?xml", 5) == 0) {
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
throw_(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
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -560,10 +558,10 @@ static void clock_out_from_timelog(const moment_t& when,
|
|||
time_entries.clear();
|
||||
}
|
||||
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) {
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
"When multiple check-ins are active, checking out requires an account");
|
||||
}
|
||||
else {
|
||||
|
|
@ -580,7 +578,7 @@ static void clock_out_from_timelog(const moment_t& when,
|
|||
}
|
||||
|
||||
if (! found)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
"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;
|
||||
|
||||
if (curr->_date < event.checkin)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
"Timelog check-out date less than corresponding check-in");
|
||||
|
||||
char buf[32];
|
||||
|
|
@ -609,7 +607,7 @@ static void clock_out_from_timelog(const moment_t& when,
|
|||
curr->add_transaction(xact);
|
||||
|
||||
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
|
||||
curr.release();
|
||||
}
|
||||
|
|
@ -622,7 +620,6 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
static bool added_auto_entry_hook = false;
|
||||
static char line[MAX_LINE + 1];
|
||||
unsigned int count = 0;
|
||||
unsigned int errors = 0;
|
||||
|
||||
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;
|
||||
|
||||
while (in.good() && ! in.eof()) {
|
||||
#if 0
|
||||
try {
|
||||
#endif
|
||||
in.getline(line, MAX_LINE);
|
||||
if (in.eof())
|
||||
break;
|
||||
end_pos = beg_pos + std::strlen(line) + 1;
|
||||
linenum++;
|
||||
in.getline(line, MAX_LINE);
|
||||
if (in.eof())
|
||||
break;
|
||||
end_pos = beg_pos + std::strlen(line) + 1;
|
||||
linenum++;
|
||||
|
||||
switch (line[0]) {
|
||||
case '\0':
|
||||
case '\r':
|
||||
break;
|
||||
PUSH_CONTEXT();
|
||||
|
||||
case ' ':
|
||||
case '\t': {
|
||||
char * p = skip_ws(line);
|
||||
if (*p && *p != '\r')
|
||||
throw_(parse_exception, "Line begins with whitespace");
|
||||
break;
|
||||
}
|
||||
switch (line[0]) {
|
||||
case '\0':
|
||||
case '\r':
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t': {
|
||||
char * p = skip_ws(line);
|
||||
if (*p && *p != '\r')
|
||||
throw_(parse_error, "Line begins with whitespace");
|
||||
break;
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
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_exception,
|
||||
"Cannot double check-in to the same account");
|
||||
|
||||
time_entries.push_back(event);
|
||||
break;
|
||||
clock_out_from_timelog
|
||||
(parse_datetime(date),
|
||||
p ? account_stack.front()->find_account(p) : NULL, n, journal);
|
||||
count++;
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
#endif // TIMELOG_SUPPORT
|
||||
|
||||
case 'D': { // a default commodity for "entry"
|
||||
amount_t amt(skip_ws(line + 1));
|
||||
commodity_t::default_commodity = &amt.commodity();
|
||||
break;
|
||||
case 'D': { // a default commodity for "entry"
|
||||
amount_t amt(skip_ws(line + 1));
|
||||
commodity_t::default_commodity = &amt.commodity();
|
||||
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
|
||||
journal->basket =
|
||||
account_stack.front()->find_account(skip_ws(line + 1));
|
||||
break;
|
||||
string symbol;
|
||||
parse_symbol(symbol_and_price, symbol);
|
||||
amount_t price(symbol_and_price);
|
||||
|
||||
case 'C': // a set of conversions
|
||||
if (char * p = std::strchr(line + 1, '=')) {
|
||||
*p++ = '\0';
|
||||
parse_conversion(line + 1, p);
|
||||
}
|
||||
break;
|
||||
if (commodity_t * commodity = commodity_t::find_or_create(symbol))
|
||||
commodity->add_price(datetime, price);
|
||||
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;
|
||||
case 'N': { // don't download prices
|
||||
char * p = skip_ws(line + 1);
|
||||
string symbol;
|
||||
parse_symbol(p, symbol);
|
||||
|
||||
char * symbol_and_price;
|
||||
moment_t datetime;
|
||||
if (commodity_t * commodity = commodity_t::find_or_create(symbol))
|
||||
commodity->add_flags(COMMODITY_STYLE_NOMARKET);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
case 'Y': // set current year
|
||||
#if 0
|
||||
// jww (2007-04-18): Need to set this up again
|
||||
date_t::current_year = std::atoi(skip_ws(line + 1));
|
||||
// jww (2007-04-18): Need to set this up again
|
||||
date_t::current_year = std::atoi(skip_ws(line + 1));
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
|
||||
#ifdef TIMELOG_SUPPORT
|
||||
case 'h':
|
||||
case 'b':
|
||||
case 'h':
|
||||
case 'b':
|
||||
#endif
|
||||
case ';': // comment
|
||||
break;
|
||||
case ';': // comment
|
||||
break;
|
||||
|
||||
case '-': // option setting
|
||||
throw_(parse_exception, "Option settings are not allowed in journal files");
|
||||
case '-': // option setting
|
||||
throw_(parse_error, "Option settings are not allowed in journal files");
|
||||
|
||||
case '=': { // automated entry
|
||||
if (! added_auto_entry_hook) {
|
||||
journal->add_entry_finalizer(&auto_entry_finalizer);
|
||||
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 '=': { // automated entry
|
||||
if (! added_auto_entry_hook) {
|
||||
journal->add_entry_finalizer(&auto_entry_finalizer);
|
||||
added_auto_entry_hook = true;
|
||||
}
|
||||
|
||||
case '~': { // period entry
|
||||
period_entry_t * pe = new period_entry_t(skip_ws(line + 1));
|
||||
if (! pe->period)
|
||||
throw_(parse_exception, string("Parsing time period '") + skip_ws(line + 1) + "'");
|
||||
|
||||
if (parse_transactions(in, journal, account_stack.front(), *pe,
|
||||
"period", end_pos)) {
|
||||
if (pe->finalize()) {
|
||||
extend_entry_base(journal, *pe, true);
|
||||
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;
|
||||
std::auto_ptr<auto_entry_t> ae(new auto_entry_t(skip_ws(line + 1)));
|
||||
if (parse_transactions(in, journal, account_stack.front(), *ae,
|
||||
"automated", end_pos)) {
|
||||
ae->src_idx = src_idx;
|
||||
ae->beg_pos = beg_pos;
|
||||
ae->beg_line = beg_line;
|
||||
ae->end_pos = end_pos;
|
||||
ae->end_line = linenum;
|
||||
journal->auto_entries.push_back(ae.release());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
case '~': { // period entry
|
||||
std::auto_ptr<period_entry_t> pe(new period_entry_t(skip_ws(line + 1)));
|
||||
if (! pe->period)
|
||||
throw_(parse_error, string("Parsing time period '") + skip_ws(line + 1) + "'");
|
||||
|
||||
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();
|
||||
if (parse_transactions(in, journal, account_stack.front(), *pe,
|
||||
"period", end_pos)) {
|
||||
if (pe->finalize()) {
|
||||
extend_entry_base(journal, *pe, true);
|
||||
pe->src_idx = src_idx;
|
||||
pe->beg_pos = beg_pos;
|
||||
pe->beg_line = beg_line;
|
||||
pe->end_pos = end_pos;
|
||||
pe->end_line = linenum;
|
||||
journal->period_entries.push_back(pe.release());
|
||||
} else {
|
||||
throw_(parse_error, "Period entry failed to balance");
|
||||
}
|
||||
else if (word == "account") {
|
||||
account_t * acct;
|
||||
acct = account_stack.front()->find_account(p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else if (word == "end") {
|
||||
account_stack.pop_front();
|
||||
}
|
||||
else if (word == "alias") {
|
||||
char * b = p;
|
||||
if (char * e = std::strchr(b, '=')) {
|
||||
char * z = e - 1;
|
||||
while (std::isspace(*z))
|
||||
*z-- = '\0';
|
||||
*e++ = '\0';
|
||||
e = skip_ws(e);
|
||||
else
|
||||
; // jww (2007-04-30): throw an error here
|
||||
}
|
||||
else if (word == "end") {
|
||||
account_stack.pop_front();
|
||||
}
|
||||
else if (word == "alias") {
|
||||
char * b = p;
|
||||
if (char * e = std::strchr(b, '=')) {
|
||||
char * z = e - 1;
|
||||
while (std::isspace(*z))
|
||||
*z-- = '\0';
|
||||
*e++ = '\0';
|
||||
e = skip_ws(e);
|
||||
|
||||
// Once we have an alias name (b) and the target account
|
||||
// name (e), add a reference to the account in the
|
||||
// `account_aliases' map, which is used by the transaction
|
||||
// parser to resolve alias references.
|
||||
account_t * acct = account_stack.front()->find_account(e);
|
||||
// Once we have an alias name (b) and the target account
|
||||
// name (e), add a reference to the account in the
|
||||
// `account_aliases' map, which is used by the transaction
|
||||
// parser to resolve alias references.
|
||||
if (account_t * acct = account_stack.front()->find_account(e)) {
|
||||
std::pair<accounts_map::iterator, bool> result
|
||||
= account_aliases.insert(accounts_pair(b, acct));
|
||||
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 {
|
||||
delete entry;
|
||||
throw_(parse_exception, "Entry does not balance");
|
||||
; // jww (2007-04-30): throw an error here
|
||||
}
|
||||
} else {
|
||||
throw_(parse_exception, "Failed to parse entry");
|
||||
}
|
||||
TRACE_STOP(entries, 1);
|
||||
|
||||
end_pos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
}
|
||||
catch (error * err) {
|
||||
for (std::list<std::pair<string, int> >::reverse_iterator i =
|
||||
include_stack.rbegin();
|
||||
i != include_stack.rend();
|
||||
i++)
|
||||
err->context.push_back(new include_context((*i).first, (*i).second,
|
||||
"In file included from"));
|
||||
err->context.push_front(new file_context(pathname, linenum - 1));
|
||||
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.
|
||||
|
||||
std::cout.flush();
|
||||
if (errors > 0 && err->context.size() > 1)
|
||||
std::cerr << std::endl;
|
||||
err->reveal_context(std::cerr, "Error");
|
||||
std::cerr << err->what() << std::endl;
|
||||
delete err;
|
||||
errors++;
|
||||
// compile(&journal->defs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#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()) {
|
||||
|
|
@ -956,9 +940,6 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
if (added_auto_entry_hook)
|
||||
journal->remove_entry_finalizer(&auto_entry_finalizer);
|
||||
|
||||
if (errors > 0)
|
||||
throw (int)errors;
|
||||
|
||||
TRACE_STOP(parsing_total, 1);
|
||||
|
||||
return count;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ inline bool is_valid_moment(const moment_t& moment) {
|
|||
|
||||
extern const moment_t& now;
|
||||
|
||||
DECLARE_EXCEPTION(datetime_exception);
|
||||
DECLARE_EXCEPTION(datetime_error);
|
||||
|
||||
class interval_t
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
DECLARE_EXCEPTION(assertion_failed);
|
||||
|
||||
void debug_assert(const string& reason,
|
||||
const string& func,
|
||||
const string& file,
|
||||
|
|
@ -18,7 +20,7 @@ void debug_assert(const string& reason,
|
|||
std::ostringstream buf;
|
||||
buf << "Assertion failed in \"" << file << "\", line " << line
|
||||
<< ": " << reason;
|
||||
throw exception(buf.str(), context());
|
||||
throw assertion_failed(buf.str());
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
@ -618,6 +620,7 @@ void finish_timer(const char * name)
|
|||
namespace ledger {
|
||||
|
||||
std::ostringstream _exc_buffer;
|
||||
ptr_list<context> context_stack;
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
|
|
|
|||
55
src/utils.h
55
src/utils.h
|
|
@ -9,24 +9,13 @@
|
|||
*/
|
||||
|
||||
namespace ledger {
|
||||
#if ! defined(USE_BOOST_PYTHON)
|
||||
using namespace boost;
|
||||
|
||||
#if defined(VERIFY_ON) && ! defined(USE_BOOST_PYTHON)
|
||||
class string;
|
||||
#else
|
||||
typedef std::string string;
|
||||
#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 ptime::time_duration_type time_duration;
|
||||
|
|
@ -35,6 +24,9 @@ namespace ledger {
|
|||
typedef posix_time::seconds seconds;
|
||||
|
||||
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
|
||||
#if defined(ASSERTS_ON)
|
||||
|
||||
#include <boost/current_function.hpp>
|
||||
|
||||
namespace ledger {
|
||||
void debug_assert(const string& reason, const string& func,
|
||||
const string& file, unsigned long line);
|
||||
|
|
@ -247,11 +237,7 @@ extern unsigned int _trace_level;
|
|||
extern std::string _log_category;
|
||||
|
||||
inline bool category_matches(const char * cat) {
|
||||
return (_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()] == '.'));
|
||||
return starts_with(_log_category, cat);
|
||||
}
|
||||
|
||||
#define SHOW_DEBUG(cat) \
|
||||
|
|
@ -403,21 +389,44 @@ void finish_timer(const char * name);
|
|||
* Exception handling
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "context.h"
|
||||
|
||||
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;
|
||||
|
||||
template <typename T>
|
||||
inline void throw_func(const std::string& message) {
|
||||
_exc_buffer.str("");
|
||||
throw T(message, context());
|
||||
throw T(message);
|
||||
}
|
||||
|
||||
#define throw_(cls, msg) \
|
||||
((_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
|
||||
|
||||
/**********************************************************************
|
||||
|
|
|
|||
480
src/value.cc
480
src/value.cc
File diff suppressed because it is too large
Load diff
|
|
@ -573,7 +573,7 @@ class value_context : public error_context
|
|||
};
|
||||
#endif
|
||||
|
||||
DECLARE_EXCEPTION(value_exception);
|
||||
DECLARE_EXCEPTION(value_error);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
|
|
|
|||
|
|
@ -382,14 +382,14 @@ document_t * document_t::parser_t::parse(std::istream& in)
|
|||
catch (const std::exception& err) {
|
||||
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
XML_ParserFree(parser);
|
||||
throw_(parse_exception, err.what());
|
||||
throw_(parse_error, err.what());
|
||||
}
|
||||
|
||||
if (! have_error.empty()) {
|
||||
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
#if 0
|
||||
// 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;
|
||||
#endif
|
||||
have_error = "";
|
||||
|
|
@ -399,7 +399,7 @@ document_t * document_t::parser_t::parse(std::istream& in)
|
|||
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
|
||||
XML_ParserFree(parser);
|
||||
throw_(parse_exception, err);
|
||||
throw_(parse_error, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace xml {
|
|||
|
||||
#define XML_NODE_IS_PARENT 0x1
|
||||
|
||||
DECLARE_EXCEPTION(conversion_exception);
|
||||
DECLARE_EXCEPTION(conversion_error);
|
||||
|
||||
class parent_node_t;
|
||||
class document_t;
|
||||
|
|
@ -85,7 +85,7 @@ public:
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
@ -255,7 +255,7 @@ class xml_parser_t : public parser_t
|
|||
const string * original_file = NULL);
|
||||
};
|
||||
|
||||
DECLARE_EXCEPTION(parse_exception);
|
||||
DECLARE_EXCEPTION(parse_error);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
|
|||
catch (const std::exception& err) {
|
||||
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
XML_ParserFree(parser);
|
||||
throw_(parse_exception, err.what());
|
||||
throw_(parse_error, err.what());
|
||||
}
|
||||
|
||||
if (! have_error.empty()) {
|
||||
|
|
@ -225,7 +225,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
|
|||
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
|
||||
XML_ParserFree(parser);
|
||||
throw_(parse_exception, err);
|
||||
throw_(parse_error, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
86
src/xpath.cc
86
src/xpath.cc
|
|
@ -382,7 +382,7 @@ void xpath_t::token_t::next(std::istream& in, unsigned short flags)
|
|||
kind = VALUE;
|
||||
value = temp;
|
||||
}
|
||||
catch (amount_exception& err) {
|
||||
catch (amount_error& err) {
|
||||
// If the amount had no commodity, it must be an unambiguous
|
||||
// variable reference
|
||||
|
||||
|
|
@ -414,13 +414,13 @@ void xpath_t::token_t::unexpected()
|
|||
{
|
||||
switch (kind) {
|
||||
case TOK_EOF:
|
||||
throw_(parse_exception, "Unexpected end of expression");
|
||||
throw_(parse_error, "Unexpected end of expression");
|
||||
case IDENT:
|
||||
throw_(parse_exception, "Unexpected symbol '" << value << "'");
|
||||
throw_(parse_error, "Unexpected symbol '" << value << "'");
|
||||
case VALUE:
|
||||
throw_(parse_exception, "Unexpected value '" << value << "'");
|
||||
throw_(parse_error, "Unexpected value '" << value << "'");
|
||||
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 (wanted)
|
||||
throw_(parse_exception, "Missing '" << wanted << "'");
|
||||
throw_(parse_error, "Missing '" << wanted << "'");
|
||||
else
|
||||
throw_(parse_exception, "Unexpected end");
|
||||
throw_(parse_error, "Unexpected end");
|
||||
} else {
|
||||
if (wanted)
|
||||
throw_(parse_exception, "Invalid char '" << c <<
|
||||
throw_(parse_error, "Invalid char '" << c <<
|
||||
"' (wanted '" << wanted << "')");
|
||||
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
|
||||
= symbols.insert(symbol_pair(name, def));
|
||||
if (! result2.second)
|
||||
throw_(compile_exception,
|
||||
throw_(compile_error,
|
||||
"Redefinition of '" << name << "' in same scope");
|
||||
}
|
||||
def->acquire();
|
||||
|
|
@ -536,7 +536,7 @@ bool xpath_t::function_scope_t::resolve(const string& name,
|
|||
if (value->type == value_t::XML_NODE)
|
||||
result.set_string(value->to_xml_node()->text());
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
|
@ -604,7 +604,7 @@ void xpath_t::op_t::get_value(value_t& result) const
|
|||
result = (long)arg_index;
|
||||
break;
|
||||
default:
|
||||
throw_(calc_exception,
|
||||
throw_(calc_error,
|
||||
"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;
|
||||
}
|
||||
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
|
||||
|
|
@ -689,7 +689,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
|
|||
case token_t::AT_SYM:
|
||||
tok = next_token(in, tflags);
|
||||
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->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:
|
||||
node.reset(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL));
|
||||
if (! node.get())
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
tok = next_token(in, tflags);
|
||||
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_right(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL));
|
||||
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);
|
||||
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_right(parse_predicate_expr(in, tflags));
|
||||
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);
|
||||
}
|
||||
|
|
@ -822,7 +822,7 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
|
|||
case token_t::EXCLAM: {
|
||||
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
|
||||
if (! texpr.get())
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
// A very quick optimization
|
||||
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: {
|
||||
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
|
||||
if (! texpr.get())
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
// A very quick optimization
|
||||
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: {
|
||||
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
|
||||
if (! texpr.get())
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
// A very quick optimization
|
||||
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_right(parse_union_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
} else {
|
||||
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_right(parse_mul_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
|
||||
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_right(parse_add_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
|
||||
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 (tok.kind == token_t::PLUS)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
else
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
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_right(parse_and_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
} else {
|
||||
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_right(parse_or_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
} else {
|
||||
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->right->set_left(parse_querycolon_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
tok = next_token(in, tflags);
|
||||
if (tok.kind != token_t::COLON)
|
||||
tok.unexpected(); // jww (2006-09-09): wanted :
|
||||
node->right->set_right(parse_querycolon_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
} else {
|
||||
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_right(parse_value_expr(in, tflags));
|
||||
if (! node->right)
|
||||
throw_(parse_exception,
|
||||
throw_(parse_error,
|
||||
tok.symbol << " operator not followed by argument");
|
||||
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)) {
|
||||
throw_(parse_exception, "Failed to parse value expression");
|
||||
throw_(parse_error, "Failed to parse value expression");
|
||||
}
|
||||
|
||||
return node.release();
|
||||
|
|
@ -1195,7 +1195,7 @@ void xpath_t::op_t::find_values(value_t * context, scope_t * scope,
|
|||
}
|
||||
}
|
||||
} 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));
|
||||
|
||||
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) {
|
||||
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:
|
||||
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)
|
||||
return wrap_value(context->to_xml_node()->parent)->acquire();
|
||||
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:
|
||||
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
|
||||
return wrap_value(context->to_xml_node()->document->top)->acquire();
|
||||
|
||||
case document_t::ALL: {
|
||||
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();
|
||||
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);
|
||||
|
||||
|
|
@ -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())
|
||||
return wrap_value((*scope->args.to_sequence())[arg_index])->acquire();
|
||||
else
|
||||
throw_(compile_exception, "Reference to non-existing argument");
|
||||
throw_(compile_error, "Reference to non-existing argument");
|
||||
} else {
|
||||
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)
|
||||
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);
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
else {
|
||||
throw_(calc_exception, "Unknown function name '" << *left->name << "'");
|
||||
throw_(calc_error, "Unknown function name '" << *left->name << "'");
|
||||
}
|
||||
}
|
||||
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++) {
|
||||
assert((*i).type != value_t::SEQUENCE);
|
||||
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)");
|
||||
|
||||
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:
|
||||
throw_(compile_exception, "Attempting to apply path selection "
|
||||
throw_(compile_error, "Attempting to apply path selection "
|
||||
"to non-node(s)");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ public:
|
|||
static void initialize();
|
||||
static void shutdown();
|
||||
|
||||
DECLARE_EXCEPTION(parse_exception);
|
||||
DECLARE_EXCEPTION(compile_exception);
|
||||
DECLARE_EXCEPTION(calc_exception);
|
||||
DECLARE_EXCEPTION(parse_error);
|
||||
DECLARE_EXCEPTION(compile_error);
|
||||
DECLARE_EXCEPTION(calc_error);
|
||||
|
||||
#if 0
|
||||
class context : public error_context {
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ void BasicAmountTestCase::testIntegerDivision()
|
|||
amount_t x1(123L);
|
||||
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), 0L / x1);
|
||||
assertEqual(x1, x1 / 1L);
|
||||
|
|
@ -376,7 +376,7 @@ void BasicAmountTestCase::testFractionalDivision()
|
|||
amount_t x1(123.123);
|
||||
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"), 1.0 / x1);
|
||||
assertEqual(x1, x1 / 1.0);
|
||||
|
|
|
|||
|
|
@ -232,13 +232,13 @@ void CommodityAmountTestCase::testAddition()
|
|||
assertEqual(string("$246.90"), (x1 + x1).to_string());
|
||||
assertEqual(string("$246.91"), (x1 + x2).to_string());
|
||||
|
||||
assertThrow(x1 + x0, amount_exception);
|
||||
assertThrow(x1 + x3, amount_exception);
|
||||
assertThrow(x1 + x4, amount_exception);
|
||||
assertThrow(x1 + x5, amount_exception);
|
||||
assertThrow(x1 + x6, amount_exception);
|
||||
assertThrow(x1 + 123.45, amount_exception);
|
||||
assertThrow(x1 + 123L, amount_exception);
|
||||
assertThrow(x1 + x0, amount_error);
|
||||
assertThrow(x1 + x3, amount_error);
|
||||
assertThrow(x1 + x4, amount_error);
|
||||
assertThrow(x1 + x5, amount_error);
|
||||
assertThrow(x1 + x6, amount_error);
|
||||
assertThrow(x1 + 123.45, amount_error);
|
||||
assertThrow(x1 + 123L, amount_error);
|
||||
|
||||
assertEqual(amount_t("DM 246.90"), x3 + x3);
|
||||
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.01"), (x1 - x2).to_string());
|
||||
|
||||
assertThrow(x1 - x0, amount_exception);
|
||||
assertThrow(x1 - x3, amount_exception);
|
||||
assertThrow(x1 - x4, amount_exception);
|
||||
assertThrow(x1 - x5, amount_exception);
|
||||
assertThrow(x1 - x6, amount_exception);
|
||||
assertThrow(x1 - 123.45, amount_exception);
|
||||
assertThrow(x1 - 123L, amount_exception);
|
||||
assertThrow(x1 - x0, amount_error);
|
||||
assertThrow(x1 - x3, amount_error);
|
||||
assertThrow(x1 - x4, amount_error);
|
||||
assertThrow(x1 - x5, amount_error);
|
||||
assertThrow(x1 - x6, amount_error);
|
||||
assertThrow(x1 - 123.45, amount_error);
|
||||
assertThrow(x1 - 123L, amount_error);
|
||||
|
||||
assertEqual(amount_t("DM 0.00"), x3 - x3);
|
||||
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("$15199.99986168"), (x2 * x1).to_string());
|
||||
|
||||
assertThrow(x1 * x3, amount_exception);
|
||||
assertThrow(x1 * x4, amount_exception);
|
||||
assertThrow(x1 * x5, amount_exception);
|
||||
assertThrow(x1 * x3, amount_error);
|
||||
assertThrow(x1 * x4, amount_error);
|
||||
assertThrow(x1 * x5, amount_error);
|
||||
|
||||
x1 *= amount_t("123.12");
|
||||
assertEqual(internalAmount("$15158.5344"), x1);
|
||||
|
|
@ -410,7 +410,7 @@ void CommodityAmountTestCase::testDivision()
|
|||
amount_t x4("123.45 euro");
|
||||
amount_t x5("123.45€");
|
||||
|
||||
assertThrow(x1 / 0L, amount_exception);
|
||||
assertThrow(x1 / 0L, amount_error);
|
||||
assertEqual(amount_t("$0.00"), 0L / x1);
|
||||
assertEqual(x1, x1 / 1L);
|
||||
assertEqual(internalAmount("$0.00812216"), 1L / x1);
|
||||
|
|
@ -428,9 +428,9 @@ void CommodityAmountTestCase::testDivision()
|
|||
assertEqual(string("$1.00"), (x1 / x2).to_string());
|
||||
assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_string());
|
||||
|
||||
assertThrow(x1 / x3, amount_exception);
|
||||
assertThrow(x1 / x4, amount_exception);
|
||||
assertThrow(x1 / x5, amount_exception);
|
||||
assertThrow(x1 / x3, amount_error);
|
||||
assertThrow(x1 / x4, amount_error);
|
||||
assertThrow(x1 / x5, amount_error);
|
||||
|
||||
x1 /= amount_t("123.12");
|
||||
assertEqual(internalAmount("$1.00"), x1);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue