Removed the binary caching code, and the XML, QIF and Gnucash parsers.

This commit is contained in:
John Wiegley 2009-02-03 12:21:54 -04:00
parent 9bdcbffb15
commit 3434650848
37 changed files with 6 additions and 2979 deletions

6
.gitmodules vendored
View file

@ -1,12 +1,6 @@
[submodule "lib/cppunit"]
path = lib/cppunit
url = git://github.com/jwiegley/cppunit.git
[submodule "lib/libofx"]
path = lib/libofx
url = git://github.com/jwiegley/libofx.git
[submodule "lib/utfcpp"]
path = lib/utfcpp
url = git://github.com/jwiegley/utfcpp.git
[submodule "lib/irrxml"]
path = lib/irrxml
url = git://github.com/jwiegley/irrxml.git

View file

@ -10,8 +10,7 @@ lib_LTLIBRARIES = \
libledger_util.la
lib_cppflags = -I$(srcdir)/src -I$(srcdir)/lib \
-I$(srcdir)/lib/utfcpp/source \
-I$(srcdir)/lib/irrxml/src
-I$(srcdir)/lib/utfcpp/source
libledger_util_la_SOURCES = \
src/utils.cc \
@ -19,7 +18,6 @@ libledger_util_la_SOURCES = \
src/times.cc \
src/mask.cc \
src/stream.cc \
src/binary.cc \
lib/sha1.cpp
libledger_util_la_CPPFLAGS = $(lib_cppflags)
@ -63,16 +61,8 @@ libledger_data_la_LDFLAGS = -release $(VERSION).0
libledger_parse_la_SOURCES = \
src/textual.cc \
src/cache.cc \
src/xml.cc \
src/csv.cc \
src/emacs.cc \
src/qif.cc \
src/gnucash.cc \
lib/irrxml/src/irrXML.cpp
if HAVE_LIBOFX
libledger_parse_la_SOURCES += src/ofx.cc
endif
src/emacs.cc
libledger_parse_la_CPPFLAGS = $(lib_cppflags)
libledger_parse_la_LDFLAGS = -release $(VERSION).0
@ -103,7 +93,6 @@ pkginclude_HEADERS = \
src/times.h \
src/mask.h \
src/stream.h \
src/binary.h \
\
src/amount.h \
src/commodity.h \
@ -130,13 +119,8 @@ pkginclude_HEADERS = \
src/compare.h \
\
src/textual.h \
src/cache.h \
src/xml.h \
src/csv.h \
src/emacs.h \
src/qif.h \
src/gnucash.h \
src/ofx.h \
\
src/session.h \
src/report.h \
@ -163,15 +147,7 @@ pkginclude_HEADERS = \
lib/utfcpp/source/utf8.h \
lib/utfcpp/source/utf8/checked.h \
lib/utfcpp/source/utf8/core.h \
lib/utfcpp/source/utf8/unchecked.h \
\
lib/irrxml/src/CXMLReaderImpl.h \
lib/irrxml/src/fast_atof.h \
lib/irrxml/src/heapsort.h \
lib/irrxml/src/irrArray.h \
lib/irrxml/src/irrString.h \
lib/irrxml/src/irrTypes.h \
lib/irrxml/src/irrXML.h
lib/utfcpp/source/utf8/unchecked.h
CLEANFILES =
@ -286,10 +262,6 @@ PYLIBS = ledger_python \
boost_regex$(BOOST_SUFFIX) \
boost_python$(BOOST_SUFFIX)
if HAVE_LIBOFX
PYLIBS += ofx
endif
ledger.so: $(ledger_so_SOURCES) $(ledger_so_DEPENDENCIES)
BUILD_DIR=`cd $(top_builddir); pwd`; \
SRC_DIR=`cd $(srcdir); pwd`; \

View file

@ -220,28 +220,6 @@ else
AC_MSG_FAILURE("Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)")
fi
# check for libofx
AC_CACHE_CHECK(
[if libofx is available],
[libofx_avail_cv_],
[libofx_save_libs=$LIBS
LIBS="-lofx $LIBS"
AC_LANG_PUSH(C++)
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <libofx.h>]],
[[LibofxContextPtr libofx_context = libofx_get_new_context();]])],
[libofx_avail_cv_=true],
[libofx_avail_cv_=false])
AC_LANG_POP
LIBS=$libofx_save_libs])
if [ test x$libofx_avail_cv_ = xtrue ]; then
AC_DEFINE([HAVE_LIBOFX], [1], [Whether libofx is available])
LIBS="-lofx $LIBS"
fi
AM_CONDITIONAL(HAVE_LIBOFX, test x$libofx_avail_cv_ = xtrue)
# check for Python
AM_PATH_PYTHON(2.4,, :)
if [test "$PYTHON" != :]; then

@ -1 +0,0 @@
Subproject commit e0f5ec13193e413ddcfcf70bcb8886c0c6a8a60c

@ -1 +0,0 @@
Subproject commit 31ab2c052edb3e72fc1fda385d6d118c479407f3

View file

@ -84,39 +84,6 @@ void py_print(amount_t& amount, object out) {
}
}
void py_read_1(amount_t& amount, object in) {
if (PyFile_Check(in.ptr())) {
pyifstream instr(reinterpret_cast<PyFileObject *>(in.ptr()));
amount.read(instr);
} else {
PyErr_SetString(PyExc_IOError,
"Argument to amount.read(file) is not a file object");
}
}
void py_read_2(amount_t& amount, const std::string& str) {
const char * p = str.c_str();
amount.read(p);
}
void py_write_xml_1(amount_t& amount, object out) {
if (PyFile_Check(out.ptr())) {
pyofstream outstr(reinterpret_cast<PyFileObject *>(out.ptr()));
amount.write_xml(outstr);
} else {
PyErr_SetString(PyExc_IOError,
"Argument to amount.write_xml(file) is not a file object");
}
}
void py_write_xml_2(amount_t& amount, object out, const int depth) {
if (PyFile_Check(out.ptr())) {
pyofstream outstr(reinterpret_cast<PyFileObject *>(out.ptr()));
amount.write_xml(outstr, depth);
} else {
PyErr_SetString(PyExc_IOError,
"Argument to amount.write_xml(file, depth) is not a file object");
}
}
#define EXC_TRANSLATOR(type) \
void exc_translate_ ## type(const type& err) { \
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
@ -338,14 +305,6 @@ internal precision.")
.def("print_", py_print)
.def("read", py_read_1)
.def("read", py_read_2)
.def("write", &amount_t::write)
.def("read_xml", &amount_t::read_xml)
.def("write_xml", py_write_xml_1)
.def("write_xml", py_write_xml_2)
.def("dump", &amount_t::dump)
.def("valid", &amount_t::valid)

View file

@ -58,20 +58,6 @@ void py_set_string(value_t& amount, const string& str) {
return amount.set_string(str);
}
void py_read_1(value_t& amount, object in) {
if (PyFile_Check(in.ptr())) {
pyifstream instr(reinterpret_cast<PyFileObject *>(in.ptr()));
amount.read(instr);
} else {
PyErr_SetString(PyExc_IOError,
"Argument to amount.parse(file) is not a file object");
}
}
void py_read_2(value_t& amount, const std::string& str) {
const char * p = str.c_str();
amount.read(p);
}
#define EXC_TRANSLATOR(type) \
void exc_translate_ ## type(const type& err) { \
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
@ -278,10 +264,6 @@ void export_value()
.def("dump", &value_t::dump)
.def("print", &value_t::print)
.def("read", py_read_1)
.def("read", py_read_2)
.def("write", &value_t::write)
.def("valid", &value_t::valid)
;

View file

