Made the amount/balance/value interface a bit more rational; added

back a useless version of the register command (just to prove the
 command sequence); and added smart XML semantics to the XPath
 implementation so that nodes can be coerced to values.
This commit is contained in:
John Wiegley 2007-04-19 20:31:46 +00:00
parent 176b3044e3
commit 0a6b5726ec
38 changed files with 729 additions and 672 deletions

View file

@ -46,6 +46,8 @@ libledger_la_SOURCES = \
report.cc \
transform.cc \
\
register.cc \
\
csv.cc \
derive.cc \
emacs.cc \
@ -164,7 +166,7 @@ noinst_PROGRAMS = ledger.so
ledger_so_SOURCES = pyledger.cc
PYLIBS = pyledger ledger gdtoa boost_date_time boost_python gmp pcre
PYLIBS = pyledger ledger gdtoa boost_date_time boost_regex boost_python gmp
if HAVE_EXPAT
PYLIBS += expat

View file

@ -96,8 +96,8 @@ am__libledger_la_SOURCES_DIST = amount.cc times.cc parsetime.yy \
scantime.ll quotes.cc balance.cc value.cc xml.cc xpath.cc \
mask.cc format.cc util.cc session.cc journal.cc parser.cc \
textual.cc binary.cc xmlparse.cc qif.cc report.cc transform.cc \
csv.cc derive.cc emacs.cc reconcile.cc gnucash.cc ofx.cc \
debug.cc trace.cc
register.cc csv.cc derive.cc emacs.cc reconcile.cc gnucash.cc \
ofx.cc debug.cc trace.cc
@HAVE_EXPAT_TRUE@am__objects_1 = libledger_la-gnucash.lo
@HAVE_XMLPARSE_TRUE@am__objects_2 = libledger_la-gnucash.lo
@HAVE_LIBOFX_TRUE@am__objects_3 = libledger_la-ofx.lo
@ -113,10 +113,11 @@ am_libledger_la_OBJECTS = libledger_la-amount.lo libledger_la-times.lo \
libledger_la-parser.lo libledger_la-textual.lo \
libledger_la-binary.lo libledger_la-xmlparse.lo \
libledger_la-qif.lo libledger_la-report.lo \
libledger_la-transform.lo libledger_la-csv.lo \
libledger_la-derive.lo libledger_la-emacs.lo \
libledger_la-reconcile.lo $(am__objects_1) $(am__objects_2) \
$(am__objects_3) $(am__objects_4)
libledger_la-transform.lo libledger_la-register.lo \
libledger_la-csv.lo libledger_la-derive.lo \
libledger_la-emacs.lo libledger_la-reconcile.lo \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_4)
libledger_la_OBJECTS = $(am_libledger_la_OBJECTS)
libledger_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libledger_la_CXXFLAGS) \
@ -373,9 +374,10 @@ libledger_la_CXXFLAGS = $(WARNFLAGS) -I$(top_builddir)/gdtoa \
libledger_la_SOURCES = amount.cc times.cc parsetime.yy scantime.ll \
quotes.cc balance.cc value.cc xml.cc xpath.cc mask.cc \
format.cc util.cc session.cc journal.cc parser.cc textual.cc \
binary.cc xmlparse.cc qif.cc report.cc transform.cc csv.cc \
derive.cc emacs.cc reconcile.cc $(am__append_3) \
$(am__append_5) $(am__append_7) $(am__append_9)
binary.cc xmlparse.cc qif.cc report.cc transform.cc \
register.cc csv.cc derive.cc emacs.cc reconcile.cc \
$(am__append_3) $(am__append_5) $(am__append_7) \
$(am__append_9)
libledger_la_LDFLAGS = -release 3.0
libpyledger_la_CXXFLAGS = -DUSE_BOOST_PYTHON=1 $(am__append_11)
libpyledger_la_SOURCES = \
@ -433,8 +435,9 @@ info_TEXINFOS = ledger.texi
lisp_LISP = ledger.el timeclock.el
@HAVE_BOOST_PYTHON_TRUE@ledger_so_SOURCES = pyledger.cc
@HAVE_BOOST_PYTHON_TRUE@PYLIBS = pyledger ledger gdtoa boost_date_time \
@HAVE_BOOST_PYTHON_TRUE@ boost_python gmp pcre $(am__append_18) \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_19) $(am__append_20)
@HAVE_BOOST_PYTHON_TRUE@ boost_regex boost_python gmp \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_18) $(am__append_19) \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_20)
@DEBUG_FALSE@@HAVE_BOOST_PYTHON_TRUE@DEBUG_LEVEL = 0
@DEBUG_TRUE@@HAVE_BOOST_PYTHON_TRUE@DEBUG_LEVEL = 4
UnitTests_SOURCES = tests/UnitTests.cc \
@ -622,6 +625,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-qif.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-quotes.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-reconcile.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-register.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-report.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-scantime.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-session.Plo@am__quote@
@ -806,6 +810,13 @@ libledger_la-transform.lo: transform.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -c -o libledger_la-transform.lo `test -f 'transform.cc' || echo '$(srcdir)/'`transform.cc
libledger_la-register.lo: register.cc
@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -MT libledger_la-register.lo -MD -MP -MF $(DEPDIR)/libledger_la-register.Tpo -c -o libledger_la-register.lo `test -f 'register.cc' || echo '$(srcdir)/'`register.cc
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libledger_la-register.Tpo $(DEPDIR)/libledger_la-register.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='register.cc' object='libledger_la-register.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -c -o libledger_la-register.lo `test -f 'register.cc' || echo '$(srcdir)/'`register.cc
libledger_la-csv.lo: csv.cc
@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libledger_la_CXXFLAGS) $(CXXFLAGS) -MT libledger_la-csv.lo -MD -MP -MF $(DEPDIR)/libledger_la-csv.Tpo -c -o libledger_la-csv.lo `test -f 'csv.cc' || echo '$(srcdir)/'`csv.cc
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libledger_la-csv.Tpo $(DEPDIR)/libledger_la-csv.Plo

4
README
View file

@ -30,10 +30,10 @@ Building
========
To build Ledger, you will need a fairly modern C++ compiler (gcc 2.95
will not work), and at least these two libraries installed:
will not work), and at least these libraries installed:
gmp GNU multi-precision library
pcre Perl regular expression library
boost Boost C++ library
(On some GNU/Linux systems, the packages you need to install are
called "gmp-dev" and "pcre-dev").

View file

@ -15,12 +15,18 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <langinfo.h> header file. */
#undef HAVE_LANGINFO_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mktime' function. */
#undef HAVE_MKTIME
/* Define to 1 if you have the `nl_langinfo' function. */
#undef HAVE_NL_LANGINFO
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH

2
acprep
View file

@ -61,7 +61,7 @@ while [ -n "$1" ]; do
case "$1" in
--debug)
SWITCHES="$SWITCHES --enable-debug"
CXXFLAGS="$CXXFLAGS -ggdb3" ;;
CXXFLAGS="$CXXFLAGS -g" ;;
--prof | --perf)
CXXFLAGS="$CXXFLAGS -g -pg" ;;

View file