@ -30,7 +30,6 @@
*/
#include "amount.h"
#include "binary.h"
namespace ledger {
@ -1021,225 +1020,6 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
_out << out.str();
}
void amount_t::read(std::istream& in)
{
using namespace ledger::binary;
// Read in the commodity for this amount
commodity_t::ident_t ident;
read_long(in, ident);
if (ident == 0xffffffff)
commodity_ = NULL;
else if (ident == 0)
commodity_ = current_pool->null_commodity;
else {
commodity_ = current_pool->find(ident);
assert(commodity_);
}
// Read in the quantity
char byte;
in.read(&byte, sizeof(byte));
if (byte < 3) {
quantity = new bigint_t;
unsigned short len;
in.read(reinterpret_cast<char *>(&len), sizeof(len));
assert(len < 4096);
static char buf[4096];
in.read(buf, len);
mpz_import(temp, len / sizeof(short), 1, sizeof(short),
0, 0, buf);
mpq_set_num(MP(quantity), temp);
in.read(reinterpret_cast<char *>(&len), sizeof(len));
assert(len < 4096);
in.read(buf, len);
mpz_import(temp, len / sizeof(short), 1, sizeof(short),
0, 0, buf);
mpq_set_den(MP(quantity), temp);
char negative;
in.read(&negative, sizeof(negative));
if (negative)
mpq_neg(MP(quantity), MP(quantity));
in.read(reinterpret_cast<char *>(&quantity->prec), sizeof(quantity->prec));
bigint_t::flags_t tflags;
in.read(reinterpret_cast<char *>(&tflags), sizeof(tflags));
quantity->set_flags(tflags);
}
else {
assert(false);
}
}
void amount_t::read(const char *& data,
char ** pool,
char ** pool_next)
{
using namespace ledger::binary;
// Read in the commodity for this amount
commodity_t::ident_t ident;
read_long(data, ident);
if (ident == 0xffffffff)
commodity_ = NULL;
else if (ident == 0)
commodity_ = current_pool->null_commodity;
else {
commodity_ = current_pool->find(ident);
assert(commodity_);
}
// Read in the quantity
char byte = *data++;;
if (byte < 3) {
if (byte == 2) {
quantity = new(reinterpret_cast<bigint_t *>(*pool_next)) bigint_t;
*pool_next += sizeof(bigint_t);
} else {
quantity = new bigint_t;
}
unsigned short len =
*reinterpret_cast<unsigned short *>(const_cast<char *>(data));
data += sizeof(unsigned short);
mpz_init(temp);
mpz_import(temp, len / sizeof(short), 1, sizeof(short),
0, 0, data);
data += len;
mpq_set_num(MP(quantity), temp);
len = *reinterpret_cast<unsigned short *>(const_cast<char *>(data));
data += sizeof(unsigned short);
mpz_init(temp);
mpz_import(temp, len / sizeof(short), 1, sizeof(short),
0, 0, data);
data += len;
mpq_set_den(MP(quantity), temp);
char negative = *data++;
if (negative)
mpq_neg(MP(quantity), MP(quantity));
quantity->prec = *reinterpret_cast<precision_t *>(const_cast<char *>(data));
data += sizeof(precision_t);
quantity->set_flags(*reinterpret_cast<bigint_t::flags_t *>(const_cast<char *>(data)));
data += sizeof(bigint_t::flags_t);
if (byte == 2)
quantity->add_flags(BIGINT_BULK_ALLOC);
} else {
uint_fast32_t index = *reinterpret_cast<uint_fast32_t *>(const_cast<char *>(data));
data += sizeof(uint_fast32_t);
quantity = reinterpret_cast<bigint_t *>(*pool + (index - 1) * sizeof(bigint_t));
DEBUG("amounts.refs",
quantity << " ref++, now " << (quantity->ref + 1));
quantity->ref++;
}
}
namespace {
void write_bytes(std::ostream& out,
const char * buf,
const std::size_t size)
{
unsigned short len = size * sizeof(short);
out.write(reinterpret_cast<char *>(&len), sizeof(len));
if (len) {
assert(len < 4096);
out.write(buf, len);
}
}
}
void amount_t::write(std::ostream& out, std::size_t index) const
{
using namespace ledger::binary;
// Write out the commodity for this amount
if (! quantity)
throw_(amount_error, "Cannot serialize an uninitialized amount");
if (commodity_)
write_long(out, commodity_->ident);
else
write_long<commodity_t::ident_t>(out, 0xffffffff);
// Write out the quantity
char byte;
if (index == 0 || quantity->index == 0) {
if (index != 0) {
quantity->index = index; // if !optimized, this is garbage
byte = 2;
} else {
byte = 1;
}
out.write(&byte, sizeof(byte));
std::size_t size;
static char buf[4096];
mpq_get_num(temp, MP(quantity));
mpz_export(buf, &size, 1, sizeof(short), 0, 0, temp);
write_bytes(out, buf, size);
mpq_get_den(temp, MP(quantity));
mpz_export(buf, &size, 1, sizeof(short), 0, 0, temp);
write_bytes(out, buf, size);
byte = mpq_sgn(MP(quantity)) < 0 ? 1 : 0;
out.write(&byte, sizeof(byte));
out.write(reinterpret_cast<char *>(&quantity->prec), sizeof(quantity->prec));
bigint_t::flags_t tflags = quantity->flags() & ~BIGINT_BULK_ALLOC;
assert(sizeof(tflags) == sizeof(bigint_t::flags_t));
out.write(reinterpret_cast<char *>(&tflags), sizeof(tflags));
} else {
assert(quantity->ref > 1);
// Since this value has already been written, we simply write
// out a reference to which one it was.
byte = 3;
out.write(&byte, sizeof(byte));
out.write(reinterpret_cast<char *>(&quantity->index), sizeof(quantity->index));
}
}
void amount_t::read_xml(std::istream& in)
{
}
void amount_t::write_xml(std::ostream& out, const int depth) const
{
out << xml_str("<amount>\n", depth);
if (has_commodity())
commodity().write_xml(out, depth + 1);
out << xml_str("<quantity>", depth + 1)
<< quantity_string()
<< "</quantity>\n";
out << xml_str("</amount>\n", depth);
}
bool amount_t::valid() const
{
if (quantity) {

View file

@ -671,51 +671,6 @@ public:
/*@}*/
/** @name Serialization
*/
/*@{*/
/** An amount may be deserialized from an input stream or a character
pointer, and it may be serialized to an output stream. The methods
used are:
read(istream) reads an amount from the given input stream. It
must have been put there using `write(ostream)'. The required
flow of logic is:
amount_t::current_pool->write(out)
amount.write(out) // write out all amounts
amount_t::current_pool->read(in)
amount.read(in)
read(char *&) reads an amount from data which has been read from
an input stream into a buffer. It advances the pointer passed in
to the end of the deserialized amount.
write(ostream, [bool]) writes an amount to an output stream in a
compact binary format. If the second parameter is true,
quantities with multiple reference counts will be written in an
optimized fashion. NOTE: This form of usage is valid only for
the binary journal writer, it should not be used otherwise, as it
has strict requirements for reading that only the binary reader
knows about.
*/
void read(std::istream& in);
void read(const char *& data,
char ** pool = NULL,
char ** pool_next = NULL);
void write(std::ostream& out, std::size_t index = 0) const;
/*@}*/
/** @name XML Serialization
*/
/*@{*/
void read_xml(std::istream& in);
void write_xml(std::ostream& out, const int depth = 0) const;
/*@}*/
/** @name Debugging
*/
/*@{*/

View file

@ -252,14 +252,4 @@ void balance_t::print(std::ostream& out,
}
}
void balance_t::write_xml(std::ostream& out, const int depth) const
{
out << xml_str("<balance>\n", depth);
foreach (const amounts_map::value_type& pair, amounts)
pair.second.write_xml(out, depth + 1);
out << xml_str("</balance>\n", depth);
}
} // namespace ledger

View file

@ -475,15 +475,6 @@ public:
void print(std::ostream& out, const int first_width,
const int latter_width = -1) const;
/** @name XML Serialization
*/
/*@{*/
void read_xml(std::istream& in);
void write_xml(std::ostream& out, const int depth = 0) const;
/*@}*/
/**
* Debugging methods. There are two methods defined to help with
* debugging:

View file

@ -53,15 +53,4 @@ balance_pair_t::value(const optional<datetime_t>& moment,
return none;
}
void balance_pair_t::write_xml(std::ostream& out, const int depth) const
{
out << xml_str("<balance-pair>\n", depth);
quantity().write_xml(out, depth + 1);
if (cost)
cost->write_xml(out, depth + 1);
out << xml_str("</balance-pair>\n", depth);
}
} // namespace ledger

View file

@ -343,15 +343,6 @@ public:
return balance_t::operator==(val);
}
/** @name XML Serialization
*/
/*@{*/
void read_xml(std::istream& in);
void write_xml(std::ostream& out, const int depth = 0) const;
/*@}*/
/**
* Debugging methods. There is only one method specifically for
* balance pairs to help with debugging:

View file

@ -1,188 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "binary.h"
namespace ledger {
namespace binary {
void read_bool(std::istream& in, bool& num)
{
read_guard(in, 0x2005);
unsigned char val;
in.read(reinterpret_cast<char *>(&val), sizeof(val));
num = val == 1;
read_guard(in, 0x2006);
}
void read_bool(const char *& data, bool& num)
{
read_guard(data, 0x2005);
const unsigned char val = *reinterpret_cast<const unsigned char *>(data);
data += sizeof(unsigned char);
num = val == 1;
read_guard(data, 0x2006);
}
void read_string(std::istream& in, string& str)
{
read_guard(in, 0x3001);
unsigned char len;
read_number_nocheck(in, len);
if (len == 0xff) {
unsigned short slen;
read_number_nocheck(in, slen);
char * buf = new char[slen + 1];
in.read(buf, slen);
buf[slen] = '\0';
str = buf;
checked_array_delete(buf);
}
else if (len) {
char buf[256];
in.read(buf, len);
buf[len] = '\0';
str = buf;
} else {
str = "";
}
read_guard(in, 0x3002);
}
void read_string(const char *& data, string& str)
{
read_guard(data, 0x3001);
unsigned char len;
read_number_nocheck(data, len);
if (len == 0xff) {
unsigned short slen;
read_number_nocheck(data, slen);
str = string(data, slen);
data += slen;
}
else if (len) {
str = string(data, len);
data += len;
}
else {
str = "";
}
read_guard(data, 0x3002);
}
void read_string(const char *& data, string * str)
{
read_guard(data, 0x3001);
unsigned char len;
read_number_nocheck(data, len);
if (len == 0xff) {
unsigned short slen;
read_number_nocheck(data, slen);
new(str) string(data, slen);
data += slen;
}
else if (len) {
new(str) string(data, len);
data += len;
}
else {
new(str) string("");
}
read_guard(data, 0x3002);
}
void read_string(std::istream& in, optional<string>& str)
{
if (read_bool(in)) {
string temp;
read_string(in, temp);
str = temp;
} else {
str = none;
}
}
void read_string(const char *& data, optional<string>& str)
{
if (read_bool(data)) {
string temp;
read_string(data, temp);
str = temp;
} else {
str = none;
}
}
void write_bool(std::ostream& out, bool num)
{
write_guard(out, 0x2005);
unsigned char val = num ? 1 : 0;
out.write(reinterpret_cast<char *>(&val), sizeof(val));
write_guard(out, 0x2006);
}
void write_string(std::ostream& out, const string& str)
{
write_guard(out, 0x3001);
std::size_t len = str.length();
if (len > 255) {
assert(len < 65536);
write_number_nocheck<unsigned char>(out, 0xff);
write_number_nocheck<unsigned short>(out, len);
} else {
write_number_nocheck<unsigned char>(out, len);
}
if (len)
out.write(str.c_str(), len);
write_guard(out, 0x3002);
}
void write_string(std::ostream& out, const optional<string>& str)
{
if (str) {
write_bool(out, true);
write_string(out, *str);
} else {
write_bool(out, false);
}
}
} // namespace binary
} // namespace ledger

View file

@ -1,286 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @addtogroup util
*/
/**
* @file binary.h
* @author John Wiegley
*
* @ingroup util
*
* @brief General binary object streaming.
*/
#ifndef BINARY_H
#define BINARY_H
#include "utils.h"
namespace ledger {
namespace binary {
template <typename T>
inline void read_number_nocheck(std::istream& in, T& num) {
in.read(reinterpret_cast<char *>(&num), sizeof(num));
}
template <typename T>
inline void read_number_nocheck(const char *& data, T& num) {
num = *reinterpret_cast<const T *>(data);
data += sizeof(T);
}
template <typename T>
inline T read_number_nocheck(std::istream& in) {
T num;
read_number_nocheck(in, num);
return num;
}
template <typename T>
inline T read_number_nocheck(const char *& data) {
T num;
read_number_nocheck(data, num);
return num;
}
#if DEBUG_LEVEL >= ALPHA
#define read_guard(in, id) \
if (read_number_nocheck<unsigned short>(in) != id) \
assert(false);
#else
#define read_guard(in, id)
#endif
template <typename T>
inline void read_number(std::istream& in, T& num) {
read_guard(in, 0x2003);
in.read(reinterpret_cast<char *>(&num), sizeof(num));
read_guard(in, 0x2004);
}
template <typename T>
inline void read_number(const char *& data, T& num) {
read_guard(data, 0x2003);
num = *reinterpret_cast<const T *>(data);
data += sizeof(T);
read_guard(data, 0x2004);
}
template <typename T>
inline T read_number(std::istream& in) {
T num;
read_number(in, num);
return num;
}
template <typename T>
inline T read_number(const char *& data) {
T num;
read_number(data, num);
return num;
}
void read_bool(std::istream& in, bool& num);
void read_bool(const char *& data, bool& num);
inline bool read_bool(std::istream& in) {
bool num;
read_bool(in, num);
return num;
}
inline bool read_bool(const char *& data) {
bool num;
read_bool(data, num);
return num;
}
template <typename T>
void read_long(std::istream& in, T& num)
{
read_guard(in, 0x2001);
unsigned char len;
read_number_nocheck(in, len);
num = 0;
unsigned char temp;
if (len > 3) {
read_number_nocheck(in, temp);
num |= static_cast<unsigned long>(temp) << 24;
}
if (len > 2) {
read_number_nocheck(in, temp);
num |= static_cast<unsigned long>(temp) << 16;
}
if (len > 1) {
read_number_nocheck(in, temp);
num |= static_cast<unsigned long>(temp) << 8;
}
read_number_nocheck(in, temp);
num |= static_cast<unsigned long>(temp);
read_guard(in, 0x2002);
}
template <typename T>
void read_long(const char *& data, T& num)
{
read_guard(data, 0x2001);
uint_least8_t len;
read_number_nocheck(data, len);
num = static_cast<T>(0);
uint_least8_t temp;
if (len > 3) {
read_number_nocheck(data, temp);
num = static_cast<T>(static_cast<uint_least32_t>(num) |
(static_cast<uint_least32_t>(temp) << 24));
}
if (len > 2) {
read_number_nocheck(data, temp);
num = static_cast<T>(static_cast<uint_least32_t>(num) |
(static_cast<uint_least32_t>(temp) << 16));
}
if (len > 1) {
read_number_nocheck(data, temp);
num = static_cast<T>(static_cast<uint_least32_t>(num) |
(static_cast<uint_least32_t>(temp) << 8));
}
read_number_nocheck(data, temp);
num = static_cast<T>(static_cast<uint_least32_t>(num) |
static_cast<uint_least32_t>(temp));
read_guard(data, 0x2002);
}
template <typename T>
inline T read_long(std::istream& in) {
T num;
read_long(in, num);
return num;
}
template <typename T>
inline T read_long(const char *& data) {
T num;
read_long(data, num);
return num;
}
void read_string(std::istream& in, string& str);
void read_string(const char *& data, string& str);
void read_string(const char *& data, string * str);
inline string read_string(std::istream& in) {
string temp;
read_string(in, temp);
return temp;
}
inline string read_string(const char *& data) {
string temp;
read_string(data, temp);
return temp;
}
void read_string(std::istream& in, optional<string>& str);
void read_string(const char *& data, optional<string>& str);
template <typename T>
inline void write_number_nocheck(std::ostream& out, T num) {
out.write(reinterpret_cast<char *>(&num), sizeof(num));
}
#if DEBUG_LEVEL >= ALPHA
#define write_guard(out, id) \
write_number_nocheck<unsigned short>(out, id)
#else
#define write_guard(in, id)
#endif
template <typename T>
inline void write_number(std::ostream& out, T num) {
write_guard(out, 0x2003);
out.write(reinterpret_cast<char *>(&num), sizeof(num));
write_guard(out, 0x2004);
}
void write_bool(std::ostream& out, bool num);
template <typename T>
void write_long(std::ostream& out, T num)
{
write_guard(out, 0x2001);
unsigned char len = 4;
if (static_cast<unsigned long>(num) < 0x00000100UL)
len = 1;
else if (static_cast<unsigned long>(num) < 0x00010000UL)
len = 2;
else if (static_cast<unsigned long>(num) < 0x01000000UL)
len = 3;
write_number_nocheck<unsigned char>(out, len);
unsigned char temp;
if (len > 3) {
temp = (static_cast<unsigned long>(num) & 0xFF000000UL) >> 24;
write_number_nocheck(out, temp);
}
if (len > 2) {
temp = (static_cast<unsigned long>(num) & 0x00FF0000UL) >> 16;
write_number_nocheck(out, temp);
}
if (len > 1) {
temp = (static_cast<unsigned long>(num) & 0x0000FF00UL) >> 8;
write_number_nocheck(out, temp);
}
temp = (static_cast<unsigned long>(num) & 0x000000FFUL);
write_number_nocheck(out, temp);
write_guard(out, 0x2002);
}
void write_string(std::ostream& out, const string& str);
void write_string(std::ostream& out, const optional<string>& str);
} // namespace binary
} // namespace ledger
#endif // BINARY_H

View file