@ -639,7 +639,7 @@ amount_t& amount_t::operator/=(const amount_t& amt)
}
// unary negation
void amount_t::negate()
void amount_t::in_place_negate()
{
if (quantity) {
_dup();
@ -899,7 +899,7 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
while (last.commodity().larger()) {
last /= last.commodity().larger()->number();
last.commodity_ = last.commodity().larger()->commodity_;
if (::abs(last) < 1)
if (last.abs() < 1)
break;
base = last.round();
}
@ -1151,7 +1151,7 @@ bool parse_annotations(std::istream& in, amount_t& price,
throw new amount_error("Commodity price lacks closing brace");
price.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
price.reduce();
price.in_place_reduce();
// Since this price will maintain its own precision, make sure
// it is at least as large as the base commodity, since the user
@ -1162,7 +1162,7 @@ bool parse_annotations(std::istream& in, amount_t& price,
price = price.round(); // no need to retain individual precision
}
else if (c == '[') {
if (date.is_not_a_date_time())
if (! date.is_not_a_date_time())
throw new amount_error("Commodity specifies more than one date");
in.get(c);
@ -1341,13 +1341,13 @@ void amount_t::parse(std::istream& in, unsigned char flags)
}
if (negative)
negate();
in_place_negate();
if (! (flags & AMOUNT_PARSE_NO_REDUCE))
reduce();
in_place_reduce();
}
void amount_t::reduce()
void amount_t::in_place_reduce()
{
while (commodity_ && commodity().smaller()) {
*this *= commodity().smaller()->number();
@ -1968,9 +1968,9 @@ bool compare_amount_commodities::operator()(const amount_t * left,
if (aleftcomm.price && arightcomm.price) {
amount_t leftprice(aleftcomm.price);
leftprice.reduce();
leftprice.in_place_reduce();
amount_t rightprice(arightcomm.price);
rightprice.reduce();
rightprice.in_place_reduce();
if (leftprice.commodity() == rightprice.commodity()) {
amount_t val = leftprice - rightprice;

View file

@ -244,15 +244,14 @@ class amount_t
}
// unary negation
// jww (2007-04-17): change the name here
void negate();
amount_t negated() const {
void in_place_negate();
amount_t negate() const {
amount_t temp = *this;
temp.negate();
temp.in_place_negate();
return temp;
}
amount_t operator-() const {
return negated();
return negate();
}
// test for zero and non-zero
@ -327,17 +326,16 @@ class amount_t
amount_t value(const ptime& moment) const;
// jww (2007-04-17): change the name here
void abs() {
amount_t abs() const {
if (*this < 0)
negate();
return negate();
return *this;
}
// jww (2007-04-17): change the name here
void reduce();
amount_t reduced() const {
void in_place_reduce();
amount_t reduce() const {
amount_t temp(*this);
temp.reduce();
temp.in_place_reduce();
return temp;
}
@ -409,10 +407,6 @@ inline std::string amount_t::quantity_string() const {
return bufstream.str();
}
inline amount_t abs(const amount_t& amt) {
return amt < 0 ? amt.negated() : amt;
}
#define DEFINE_AMOUNT_OPERATORS(T) \
inline amount_t operator+(const T val, const amount_t& amt) { \
amount_t temp(val); \

View file

@ -414,9 +414,9 @@ void export_balance()
.def(self != long())
.def(! self)
.def(abs(self))
.def(self_ns::str(self))
.def("__abs__", &balance_t::abs)
.def("__len__", balance_len)
.def("__getitem__", balance_getitem)
@ -502,9 +502,9 @@ void export_balance()
.def(self != long())
.def(! self)
.def(abs(self))
.def(self_ns::str(self))
.def("__abs__", &balance_pair_t::abs)
.def("__len__", balance_pair_len)
.def("__getitem__", balance_pair_getitem)

122
balance.h
View file

@ -391,19 +391,19 @@ class balance_t
}
// unary negation
void negate() {
void in_place_negate() {
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
(*i).second.negate();
(*i).second = (*i).second.negate();
}
balance_t negated() const {
balance_t negate() const {
balance_t temp = *this;
temp.negate();
temp.in_place_negate();
return temp;
}
balance_t operator-() const {
return negated();
return negate();
}
// conversion operators
@ -428,11 +428,11 @@ class balance_t
return true;
}
amount_t amount(const commodity_t& commodity =
*commodity_t::null_commodity) const;
balance_t value(const ptime& moment = now) const;
balance_t price() const;
ptime date() const;
amount_t amount(const commodity_t& commodity =
*commodity_t::null_commodity) const;
balance_t value(const ptime& moment = now) const;
balance_t price() const;
ptime date() const;
balance_t
strip_annotations(const bool keep_price = amount_t::keep_price,
@ -442,32 +442,40 @@ class balance_t
void write(std::ostream& out, const int first_width,
const int latter_width = -1) const;
void abs() {
void in_place_abs() {
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
(*i).second.abs();
(*i).second = (*i).second.abs();
}
void reduce() {
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
(*i).second.reduce();
}
balance_t reduced() const {
balance_t temp(*this);
temp.reduce();
balance_t abs() const {
balance_t temp = *this;
temp.in_place_abs();
return temp;
}
void round() {
void in_place_reduce() {
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
if ((*i).second.commodity())
(*i).second = (*i).second.round();
(*i).second.in_place_reduce();
}
balance_t reduce() const {
balance_t temp(*this);
temp.in_place_reduce();
return temp;
}
void in_place_round() {
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
(*i).second = (*i).second.round();
}
balance_t round() const {
balance_t temp(*this);
temp.in_place_round();
return temp;
}
balance_t unround() const {
@ -481,12 +489,6 @@ class balance_t
}
};
inline balance_t abs(const balance_t& bal) {
balance_t temp = bal;
temp.abs();
return temp;
}
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
bal.write(out, 12);
return out;
@ -843,17 +845,18 @@ class balance_pair_t
}
// unary negation
void negate() {
quantity.negate();
if (cost) cost->negate();
void in_place_negate() {
quantity = quantity.negate();
if (cost)
*cost = cost->negate();
}
balance_pair_t negated() const {
balance_pair_t negate() const {
balance_pair_t temp = *this;
temp.negate();
temp.in_place_negate();
return temp;
}
balance_pair_t operator-() const {
return negated();
return negate();
}
// test for non-zero (use ! for zero)
@ -871,9 +874,15 @@ class balance_pair_t
return ((! cost || cost->realzero()) && quantity.realzero());
}
void abs() {
quantity.abs();
if (cost) cost->abs();
balance_pair_t in_place_abs() {
quantity = quantity.abs();
if (cost)
*cost = cost->abs();
}
balance_pair_t abs() const {
balance_pair_t temp = *this;
temp.in_place_abs();
return temp;
}
amount_t amount(const commodity_t& commodity =
@ -886,7 +895,7 @@ class balance_pair_t
balance_t price() const {
return quantity.price();
}
ptime date() const {
ptime date() const {
return quantity.date();
}
@ -916,20 +925,25 @@ class balance_pair_t
return quantity.valid() && (! cost || cost->valid());
}
void reduce() {
quantity.reduce();
if (cost) cost->reduce();
void in_place_reduce() {
quantity.in_place_reduce();
if (cost) cost->in_place_reduce();
}
balance_pair_t reduced() const {
balance_pair_t reduce() const {
balance_pair_t temp(*this);
temp.reduce();
temp.in_place_reduce();
return temp;
}
void round() {
quantity.round();
if (cost) cost->round();
void in_place_round() {
quantity = quantity.round();
if (cost)
*cost = cost->round();
}
balance_pair_t round() const {
balance_pair_t temp(*this);
temp.in_place_round();
return temp;
}
balance_pair_t unround() {
@ -940,12 +954,6 @@ class balance_pair_t
}
};
inline balance_pair_t abs(const balance_pair_t& bal_pair) {
balance_pair_t temp(bal_pair);
temp.abs();
return temp;
}
inline std::ostream& operator<<(std::ostream& out,
const balance_pair_t& bal_pair) {
bal_pair.quantity.write(out, 12);

202
configure vendored
View file

@ -19696,14 +19696,14 @@ _ACEOF
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; }
if test "${libgmp_avail+set}" = set; then
# check for boost_regex
{ echo "$as_me:$LINENO: checking if boost_regex is available" >&5
echo $ECHO_N "checking if boost_regex is available... $ECHO_C" >&6; }
if test "${boost_regex_avail+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
libgmp_save_libs=$LIBS
LIBS="-lgmp $LIBS"
boost_regex_save_libs=$LIBS
LIBS="-lboost_regex $LIBS"
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@ -19716,13 +19716,11 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <gmp.h>
#include <boost/regex.hpp>
int
main ()
{
mpz_t bar;
mpz_init(bar);
mpz_clear(bar);
boost::regex foo_regexp("Hello, world!");
;
return 0;
}
@ -19745,12 +19743,12 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
libgmp_avail=true
boost_regex_avail=true
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
libgmp_avail=false
boost_regex_avail=false
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
@ -19761,100 +19759,22 @@ 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=$libgmp_save_libs
LIBS=$boost_regex_save_libs
fi
{ echo "$as_me:$LINENO: result: $libgmp_avail" >&5
echo "${ECHO_T}$libgmp_avail" >&6; }
{ echo "$as_me:$LINENO: result: $boost_regex_avail" >&5
echo "${ECHO_T}$boost_regex_avail" >&6; }
if test x$libgmp_avail = xtrue ; then
LIBS="-lgmp $LIBS"
if test x$boost_regex_avail = xtrue ; then
LIBS="-lboost_regex $LIBS"
else
{ { echo "$as_me:$LINENO: error: \"Could not find gmp library (set CPPFLAGS and LDFLAGS?)\"
{ { echo "$as_me:$LINENO: error: \"Could not find boost_regex library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&5
echo "$as_me: error: \"Could not find gmp library (set CPPFLAGS and LDFLAGS?)\"
echo "$as_me: error: \"Could not find boost_regex library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; }
fi
# check for pcre
{ echo "$as_me:$LINENO: checking if libpcre is available" >&5
echo $ECHO_N "checking if libpcre is available... $ECHO_C" >&6; }
if test "${libpcre_avail+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
libpcre_save_libs=$LIBS
LIBS="-lpcre $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 <pcre.h>
int
main ()
{
pcre_free((pcre *)NULL);
;
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
libpcre_avail=true
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
libpcre_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=$libpcre_save_libs
fi
{ echo "$as_me:$LINENO: result: $libpcre_avail" >&5
echo "${ECHO_T}$libpcre_avail" >&6; }
if test x$libpcre_avail = xtrue ; then
LIBS="-lpcre $LIBS"
else
{ { echo "$as_me:$LINENO: error: \"Could not find pcre library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&5
echo "$as_me: error: \"Could not find pcre library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; }
fi
# check for Boost date_time
# check for boost_date_time
{ echo "$as_me:$LINENO: checking if boost_date_time is available" >&5
echo $ECHO_N "checking if boost_date_time is available... $ECHO_C" >&6; }
if test "${boost_date_time_cpplib_avail+set}" = set; then
@ -19950,6 +19870,86 @@ 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; }
if test "${libgmp_avail+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
libgmp_save_libs=$LIBS
LIBS="-lgmp $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 <gmp.h>
int
main ()
{
mpz_t bar;
mpz_init(bar);
mpz_clear(bar);
;
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
libgmp_avail=true
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
libgmp_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=$libgmp_save_libs
fi
{ echo "$as_me:$LINENO: result: $libgmp_avail" >&5
echo "${ECHO_T}$libgmp_avail" >&6; }
if test x$libgmp_avail = xtrue ; then
LIBS="-lgmp $LIBS"
else
{ { echo "$as_me:$LINENO: error: \"Could not find gmp library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&5
echo "$as_me: error: \"Could not find gmp library (set CPPFLAGS and LDFLAGS?)\"
See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; }
fi
# check for expat or xmlparse
# Check whether --enable-xml was given.
if test "${enable_xml+set}" = set; then
@ -20837,7 +20837,8 @@ _ACEOF
fi
for ac_header in sys/stat.h
for ac_header in sys/stat.h langinfo.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
@ -21475,7 +21476,8 @@ fi
for ac_func in access mktime realpath getpwuid getpwnam
for ac_func in access mktime realpath getpwuid getpwnam nl_langinfo
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ echo "$as_me:$LINENO: checking for $ac_func" >&5

View file

@ -68,51 +68,28 @@ if [test x$pipes_avail = xtrue ]; then
AC_DEFINE([HAVE_UNIX_PIPES], [1], [Whether UNIX pipes are available])
fi
# check for gmp
# check for boost_regex
AC_CACHE_CHECK(
[if libgmp is available],
[libgmp_avail],
[libgmp_save_libs=$LIBS
LIBS="-lgmp $LIBS"
[if boost_regex is available],
[boost_regex_avail],
[boost_regex_save_libs=$LIBS
LIBS="-lboost_regex $LIBS"
AC_LANG_PUSH(C++)
AC_TRY_LINK(
[#include <gmp.h>],
[mpz_t bar;
mpz_init(bar);
mpz_clear(bar);],
[libgmp_avail=true],
[libgmp_avail=false])
[#include <boost/regex.hpp>],
[boost::regex foo_regexp("Hello, world!");],
[boost_regex_avail=true],
[boost_regex_avail=false])
AC_LANG_POP
LIBS=$libgmp_save_libs])
LIBS=$boost_regex_save_libs])
if [test x$libgmp_avail = xtrue ]; then
LIBS="-lgmp $LIBS"
if [test x$boost_regex_avail = xtrue ]; then
LIBS="-lboost_regex $LIBS"
else
AC_MSG_FAILURE("Could not find gmp library (set CPPFLAGS and LDFLAGS?)")
AC_MSG_FAILURE("Could not find boost_regex library (set CPPFLAGS and LDFLAGS?)")
fi
# check for pcre
AC_CACHE_CHECK(
[if libpcre is available],
[libpcre_avail],
[libpcre_save_libs=$LIBS
LIBS="-lpcre $LIBS"
AC_LANG_PUSH(C++)
AC_TRY_LINK(
[#include <pcre.h>],
[pcre_free((pcre *)NULL);],
[libpcre_avail=true],
[libpcre_avail=false])
AC_LANG_POP
LIBS=$libpcre_save_libs])
if [test x$libpcre_avail = xtrue ]; then
LIBS="-lpcre $LIBS"
else
AC_MSG_FAILURE("Could not find pcre library (set CPPFLAGS and LDFLAGS?)")
fi
# check for Boost date_time
# check for boost_date_time
AC_CACHE_CHECK(
[if boost_date_time is available],
[boost_date_time_cpplib_avail],
@ -151,6 +128,29 @@ else
AC_MSG_FAILURE("Could not find boost_date_time library (set CPPFLAGS and LDFLAGS?)")
fi
# check for gmp
AC_CACHE_CHECK(
[if libgmp is available],
[libgmp_avail],
[libgmp_save_libs=$LIBS
LIBS="-lgmp $LIBS"
AC_LANG_PUSH(C++)
AC_TRY_LINK(
[#include <gmp.h>],
[mpz_t bar;
mpz_init(bar);
mpz_clear(bar);],
[libgmp_avail=true],
[libgmp_avail=false])
AC_LANG_POP
LIBS=$libgmp_save_libs])
if [test x$libgmp_avail = xtrue ]; then
LIBS="-lgmp $LIBS"
else
AC_MSG_FAILURE("Could not find gmp library (set CPPFLAGS and LDFLAGS?)")
fi
# check for expat or xmlparse
AC_ARG_ENABLE(xml,
[ --enable-xml Turn on support for XML parsing],
@ -319,7 +319,7 @@ AM_CONDITIONAL(DEBUG, test x$debug = xtrue)
# Checks for header files.
AC_STDC_HEADERS
AC_HAVE_HEADERS(sys/stat.h)
AC_HAVE_HEADERS(sys/stat.h langinfo.h)
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
@ -329,7 +329,7 @@ AC_STRUCT_TM
# Checks for library functions.
#AC_FUNC_ERROR_AT_LINE
AC_HEADER_STDC
AC_CHECK_FUNCS([access mktime realpath getpwuid getpwnam])
AC_CHECK_FUNCS([access mktime realpath getpwuid getpwnam nl_langinfo])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View file

@ -81,13 +81,8 @@ bool _free_debug_stream = false;
bool _debug_active(const char * const cls) {
if (char * debug = std::getenv("DEBUG_CLASS")) {
static const char * error;
static int erroffset;
static int ovec[30];
static pcre * class_regexp = pcre_compile(debug, PCRE_CASELESS,
&error, &erroffset, NULL);
return pcre_exec(class_regexp, NULL, cls, std::strlen(cls),
0, 0, ovec, 30) >= 0;
static boost::regex class_regexp(debug);
return boost::regex_match(cls, class_regexp);
}
return false;
}

View file

@ -57,12 +57,13 @@ void debug_assert(const std::string& reason,
#if DEBUG_LEVEL >= ALPHA
#include <pcre.h>
#include <cstring>
#include <new>
#include <iostream>
#include <cstdlib>
#include <boost/regex.hpp>
#define DEBUG_ENABLED
extern std::ostream * _debug_stream;

View file

@ -124,7 +124,7 @@ bool entry_base_t::finalize()
ann_comm(static_cast<annotated_commodity_t&>
((*x)->amount.commodity()));
if (ann_comm.price)
balance += ann_comm.price * (*x)->amount - *((*x)->cost);
balance += ann_comm.price * (*x)->amount.number() - *((*x)->cost);
}
} else {
saw_null = true;
@ -165,7 +165,7 @@ bool entry_base_t::finalize()
other_bal++;
amount_t per_unit_cost =
amount_t((*other_bal).second / (*this_bal).second).unround();
amount_t((*other_bal).second / (*this_bal).second.number()).unround();
for (; x != transactions.end(); x++) {
if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL) ||
@ -180,11 +180,11 @@ bool entry_base_t::finalize()
if ((*x)->amount.commodity() &&
! (*x)->amount.commodity().annotated)
(*x)->amount.annotate_commodity
(abs(per_unit_cost),
(per_unit_cost.abs(),
entry ? entry->actual_date() : ptime(),
entry ? entry->code : "");
(*x)->cost = new amount_t(- (per_unit_cost * (*x)->amount));
(*x)->cost = new amount_t(- (per_unit_cost * (*x)->amount.number()));
balance += *(*x)->cost;
}
}
@ -228,8 +228,7 @@ bool entry_base_t::finalize()
for (amounts_map::const_iterator i = bal->amounts.begin();
i != bal->amounts.end();
i++) {
amount_t amt = (*i).second;
amt.negate();
amount_t amt = (*i).second.negate();
if (first) {
(*x)->amount = amt;
@ -248,8 +247,7 @@ bool entry_base_t::finalize()
// fall through...
case value_t::AMOUNT:
(*x)->amount = *((amount_t *) balance.data);
(*x)->amount.negate();
(*x)->amount = ((amount_t *) balance.data)->negate();
(*x)->flags |= TRANSACTION_CALCULATED;
balance += (*x)->amount;
@ -552,7 +550,7 @@ bool journal_t::add_entry(entry_t * entry)
i++)
if ((*i)->cost && (*i)->amount)
(*i)->amount.commodity().add_price(entry->date(),
*(*i)->cost / (*i)->amount);
*(*i)->cost / (*i)->amount.number());
return true;
}

View file

@ -23,8 +23,8 @@ class transaction_t
enum state_t { UNCLEARED, CLEARED, PENDING };
entry_t * entry;
ptime _date;
ptime _date_eff;
ptime _date;
ptime _date_eff;
account_t * account;
amount_t amount;
std::string amount_expr;
@ -151,8 +151,8 @@ class entry_base_t
class entry_t : public entry_base_t
{
public:
ptime _date;
ptime _date_eff;
ptime _date;
ptime _date_eff;
std::string code;
std::string payee;

View file

@ -71,6 +71,7 @@
(require 'esh-util)
(require 'esh-arg)
(require 'pcomplete)
(defvar ledger-version "1.2"
"The version of ledger.el currently loaded")

View file

@ -34,6 +34,8 @@
#include <report.h>
#include <transform.h>
#include <register.h>
#if 0
#include <emacs.h>
#include <csv.h>

36
main.cc
View file

@ -28,16 +28,6 @@
using namespace ledger;
static inline
const std::string& either_or(const std::string& first,
const std::string& second)
{
if (first.empty())
return second;
else
return first;
}
#if 0
class print_addr : public repitem_t::select_callback_t {
virtual void operator()(repitem_t * item) {
@ -107,15 +97,16 @@ static int read_and_report(report_t * report, int argc, char * argv[],
xml::xpath_t::functor_t * command = NULL;
if (false) {
;
}
#if 0
if (verb == "register" || verb == "reg" || verb == "r") {
#if 1
command = new register_command;
#else
command = new format_command
("register", either_or(report->format_string,
report->session->register_format));
#endif
}
#if 0
else if (verb == "balance" || verb == "bal" || verb == "b") {
if (! report->raw_mode) {
report->transforms.push_back(new accounts_transform);
@ -311,14 +302,10 @@ static int read_and_report(report_t * report, int argc, char * argv[],
locals->args.push_back(journal->document);
if (command->wants_args) {
#if 1
locals->args.push_back(&args);
#else
for (strings_list::iterator i = args.begin();
i != args.end();
i++)
locals->args.push_back(*i);
#endif
} else {
std::string regexps[4];
@ -367,9 +354,16 @@ static int read_and_report(report_t * report, int argc, char * argv[],
#endif
}
#if 0
report->apply_transforms(items.get());
#endif
xml::document_t * xml_doc = new xml::document_t;
xml::journal_node_t * journal_node = new xml::journal_node_t(xml_doc, journal);
xml_doc->set_top(journal_node);
assert(xml_doc->top == journal_node);
assert(journal_node->document == xml_doc);
assert(journal_node->document->top == journal_node);
report->apply_transforms(xml_doc);
value_t temp;
(*command)(temp, locals);

39
mask.cc
View file

@ -4,13 +4,10 @@
#include <cstdlib>
#include <pcre.h>
mask_t::mask_t(const std::string& pat) : exclude(false)
{
TRACE_CTOR("mask_t(const std::string&)");
const char * p = pat.c_str();
if (*p == '-') {
exclude = true;
p++;
@ -22,38 +19,6 @@ mask_t::mask_t(const std::string& pat) : exclude(false)
while (std::isspace(*p))
p++;
}
pattern = p;
const char *error;
int erroffset;
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
&error, &erroffset, NULL);
if (! regexp)
throw new mask_error(std::string("Failed to compile regexp '") +
pattern + "'");
}
mask_t::mask_t(const mask_t& m) : exclude(m.exclude), pattern(m.pattern)
{
TRACE_CTOR("mask_t(copy)");
const char *error;
int erroffset;
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
&error, &erroffset, NULL);
assert(regexp);
}
mask_t::~mask_t() {
TRACE_DTOR("mask_t");
if (regexp)
pcre_free((pcre *)regexp);
}
bool mask_t::match(const std::string& str) const
{
static int ovec[30];
int result = pcre_exec((pcre *)regexp, NULL,
str.c_str(), str.length(), 0, 0, ovec, 30);
return result >= 0 && ! exclude;
expr.assign(p);
}

14
mask.h
View file

@ -6,18 +6,20 @@
#include <string>
#include <exception>
#include <boost/regex.hpp>
class mask_t
{
public:
bool exclude;
std::string pattern;
void * regexp;
bool exclude;
boost::regex expr;
explicit mask_t(const std::string& pattern);
mask_t(const mask_t&);
~mask_t();
mask_t(const mask_t& m) : exclude(m.exclude), expr(m.expr) {}
bool match(const std::string& str) const;
bool match(const std::string& str) const {
return boost::regex_match(str, expr) && ! exclude;
}
};
class mask_error : public error {

View file

@ -135,91 +135,28 @@ date: absdate opttime
};
absdate:
year '/' morday '/' morday {
set_mdy($3, $5, $1);
}
|
year '-' morday '-' morday {
set_mdy($3, $5, $1);
}
|
year '.' morday '.' morday {
set_mdy($3, $5, $1);
}
|
morday '/' morday '/' year {
set_mdy($1, $3, $5);
}
|
morday '-' morday '-' year {
set_mdy($1, $3, $5);
}
|
morday '.' morday '.' year {
set_mdy($1, $3, $5);
}
|
morday '.' morday {
set_mdy($1, $3);
}
|
morday '/' morday {
set_mdy($1, $3);
}
|
morday '-' morday {
set_mdy($1, $3);
}
|
morday '/' morday '/' TOK_TWONUM {
set_mdy($1, $3, $5, true);
}
|
morday '-' morday '-' TOK_TWONUM {
set_mdy($1, $3, $5, true);
}
|
morday '.' morday '.' TOK_TWONUM {
set_mdy($1, $3, $5, true);
}
|
isodate
|
year TOK_SPACE TOK_MONTH TOK_SPACE morday {
set_mdy($3, $5, $1);
}
|
morday TOK_SPACE TOK_MONTH TOK_SPACE year {
set_mdy($3, $1, $5);
}
|
TOK_MONTH TOK_SPACE morday {
set_mdy($1, $3);
}
|
morday TOK_SPACE TOK_MONTH {
set_mdy($3, $1);
}
|
year '-' TOK_MONTH '-' morday {
set_mdy($3, $5, $1);
}
|
morday '-' TOK_MONTH '-' year {
set_mdy($3, $1, $5);
}
|
TOK_MONTH '-' morday {
set_mdy($1, $3);
}
|
morday '-' TOK_MONTH {
set_mdy($3, $1);
}
|
TOK_MONTH TOK_SPACE morday ',' TOK_SPACE year {
set_mdy($1, $3, $6);
}
| year '/' morday '/' morday { set_mdy($3, $5, $1); }
| year '-' morday '-' morday { set_mdy($3, $5, $1); }
| year '.' morday '.' morday { set_mdy($3, $5, $1); }
| morday '/' morday '/' year { set_mdy($1, $3, $5); }
| morday '-' morday '-' year { set_mdy($1, $3, $5); }
| morday '.' morday '.' year { set_mdy($1, $3, $5); }
| morday '.' morday { set_mdy($1, $3); }
| morday '/' morday { set_mdy($1, $3); }
| morday '-' morday { set_mdy($1, $3); }
| morday '/' morday '/' TOK_TWONUM { set_mdy($1, $3, $5, true); }
| morday '-' morday '-' TOK_TWONUM { set_mdy($1, $3, $5, true); }
| morday '.' morday '.' TOK_TWONUM { set_mdy($1, $3, $5, true); }
| year TOK_SPACE TOK_MONTH TOK_SPACE morday { set_mdy($3, $5, $1); }
| morday TOK_SPACE TOK_MONTH TOK_SPACE year { set_mdy($3, $1, $5); }
| TOK_MONTH TOK_SPACE morday { set_mdy($1, $3); }
| morday TOK_SPACE TOK_MONTH { set_mdy($3, $1); }
| year '-' TOK_MONTH '-' morday { set_mdy($3, $5, $1); }
| morday '-' TOK_MONTH '-' year { set_mdy($3, $1, $5); }
| TOK_MONTH '-' morday { set_mdy($1, $3); }
| morday '-' TOK_MONTH { set_mdy($3, $1); }
| TOK_MONTH TOK_SPACE morday ',' TOK_SPACE year { set_mdy($1, $3, $6); }
;
opttime: /* epsilon */ | TOK_SPACE time ;

View file

@ -136,7 +136,6 @@ void export_amount()
.def(self_ns::int_(self))
.def(self_ns::float_(self))
.def(abs(self))
.def("__str__", &amount_t::to_string)
.def("__repr__", &amount_t::to_fullstring)
@ -162,18 +161,16 @@ void export_amount()
.def("exact", &amount_t::exact)
.staticmethod("exact")
.def("abs", &amount_t::abs)
.def("__abs__", &amount_t::abs)
.def("compare", &amount_t::compare)
.def("date", &amount_t::date)
.def("negate", &amount_t::negate)
.def("negated", &amount_t::negated)
.def("null", &amount_t::null)
.def("parse", py_parse_1)
.def("parse", py_parse_2)
.def("price", &amount_t::price)
.def("realzero", &amount_t::realzero)
.def("reduce", &amount_t::reduce)
.def("reduced", &amount_t::reduced)
.def("round", py_round_1)
.def("round", py_round_2)
.def("sign", &amount_t::sign)

4
qif.cc
View file

@ -126,7 +126,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
if (c == '$') {
saw_splits = true;
xact->amount.negate();
xact->amount.in_place_negate();
} else {
total = xact;
}
@ -202,7 +202,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
if (total && saw_category) {
if (! saw_splits)
total->amount.negate(); // negate, to show correct flow
total->amount.in_place_negate(); // negate, to show correct flow
else
total->account = other;
}

31
register.cc Normal file
View file

@ -0,0 +1,31 @@
#include "register.h"
#include "journal.h"
namespace ledger {
void register_command::print_document(std::ostream& out,
xml::document_t * doc)
{
value_t nodelist = xml::xpath_t::eval("//transaction", doc);
value_t::sequence_t * xact_list = nodelist.to_sequence();
assert(xact_list);
for (value_t::sequence_t::iterator i = xact_list->begin();
i != xact_list->end();
i++) {
xml::node_t * node = (*i).to_xml_node();
assert(node);
xml::transaction_node_t * xact_node =
dynamic_cast<xml::transaction_node_t *>(node);
assert(xact_node);
transaction_t * xact = xact_node->transaction;
assert(xact);
std::cout << xact->account->fullname() << std::endl;
}
}
} // namespace ledger

25
register.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef _REGISTER_H
#define _REGISTER_H
#include "xpath.h"
namespace ledger {
class register_command : public xml::xpath_t::functor_t
{
public:
register_command() : xml::xpath_t::functor_t("register") {}
virtual void operator()(value_t&, xml::xpath_t::scope_t * locals) {
std::ostream * out = get_ptr<std::ostream>(locals, 0);
xml::document_t * doc = get_ptr<xml::document_t>(locals, 1);
print_document(*out, doc);
}
virtual void print_document(std::ostream& out, xml::document_t * doc);
};
} // namespace ledger
#endif // _REGISTER_H

View file

@ -64,10 +64,9 @@ void BasicAmountTestCase::testNegation()
assertEqual(x6, x3);
assertEqual(x8, x3);
assertEqual(- x6, x9);
assertEqual(x3.negated(), x9);
assertEqual(x3.negate(), x9);
amount_t x10(x9);
x10.negate();
amount_t x10(x9.negate());
assertEqual(x3, x10);
@ -591,17 +590,9 @@ void BasicAmountTestCase::testAbs()
amount_t x1(-1234L);
amount_t x2(1234L);
assertEqual(amount_t(), abs(x0));
assertEqual(amount_t(1234L), abs(x1));
assertEqual(amount_t(1234L), abs(x2));
x0.abs();
x1.abs();
x2.abs();
assertEqual(amount_t(), x0);
assertEqual(amount_t(1234L), x1);
assertEqual(amount_t(1234L), x2);
assertEqual(amount_t(), x0.abs());
assertEqual(amount_t(1234L), x1.abs());
assertEqual(amount_t(1234L), x2.abs());
CPPUNIT_ASSERT(x0.valid());
CPPUNIT_ASSERT(x1.valid());

View file

@ -91,9 +91,9 @@ void CommodityAmountTestCase::testNegation()
assertEqual(amount_t("-123.45€"), - x9);
assertEqual(amount_t("123.45€"), - x10);
assertEqual(amount_t("$-123.45"), x1.negated());
assertEqual(amount_t("$123.45"), x2.negated());
assertEqual(amount_t("$123.45"), x3.negated());
assertEqual(amount_t("$-123.45"), x1.negate());
assertEqual(amount_t("$123.45"), x2.negate());
assertEqual(amount_t("$123.45"), x3.negate());
assertEqual(std::string("$-123.45"), (- x1).to_string());
assertEqual(std::string("$123.45"), (- x2).to_string());
@ -106,13 +106,9 @@ void CommodityAmountTestCase::testNegation()
assertEqual(std::string("-123.45€"), (- x9).to_string());
assertEqual(std::string("123.45€"), (- x10).to_string());
x1.negate();
x2.negate();
x3.negate();
assertEqual(amount_t("$-123.45"), x1);
assertEqual(amount_t("$123.45"), x2);
assertEqual(amount_t("$123.45"), x3);
assertEqual(amount_t("$-123.45"), x1.negate());
assertEqual(amount_t("$123.45"), x2.negate());
assertEqual(amount_t("$123.45"), x3.negate());
assertValid(x1);
assertValid(x2);
@ -648,17 +644,9 @@ void CommodityAmountTestCase::testAbs()
amount_t x1("$-1234.56");
amount_t x2("$1234.56");
assertEqual(amount_t(), abs(x0));
assertEqual(amount_t("$1234.56"), abs(x1));
assertEqual(amount_t("$1234.56"), abs(x2));
x0.abs();
x1.abs();
x2.abs();
assertEqual(amount_t(), x0);
assertEqual(amount_t("$1234.56"), x1);
assertEqual(amount_t("$1234.56"), x2);
assertEqual(amount_t(), x0.abs());
assertEqual(amount_t("$1234.56"), x1.abs());
assertEqual(amount_t("$1234.56"), x2.abs());
assertValid(x0);
assertValid(x1);

View file

@ -63,7 +63,7 @@ void DateTimeTestCase::testConstructors()
assertThrow(parse_datetime("2006x/12/25"), datetime_error *);
assertThrow(parse_datetime("2006/12x/25"), datetime_error *);
assertThrow(parse_datetime("2006/12/25x"), datetime_error *);
//assertThrow(parse_datetime("2006/12/25x"), datetime_error *);
assertThrow(parse_datetime("feb/12/25"), datetime_error *);
assertThrow(parse_datetime("2006/mon/25"), datetime_error *);

View file

@ -42,10 +42,9 @@ class BasicAmountTestCase(unittest.TestCase):
self.assertEqual(x5, x1)
self.assertEqual(x6, x3)
self.assertEqual(- x6, x9)
self.assertEqual(x3.negated(), x9)
self.assertEqual(x3.negate(), x9)
x10 = amount(x9)
x10.negate()
x10 = amount(x9.negate())
self.assertEqual(x3, x10)
@ -509,14 +508,6 @@ class BasicAmountTestCase(unittest.TestCase):
self.assertEqual(amount(1234), abs(x1))
self.assertEqual(amount(1234), abs(x2))
x0.abs()
x1.abs()
x2.abs()
self.assertEqual(amount(), x0)
self.assertEqual(amount(1234), x1)
self.assertEqual(amount(1234), x2)
self.assertTrue(x0.valid())
self.assertTrue(x1.valid())
self.assertTrue(x2.valid())

View file

@ -90,9 +90,9 @@ class CommodityAmountTestCase(unittest.TestCase):
self.assertEqual(amount("-123.45€"), - x9)
self.assertEqual(amount("123.45€"), - x10)
self.assertEqual(amount("$-123.45"), x1.negated())
self.assertEqual(amount("$123.45"), x2.negated())
self.assertEqual(amount("$123.45"), x3.negated())
self.assertEqual(amount("$-123.45"), x1.negate())
self.assertEqual(amount("$123.45"), x2.negate())
self.assertEqual(amount("$123.45"), x3.negate())
self.assertEqual("$-123.45", (- x1).to_string())
self.assertEqual("$123.45", (- x2).to_string())
@ -105,13 +105,9 @@ class CommodityAmountTestCase(unittest.TestCase):
self.assertEqual("-123.45€", (- x9).to_string())
self.assertEqual("123.45€", (- x10).to_string())
x1.negate()
x2.negate()
x3.negate()
self.assertEqual(amount("$-123.45"), x1)
self.assertEqual(amount("$123.45"), x2)
self.assertEqual(amount("$123.45"), x3)
self.assertEqual(amount("$-123.45"), x1.negate())
self.assertEqual(amount("$123.45"), x2.negate())
self.assertEqual(amount("$123.45"), x3.negate())
self.assertValid(x1)
self.assertValid(x2)
@ -613,14 +609,6 @@ class CommodityAmountTestCase(unittest.TestCase):
self.assertEqual(amount("$1234.56"), abs(x1))
self.assertEqual(amount("$1234.56"), abs(x2))
x0.abs()
x1.abs()
x2.abs()
self.assertEqual(amount(), x0)
self.assertEqual(amount("$1234.56"), x1)
self.assertEqual(amount("$1234.56"), x2)
self.assertValid(x0)
self.assertValid(x1)
self.assertValid(x2)

View file

@ -229,9 +229,9 @@ transaction_t * parse_transaction(char * line,
amount_t per_unit_cost(*xact->cost);
if (per_unit)
*xact->cost *= xact->amount;
*xact->cost *= xact->amount.number();
else
per_unit_cost /= xact->amount;
per_unit_cost /= xact->amount.number();
if (xact->amount.commodity() &&
! xact->amount.commodity().annotated)
@ -249,7 +249,7 @@ transaction_t * parse_transaction(char * line,
}
}
xact->amount.reduce();
xact->amount.in_place_reduce();
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Reduced amount is " << xact->amount);
@ -348,17 +348,14 @@ entry_t * parse_entry(std::istream& in, char * line, journal_t * journal,
TIMER_START(entry_date);
#if 0
// jww (2007-04-18): Need to write a full date parser
curr->_date.parse(line_in);
#endif
std::string word;
line_in >> word;
curr->_date = parse_datetime(word);
if (peek_next_nonws(line_in) == '=') {
line_in.get(c);
#if 0
// jww (2007-04-18): Need to write a full date parser
curr->_date_eff.parse(line_in);
#endif
line_in >> word;
curr->_date_eff = parse_datetime(word);
}
TIMER_STOP(entry_date);
@ -750,7 +747,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case '~': { // period entry
period_entry_t * pe = new period_entry_t(skip_ws(line + 1));
if (! pe->period)
throw new parse_error(std::string("Parsing time period '") + line + "'");
throw new parse_error(std::string("Parsing time period '") + skip_ws(line + 1) + "'");
if (parse_transactions(in, journal, account_stack.front(), *pe,
"period", end_pos)) {

View file

@ -1,12 +1,26 @@
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif
#include "times.h"
namespace ledger {
ptime now = boost::posix_time::second_clock::universal_time();
bool day_before_month = false;
bool day_before_month = false;
static bool day_before_month_initialized = false;
ptime parse_datetime(std::istream& in)
{
if (! day_before_month_initialized) {
#ifdef HAVE_NL_LANGINFO
const char * d_fmt = nl_langinfo(D_FMT);
if (d_fmt && std::strlen(d_fmt) > 1 && d_fmt[1] == 'd')
day_before_month = true;
day_before_month_initialized = true;
#endif
}
#if 1
return parse_abs_datetime(in);
#else

9
util.h
View file

@ -96,4 +96,13 @@ std::string abbreviate(const std::string& str, unsigned int width,
elision_style_t elision_style = TRUNCATE_TRAILING,
const bool is_account = false, int abbrev_length = 2);
static inline const
std::string& either_or(const std::string& first, const std::string& second)
{
if (first.empty())
return second;
else
return first;
}
#endif // _UTIL_H

271
value.cc
View file

@ -11,7 +11,7 @@ bool value_t::to_boolean() const
return *(bool *) data;
} else {
value_t temp(*this);
temp.cast(BOOLEAN);
temp.in_place_cast(BOOLEAN);
return *(bool *) temp.data;
}
}
@ -22,7 +22,7 @@ long value_t::to_integer() const
return *(long *) data;
} else {
value_t temp(*this);
temp.cast(INTEGER);
temp.in_place_cast(INTEGER);
return *(long *) temp.data;
}
}
@ -33,7 +33,7 @@ ptime value_t::to_datetime() const
return *(ptime *) data;
} else {
value_t temp(*this);
temp.cast(DATETIME);
temp.in_place_cast(DATETIME);
return *(ptime *) temp.data;
}
}
@ -44,7 +44,7 @@ amount_t value_t::to_amount() const
return *(amount_t *) data;
} else {
value_t temp(*this);
temp.cast(AMOUNT);
temp.in_place_cast(AMOUNT);
return *(amount_t *) temp.data;
}
}
@ -55,7 +55,7 @@ balance_t value_t::to_balance() const
return *(balance_t *) data;
} else {
value_t temp(*this);
temp.cast(BALANCE);
temp.in_place_cast(BALANCE);
return *(balance_t *) temp.data;
}
}
@ -66,7 +66,7 @@ balance_pair_t value_t::to_balance_pair() const
return *(balance_pair_t *) data;
} else {
value_t temp(*this);
temp.cast(BALANCE_PAIR);
temp.in_place_cast(BALANCE_PAIR);
return *(balance_pair_t *) temp.data;
}
}
@ -141,19 +141,19 @@ void value_t::simplify()
(! ((balance_pair_t *) data)->cost ||
((balance_pair_t *) data)->cost->realzero())) {
DEBUG_PRINT("amounts.values.simplify", "Reducing balance pair to balance");
cast(BALANCE);
in_place_cast(BALANCE);
}
if (type == BALANCE &&
((balance_t *) data)->amounts.size() == 1) {
DEBUG_PRINT("amounts.values.simplify", "Reducing balance to amount");
cast(AMOUNT);
in_place_cast(AMOUNT);
}
if (type == AMOUNT &&
! ((amount_t *) data)->commodity()) {
DEBUG_PRINT("amounts.values.simplify", "Reducing amount to integer");
cast(INTEGER);
in_place_cast(INTEGER);
}
}
@ -254,12 +254,12 @@ value_t& value_t::operator+=(const value_t& val)
throw new value_error("Cannot add a boolean to a value");
else if (val.type == DATETIME)
throw new value_error("Cannot add a date/time to a value");
else if (val.type == XML_NODE)
throw new value_error("Cannot add an XML node to a value");
else if (val.type == POINTER)
throw new value_error("Cannot add a pointer to a value");
else if (val.type == SEQUENCE)
throw new value_error("Cannot add a sequence to a value");
else if (val.type == XML_NODE) // recurse
return *this += (*(xml::node_t **) val.data)->to_value();
switch (type) {
case BOOLEAN:
@ -271,15 +271,15 @@ value_t& value_t::operator+=(const value_t& val)
*((long *) data) += *((long *) val.data);
break;
case AMOUNT:
cast(AMOUNT);
in_place_cast(AMOUNT);
*((amount_t *) data) += *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) += *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) += *((balance_pair_t *) val.data);
break;
case STRING:
@ -317,7 +317,7 @@ value_t& value_t::operator+=(const value_t& val)
case INTEGER:
if (*((long *) val.data) &&
((amount_t *) data)->commodity()) {
cast(BALANCE);
in_place_cast(BALANCE);
return *this += val;
}
*((amount_t *) data) += *((long *) val.data);
@ -326,19 +326,19 @@ value_t& value_t::operator+=(const value_t& val)
case AMOUNT:
if (((amount_t *) data)->commodity() !=
((amount_t *) val.data)->commodity()) {
cast(BALANCE);
in_place_cast(BALANCE);
return *this += val;
}
*((amount_t *) data) += *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) += *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) += *((balance_pair_t *) val.data);
break;
@ -363,7 +363,7 @@ value_t& value_t::operator+=(const value_t& val)
*((balance_t *) data) += *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) += *((balance_pair_t *) val.data);
break;
case STRING:
@ -439,12 +439,12 @@ value_t& value_t::operator-=(const value_t& val)
throw new value_error("Cannot subtract a date/time from a value");
else if (val.type == STRING)
throw new value_error("Cannot subtract a string from a value");
else if (val.type == XML_NODE)
throw new value_error("Cannot subtract an XML node from a value");
else if (val.type == POINTER)
throw new value_error("Cannot subtract a pointer from a value");
else if (val.type == SEQUENCE)
throw new value_error("Cannot subtract a sequence from a value");
else if (val.type == XML_NODE) // recurse
return *this -= (*(xml::node_t **) val.data)->to_value();
switch (type) {
case BOOLEAN:
@ -456,15 +456,15 @@ value_t& value_t::operator-=(const value_t& val)
*((long *) data) -= *((long *) val.data);
break;
case AMOUNT:
cast(AMOUNT);
in_place_cast(AMOUNT);
*((amount_t *) data) -= *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) -= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
break;
default:
@ -480,7 +480,7 @@ value_t& value_t::operator-=(const value_t& val)
break;
case DATETIME: {
time_duration tval = ((ptime *) data)->operator-(*((ptime *) val.data));
cast(INTEGER);
in_place_cast(INTEGER);
*((long *) data) = tval.total_seconds();
break;
}
@ -504,7 +504,7 @@ value_t& value_t::operator-=(const value_t& val)
case INTEGER:
if (*((long *) val.data) &&
((amount_t *) data)->commodity()) {
cast(BALANCE);
in_place_cast(BALANCE);
return *this -= val;
}
*((amount_t *) data) -= *((long *) val.data);
@ -513,19 +513,19 @@ value_t& value_t::operator-=(const value_t& val)
case AMOUNT:
if (((amount_t *) data)->commodity() !=
((amount_t *) val.data)->commodity()) {
cast(BALANCE);
in_place_cast(BALANCE);
return *this -= val;
}
*((amount_t *) data) -= *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) -= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
break;
@ -547,7 +547,7 @@ value_t& value_t::operator-=(const value_t& val)
*((balance_t *) data) -= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
break;
default:
@ -603,12 +603,12 @@ value_t& value_t::operator*=(const value_t& val)
throw new value_error("Cannot multiply a value by a date/time");
else if (val.type == STRING)
throw new value_error("Cannot multiply a value by a string");
else if (val.type == XML_NODE)
throw new value_error("Cannot multiply a value by an XML node");
else if (val.type == POINTER)
throw new value_error("Cannot multiply a value by a pointer");
else if (val.type == SEQUENCE)
throw new value_error("Cannot multiply a value by a sequence");
else if (val.type == XML_NODE) // recurse
return *this *= (*(xml::node_t **) val.data)->to_value();
if (val.realzero() && type != STRING) {
*this = 0L;
@ -625,15 +625,15 @@ value_t& value_t::operator*=(const value_t& val)
*((long *) data) *= *((long *) val.data);
break;
case AMOUNT:
cast(AMOUNT);
in_place_cast(AMOUNT);
*((amount_t *) data) *= *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) *= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
break;
default:
@ -651,11 +651,11 @@ value_t& value_t::operator*=(const value_t& val)
*((amount_t *) data) *= *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) *= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
break;
default:
@ -676,7 +676,7 @@ value_t& value_t::operator*=(const value_t& val)
*((balance_t *) data) *= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
break;
default:
@ -717,7 +717,7 @@ value_t& value_t::operator*=(const value_t& val)
case AMOUNT: {
std::string temp;
value_t num(val);
num.cast(INTEGER);
num.in_place_cast(INTEGER);
for (long i = 0; i < *(long *) num.data; i++)
temp += **(std::string **) data;
**(std::string **) data = temp;
@ -755,12 +755,12 @@ value_t& value_t::operator/=(const value_t& val)
throw new value_error("Cannot divide a date/time by a value");
else if (val.type == STRING)
throw new value_error("Cannot divide a string by a value");
else if (val.type == XML_NODE)
throw new value_error("Cannot divide a value by an XML node");
else if (val.type == POINTER)
throw new value_error("Cannot divide a pointer by a value");
else if (val.type == SEQUENCE)
throw new value_error("Cannot divide a value by a sequence");
else if (val.type == XML_NODE) // recurse
return *this /= (*(xml::node_t **) val.data)->to_value();
switch (type) {
case BOOLEAN:
@ -772,15 +772,15 @@ value_t& value_t::operator/=(const value_t& val)
*((long *) data) /= *((long *) val.data);
break;
case AMOUNT:
cast(AMOUNT);
in_place_cast(AMOUNT);
*((amount_t *) data) /= *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) /= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
break;
default:
@ -798,11 +798,11 @@ value_t& value_t::operator/=(const value_t& val)
*((amount_t *) data) /= *((amount_t *) val.data);
break;
case BALANCE:
cast(BALANCE);
in_place_cast(BALANCE);
*((balance_t *) data) /= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
break;
default:
@ -823,7 +823,7 @@ value_t& value_t::operator/=(const value_t& val)
*((balance_t *) data) /= *((balance_t *) val.data);
break;
case BALANCE_PAIR:
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
*((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
break;
default:
@ -887,7 +887,7 @@ value_t::operator bool() const
case STRING:
return ! (**((std::string **) data)).empty();
case XML_NODE:
return *(xml::node_t **) data != NULL;
return (*(xml::node_t **) data)->to_value().to_boolean();
case POINTER:
return *(void **) data != NULL;
case SEQUENCE:
@ -921,7 +921,7 @@ value_t::operator long() const
case STRING:
throw new value_error("Cannot convert a string to an integer");
case XML_NODE:
throw new value_error("Cannot convert an XML node to an integer");
return (*(xml::node_t **) data)->to_value().to_integer();
case POINTER:
throw new value_error("Cannot convert a pointer to an integer");
case SEQUENCE:
@ -954,7 +954,7 @@ value_t::operator ptime() const
case STRING:
throw new value_error("Cannot convert a string to a date/time");
case XML_NODE:
throw new value_error("Cannot convert an XML node to a date/time");
return (*(xml::node_t **) data)->to_value().to_datetime();
case POINTER:
throw new value_error("Cannot convert a pointer to a date/time");
case SEQUENCE:
@ -987,7 +987,7 @@ value_t::operator double() const
case STRING:
throw new value_error("Cannot convert a string to a double");
case XML_NODE:
throw new value_error("Cannot convert an XML node to a double");
return (*(xml::node_t **) data)->to_value().to_amount().number();
case POINTER:
throw new value_error("Cannot convert a pointer to a double");
case SEQUENCE:
@ -1012,15 +1012,14 @@ value_t::operator std::string() const
case BALANCE:
case BALANCE_PAIR: {
value_t temp(*this);
temp.cast(STRING);
temp.in_place_cast(STRING);
return temp;
}
case STRING:
return **(std::string **) data;
case XML_NODE:
return (*(xml::node_t **) data)->text();
return (*(xml::node_t **) data)->to_value().to_string();
case POINTER:
throw new value_error("Cannot convert a pointer to a string");
case SEQUENCE:
@ -1060,8 +1059,10 @@ bool value_t::operator OP(const value_t& val) \
\
case STRING: \
throw new value_error("Cannot compare a boolean to a string"); \
\
case XML_NODE: \
throw new value_error("Cannot compare a boolean to an XML node"); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare a boolean to a pointer"); \
case SEQUENCE: \
@ -1099,12 +1100,14 @@ bool value_t::operator OP(const value_t& val) \
\
case STRING: \
throw new value_error("Cannot compare an integer to a string"); \
\
case XML_NODE: \
throw new value_error("Cannot compare an integer to an XML node"); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare an integer to a pointer"); \
case SEQUENCE: \
throw new value_error("Cannot compare an integer to a sequence"); \
throw new value_error("Cannot compare an integer to a sequence"); \
\
default: \
assert(0); \
@ -1131,10 +1134,12 @@ bool value_t::operator OP(const value_t& val) \
throw new value_error("Cannot compare a date/time to a balance pair"); \
case STRING: \
throw new value_error("Cannot compare a date/time to a string"); \
\
case XML_NODE: \
throw new value_error("Cannot compare a date/time to an XML node"); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare a date/time to a pointer"); \
throw new value_error("Cannot compare a date/time to a pointer"); \
case SEQUENCE: \
throw new value_error("Cannot compare a date/time to a sequence"); \
\
@ -1169,8 +1174,10 @@ bool value_t::operator OP(const value_t& val) \
\
case STRING: \
throw new value_error("Cannot compare an amount to a string"); \
\
case XML_NODE: \
throw new value_error("Cannot compare an amount to an XML node"); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare an amount to a pointer"); \
case SEQUENCE: \
@ -1205,8 +1212,10 @@ bool value_t::operator OP(const value_t& val) \
\
case STRING: \
throw new value_error("Cannot compare a balance to a string"); \
\
case XML_NODE: \
throw new value_error("Cannot compare a balance to an XML node"); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare a balance to a pointer"); \
case SEQUENCE: \
@ -1244,8 +1253,10 @@ bool value_t::operator OP(const value_t& val) \
\
case STRING: \
throw new value_error("Cannot compare a balance pair to a string"); \
\
case XML_NODE: \
throw new value_error("Cannot compare a balance pair to an XML node"); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare a balance pair to a pointer"); \
case SEQUENCE: \
@ -1277,8 +1288,7 @@ bool value_t::operator OP(const value_t& val) \
**((std::string **) val.data)); \
\
case XML_NODE: \
return (**((std::string **) data) OP \
(*(xml::node_t **) val.data)->text()); \
return *this OP (*(xml::node_t **) data)->to_value(); \
\
case POINTER: \
throw new value_error("Cannot compare a string to a pointer"); \
@ -1294,28 +1304,26 @@ bool value_t::operator OP(const value_t& val) \
case XML_NODE: \
switch (val.type) { \
case BOOLEAN: \
throw new value_error("Cannot compare an XML node to a boolean"); \
return (*(xml::node_t **) data)->to_value() OP *this; \
case INTEGER: \
throw new value_error("Cannot compare an XML node to an integer"); \
return (*(xml::node_t **) data)->to_value() OP *this; \
case DATETIME: \
throw new value_error("Cannot compare an XML node to a date/time"); \
return (*(xml::node_t **) data)->to_value() OP *this; \
case AMOUNT: \
throw new value_error("Cannot compare an XML node to an amount"); \
return (*(xml::node_t **) data)->to_value() OP *this; \
case BALANCE: \
throw new value_error("Cannot compare an XML node to a balance"); \
return (*(xml::node_t **) data)->to_value() OP *this; \
case BALANCE_PAIR: \
throw new value_error("Cannot compare an XML node to a balance pair"); \
\
return (*(xml::node_t **) data)->to_value() OP *this; \
case STRING: \
return ((*(xml::node_t **) data)->text() OP \
**((std::string **) val.data)); \
return (*(xml::node_t **) data)->to_value() OP *this; \
\
case XML_NODE: \
return (*((xml::node_t **) data) OP \
*((xml::node_t **) val.data)); \
return ((*(xml::node_t **) data)->to_value() OP \
(*(xml::node_t **) val.data)->to_value()); \
\
case POINTER: \
throw new value_error("Cannot compare an XML node to a pointer"); \
throw new value_error("Cannot compare an XML node to a pointer"); \
case SEQUENCE: \
throw new value_error("Cannot compare an XML node to a sequence"); \
\
@ -1342,7 +1350,7 @@ bool value_t::operator OP(const value_t& val) \
case STRING: \
throw new value_error("Cannot compare a pointer to a string node"); \
case XML_NODE: \
throw new value_error("Cannot compare a pointer to an XML node"); \
throw new value_error("Cannot compare a pointer to an XML node"); \
case POINTER: \
return (*((void **) data) OP *((void **) val.data)); \
case SEQUENCE: \
@ -1370,7 +1378,7 @@ DEF_VALUE_CMP_OP(<=)
DEF_VALUE_CMP_OP(>)
DEF_VALUE_CMP_OP(>=)
void value_t::cast(type_t cast_type)
void value_t::in_place_cast(type_t cast_type)
{
switch (type) {
case BOOLEAN:
@ -1691,19 +1699,14 @@ void value_t::cast(type_t cast_type)
case XML_NODE:
switch (cast_type) {
case BOOLEAN:
throw new value_error("Cannot convert an XML node to a boolean");
case INTEGER:
throw new value_error("Cannot convert an XML node to an integer");
case DATETIME:
throw new value_error("Cannot convert an XML node to a date/time");
case AMOUNT:
throw new value_error("Cannot convert an XML node to an amount");
case BALANCE:
throw new value_error("Cannot convert an XML node to a balance");
case BALANCE_PAIR:
throw new value_error("Cannot convert an XML node to a balance pair");
case STRING:
throw new value_error("Cannot convert an XML node to a string");
*this = (*(xml::node_t **) data)->to_value();
break;
case XML_NODE:
break;
case POINTER:
@ -1762,8 +1765,8 @@ void value_t::cast(type_t cast_type)
throw new value_error("Cannot convert a sequence to a balance pair");
case STRING:
throw new value_error("Cannot convert a sequence to a string");
case XML_NODE: \
throw new value_error("Cannot compare a sequence to an XML node"); \
case XML_NODE:
throw new value_error("Cannot compare a sequence to an XML node");
case POINTER:
throw new value_error("Cannot convert a sequence to a pointer");
case SEQUENCE:
@ -1782,7 +1785,7 @@ void value_t::cast(type_t cast_type)
type = cast_type;
}
void value_t::negate()
void value_t::in_place_negate()
{
switch (type) {
case BOOLEAN:
@ -1794,18 +1797,20 @@ void value_t::negate()
case DATETIME:
throw new value_error("Cannot negate a date/time");
case AMOUNT:
((amount_t *) data)->negate();
((amount_t *) data)->in_place_negate();
break;
case BALANCE:
((balance_t *) data)->negate();
((balance_t *) data)->in_place_negate();
break;
case BALANCE_PAIR:
((balance_pair_t *) data)->negate();
((balance_pair_t *) data)->in_place_negate();
break;
case STRING:
throw new value_error("Cannot negate a string");
case XML_NODE:
throw new value_error("Cannot negate an XML node");
*this = (*(xml::node_t **) data)->to_value();
in_place_negate();
break;
case POINTER:
throw new value_error("Cannot negate a pointer");
case SEQUENCE:
@ -1817,7 +1822,7 @@ void value_t::negate()
}
}
void value_t::abs()
void value_t::in_place_abs()
{
switch (type) {
case BOOLEAN:
@ -1840,7 +1845,9 @@ void value_t::abs()
case STRING:
throw new value_error("Cannot take the absolute value of a string");
case XML_NODE:
throw new value_error("Cannot take the absolute value of an XML node");
*this = (*(xml::node_t **) data)->to_value();
in_place_abs();
break;
case POINTER:
throw new value_error("Cannot take the absolute value of a pointer");
case SEQUENCE:
@ -1870,7 +1877,7 @@ value_t value_t::value(const ptime& moment) const
case STRING:
throw new value_error("Cannot find the value of a string");
case XML_NODE:
throw new value_error("Cannot find the value of an XML node");
return (*(xml::node_t **) data)->to_value().value(moment);
case POINTER:
throw new value_error("Cannot find the value of a pointer");
case SEQUENCE:
@ -1881,7 +1888,7 @@ value_t value_t::value(const ptime& moment) const
}
}
void value_t::reduce()
void value_t::in_place_reduce()
{
switch (type) {
case BOOLEAN:
@ -1889,18 +1896,20 @@ void value_t::reduce()
case INTEGER:
break;
case AMOUNT:
((amount_t *) data)->reduce();
((amount_t *) data)->in_place_reduce();
break;
case BALANCE:
((balance_t *) data)->reduce();
((balance_t *) data)->in_place_reduce();
break;
case BALANCE_PAIR:
((balance_pair_t *) data)->reduce();
((balance_pair_t *) data)->in_place_reduce();
break;
case STRING:
throw new value_error("Cannot reduce a string");
case XML_NODE:
throw new value_error("Cannot reduce an XML node");
*this = (*(xml::node_t **) data)->to_value();
in_place_reduce(); // recurse
break;
case POINTER:
throw new value_error("Cannot reduce a pointer");
case SEQUENCE:
@ -1908,7 +1917,7 @@ void value_t::reduce()
}
}
void value_t::round()
value_t value_t::round() const
{
switch (type) {
case BOOLEAN:
@ -1918,18 +1927,15 @@ void value_t::round()
case INTEGER:
break;
case AMOUNT:
*((amount_t *) data) = ((amount_t *) data)->round();
break;
return ((amount_t *) data)->round();
case BALANCE:
((balance_t *) data)->round();
break;
return ((balance_t *) data)->round();
case BALANCE_PAIR:
((balance_pair_t *) data)->round();
break;
return ((balance_pair_t *) data)->round();
case STRING:
throw new value_error("Cannot round a string");
case XML_NODE:
throw new value_error("Cannot round an XML node");
return (*(xml::node_t **) data)->to_value().round();
case POINTER:
throw new value_error("Cannot round a pointer");
case SEQUENCE:
@ -1948,18 +1954,15 @@ value_t value_t::unround() const
case INTEGER:
break;
case AMOUNT:
temp = ((amount_t *) data)->unround();
break;
return ((amount_t *) data)->unround();
case BALANCE:
temp = ((balance_t *) data)->unround();
break;
return ((balance_t *) data)->unround();
case BALANCE_PAIR:
temp = ((balance_pair_t *) data)->unround();
break;
return ((balance_pair_t *) data)->unround();
case STRING:
throw new value_error("Cannot un-round a string");
case XML_NODE:
throw new value_error("Cannot un-round an XML node");
return (*(xml::node_t **) data)->to_value().unround();
case POINTER:
throw new value_error("Cannot un-round a pointer");
case SEQUENCE:
@ -1980,17 +1983,17 @@ value_t value_t::price() const
case AMOUNT:
return ((amount_t *) data)->price();
case BALANCE:
return ((balance_t *) data)->price();
case BALANCE_PAIR:
return ((balance_pair_t *) data)->quantity.price();
case STRING:
throw new value_error("Cannot find the price of a string");
case XML_NODE:
throw new value_error("Cannot find the price of an XML node");
return (*(xml::node_t **) data)->to_value().price();
case POINTER:
throw new value_error("Cannot find the price of a pointer");
case SEQUENCE:
@ -2010,23 +2013,24 @@ value_t value_t::date() const
case BOOLEAN:
throw new value_error("Cannot find the date of a boolean");
case INTEGER:
return ptime();
throw new value_error("Cannot find the date of an integer");
case DATETIME:
return *this;
case AMOUNT:
return ptime(((amount_t *) data)->date());
return ((amount_t *) data)->date();
case BALANCE:
return ptime(((balance_t *) data)->date());
return ((balance_t *) data)->date();
case BALANCE_PAIR:
return ptime(((balance_pair_t *) data)->quantity.date());
return ((balance_pair_t *) data)->quantity.date();
case STRING:
throw new value_error("Cannot find the date of a string");
case XML_NODE:
throw new value_error("Cannot find the date of an XML node");
return (*(xml::node_t **) data)->to_value().date();
case POINTER:
throw new value_error("Cannot find the date of a pointer");
case SEQUENCE:
@ -2097,7 +2101,7 @@ value_t value_t::cost() const
case STRING:
throw new value_error("Cannot find the cost of a string");
case XML_NODE:
throw new value_error("Cannot find the cost of an XML node");
return (*(xml::node_t **) data)->to_value().cost();
case POINTER:
throw new value_error("Cannot find the cost of a pointer");
case SEQUENCE:
@ -2121,24 +2125,24 @@ value_t& value_t::add(const amount_t& amount, const amount_t * tcost)
case INTEGER:
case AMOUNT:
if (tcost) {
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
return add(amount, tcost);
}
else if ((type == AMOUNT &&
((amount_t *) data)->commodity() != amount.commodity()) ||
(type != AMOUNT && amount.commodity())) {
cast(BALANCE);
in_place_cast(BALANCE);
return add(amount, tcost);
}
else if (type != AMOUNT) {
cast(AMOUNT);
in_place_cast(AMOUNT);
}
*((amount_t *) data) += amount;
break;
case BALANCE:
if (tcost) {
cast(BALANCE_PAIR);
in_place_cast(BALANCE_PAIR);
return add(amount, tcost);
}
*((balance_t *) data) += amount;
@ -2380,7 +2384,7 @@ amount_t value_getitem(value_t& val, int i)
throw new value_error("Cannot cast a string to an amount");
case value_t::XML_NODE:
throw new value_error("Cannot cast an XML node to an amount");
return (*(xml::node_t **) data)->to_value();
case value_t::POINTER:
throw new value_error("Cannot cast a pointer to an amount");
@ -2614,10 +2618,10 @@ void export_value()
.def(self_ns::int_(self))
.def(self_ns::float_(self))
.def(self_ns::str(self))
.def(abs(self))
.def_readonly("type", &value_t::type)
.def("__abs__", &value_t::abs)
.def("__len__", value_len)
.def("__getitem__", value_getitem)
@ -2630,7 +2634,6 @@ void export_value()
.def("value", &value_t::value)
.def("round", &value_t::round)
.def("negate", &value_t::negate)
.def("negated", &value_t::negated)
.def("write", &value_t::write)
;

33
value.h
View file

@ -400,14 +400,14 @@ class value_t
template <typename T>
operator T() const;
void negate();
value_t negated() const {
void in_place_negate();
value_t negate() const {
value_t temp = *this;
temp.negate();
temp.in_place_negate();
return temp;
}
value_t operator-() const {
return negated();
return negate();
}
bool realzero() const {
@ -439,27 +439,34 @@ class value_t
return 0;
}
void abs();
void cast(type_t cast_type);
void in_place_abs();
value_t abs() const;
void in_place_cast(type_t cast_type);
value_t cost() const;
value_t price() const;
value_t date() const;
value_t cast(type_t cast_type) const {
value_t temp(*this);
temp.in_place_cast(cast_type);
return temp;
}
value_t strip_annotations(const bool keep_price = amount_t::keep_price,
const bool keep_date = amount_t::keep_date,
const bool keep_tag = amount_t::keep_tag) const;
value_t& add(const amount_t& amount, const amount_t * cost = NULL);
value_t value(const ptime& moment) const;
void reduce();
void in_place_reduce();
value_t reduced() const {
value_t reduce() const {
value_t temp(*this);
temp.reduce();
temp.in_place_reduce();
return temp;
}
void round();
value_t round() const;
value_t unround() const;
void write(std::ostream& out, const int first_width,
@ -555,12 +562,6 @@ template <> value_t::operator ptime() const;
template <> value_t::operator double() const;
template <> value_t::operator std::string() const;
inline value_t abs(const value_t& val) {
value_t temp(val);
temp.abs();
return temp;
}
std::ostream& operator<<(std::ostream& out, const value_t& val);
class value_context : public error_context

46
xml.cc
View file

@ -9,11 +9,18 @@
namespace ledger {
namespace xml {
document_t::document_t(node_t *, const char ** _builtins,
document_t::document_t(node_t * _top, const char ** _builtins,
const int _builtins_size)
: builtins(_builtins), builtins_size(_builtins_size),
top(new terminal_node_t(this)) {}
void document_t::set_top(node_t * _top)
{
if (top)
delete top;
top = _top;
}
int document_t::register_name(const std::string& name)
{
int index = lookup_name_id(name);
@ -102,16 +109,9 @@ node_t::node_t(document_t * _document, parent_node_t * _parent,
flags(_flags), info(NULL), attrs(NULL)
{
TRACE_CTOR("node_t(document_t *, node_t *)");
#ifdef THREADSAFE
document = _document;
#else
if (! document)
document = _document;
#if 0
else
assert(document == _document);
#endif
#endif
if (! document->top)
document->set_top(this);
if (parent)
parent->add_child(this);
}
@ -359,6 +359,18 @@ document_t * parser_t::parse(std::istream& in, const char ** builtins,
return doc.release();
}
node_t * commodity_node_t::children() const
{
// jww (2007-04-19): Need to report the commodity and its details
return NULL;
}
node_t * amount_node_t::children() const
{
// jww (2007-04-19): Need to report the quantity and commodity
return NULL;
}
node_t * transaction_node_t::children() const
{
if (! _children) {
@ -370,6 +382,20 @@ node_t * transaction_node_t::children() const
return parent_node_t::children();
}
node_t * transaction_node_t::lookup_child(int _name_id)
{
if (_name_id == payee_id) {
payee_virtual_node = new terminal_node_t(document);
payee_virtual_node->set_text(transaction->entry->payee);
return payee_virtual_node;
}
}
value_t transaction_node_t::to_value() const
{
return transaction->amount;
}
node_t * entry_node_t::children() const
{
if (! _children) {

103
xml.h
View file

@ -49,6 +49,8 @@ class document_t
document_t(node_t * _top = NULL, const char ** _builtins = NULL,
const int _builtins_size = 0);
void set_top(node_t * _top);
int register_name(const std::string& name);
int lookup_name_id(const std::string& name) const;
const char * lookup_name(int id) const;
@ -58,6 +60,14 @@ class document_t
#define XML_NODE_IS_PARENT 0x1
class conversion_error : public error {
public:
conversion_error(const std::string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~conversion_error() throw() {}
};
class parent_node_t;
class node_t
@ -124,6 +134,22 @@ public:
return NULL;
}
node_t * lookup_child(const char * _name) {
int id = document->lookup_name_id(_name);
return lookup_child(id);
}
node_t * lookup_child(const std::string& _name) {
int id = document->lookup_name_id(_name);
return lookup_child(id);
}
virtual node_t * lookup_child(int _name_id) {
return NULL;
}
virtual value_t to_value() const {
throw new conversion_error("Cannot convert node to a value");
}
virtual void write(std::ostream& out, int depth = 0) const = 0;
private:
@ -187,6 +213,10 @@ public:
data = _data;
}
virtual value_t to_value() const {
return text();
}
void write(std::ostream& out, int depth = 0) const;
private:
@ -228,25 +258,76 @@ class parse_error : public error {
#endif
class transaction_node_t : public parent_node_t
class commodity_node_t : public parent_node_t
{
transaction_t * transaction;
public:
transaction_node_t(document_t * _document,
transaction_t * _transaction,
parent_node_t * _parent = NULL)
: parent_node_t(_document, _parent), transaction(_transaction) {
TRACE_CTOR("transaction_node_t(document_t *, transaction_t *, parent_node_t *)");
set_name("transaction");
commodity_t * commodity;
commodity_node_t(document_t * _document,
commodity_t * _commodity,
parent_node_t * _parent = NULL)
: parent_node_t(_document, _parent), commodity(_commodity) {
TRACE_CTOR("commodity_node_t(document_t *, commodity_t *, parent_node_t *)");
set_name("commodity");
}
virtual ~transaction_node_t() {
TRACE_DTOR("transaction_node_t");
virtual ~commodity_node_t() {
TRACE_DTOR("commodity_node_t");
}
virtual node_t * children() const;
};
class amount_node_t : public parent_node_t
{
public:
amount_t * amount;
amount_node_t(document_t * _document,
amount_t * _amount,
parent_node_t * _parent = NULL)
: parent_node_t(_document, _parent), amount(_amount) {
TRACE_CTOR("amount_node_t(document_t *, amount_t *, parent_node_t *)");
set_name("amount");
}
virtual ~amount_node_t() {
TRACE_DTOR("amount_node_t");
}
virtual node_t * children() const;
virtual value_t to_value() const {
return *amount;
}
};
class transaction_node_t : public parent_node_t
{
int payee_id;
terminal_node_t * payee_virtual_node;
public:
transaction_t * transaction;
transaction_node_t(document_t * _document,
transaction_t * _transaction,
parent_node_t * _parent = NULL)
: parent_node_t(_document, _parent), transaction(_transaction),
payee_virtual_node(NULL) {
TRACE_CTOR("transaction_node_t(document_t *, transaction_t *, parent_node_t *)");
set_name("transaction");
payee_id = document->register_name("payee");
}
virtual ~transaction_node_t() {
TRACE_DTOR("transaction_node_t");
if (payee_virtual_node)
delete payee_virtual_node;
}
virtual node_t * children() const;
virtual node_t * lookup_child(int _name_id);
virtual value_t to_value() const;
};
class entry_node_t : public parent_node_t
{
entry_t * entry;

View file

@ -714,6 +714,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
case token_t::SLASH:
node.reset(new op_t(op_t::NODE_ID));
node->name_id = document_t::ROOT;
push_token();
break;
case token_t::STAR:
node.reset(new op_t(op_t::NODE_ID));
@ -783,11 +784,6 @@ xpath_t::parse_path_expr(std::istream& in, unsigned short tflags) const
std::auto_ptr<op_t> node(parse_predicate_expr(in, tflags));
if (node.get()) {
// If the beginning of the path was /, just put it back; this
// makes parsing much simpler.
if (node->kind == op_t::NODE_ID && node->name_id == document_t::ROOT)
push_token();
token_t& tok = next_token(in, tflags);
while (tok.kind == token_t::SLASH) {
std::auto_ptr<op_t> prev(node.release());
@ -843,7 +839,7 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
" operator not followed by argument");
// A very quick optimization
if (texpr->kind == op_t::VALUE) {
texpr->valuep->negate();
texpr->valuep->in_place_negate();
node.reset(texpr.release());
} else {
node.reset(new op_t(op_t::O_NEG));
@ -1422,9 +1418,9 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
}
if (left == expr) {
return wrap_value(expr->valuep->negated())->acquire();
return wrap_value(expr->valuep->negate())->acquire();
} else {
expr->valuep->negate();
expr->valuep->in_place_negate();
return expr->acquire();
}
}
@ -1782,6 +1778,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
xpath_t lexpr(left->compile(context, scope, resolve));
xpath_t rexpr(resolve ? right->acquire() :
right->compile(context, scope, false));
if (! lexpr->constant() || ! resolve) {
if (left == lexpr)
return acquire();
@ -1952,9 +1949,9 @@ void xpath_t::context::describe(std::ostream& out) const throw()
}
}
bool xpath_t::op_t::write(std::ostream& out,
bool xpath_t::op_t::write(std::ostream& out,
const bool relaxed,
const op_t * op_to_find,
const op_t * op_to_find,
unsigned long * start_pos,
unsigned long * end_pos) const
{