@ -1,896 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "cache.h"
#include "binary.h"
namespace ledger {
using namespace binary;
#if 0
void read_xact(const char *& data, xact_t * xact)
{
read_number(data, xact->_date);
read_number(data, xact->_date_eff);
xact->account = accounts[read_long<account_t::ident_t>(data) - 1];
unsigned char flag = read_number<unsigned char>(data);
if (flag == 0) {
xact->amount.read(data);
}
else if (flag == 1) {
xact->amount.read(data);
xact->amount_expr = expr_t();
xact->amount_expr->set_text(read_string(data));
}
else {
xact->amount_expr = expr_t();
xact->amount_expr->read(data);
}
if (read_bool(data)) {
xact->cost = amount_t();
xact->cost->read(data);
xact->cost_expr = expr_t();
xact->cost_expr->read(data);
} else {
xact->cost = none;
}
read_number(data, xact->state);
xact->set_flags(read_number<xact_t::flags_t>(data));
xact->add_flags(XACT_BULK_ALLOC);
read_string(data, xact->note);
// jww (2009-02-01): Use istream_pos_type
xact->beg_pos = read_long<unsigned long>(data);
read_long(data, xact->beg_line);
xact->end_pos = read_long<unsigned long>(data);
read_long(data, xact->end_line);
xact->data = NULL;
if (xact->amount_expr)
expr_t::compute_amount(xact->amount_expr.get(), xact->amount, xact);
}
void write_amount(std::ostream& out, amount_t& amt)
{
amt.write(out, ++bigints_index);
bigints_count++;
}
void write_xact(std::ostream& out, xact_t * xact,
bool ignore_calculated)
{
write_number(out, xact->_date);
write_number(out, xact->_date_eff);
write_long(out, xact->account->ident);
if (ignore_calculated && xact->has_flags(XACT_CALCULATED)) {
write_number<unsigned char>(out, 0);
amount_t temp;
write_amount(out, temp);
}
else if (xact->amount_expr) {
write_number<unsigned char>(out, 2);
// jww (2008-07-30): Um, is this right?
xact->amount_expr->write(out);
}
else if (! xact->amount_expr->text().empty()) {
write_number<unsigned char>(out, 1);
write_amount(out, xact->amount);
write_string(out, xact->amount_expr->text());
}
else {
write_number<unsigned char>(out, 0);
write_amount(out, xact->amount);
}
if (xact->cost &&
(! (ignore_calculated && xact->has_flags(XACT_CALCULATED)))) {
write_bool(out, true);
write_amount(out, *xact->cost);
// jww (2008-07-30): What if there is no cost expression?
xact->cost_expr->write(out);
} else {
write_bool(out, false);
}
write_number(out, xact->state);
write_number(out, xact->flags());
write_string(out, xact->note);
write_long(out, xact->beg_pos);
write_long(out, xact->beg_line);
write_long(out, xact->end_pos);
write_long(out, xact->end_line);
}
void read_entry_base(const char *& data, entry_base_t * entry,
xact_t *& xact_pool, bool& finalize)
{
read_long(data, entry->src_idx);
// jww (2008-07-31): Use istream_pos_type
entry->beg_pos = read_long<unsigned long>(data);
read_long(data, entry->beg_line);
entry->end_pos = read_long<unsigned long>(data);
read_long(data, entry->end_line);
bool ignore_calculated = read_bool(data);
for (std::size_t i = 0, count = read_long<std::size_t>(data);
i < count;
i++) {
new(xact_pool) xact_t;
read_xact(data, xact_pool);
if (ignore_calculated && xact_pool->has_flags(XACT_CALCULATED))
finalize = true;
entry->add_xact(xact_pool++);
}
}
void write_entry_base(std::ostream& out, entry_base_t * entry)
{
write_long(out, entry->src_idx);
write_long(out, entry->beg_pos);
write_long(out, entry->beg_line);
write_long(out, entry->end_pos);
write_long(out, entry->end_line);
bool ignore_calculated = false;
foreach (transaction_t * xact, entry->xacts)
if (xact->amount_expr) {
ignore_calculated = true;
break;
}
write_bool(out, ignore_calculated);
write_long(out, entry->xacts.size());
foreach (transaction_t * xact, entry->xacts)
write_xact(out, xact, ignore_calculated);
}
void read_entry(const char *& data, entry_t * entry,
xact_t *& xact_pool, bool& finalize)
{
read_entry_base(data, entry, xact_pool, finalize);
read_number(data, entry->_date);
read_number(data, entry->_date_eff);
read_string(data, entry->code);
read_string(data, entry->payee);
}
void write_entry(std::ostream& out, entry_t * entry)
{
write_entry_base(out, entry);
write_number(out, entry->_date);
write_number(out, entry->_date_eff);
write_string(out, entry->code);
write_string(out, entry->payee);
}
void read_auto_entry(const char *& data, auto_entry_t * entry,
xact_t *& xact_pool)
{
bool ignore;
read_entry_base(data, entry, xact_pool, ignore);
expr_t expr;
expr.read(data);
entry->predicate = item_predicate<xact_t>(expr);
}
void write_auto_entry(std::ostream& out, auto_entry_t * entry)
{
write_entry_base(out, entry);
entry->predicate.predicate.write(out);
}
void read_period_entry(const char *& data, period_entry_t * entry,
xact_t *& xact_pool, bool& finalize)
{
read_entry_base(data, entry, xact_pool, finalize);
read_string(data, &entry->period_string);
std::istringstream stream(entry->period_string);
entry->period.parse(stream);
}
void write_period_entry(std::ostream& out, period_entry_t * entry)
{
write_entry_base(out, entry);
write_string(out, entry->period_string);
}
commodity_t::base_t * read_commodity_base(const char *& data)
{
string str;
read_string(data, str);
std::auto_ptr<commodity_t::base_t> commodity(new commodity_t::base_t(str));
read_string(data, str);
if (! str.empty())
commodity->name = str;
read_string(data, str);
if (! str.empty())
commodity->note = str;
read_number(data, commodity->precision);
commodity_t::base_t::flags_t flags;
read_number(data, flags);
commodity->set_flags(flags);
return commodity.release();
}
void write_commodity_base(std::ostream& out, commodity_t::base_t * commodity)
{
// jww (2008-04-22): Not using this anymore?
//commodity->ident = ++base_commodity_index;
write_string(out, commodity->symbol);
// jww (2008-04-22): What to do with optional members?
write_string(out, *commodity->name);
write_string(out, *commodity->note);
write_number(out, commodity->precision);
write_number(out, commodity->flags());
}
void read_commodity_base_extra(const char *& data,
commodity_t::ident_t ident)
{
commodity_t::base_t * commodity = base_commodities[ident];
bool read_history = false;
// jww (2008-07-31): create a function read_size which does
// read_long<std::size_t>. Don't use read_number<std::size_t>, but it
// wastes too much space.
for (std::size_t i = 0, count = read_long<std::size_t>(data);
i < count;
i++) {
datetime_t when;
read_number(data, when);
amount_t amt;
amt.read(data);
// Upon insertion, amt will be copied, which will cause the amount to be
// duplicated (and thus not lost when the journal's item_pool is deleted).
if (! commodity->history)
commodity->history = commodity_t::history_t();
commodity->history->prices.insert(commodity_t::history_t::value_type(when, amt));
read_history = true;
}
if (read_history)
read_number(data, commodity->history->last_lookup);
if (read_bool(data)) {
amount_t amt;
amt.read(data);
commodity->smaller = amount_t(amt);
}
if (read_bool(data)) {
amount_t amt;
amt.read(data);
commodity->larger = amount_t(amt);
}
}
void write_commodity_base_extra(std::ostream& out,
commodity_t::base_t * commodity)
{
#if 0
// jww (2008-04-22): What did bogus_time used to do?
if (commodity->history && commodity->history->bogus_time)
commodity->remove_price(commodity->history->bogus_time);
#endif
if (! commodity->history) {
write_long<std::size_t>(out, 0);
} else {
write_long<std::size_t>(out, commodity->history->prices.size());
foreach (commodity_t::history_map::value_type& pair,
commodity->history->prices) {
write_number(out, pair.first);
write_amount(out, pair.second);
}
write_number(out, commodity->history->last_lookup);
}
if (commodity->smaller) {
write_bool(out, true);
write_amount(out, *commodity->smaller);
} else {
write_bool(out, false);
}
if (commodity->larger) {
write_bool(out, true);
write_amount(out, *commodity->larger);
} else {
write_bool(out, false);
}
}
commodity_t * read_commodity(const char *& data)
{
commodity_t::base_t * base =
base_commodities[read_long<commodity_t::ident_t>(data) - 1];
commodity_t * commodity =
new commodity_t(amount_t::current_pool,
shared_ptr<commodity_t::base_t>(base));
*commodities_next++ = commodity;
string str;
read_string(data, str);
if (! str.empty())
commodity->qualified_symbol = str;
commodity->annotated = false;
return commodity;
}
void write_commodity(std::ostream& out, commodity_t * commodity)
{
commodity->ident = ++commodity_index;
// jww (2008-04-22): Is this used anymore?
//write_long(out, commodity->base->ident);
// jww (2008-04-22): Optional!
write_string(out, *commodity->qualified_symbol);
}
commodity_t * read_commodity_annotated(const char *& data)
{
commodity_t * commodity =
commodities[read_long<commodity_t::ident_t>(data) - 1];
annotation_t details;
string str;
read_string(data, str);
// This read-and-then-assign causes a new amount to be allocated which does
// not live within the bulk allocation pool, since that pool will be deleted
// *before* the commodities are destroyed.
amount_t amt;
amt.read(data);
details.price = amt;
#if 0
// jww (2008-04-22): These are optional members!
read_number(data, details.date);
read_string(data, details.tag);
#endif
annotated_commodity_t * ann_comm =
new annotated_commodity_t(commodity, details);
*commodities_next++ = ann_comm;
if (! str.empty())
ann_comm->qualified_symbol = str;
return ann_comm;
}
void write_commodity_annotated(std::ostream& out,
commodity_t * commodity)
{
commodity->ident = ++commodity_index;
// jww (2008-04-22): No longer needed?
//write_long(out, commodity->base->ident);
// jww (2008-04-22): Optional!
write_string(out, *commodity->qualified_symbol);
annotated_commodity_t * ann_comm =
static_cast<annotated_commodity_t *>(commodity);
// jww (2008-04-22): No longer needed?
//write_long(out, ann_comm->base->ident);
// jww (2008-04-22): Make a write_annotation_details function; and optional!
if (ann_comm->details.price) {
write_bool(out, true);
write_amount(out, *ann_comm->details.price);
} else {
write_bool(out, false);
}
if (ann_comm->details.date) {
write_bool(out, true);
ann_comm->details.date->write(out);
} else {
write_bool(out, false);
}
if (ann_comm->details.tag) {
write_bool(out, true);
ann_comm->details.tag->write(out);
} else {
write_bool(out, false);
}
}
inline
account_t * read_account(const char *& data, account_t * master = NULL)
{
account_t * acct = new account_t(NULL);
accounts[account_ident++] = acct;
account_t::ident_t id;
read_long(data, id); // parent id
if (id == 0xffffffff)
acct->parent = NULL;
else
acct->parent = accounts[id - 1];
read_string(data, acct->name);
read_string(data, acct->note);
read_number(data, acct->depth);
// If all of the subaccounts will be added to a different master
// account, throw away what we've learned about the recorded
// journal's own master account.
if (master && acct != master) {
checked_delete(acct);
acct = master;
}
for (std::size_t i = 0, count = read_long<std::size_t>(data);
i < count;
i++) {
account_t * child = read_account(data);
child->parent = acct;
assert(acct != child);
acct->add_account(child);
}
return acct;
}
namespace {
inline account_t::ident_t count_accounts(account_t * account)
{
account_t::ident_t count = 1;
foreach (accounts_map::value_type& pair, account->accounts)
count += count_accounts(pair.second);
return count;
}
}
void write_account(std::ostream& out, account_t * account)
{
account->ident = ++account_ident;
if (account->parent)
write_long(out, account->parent->ident);
else
write_long<account_t::ident_t>(out, 0xffffffff);
write_string(out, account->name);
write_string(out, account->note);
write_number(out, account->depth);
write_number<std::size_t>(out, account->accounts.size());
foreach (accounts_map::value_type& pair, account->accounts)
write_account(out, pair.second);
}
std::size_t read_journal(std::istream& in,
const path& file,
journal_t& journal,
account_t * master)
{
using namespace binary;
// Read in the files that participated in this journal, so that they
// can be checked for changes on reading.
if (! file.empty()) {
for (unsigned short i = 0, count = read_number<unsigned short>(in);
i < count;
i++) {
path pathname = read_string(in);
std::time_t old_mtime;
read_number(in, old_mtime);
struct stat info;
// jww (2008-04-22): can this be done differently now?
stat(pathname.string().c_str(), &info);
if (std::difftime(info.st_mtime, old_mtime) > 0)
return 0;
sources.push_back(pathname);
}
// Make sure that the cache uses the same price database,
// otherwise it means that LEDGER_PRICE_DB has been changed, and
// we should ignore this cache file.
if (read_bool(in)) {
string pathname;
read_string(in, pathname);
if (! price_db ||
price_db->string() != std::string(pathname))
return 0;
}
}
// jww (2008-07-31): bind master to session.master
if (read_bool(data))
basket = accounts[read_long<account_t::ident_t>(data) - 1];
// Read in the entries and xacts
for (std::size_t i = 0; i < count; i++) {
new(entry_pool) entry_t;
bool finalize = false;
read_entry(data, entry_pool, xact_pool, finalize);
entry_pool->journal = &journal;
if (finalize && ! entry_pool->finalize())
continue;
entries.push_back(entry_pool++);
}
for (std::size_t i = 0; i < auto_count; i++) {
auto_entry_t * auto_entry = new auto_entry_t;
read_auto_entry(data, auto_entry, xact_pool);
auto_entry->journal = &journal;
auto_entries.push_back(auto_entry);
}
for (std::size_t i = 0; i < period_count; i++) {
period_entry_t * period_entry = new period_entry_t;
bool finalize = false;
read_period_entry(data, period_entry, xact_pool, finalize);
period_entry->journal = &journal;
if (finalize && ! period_entry->finalize())
continue;
period_entries.push_back(period_entry);
}
VERIFY(journal.valid());
return count;
}
std::pair<std::size_t, std::size_t>
write_journal(std::ostream& out, const journal_t& journal)
{
using namespace binary;
// Write out the files that participated in this journal, so that
// they can be checked for changes on reading.
if (sources.empty()) {
write_number<unsigned short>(out, 0);
} else {
write_number<unsigned short>(out, sources.size());
foreach (const path& path, sources) {
write_string(out, path.string());
struct stat info;
stat(path.string().c_str(), &info);
write_number(out, std::time_t(info.st_mtime));
}
// Write out the price database that relates to this data file, so
// that if it ever changes the cache can be invalidated.
if (price_db) {
write_bool(out, true);
write_string(out, price_db->string());
} else {
write_bool(out, false);
}
}
// Write out the basket accounts
if (basket) {
write_bool(out, true);
write_long(out, basket->ident);
} else {
write_bool(out, false);
}
// Write out the entries and xacts
std::size_t this_entry_count = 0;
std::size_t this_xact_count = 0;
foreach (entry_t * entry, entries) {
write_entry(out, entry);
this_entry_count++;
this_xact_count += entry->xacts.size();
}
foreach (auto_entry_t * entry, auto_entries) {
write_auto_entry(out, entry);
this_entry_count++;
this_xact_count += entry->xacts.size();
}
foreach (period_entry_t * entry, period_entries) {
write_period_entry(out, entry);
this_entry_count++;
this_xact_count += entry->xacts.size();
}
return std::pair<std::size_t, std::size_t>(this_entry_count,
this_xact_count);
}
std::size_t read_session(std::istream& in,
const path& file,
session_t& session)
{
using namespace binary;
// Read all of the data in at once, so that we're just dealing with
// a big data buffer.
std::size_t data_size = read_number<std::size_t>(in);
scoped_array<char> data_pool(new char[data_size]);
in.read(data_pool, data_size);
const char * data = data_pool.get();
// Read in the accounts
accounts.resize(read_number<std::size_t>(data));
account_ident = 0;
if (session.master)
checked_delete(session.master);
session.master = read_account(data);
// Allocate the memory needed for the entries, xacts and bigints in one
// large block, which is then chopped up and custom constructed as
// necessary.
entry_count = read_number<std::size_t>(data);
auto_entry_count = read_number<std::size_t>(data);
period_entry_count = read_number<std::size_t>(data);
xact_count = read_number<std::size_t>(data);
bigints_count = read_number<std::size_t>(data);
#define ENTRIES_SIZE (sizeof(entry_t) * entry_count)
#define XACTS_SIZE (sizeof(xact_t) * xact_count)
#define BIGINTS_SIZE (amount_t::sizeof_bigint_t() * bigints_count)
#define ENTRIES_OFFSET 0
#define XACTS_OFFSET ENTRIES_SIZE
#define BIGINTS_OFFSET (ENTRIES_SIZE + XACTS_SIZE)
item_pool.reset(new char[ENTRIES_SIZE + XACTS_SIZE + BIGINTS_SIZE]);
entry_pool = reinterpret_cast<entry_t *>(item_pool.get() + ENTRIES_OFFSET);
xact_pool = reinterpret_cast<xact_t *>(item_pool.get() + XACTS_OFFSET);
bigints = item_pool.get() + BIGINTS_OFFSET;
bigints_next = bigints;
bigint_ident = 0;
#if 0
// Read in the base commodities and the derived commodities
base_commodity_count = read_number<std::size_t>(data);
base_commodities.resize(base_commodity_count);
for (std::size_t i = 0; i < base_commodity_count; i++) {
commodity_t::base_t * base = read_commodity_base(data);
session.commodity_pool->commodities.push_back(base);
std::pair<base_commodities_map::iterator, bool> result =
commodity_base_t::commodities.insert
(base_commodities_pair(commodity->symbol, commodity));
if (! result.second) {
base_commodities_map::iterator c =
commodity_t::base_t::commodities.find(commodity->symbol);
// It's possible the user might have used a commodity in a value
// expression passed to an option, we'll just override the flags, but
// keep the commodity pointer intact.
if (c == commodity_t::base_t::commodities.end())
throw_(cache_error, "Failed to read base commodity from cache: "
<< commodity->symbol);
(*c).second->name = commodity->name;
(*c).second->note = commodity->note;
(*c).second->precision = commodity->precision;
(*c).second->flags = commodity->flags;
if ((*c).second->smaller)
checked_delete((*c).second->smaller);
(*c).second->smaller = commodity->smaller;
if ((*c).second->larger)
checked_delete((*c).second->larger);
(*c).second->larger = commodity->larger;
*(base_commodities_next - 1) = (*c).second;
checked_delete(commodity);
}
}
commodity_count = read_number<std::size_t>(data);
commodities.resize(commodity_count);
for (std::size_t i = 0; i < commodity_count; i++) {
commodity_t * commodity;
string mapping_key;
if (! read_bool(data)) {
commodity = read_commodity(data);
mapping_key = commodity->base->symbol;
} else {
read_string(data, mapping_key);
commodity = read_commodity_annotated(data);
}
session.commodity_pool->commodities.push_back(commodity);
if (! result.second) {
commodities_map::iterator c =
commodity_t::commodities.find(mapping_key);
if (c == commodity_t::commodities.end())
throw_(cache_error, "Failed to read commodity from cache: "
<< commodity->symbol());
*(commodities_next - 1) = (*c).second;
checked_delete(commodity);
}
}
for (std::size_t i = 0; i < base_commodity_count; i++)
read_commodity_base_extra(data, i);
commodity_t::ident_t ident = read_number<commodity_t::ident_t>(data);
if (ident == 0xffffffff || ident == 0)
session.commodity_pool->default_commodity = NULL;
else
session.commodity_pool->default_commodity = commodities[ident - 1];
#endif
// Clean up and return the number of entries read
accounts.clear();
commodities.clear();
VERIFY(session.valid());
return count;
}
void write_session(std::ostream& out, session_t& session)
{
using namespace binary;
write_number_nocheck(out, binary_magic_number);
write_number_nocheck(out, format_version);
// This number gets patched at the end of the function
ostream_pos_type data_val = out.tellp();
write_number<std::size_t>(out, 0);
// Write out the accounts
write_number<std::size_t>(out, count_accounts(session.master));
write_account(out, session.master);
// Write out the number of entries, xacts, and amounts
write_number<std::size_t>(out, entries.size());
write_number<std::size_t>(out, auto_entries.size());
write_number<std::size_t>(out, period_entries.size());
// These two numbers get patched at the end of the function
ostream_pos_type xacts_val = out.tellp();
write_number<std::size_t>(out, 0);
ostream_pos_type bigints_val = out.tellp();
write_number<std::size_t>(out, 0);
bigint_ident = 0;
#if 0
// Write out the commodities
// jww (2008-04-22): This whole section needs to be reworked
write_number<std::size_t>(out, session.commodity_pool->commodities.size());
write_number<std::size_t>(out, session.commodity_pool->commodities.size());
for (base_commodities_map::value_type pair, commodity_t::base_t::commodities)
write_commodity_base(out, pair.second);
write_number<commodity_t::ident_t>
(out, commodity_t::commodities.size());
for (commodities_map::value_type pair, commodity_t::commodities) {
if (! pair.second->annotated) {
write_bool(out, false);
write_commodity(out, pair.second);
}
}
for (commodities_map::value_type pair, commodity_t::commodities) {
if (pair.second->annotated) {
write_bool(out, true);
write_string(out, pair.first); // the mapping key
write_commodity_annotated(out, pair.second);
}
}
// Write out the history and smaller/larger convertible links after
// both the base and the main commodities have been written, since
// the amounts in both will refer to the mains.
for (base_commodities_map::const_iterator i =
commodity_t::base_t::commodities.begin();
i != commodity_t::base_t::commodities.end();
i++)
write_commodity_base_extra(out, (*i).second);
if (commodity_t::default_commodity)
write_number(out, commodity_t::default_commodity->ident);
else
write_number<commodity_t::ident_t>(out, 0xffffffff);
#endif
// Back-patch several counts which were not known beforehand
out.seekp(data_val);
write_number<std::size_t>(out, (static_cast<std::size_t>(out.tellp()) -
static_cast<std::size_t>(data_val) -
sizeof(std::size_t)));
out.seekp(xacts_val);
write_number<std::size_t>(out, xact_count);
out.seekp(bigints_val);
write_number<std::size_t>(out, bigints_count);
}
#endif
} // namespace ledger

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @addtogroup parse
*/
/**
* @file cache.h
* @author John Wiegley
*
* @ingroup parse
*
* @brief Brief
*
* Long.
*/
#ifndef CACHE_H
#define CACHE_H
#include "utils.h"
#include "session.h"
#include "journal.h"
#include "account.h"
namespace ledger {
DECLARE_EXCEPTION(cache_error, std::runtime_error);
/**
* @brief Brief
*
* Long.
*/
class binary_cache_t
{
static const unsigned long binary_magic_number = 0xFFEED765;
#if defined(DEBUG_ON)
static const unsigned long format_version = 0x00030001;
#else
static const unsigned long format_version = 0x00030000;
#endif
scoped_array<char> item_pool;
std::vector<account_t *> accounts;
account_t::ident_t account_ident;
entry_t * entry_pool; // points into item_pool
std::size_t entry_count;
std::size_t auto_entry_count;
std::size_t period_entry_count;
xact_t * xact_pool; // points into item_pool
std::size_t xact_count;
#if 0
commodity_base_t ** base_commodities; // allocated
commodity_base_t ** base_commodities_next;
uint_fast32_t base_commodity_index;
std::size_t base_commodity_count;
#endif
commodity_t ** commodities; // allocated
commodity_t ** commodities_next;
uint_fast32_t commodity_ident;
std::size_t commodity_count;
char * bigints; // points into item_pool
char * bigints_next;
uint_fast32_t bigints_index;
std::size_t bigints_count;
void read_xact(const char *& data, xact_t * xact);
void write_xact(std::ostream& out, xact_t * xact,
bool ignore_calculated);
void read_entry_base(const char *& data, entry_base_t * entry,
xact_t *& xact_pool, bool& finalize);
void write_entry_base(std::ostream& out, entry_base_t * entry);
void read_entry(const char *& data, entry_t * entry,
xact_t *& xact_pool, bool& finalize);
void write_entry(std::ostream& out, entry_t * entry);
void read_auto_entry(const char *& data, auto_entry_t * entry,
xact_t *& xact_pool);
void write_auto_entry(std::ostream& out, auto_entry_t * entry);
void read_period_entry(const char *& data, period_entry_t * entry,
xact_t *& xact_pool, bool& finalize);
void write_period_entry(std::ostream& out, period_entry_t * entry);
#if 0
commodity_t::base_t * read_commodity_base(const char *& data);
void write_commodity_base(std::ostream& out, commodity_t::base_t * commodity);
void read_commodity_base_extra(const char *& data,
commodity_t::ident_t ident);
void write_commodity_base_extra(std::ostream& out,
commodity_t::base_t * commodity);
#endif
commodity_t * read_commodity(const char *& data);
void write_commodity(std::ostream& out, commodity_t * commodity);
commodity_t * read_commodity_annotated(const char *& data);
void write_commodity_annotated(std::ostream& out,
commodity_t * commodity);
account_t * read_account(const char *& data, account_t * master = NULL);
void write_account(std::ostream& out);
std::size_t read_journal(std::istream& in,
const path& file,
journal_t& journal,
account_t * master);
void write_journal(std::ostream& out,
const journal_t& journal);
public:
binary_cache_t()
: account_ident(0),
#if 0
base_commodity_ident(0),
#endif
commodity_ident(0)
{
}
std::size_t read_session(std::istream& in, const path& file);
void write_session(std::ostream& out, session_t& session);
};
} // namespace ledger
#endif // CACHE_H

View file

@ -763,33 +763,6 @@ void annotated_commodity_t::write_annotations(std::ostream& out,
out << " (" << *info.tag << ')';
}
void commodity_t::read_xml(std::istream& in)
{
}
void commodity_t::write_xml(std::ostream& out, const int depth) const
{
out << xml_str("<commodity flags=\"", depth);
if (! (flags() & COMMODITY_STYLE_SUFFIXED)) out << 'P';
if (flags() & COMMODITY_STYLE_SEPARATED) out << 'S';
if (flags() & COMMODITY_STYLE_THOUSANDS) out << 'T';
if (flags() & COMMODITY_STYLE_EUROPEAN) out << 'E';
out << "\">\n";
out << xml_str("<symbol>", depth + 1) << symbol() << "</symbol>\n";
#if 0
// jww (2009-02-01): If this is an annotated commodity, more has to happen
if (price) {
out << xml_str("<price>", depth + 1);
price->write_xml(out, depth + 2);
out << xml_str("</price>\n", depth + 1);
}
#endif
out << xml_str("</commodity>\n", depth);
}
bool compare_amount_commodities::operator()(const amount_t * left,
const amount_t * right) const
{

View file

@ -364,13 +364,6 @@ public:
out << symbol();
}
void read(std::istream& in);
void read(char *& data);
void write(std::ostream& out) const;
void read_xml(std::istream& in);
void write_xml(std::ostream& out, const int depth = 0) const;
bool valid() const;
};

View file

@ -182,16 +182,6 @@ void expr_t::dump(std::ostream& out) const
if (ptr) ptr->dump(out, 0);
}
void expr_t::read(const char *& data)
{
if (ptr) ptr->read(data);
}
void expr_t::write(std::ostream& out) const
{
if (ptr) ptr->write(out);
}
void expr_t::initialize()
{
parser.reset(new expr_t::parser_t);

View file

@ -145,8 +145,6 @@ public:
void print(std::ostream& out) const;
void dump(std::ostream& out) const;
void read(const char *& data);
void write(std::ostream& out) const;
static value_t eval(const string& _expr, scope_t& scope);
};

View file

@ -81,13 +81,8 @@
#include <compare.h>
#include <textual.h>
#include <cache.h>
#include <xml.h>
#include <csv.h>
#include <emacs.h>
#include <qif.h>
#include <gnucash.h>
#include <ofx.h>
#include <session.h>
#include <report.h>

View file

@ -60,7 +60,6 @@ int main(int argc, char * argv[], char * envp[])
// Create the session object, which maintains nearly all state relating to
// this invocation of Ledger; and register all known journal parsers.
session = new LEDGER_SESSION_T;
register_journal_parsers(*session);
set_session_context(session);
// Create the report object, which maintains state relating to each

View file

@ -30,7 +30,6 @@
*/
#include "mask.h"
#include "binary.h"
namespace ledger {
@ -46,14 +45,4 @@ mask_t& mask_t::operator=(const string& pat)
return *this;
}
void mask_t::read(const char *& data)
{
*this = binary::read_string(data);
}
void mask_t::write(std::ostream& out) const
{
binary::write_string(out, expr.str());
}
} // namespace ledger

View file

@ -83,9 +83,6 @@ public:
bool empty() const {
return expr.empty();
}
void read(const char *& data);
void write(std::ostream& out) const;
};
inline std::ostream& operator<<(std::ostream& out, const mask_t& mask) {

View file

@ -31,7 +31,6 @@
#include "op.h"
#include "scope.h"
#include "binary.h"
namespace ledger {
@ -501,81 +500,6 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
}
}
void expr_t::op_t::read(const char *& data)
{
kind = binary::read_long<kind_t>(data);
if (kind > TERMINALS) {
set_left(new expr_t::op_t());
left()->read(data);
if (kind > UNARY_OPERATORS && binary::read_bool(data)) {
set_right(new expr_t::op_t());
right()->read(data);
}
}
switch (kind) {
case VALUE: {
value_t temp;
temp.read(data);
set_value(temp);
break;
}
case IDENT: {
string temp;
binary::read_string(data, temp);
set_ident(temp);
break;
}
case INDEX: {
long temp;
binary::read_long(data, temp);
set_index(temp);
break;
}
default:
assert(false);
break;
}
}
void expr_t::op_t::write(std::ostream& out) const
{
binary::write_long<kind_t>(out, kind);
if (kind > TERMINALS) {
left()->write(out);
if (kind > UNARY_OPERATORS) {
if (has_right()) {
binary::write_bool(out, true);
right()->write(out);
} else {
binary::write_bool(out, false);
}
}
} else {
switch (kind) {
case VALUE:
as_value().write(out);
break;
case IDENT:
binary::write_string(out, as_ident());
break;
case INDEX:
binary::write_long(out, as_index());
break;
case FUNCTION:
default:
assert(false);
break;
}
}
}
string op_context(const expr_t::ptr_op_t op, const expr_t::ptr_op_t goal)
{
ostream_pos_type start_pos, end_pos;

View file

@ -301,9 +301,6 @@ public:
bool print(std::ostream& out, const context_t& context = context_t()) const;
void dump(std::ostream& out, const int depth) const;
void read(const char *& data);
void write(std::ostream& out) const;
static ptr_op_t wrap_value(const value_t& val);
static ptr_op_t wrap_functor(const function_t& fobj);
};

View file

@ -66,9 +66,6 @@ value_t parse_command(call_scope_t& args)
result.print(out);
out << std::endl;
out << std::endl << "--- Calculated value as XML ---" << std::endl;
result.write_xml(out);
return 0L;
}

View file

@ -34,6 +34,7 @@
#include "handler.h"
#include "iterators.h"
#include "filters.h"
#include "textual.h"
namespace ledger {
@ -129,6 +130,8 @@ session_t::session_t()
init_file = home ? *home / ".ledgerrc" : "./.ledgerrc";
price_db = home ? *home / ".pricedb" : "./.pricedb";
cache_file = home ? *home / ".ledger-cache" : "./.ledger-cache";
register_parser(new textual_parser_t);
}
session_t::~session_t()

View file

@ -138,13 +138,6 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <mpfr.h>
#include "sha1.h"
#include "irrXML.h" // XML parser
#include "CXMLReaderImpl.h"
#if defined(HAVE_LIBOFX)
#include <libofx.h>
#endif
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/any.hpp>

View file

@ -536,42 +536,6 @@ inline char peek_next_nonws(std::istream& in) {
return c;
}
inline void xml_space(std::ostream& out, const int depth = 0) {
for (int i = 0; i < depth; i++)
out << " ";
}
inline void xml_print(std::ostream& out,
const string& str,
const int depth = 0) {
xml_space(out, depth);
out << str;
}
struct xml_str
{
const string& str;
const std::size_t depth;
xml_str(const string& _str, const std::size_t _depth)
: str(_str), depth(_depth) {
TRACE_CTOR(xml_str, "const string&, const std::size_t");
}
xml_str(const xml_str& other)
: str(other.str), depth(other.depth) {
TRACE_CTOR(xml_str, "copy");
}
~xml_str() throw() {
TRACE_DTOR(xml_str);
}
};
inline std::ostream& operator<<(std::ostream& out, const xml_str& obj) {
xml_space(out, obj.depth);
out << obj.str;
return out;
}
#define READ_INTO(str, targ, size, var, cond) { \
char * _p = targ; \
var = str.peek(); \

View file

@ -30,7 +30,6 @@
*/
#include "value.h"
#include "binary.h"
namespace ledger {
@ -1767,151 +1766,6 @@ void value_t::print(std::ostream& out, const bool relaxed) const
}
}
void value_t::read(std::istream& in)
{
switch (static_cast<value_t::type_t>(binary::read_long<int>(in))) {
case BOOLEAN:
set_boolean(binary::read_bool(in));
break;
case INTEGER:
set_long(binary::read_long<long>(in));
break;
case DATETIME:
set_datetime(parse_datetime(binary::read_string(in)));
break;
case DATE:
set_date(parse_date(binary::read_string(in)));
break;
case AMOUNT: {
amount_t temp;
temp.read(in);
set_amount(temp);
break;
}
default:
break;
}
throw_(value_error, "Cannot read " << label() << " from a stream");
}
void value_t::read(const char *& data)
{
switch (static_cast<value_t::type_t>(binary::read_long<int>(data))) {
case BOOLEAN:
set_boolean(binary::read_bool(data));
break;
case INTEGER:
set_long(binary::read_long<long>(data));
break;
case DATETIME:
set_datetime(parse_datetime(binary::read_string(data)));
break;
case DATE:
set_date(parse_date(binary::read_string(data)));
break;
case AMOUNT: {
amount_t temp;
temp.read(data);
set_amount(temp);
break;
}
default:
break;
}
throw_(value_error, "Cannot read " << label() << " from a stream");
}
void value_t::write(std::ostream& out) const
{
binary::write_long(out, static_cast<int>(type()));
switch (type()) {
case BOOLEAN:
binary::write_bool(out, as_boolean());
break;
case INTEGER:
binary::write_long(out, as_long());
break;
case DATETIME:
binary::write_string(out, format_datetime(as_datetime()));
break;
case DATE:
binary::write_string(out, format_date(as_date()));
break;
case AMOUNT:
as_amount().write(out);
break;
default:
break;
}
throw_(value_error, "Cannot write " << label() << " to a stream");
}
void value_t::write_xml(std::ostream& out, const int depth) const
{
out << xml_str("<value>\n", depth);
switch (type()) {
case VOID:
out << xml_str("<void />\n", depth + 1);
break;
case BOOLEAN:
out << xml_str("<bool>", depth + 1)
<< (as_boolean() ? "true" : "false")
<< "</bool>\n";
break;
case DATETIME:
out << xml_str("<datetime>", depth + 1)
<< format_datetime(as_datetime())
<< "</datetime>\n";
break;
case DATE:
out << xml_str("<date>", depth + 1)
<< format_date(as_date())
<< "</date>\n";
break;
case INTEGER:
out << xml_str("<integer>", depth + 1)
<< as_long()
<< "</integer>\n";
break;
case AMOUNT:
as_amount().write_xml(out, depth + 1);
break;
case BALANCE:
as_balance().write_xml(out, depth + 1);
break;
case BALANCE_PAIR:
as_balance_pair().write_xml(out, depth + 1);
break;
case STRING:
out << xml_str("<string>", depth + 1)
<< as_string()
<< "</string>\n";
break;
case MASK:
out << xml_str("<mask>", depth + 1)
<< as_mask()
<< "</mask>\n";
break;
case SEQUENCE:
out << xml_str("<sequence>\n", depth + 1);
foreach (const value_t& v, as_sequence())
v.write_xml(out, depth + 2);
out << xml_str("</sequence>\n", depth + 1);
break;
case POINTER:
default:
throw_(value_error, "Cannot output " << label() << " as XML");
break;
}
out << xml_str("</value>\n", depth);
}
bool value_t::valid() const
{
switch (type()) {

View file

@ -929,24 +929,6 @@ public:
const int latter_width = -1) const;
void print(std::ostream& out, const bool relaxed = true) const;
/**
* Serialization methods. A value may be deserialized from an input
* stream or a character pointer, and it may be serialized to an
* output stream. The methods used are:
*/
void read(std::istream& in);
void read(const char *& data);
void write(std::ostream& out) const;
/** @name XML Serialization
*/
/*@{*/
void read_xml(std::istream& in);
void write_xml(std::ostream& out, const int depth = 0) const;
/*@}*/
/**
* Debugging methods.
*/

View file

@ -74,20 +74,6 @@ void handle_debug_options(int argc, char * argv[])
}
}
void register_journal_parsers(session_t& session)
{
#if 0
session.register_parser(new journal_t::binary_parser_t);
#endif
session.register_parser(new xml_parser_t);
session.register_parser(new gnucash_parser_t);
#ifdef HAVE_LIBOFX
session.register_parser(new ofx_parser_t);
#endif
session.register_parser(new qif_parser_t);
session.register_parser(new textual_parser_t);
}
void read_environment_settings(report_t& report, char * envp[])
{
TRACE_START(environment, 1, "Processed environment variables");

View file

@ -44,7 +44,6 @@ typedef strings_list::iterator string_iterator;
typedef std::pair<string_iterator, string_iterator> string_iterator_pair;
void handle_debug_options(int argc, char * argv[]);
void register_journal_parsers(session_t& session);
void read_environment_settings(report_t& report, char * envp[]);
strings_list read_command_line_arguments(report_t& report,
int argc, char * argv[]);

View file

@ -1,512 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xml.h"
#include "journal.h"
#include "utils.h"
namespace ledger {
static irr::io::IrrXMLReader * current_parser;
static std::size_t count;
static journal_t * curr_journal;
static entry_t * curr_entry;
static commodity_t * curr_comm;
static string comm_flags;
static xact_t::state_t curr_state;
static string data;
static bool ignore;
static string have_error;
static void startElement(const char *name)
{
if (ignore)
return;
if (std::strcmp(name, "entry") == 0) {
assert(! curr_entry);
curr_entry = new entry_t;
curr_state = xact_t::UNCLEARED;
}
else if (std::strcmp(name, "xact") == 0) {
assert(curr_entry);
curr_entry->add_xact(new xact_t);
if (curr_state != item_t::UNCLEARED)
curr_entry->xacts.back()->set_state(curr_state);
}
else if (std::strcmp(name, "commodity") == 0) {
if (const char * p = current_parser->getAttributeValue("flags"))
comm_flags = p;
}
else if (std::strcmp(name, "total") == 0) {
ignore = true;
}
}
static void endElement(const char *name)
{
if (ignore) {
if (std::strcmp(name, "total") == 0)
ignore = false;
return;
}
if (std::strcmp(name, "entry") == 0) {
assert(curr_entry);
if (curr_journal->add_entry(curr_entry)) {
count++;
} else {
account_t * acct = curr_journal->find_account("<Unknown>");
curr_entry->add_xact(new xact_t(acct));
if (curr_journal->add_entry(curr_entry)) {
count++;
} else {
checked_delete(curr_entry);
have_error = "Entry cannot be balanced";
}
}
curr_entry = NULL;
}
else if (std::strcmp(name, "en:date") == 0) {
curr_entry->_date = parse_date(data);
}
else if (std::strcmp(name, "en:date_eff") == 0) {
curr_entry->_date_eff = parse_date(data);
}
else if (std::strcmp(name, "en:code") == 0) {
curr_entry->code = data;
}
else if (std::strcmp(name, "en:cleared") == 0) {
curr_state = xact_t::CLEARED;
}
else if (std::strcmp(name, "en:pending") == 0) {
curr_state = xact_t::PENDING;
}
else if (std::strcmp(name, "en:payee") == 0) {
curr_entry->payee = data;
}
else if (std::strcmp(name, "tr:account") == 0) {
curr_entry->xacts.back()->account = curr_journal->find_account(data);
}
else if (std::strcmp(name, "tr:cleared") == 0) {
curr_entry->xacts.back()->set_state(item_t::CLEARED);
}
else if (std::strcmp(name, "tr:pending") == 0) {
curr_entry->xacts.back()->set_state(item_t::PENDING);
}
else if (std::strcmp(name, "tr:virtual") == 0) {
curr_entry->xacts.back()->add_flags(XACT_VIRTUAL);
}
else if (std::strcmp(name, "tr:generated") == 0) {
curr_entry->xacts.back()->add_flags(XACT_AUTO);
}
else if (std::strcmp(name, "symbol") == 0) {
assert(! curr_comm);
curr_comm = amount_t::current_pool->find_or_create(data);
assert(curr_comm);
curr_comm->add_flags(COMMODITY_STYLE_SUFFIXED);
if (! comm_flags.empty()) {
for (string::size_type i = 0, l = comm_flags.length(); i < l; i++) {
switch (comm_flags[i]) {
case 'P': curr_comm->drop_flags(COMMODITY_STYLE_SUFFIXED); break;
case 'S': curr_comm->add_flags(COMMODITY_STYLE_SEPARATED); break;
case 'T': curr_comm->add_flags(COMMODITY_STYLE_THOUSANDS); break;
case 'E': curr_comm->add_flags(COMMODITY_STYLE_EUROPEAN); break;
}
}
}
}
#if 0
// jww (2006-03-02): !!!
else if (std::strcmp(name, "price") == 0) {
assert(curr_comm);
amount_t * price = new amount_t(data);
std::ostringstream symstr;
symstr << curr_comm->symbol << " {" << *price << "}";
commodity_t * priced_comm =
commodity_t::find_commodity(symstr.str(), true);
priced_comm->price = price;
priced_comm->base = curr_comm;
curr_comm = priced_comm;
}
#endif
else if (std::strcmp(name, "quantity") == 0) {
curr_entry->xacts.back()->amount.parse(data);
if (curr_comm) {
string::size_type i = data.find('.');
if (i != string::npos) {
int precision = data.length() - i - 1;
if (precision > curr_comm->precision())
curr_comm->set_precision(precision);
}
curr_entry->xacts.back()->amount.set_commodity(*curr_comm);
curr_comm = NULL;
}
}
else if (std::strcmp(name, "tr:amount") == 0) {
curr_comm = NULL;
}
}
bool xml_parser_t::test(std::istream& in) const
{
char buf[80];
char * p;
DEBUG("xml.parse", "Testing whether the file is XML...");
in.read(buf, 10);
if (utf8::is_bom(buf))
p = &buf[3];
else
p = buf;
if (std::strncmp(p, "<?xml", 5) != 0) {
in.clear();
in.seekg(0, std::ios::beg);
DEBUG("xml.parse", "Does not begin with <?xml");
return false;
}
in.getline(buf, 79); // skip rest of <?xml line
in.getline(buf, 79);
if (! std::strstr(buf, "<ledger")) {
in.clear();
in.seekg(0, std::ios::beg);
DEBUG("xml.parse", "Next line does not begin with <ledger");
return false;
}
in.clear();
in.seekg(0, std::ios::beg);
return true;
}
std::size_t xml_parser_t::parse(std::istream& in,
session_t& session,
journal_t& journal,
account_t * master,
const path * original_file)
{
TRACE_START(xml_parsing_total, 1, "Total time spent parsing XML:");
char buf[BUFSIZ];
count = 0;
curr_journal = &journal;
curr_entry = NULL;
curr_comm = NULL;
ignore = false;
irr::io::IrrXMLReader * parser =
new irr::io::CXMLReaderImpl<char, irr::io::IXMLBase>(new CStreamReadCallBack(in));
current_parser = parser;
while (parser->read()) {
switch (parser->getNodeType()) {
case irr::io::EXN_TEXT:
DEBUG("xml.parse", "Read text: " << parser->getNodeData());
if (! ignore) {
DEBUG("xml.parse", " but ignoring it");
data = parser->getNodeData();
}
break;
case irr::io::EXN_ELEMENT:
DEBUG("xml.parse", "Read element: " << parser->getNodeName());
startElement(parser->getNodeName());
break;
case irr::io::EXN_ELEMENT_END:
DEBUG("xml.parse", "End element: " << parser->getNodeName());
endElement(parser->getNodeName());
break;
default: // ignore: COMMENT, CDATA, UNKNOWN
break;
}
if (! have_error.empty()) {
parse_error err(have_error);
std::cerr << "Error: " << err.what() << std::endl;
have_error = "";
}
#if 0
if (! result) {
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser);
throw parse_error(err);
}
#endif
}
delete parser;
TRACE_FINISH(xml_parsing_total, 1);
return count;
}
void xml_write_amount(std::ostream& out, const amount_t& amount,
const int depth = 0)
{
for (int i = 0; i < depth; i++) out << ' ';
out << "<amount>\n";
commodity_t& c = amount.commodity();
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "<commodity flags=\"";
if (! (c.flags() & COMMODITY_STYLE_SUFFIXED)) out << 'P';
if (c.flags() & COMMODITY_STYLE_SEPARATED) out << 'S';
if (c.flags() & COMMODITY_STYLE_THOUSANDS) out << 'T';
if (c.flags() & COMMODITY_STYLE_EUROPEAN) out << 'E';
out << "\">\n";
for (int i = 0; i < depth + 4; i++) out << ' ';
#if 0
// jww (2006-03-02): !!!
if (c.price) {
out << "<symbol>" << c.base->symbol << "</symbol>\n";
for (int i = 0; i < depth + 4; i++) out << ' ';
out << "<price>\n";
xml_write_amount(out, *c.price, depth + 6);
for (int i = 0; i < depth + 4; i++) out << ' ';
out << "</price>\n";
} else {
out << "<symbol>" << c.symbol << "</symbol>\n";
}
#endif
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "</commodity>\n";
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "<quantity>";
out << amount.quantity_string() << "</quantity>\n";
for (int i = 0; i < depth; i++) out << ' ';
out << "</amount>\n";
}
void xml_write_value(std::ostream& out, const value_t& value,
const int depth = 0)
{
const balance_t * bal = NULL;
for (int i = 0; i < depth; i++) out << ' ';
out << "<value type=\"";
switch (value.type()) {
case value_t::BOOLEAN: out << "boolean"; break;
case value_t::INTEGER: out << "integer"; break;
case value_t::AMOUNT: out << "amount"; break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR: out << "balance"; break;
default:
assert(false);
break;
}
out << "\">\n";
switch (value.type()) {
case value_t::BOOLEAN:
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "<boolean>" << value.as_boolean() << "</boolean>\n";
break;
case value_t::INTEGER:
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "<integer>" << value.as_long() << "</integer>\n";
break;
case value_t::AMOUNT:
xml_write_amount(out, value.as_amount(), depth + 2);
break;
case value_t::BALANCE:
bal = &(value.as_balance());
// fall through...
case value_t::BALANCE_PAIR:
if (! bal)
bal = &(value.as_balance_pair().quantity());
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "<balance>\n";
foreach (const balance_t::amounts_map::value_type& pair, bal->amounts)
xml_write_amount(out, pair.second, depth + 4);
for (int i = 0; i < depth + 2; i++) out << ' ';
out << "</balance>\n";
break;
default:
assert(false);
break;
}
for (int i = 0; i < depth; i++) out << ' ';
out << "</value>\n";
}
void output_xml_string(std::ostream& out, const string& str)
{
for (const char * s = str.c_str(); *s; s++) {
switch (*s) {
case '<':
out << "&lt;";
break;
case '>':
out << "&rt;";
break;
case '&':
out << "&amp;";
break;
default:
out << *s;
break;
}
}
}
void format_xml_entries::format_last_entry()
{
std::ostream& out(report.output_stream);
#if 0
// jww (2008-05-08): Need to format these dates
out << " <entry>\n"
<< " <en:date>" << last_entry->_date.to_string("%Y/%m/%d")
<< "</en:date>\n";
if (is_valid(last_entry->_date_eff))
out << " <en:date_eff>"
<< last_entry->_date_eff.to_string("%Y/%m/%d")
<< "</en:date_eff>\n";
#endif
if (last_entry->code) {
out << " <en:code>";
output_xml_string(out, *last_entry->code);
out << "</en:code>\n";
}
if (! last_entry->payee.empty()) {
out << " <en:payee>";
output_xml_string(out, last_entry->payee);
out << "</en:payee>\n";
}
bool first = true;
foreach (xact_t * xact, last_entry->xacts) {
if (xact->has_xdata() &&
xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
if (first) {
out << " <en:xacts>\n";
first = false;
}
out << " <xact>\n";
#if 0
// jww (2008-05-08): Need to format these
if (xact->_date)
out << " <tr:date>"
<< xact->_date.to_string("%Y/%m/%d")
<< "</tr:date>\n";
if (is_valid(xact->_date_eff))
out << " <tr:date_eff>"
<< xact->_date_eff.to_string("%Y/%m/%d")
<< "</tr:date_eff>\n";
#endif
if (xact->state() == item_t::CLEARED)
out << " <tr:cleared/>\n";
else if (xact->state() == xact_t::PENDING)
out << " <tr:pending/>\n";
if (xact->has_flags(XACT_VIRTUAL))
out << " <tr:virtual/>\n";
if (xact->has_flags(XACT_AUTO))
out << " <tr:generated/>\n";
if (xact->account) {
string name = xact->account->fullname();
if (name == "<Total>")
name = "[TOTAL]";
else if (name == "<Unknown>")
name = "[UNKNOWN]";
out << " <tr:account>";
output_xml_string(out, name);
out << "</tr:account>\n";
}
out << " <tr:amount>\n";
if (xact->xdata().has_flags(XACT_EXT_COMPOUND))
xml_write_value(out, xact->xdata().value, 10);
else
xml_write_value(out, value_t(xact->amount), 10);
out << " </tr:amount>\n";
if (xact->cost) {
out << " <tr:cost>\n";
xml_write_value(out, value_t(*xact->cost), 10);
out << " </tr:cost>\n";
}
if (xact->note) {
out << " <tr:note>";
output_xml_string(out, *xact->note);
out << "</tr:note>\n";
}
if (show_totals) {
out << " <total>\n";
xml_write_value(out, xact->xdata().total, 10);
out << " </total>\n";
}
out << " </xact>\n";
xact->xdata().add_flags(XACT_EXT_DISPLAYED);
}
}
if (! first)
out << " </en:xacts>\n";
out << " </entry>\n";
}
} // namespace ledger

142
src/xml.h
View file

@ -1,142 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @addtogroup parse
*/
/**
* @file xml.h
* @author John Wiegley
*
* @ingroup parse
*
* @brief Brief
*
* Long.
*/
#ifndef _XML_H
#define _XML_H
#include "journal.h"
#include "report.h"
#include "output.h"
namespace ledger {
/**
* @brief Brief
*
* Long.
*/
class CStreamReadCallBack : public irr::io::IFileReadCallBack
{
std::istream& in;
std::size_t size;
public:
//! construct from filename
CStreamReadCallBack(std::istream& _in) : in(_in), size(0) {
TRACE_CTOR(CStreamReadCallBack, "std::istream&");
}
virtual ~CStreamReadCallBack() {
TRACE_DTOR(CStreamReadCallBack);
}
virtual int read(void * buffer, int sizeToRead)
{
in.read(static_cast<char *>(buffer), sizeToRead);
return in.gcount();
}
virtual int getSize()
{
if (size == 0) {
std::ifstream::pos_type pos = in.tellg();
in.seekg(0, std::ios_base::end);
size = in.tellg() - pos;
in.seekg(pos, std::ios_base::beg);
}
return size;
}
};
/**
* @brief Brief
*
* Long.
*/
class xml_parser_t : public journal_t::parser_t
{
public:
virtual bool test(std::istream& in) const;
virtual std::size_t parse(std::istream& in,
session_t& session,
journal_t& journal,
account_t * master = NULL,
const path * original_file = NULL);
};
/**
* @brief Brief
*
* Long.
*/
class format_xml_entries : public format_entries
{
bool show_totals;
format_xml_entries();
public:
format_xml_entries(report_t& _report,
const bool _show_totals = false)
: format_entries(_report, ""), show_totals(_show_totals) {
TRACE_CTOR(format_xml_entries, "std::ostream&, const bool");
report.output_stream << "<?xml version=\"1.0\"?>\n"
<< "<ledger version=\"2.5\">\n";
}
virtual ~format_xml_entries() throw() {
TRACE_DTOR(format_xml_entries);
}
virtual void flush() {
format_entries::flush();
report.output_stream << "</ledger>" << std::endl;
}
virtual void format_last_entry();
};
} // namespace ledger
#endif // _XML_H