summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/account.cc2
-rw-r--r--src/account.h20
-rw-r--r--src/amount.cc101
-rw-r--r--src/amount.h10
-rw-r--r--src/annotate.h46
-rw-r--r--src/archive.cc247
-rw-r--r--src/archive.h105
-rw-r--r--src/balance.cc6
-rw-r--r--src/balance.h14
-rw-r--r--src/chain.cc14
-rw-r--r--src/commodity.h83
-rw-r--r--src/derive.cc4
-rw-r--r--src/emacs.cc6
-rw-r--r--src/error.cc8
-rw-r--r--src/expr.h18
-rw-r--r--src/flags.h22
-rw-r--r--src/global.cc14
-rw-r--r--src/interactive.cc6
-rw-r--r--src/item.cc32
-rw-r--r--src/item.h97
-rw-r--r--src/journal.cc26
-rw-r--r--src/journal.h83
-rw-r--r--src/mask.h19
-rw-r--r--src/op.cc6
-rw-r--r--src/op.h28
-rw-r--r--src/output.cc4
-rw-r--r--src/pool.h18
-rw-r--r--src/post.h17
-rw-r--r--src/predicate.h13
-rw-r--r--src/py_value.cc6
-rw-r--r--src/report.cc4
-rw-r--r--src/scope.h66
-rw-r--r--src/session.cc132
-rw-r--r--src/session.h11
-rw-r--r--src/stats.cc2
-rw-r--r--src/system.hh.in69
-rw-r--r--src/textual.cc54
-rw-r--r--src/times.cc122
-rw-r--r--src/times.h88
-rw-r--r--src/utils.h12
-rw-r--r--src/value.cc22
-rw-r--r--src/value.h92
-rw-r--r--src/xact.cc4
-rw-r--r--src/xact.h69
44 files changed, 1485 insertions, 337 deletions
diff --git a/src/account.cc b/src/account.cc
index 57b66d86..52a6b436 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -458,7 +458,7 @@ void account_t::xdata_t::details_t::update(post_t& post,
posts_virtuals_count++;
if (gather_all)
- filenames.insert(post.pathname);
+ filenames.insert(post.pos->pathname);
date_t date = post.date();
diff --git a/src/account.h b/src/account.h
index 8c276c8a..9dc467bc 100644
--- a/src/account.h
+++ b/src/account.h
@@ -232,6 +232,26 @@ public:
return xdata_ && xdata_->has_flags(flags);
}
std::size_t children_with_flags(xdata_t::flags_t flags) const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<supports_flags<> >(*this);
+ ar & boost::serialization::base_object<scope_t>(*this);
+ ar & parent;
+ ar & name;
+ ar & note;
+ ar & depth;
+ ar & accounts;
+ ar & posts;
+ ar & _fullname;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
std::ostream& operator<<(std::ostream& out, const account_t& account);
diff --git a/src/amount.cc b/src/amount.cc
index a6788af9..3ac47c59 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -56,25 +56,25 @@ struct amount_t::bigint_t : public supports_flags<>
mpq_t val;
precision_t prec;
- uint_least16_t ref;
+ uint_least16_t refc;
#define MP(bigint) ((bigint)->val)
- bigint_t() : prec(0), ref(1) {
+ bigint_t() : prec(0), refc(1) {
TRACE_CTOR(bigint_t, "");
mpq_init(val);
}
bigint_t(const bigint_t& other)
: supports_flags<>(static_cast<uint_least8_t>
(other.flags() & ~BIGINT_BULK_ALLOC)),
- prec(other.prec), ref(1) {
+ prec(other.prec), refc(1) {
TRACE_CTOR(bigint_t, "copy");
mpq_init(val);
mpq_set(val, other.val);
}
~bigint_t() {
TRACE_DTOR(bigint_t);
- assert(ref == 0);
+ assert(refc == 0);
mpq_clear(val);
}
@@ -83,8 +83,8 @@ struct amount_t::bigint_t : public supports_flags<>
DEBUG("ledger.validate", "amount_t::bigint_t: prec > 128");
return false;
}
- if (ref > 16535) {
- DEBUG("ledger.validate", "amount_t::bigint_t: ref > 16535");
+ if (refc > 16535) {
+ DEBUG("ledger.validate", "amount_t::bigint_t: refc > 16535");
return false;
}
if (flags() & ~(BIGINT_BULK_ALLOC | BIGINT_KEEP_PREC)) {
@@ -94,6 +94,20 @@ struct amount_t::bigint_t : public supports_flags<>
}
return true;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int /* version */)
+ {
+ ar & boost::serialization::base_object<supports_flags<> >(*this);
+ ar & val;
+ ar & prec;
+ ar & refc;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
shared_ptr<commodity_pool_t> amount_t::current_pool;
@@ -147,8 +161,8 @@ void amount_t::_copy(const amount_t& amt)
} else {
quantity = amt.quantity;
DEBUG("amounts.refs",
- quantity << " ref++, now " << (quantity->ref + 1));
- quantity->ref++;
+ quantity << " refc++, now " << (quantity->refc + 1));
+ quantity->refc++;
}
}
commodity_ = amt.commodity_;
@@ -160,7 +174,7 @@ void amount_t::_dup()
{
VERIFY(valid());
- if (quantity->ref > 1) {
+ if (quantity->refc > 1) {
bigint_t * q = new bigint_t(*quantity);
_release();
quantity = q;
@@ -184,9 +198,9 @@ void amount_t::_release()
{
VERIFY(valid());
- DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
+ DEBUG("amounts.refs", quantity << " refc--, now " << (quantity->refc - 1));
- if (--quantity->ref == 0) {
+ if (--quantity->refc == 0) {
if (quantity->has_flags(BIGINT_BULK_ALLOC))
quantity->~bigint_t();
else
@@ -920,7 +934,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
quantity = new bigint_t;
safe_holder.reset(quantity);
}
- else if (quantity->ref > 1) {
+ else if (quantity->refc > 1) {
_release();
quantity = new bigint_t;
safe_holder.reset(quantity);
@@ -1095,8 +1109,8 @@ bool amount_t::valid() const
return false;
}
- if (quantity->ref == 0) {
- DEBUG("ledger.validate", "amount_t: quantity->ref == 0");
+ if (quantity->refc == 0) {
+ DEBUG("ledger.validate", "amount_t: quantity->refc == 0");
return false;
}
}
@@ -1107,4 +1121,63 @@ bool amount_t::valid() const
return true;
}
+#if defined(HAVE_BOOST_SERIALIZATION)
+
+template<class Archive>
+void amount_t::serialize(Archive& ar, const unsigned int /* version */)
+{
+ ar & current_pool;
+ ar & is_initialized;
+ ar & quantity;
+ ar & commodity_;
+}
+
+#endif // HAVE_BOOST_SERIALIZATION
+
} // namespace ledger
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+namespace boost {
+namespace serialization {
+
+template <class Archive>
+void serialize(Archive& ar, MP_INT& mpz, const unsigned int /* version */)
+{
+ ar & mpz._mp_alloc;
+ ar & mpz._mp_size;
+ ar & mpz._mp_d;
+}
+
+template <class Archive>
+void serialize(Archive& ar, MP_RAT& mpq, const unsigned int /* version */)
+{
+ ar & mpq._mp_num;
+ ar & mpq._mp_den;
+}
+
+template <class Archive>
+void serialize(Archive& ar, long unsigned int& integer,
+ const unsigned int /* version */)
+{
+ ar & make_binary_object(&integer, sizeof(long unsigned int));
+}
+
+} // namespace serialization
+} // namespace boost
+
+BOOST_CLASS_EXPORT(ledger::annotated_commodity_t)
+
+template void boost::serialization::serialize(boost::archive::binary_oarchive&,
+ MP_INT&, const unsigned int);
+template void boost::serialization::serialize(boost::archive::binary_iarchive&,
+ MP_RAT&, const unsigned int);
+template void boost::serialization::serialize(boost::archive::binary_iarchive&,
+ long unsigned int&,
+ const unsigned int);
+
+template void ledger::amount_t::serialize(boost::archive::binary_oarchive&,
+ const unsigned int);
+template void ledger::amount_t::serialize(boost::archive::binary_iarchive&,
+ const unsigned int);
+
+#endif // HAVE_BOOST_SERIALIZATION
diff --git a/src/amount.h b/src/amount.h
index b3c632af..f7d6986e 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -691,6 +691,16 @@ public:
bool valid() const;
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */);
+#endif // HAVE_BOOST_SERIALIZATION
+
/*@}*/
};
diff --git a/src/annotate.h b/src/annotate.h
index d98f7ef6..17c8a637 100644
--- a/src/annotate.h
+++ b/src/annotate.h
@@ -98,6 +98,21 @@ struct annotation_t : public supports_flags<>,
assert(*this);
return true;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<supports_flags<> >(*this);
+ ar & price;
+ ar & date;
+ ar & tag;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
struct keep_details_t
@@ -136,6 +151,21 @@ struct keep_details_t
return keep_price || keep_date || keep_tag;
}
bool keep_any(const commodity_t& comm) const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & keep_price;
+ ar & keep_date;
+ ar & keep_tag;
+ ar & only_actuals;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out,
@@ -183,6 +213,22 @@ public:
virtual commodity_t& strip_annotations(const keep_details_t& what_to_keep);
virtual void write_annotations(std::ostream& out) const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ explicit annotated_commodity_t() : ptr(NULL) {}
+
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<commodity_t>(*this);
+ ar & ptr;
+ ar & details;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline annotated_commodity_t&
diff --git a/src/archive.cc b/src/archive.cc
new file mode 100644
index 00000000..d631651f
--- /dev/null
+++ b/src/archive.cc
@@ -0,0 +1,247 @@
+/*
+ * 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 <system.hh>
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+
+#include "archive.h"
+#include "amount.h"
+#include "commodity.h"
+#include "pool.h"
+#include "scope.h"
+#include "account.h"
+#include "post.h"
+#include "xact.h"
+
+#define ARCHIVE_VERSION 0x03000001
+
+//BOOST_IS_ABSTRACT(ledger::scope_t)
+BOOST_CLASS_EXPORT(ledger::scope_t)
+BOOST_CLASS_EXPORT(ledger::child_scope_t)
+BOOST_CLASS_EXPORT(ledger::symbol_scope_t)
+BOOST_CLASS_EXPORT(ledger::call_scope_t)
+BOOST_CLASS_EXPORT(ledger::account_t)
+BOOST_CLASS_EXPORT(ledger::item_t)
+BOOST_CLASS_EXPORT(ledger::post_t)
+BOOST_CLASS_EXPORT(ledger::xact_base_t)
+BOOST_CLASS_EXPORT(ledger::xact_t)
+BOOST_CLASS_EXPORT(ledger::auto_xact_t)
+BOOST_CLASS_EXPORT(ledger::period_xact_t)
+
+template void ledger::journal_t::serialize(boost::archive::binary_oarchive&,
+ const unsigned int);
+template void ledger::journal_t::serialize(boost::archive::binary_iarchive&,
+ const unsigned int);
+namespace ledger {
+
+void archive_t::read_header()
+{
+ if (exists(file)) {
+ // Open the stream, read the version number and the list of sources
+ ifstream stream(file, std::ios::binary);
+ boost::archive::binary_iarchive iarchive(stream);
+
+ DEBUG("archive.journal", "Reading header from archive");
+ iarchive >> *this;
+
+ DEBUG("archive.journal",
+ "Version number: " << std::hex << version << std::dec);
+ DEBUG("archive.journal", "Number of sources: " << sources.size());
+
+ foreach (const journal_t::fileinfo_t& i, sources)
+ DEBUG("archive.journal", "Loaded source: " << *i.filename);
+ }
+}
+
+bool archive_t::should_load(const std::list<path>& data_files)
+{
+ std::size_t found = 0;
+
+ DEBUG("archive.journal", "Should the archive be loaded?");
+
+ if (! exists(file)) {
+ DEBUG("archive.journal", "No, it does not exist");
+ return false;
+ }
+
+ if (version != ARCHIVE_VERSION) {
+ DEBUG("archive.journal", "No, it fails the version check");
+ return false;
+ }
+
+ if (data_files.empty()) {
+ DEBUG("archive.journal", "No, there were no data files!");
+ return false;
+ }
+
+ if (sources.empty()) {
+ DEBUG("archive.journal", "No, there were no sources!");
+ return false;
+ }
+
+ if (data_files.size() != sources.size()) {
+ DEBUG("archive.journal", "No, number of sources doesn't match: "
+ << data_files.size() << " != " << sources.size());
+ return false;
+ }
+
+ foreach (const path& p, data_files) {
+ DEBUG("archive.journal", "Scanning for data file: " << p);
+
+ if (! exists(p)) {
+ DEBUG("archive.journal", "No, an input source no longer exists: " << p);
+ return false;
+ }
+
+ foreach (const journal_t::fileinfo_t& i, sources) {
+ assert(! i.from_stream);
+ assert(i.filename);
+
+ DEBUG("archive.journal", "Comparing against source file: " << *i.filename);
+
+ if (*i.filename == p) {
+ if (! exists(*i.filename)) {
+ DEBUG("archive.journal",
+ "No, a referent source no longer exists: " << *i.filename);
+ return false;
+ }
+
+ if (i.modtime != posix_time::from_time_t(last_write_time(p))) {
+ DEBUG("archive.journal", "No, a source's modtime has changed: " << p);
+ return false;
+ }
+
+ if (i.size != file_size(p)) {
+ DEBUG("archive.journal", "No, a source's size has changed: " << p);
+ return false;
+ }
+
+ found++;
+ }
+ }
+ }
+
+ if (found != data_files.size()) {
+ DEBUG("archive.journal", "No, not every source's name matched");
+ return false;
+ }
+
+ DEBUG("archive.journal", "Yes, it should be loaded!");
+ return true;
+}
+
+bool archive_t::should_save(shared_ptr<journal_t> journal)
+{
+ std::list<path> data_files;
+
+ DEBUG("archive.journal", "Should the archive be saved?");
+
+ if (journal->was_loaded) {
+ DEBUG("archive.journal", "No, it's one we loaded before");
+ return false;
+ }
+
+ if (journal->sources.empty()) {
+ DEBUG("archive.journal", "No, there were no sources!");
+ return false;
+ }
+
+ foreach (const journal_t::fileinfo_t& i, journal->sources) {
+ if (i.from_stream) {
+ DEBUG("archive.journal", "No, one source was from a stream");
+ return false;
+ }
+
+ if (! exists(*i.filename)) {
+ DEBUG("archive.journal",
+ "No, a source no longer exists: " << *i.filename);
+ return false;
+ }
+
+ data_files.push_back(*i.filename);
+ }
+
+ if (should_load(data_files)) {
+ DEBUG("archive.journal", "No, because it's still loadable");
+ return false;
+ }
+
+ DEBUG("archive.journal", "Yes, it should be saved!");
+ return true;
+}
+
+void archive_t::save(shared_ptr<journal_t> journal)
+{
+ INFO_START(archive, "Saved journal file cache");
+
+ ofstream archive(file, std::ios::binary);
+ boost::archive::binary_oarchive oa(archive);
+
+ version = ARCHIVE_VERSION;
+ sources = journal->sources;
+
+ foreach (const journal_t::fileinfo_t& i, sources)
+ DEBUG("archive.journal", "Saving source: " << *i.filename);
+
+ DEBUG("archive.journal",
+ "Creating archive with version " << std::hex << version << std::dec);
+ oa << *this;
+
+ DEBUG("archive.journal",
+ "Archiving journal with " << sources.size() << " sources");
+ oa << *journal;
+
+ INFO_FINISH(archive);
+}
+
+bool archive_t::load(shared_ptr<journal_t> journal)
+{
+ INFO_START(archive, "Read cached journal file");
+
+ ifstream stream(file, std::ios::binary);
+ boost::archive::binary_iarchive iarchive(stream);
+
+ // Skip past the archive header, it was already read in before
+ archive_t temp;
+ iarchive >> temp;
+
+ iarchive >> *journal.get();
+ journal->was_loaded = true;
+
+ INFO_FINISH(archive);
+
+ return true;
+}
+
+} // namespace ledger
+
+#endif // HAVE_BOOST_SERIALIZATION
diff --git a/src/archive.h b/src/archive.h
new file mode 100644
index 00000000..77272dbe
--- /dev/null
+++ b/src/archive.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup report Reporting
+ */
+
+/**
+ * @file archive.h
+ * @author John Wiegley
+ *
+ * @ingroup report
+ *
+ * @brief Brief
+ *
+ * Long.
+ */
+#ifndef _ARCHIVE_H
+#define _ARCHIVE_H
+
+#include "journal.h"
+
+namespace ledger {
+
+/**
+ * @brief Brief
+ *
+ * Long.
+ */
+class archive_t
+{
+ path file;
+ uint32_t version;
+
+ std::list<journal_t::fileinfo_t> sources;
+
+public:
+ archive_t() {
+ TRACE_CTOR(archive_t, "");
+ }
+ archive_t(const path& _file)
+ : file(_file), version(0) {
+ TRACE_CTOR(archive_t, "const path&");
+ }
+ archive_t(const archive_t& ar)
+ : file(ar.file), version(0) {
+ TRACE_CTOR(archive_t, "copy");
+ }
+ ~archive_t() {
+ TRACE_DTOR(archive_t);
+ }
+
+ void read_header();
+
+ bool should_load(const std::list<path>& data_files);
+ bool should_save(shared_ptr<journal_t> journal);
+
+ void save(shared_ptr<journal_t> journal);
+ bool load(shared_ptr<journal_t> journal);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & version;
+ ar & sources;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+};
+
+} // namespace ledger
+
+#endif // _ARCHIVE_H
diff --git a/src/balance.cc b/src/balance.cc
index 86352fa2..37628bd2 100644
--- a/src/balance.cc
+++ b/src/balance.cc
@@ -228,12 +228,14 @@ balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
return temp.commodity_amount(commodity);
throw_(amount_error,
- _("Requested amount of a balance with multiple commodities: %1") << temp);
+ _("Requested amount of a balance with multiple commodities: %1")
+ << temp);
}
#endif
}
else if (amounts.size() > 0) {
- amounts_map::const_iterator i = amounts.find(&*commodity);
+ amounts_map::const_iterator i =
+ amounts.find(const_cast<commodity_t *>(&*commodity));
if (i != amounts.end())
return i->second;
}
diff --git a/src/balance.h b/src/balance.h
index fe8afe2b..5452510b 100644
--- a/src/balance.h
+++ b/src/balance.h
@@ -80,7 +80,7 @@ class balance_t
multiplicative<balance_t, long> > > > > > > > > > > > > >
{
public:
- typedef std::map<const commodity_t *, amount_t> amounts_map;
+ typedef std::map<commodity_t *, amount_t> amounts_map;
amounts_map amounts;
@@ -523,6 +523,18 @@ public:
}
return true;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & amounts;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
diff --git a/src/chain.cc b/src/chain.cc
index 018b3812..d7d1460b 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -223,33 +223,33 @@ post_handler_ptr chain_post_handlers(report_t& report,
if (report.HANDLED(set_account_))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
- report.session.master.get(),
+ report.session.journal->master,
report.HANDLER(set_account_).str(),
report));
else if (report.HANDLED(set_payee_))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
- report.session.master.get(),
+ report.session.journal->master,
report.HANDLER(set_payee_).str(),
report));
else if (report.HANDLED(comm_as_payee))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
- report.session.master.get(),
+ report.session.journal->master,
expr_t("commodity"), report));
else if (report.HANDLED(code_as_payee))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
- report.session.master.get(),
+ report.session.journal->master,
expr_t("code"), report));
else if (report.HANDLED(payee_as_account))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
- report.session.master.get(),
+ report.session.journal->master,
expr_t("payee"), report));
else if (report.HANDLED(comm_as_account))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
- report.session.master.get(),
+ report.session.journal->master,
expr_t("commodity"), report));
else if (report.HANDLED(code_as_account))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
- report.session.master.get(),
+ report.session.journal->master,
expr_t("code"), report));
return handler;
diff --git a/src/commodity.h b/src/commodity.h
index 5d73f4e8..d91fce85 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -62,6 +62,19 @@ struct price_point_t
{
datetime_t when;
amount_t price;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & when;
+ ar & price;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -78,7 +91,7 @@ class commodity_t
public:
class base_t : public noncopyable, public supports_flags<uint_least16_t>
{
- base_t();
+ base_t() {}
public:
typedef std::map<const datetime_t, amount_t> history_map;
@@ -100,6 +113,18 @@ public:
, const int indent = 0
#endif
) const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+ private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & prices;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
typedef std::map<commodity_t *, history_t> history_by_commodity_map;
@@ -126,6 +151,18 @@ public:
optional<history_t&>
history(const optional<commodity_t&>& commodity = none);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+ private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & histories;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
#define COMMODITY_STYLE_DEFAULTS 0x000
@@ -158,6 +195,25 @@ public:
~base_t() {
TRACE_DTOR(base_t);
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+ private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<supports_flags<uint_least16_t> >(*this);
+ ar & symbol;
+ ar & precision;
+ ar & name;
+ ar & note;
+ ar & varied_history;
+ ar & smaller;
+ ar & larger;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
public:
@@ -330,6 +386,31 @@ public:
}
bool valid() const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ supports_flags<uint_least16_t> temp_flags;
+
+protected:
+ explicit commodity_t()
+ : delegates_flags<uint_least16_t>(temp_flags), parent_(NULL),
+ annotated(false) {}
+
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<delegates_flags<uint_least16_t> >(*this);
+ ar & base;
+ ar & parent_;
+ ar & qualified_symbol;
+ ar & mapping_key_;
+ ar & annotated;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
diff --git a/src/derive.cc b/src/derive.cc
index 2fe5754f..ef2d1e51 100644
--- a/src/derive.cc
+++ b/src/derive.cc
@@ -252,7 +252,7 @@ namespace {
if (tmpl.payee_mask.match((*j)->payee)) {
matching = *j;
DEBUG("derive.xact",
- "Found payee match: transaction on line " << (*j)->beg_line);
+ "Found payee match: transaction on line " << (*j)->pos->beg_line);
break;
}
}
@@ -332,7 +332,7 @@ namespace {
if (post.account_mask->match(x->account->fullname())) {
new_post.reset(new post_t(*x));
DEBUG("derive.xact",
- "Founding posting from line " << x->beg_line);
+ "Founding posting from line " << x->pos->beg_line);
break;
}
}
diff --git a/src/emacs.cc b/src/emacs.cc
index 57054690..24d3f1c1 100644
--- a/src/emacs.cc
+++ b/src/emacs.cc
@@ -40,8 +40,8 @@ namespace ledger {
void format_emacs_posts::write_xact(xact_t& xact)
{
- out << "\"" << xact.pathname << "\" "
- << (xact.beg_line + 1) << " ";
+ out << "\"" << xact.pos->pathname << "\" "
+ << (xact.pos->beg_line + 1) << " ";
tm when = gregorian::to_tm(xact.date());
std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local?
@@ -77,7 +77,7 @@ void format_emacs_posts::operator()(post_t& post)
out << "\n";
}
- out << " (" << (post.beg_line + 1) << " ";
+ out << " (" << (post.pos->beg_line + 1) << " ";
out << "\"" << post.reported_account()->fullname() << "\" \""
<< post.amount << "\"";
diff --git a/src/error.cc b/src/error.cc
index 70759b08..d5abe4de 100644
--- a/src/error.cc
+++ b/src/error.cc
@@ -96,10 +96,10 @@ string source_context(const path& file,
ifstream in(file);
in.seekg(pos, std::ios::beg);
- scoped_array<char> buf(new char[len + 1]);
- in.read(buf.get(), len);
- assert(in.gcount() == len);
- buf[len] = '\0';
+ scoped_array<char> buf(new char[static_cast<std::size_t>(len) + 1]);
+ in.read(buf.get(), static_cast<std::streamsize>(len));
+ assert(in.gcount() == static_cast<std::streamsize>(len));
+ buf[static_cast<std::size_t>(len)] = '\0';
bool first = true;
for (char * p = std::strtok(buf.get(), "\n");
diff --git a/src/expr.h b/src/expr.h
index b880fd79..83fe33dd 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -103,7 +103,7 @@ public:
expr_t(const string& _str, const uint_least8_t flags = 0);
expr_t(std::istream& in, const uint_least8_t flags = 0);
- virtual ~expr_t() throw();
+ ~expr_t() throw();
expr_t& operator=(const expr_t& _expr);
expr_t& operator=(const string& _expr) {
@@ -163,6 +163,22 @@ public:
void dump(std::ostream& out) const;
static value_t eval(const string& _expr, scope_t& scope);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & ptr;
+ ar & context;
+ ar & str;
+ if (Archive::is_loading::value)
+ compiled = false;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
std::ostream& operator<<(std::ostream& out, const expr_t& expr);
diff --git a/src/flags.h b/src/flags.h
index 21607fc2..33935556 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -99,6 +99,17 @@ public:
void drop_flags(const flags_t arg) {
_flags = static_cast<T>(static_cast<U>(_flags) & static_cast<U>(~arg));
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */)
+ {
+ ar & _flags;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -201,6 +212,17 @@ public:
void drop_flags(const flags_t arg) {
_flags.drop_flags(arg);
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */)
+ {
+ ar & _flags;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
#endif // _FLAGS_H
diff --git a/src/global.cc b/src/global.cc
index 8204bf69..9ba2a357 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -435,17 +435,18 @@ void global_scope_t::normalize_report_options(const string& verb)
item_t::use_effective_date = (rep.HANDLED(effective) &&
! rep.HANDLED(actual_dates));
- rep.session.commodity_pool->keep_base = rep.HANDLED(base);
- rep.session.commodity_pool->get_quotes = rep.session.HANDLED(download);
+ rep.session.journal->commodity_pool->keep_base = rep.HANDLED(base);
+ rep.session.journal->commodity_pool->get_quotes = rep.session.HANDLED(download);
if (rep.session.HANDLED(price_exp_))
- rep.session.commodity_pool->quote_leeway =
+ rep.session.journal->commodity_pool->quote_leeway =
rep.session.HANDLER(price_exp_).value.as_long();
if (rep.session.HANDLED(price_db_))
- rep.session.commodity_pool->price_db = rep.session.HANDLER(price_db_).str();
+ rep.session.journal->commodity_pool->price_db =
+ rep.session.HANDLER(price_db_).str();
else
- rep.session.commodity_pool->price_db = none;
+ rep.session.journal->commodity_pool->price_db = none;
if (rep.HANDLED(date_format_))
set_date_format(rep.HANDLER(date_format_).str().c_str());
@@ -542,7 +543,8 @@ void global_scope_t::normalize_report_options(const string& verb)
if (! rep.HANDLER(date_width_).specified)
rep.HANDLER(date_width_)
- .on_with(none, format_date(CURRENT_DATE(), FMT_PRINTED).length());
+ .on_with(none, static_cast<long>(format_date(CURRENT_DATE(),
+ FMT_PRINTED).length()));
long date_width = rep.HANDLER(date_width_).value.to_long();
long payee_width = (rep.HANDLER(payee_width_).specified ?
diff --git a/src/interactive.cc b/src/interactive.cc
index d2d6256b..61273f06 100644
--- a/src/interactive.cc
+++ b/src/interactive.cc
@@ -118,9 +118,9 @@ void interactive_t::verify_arguments() const
label = _("any value");
wrong_arg = false;
break;
- case 'P':
- label = _("a pointer");
- wrong_arg = ! next_arg->is_pointer();
+ case '^':
+ label = _("a scope");
+ wrong_arg = ! next_arg->is_scope();
break;
case 'S':
label = _("a sequence");
diff --git a/src/item.cc b/src/item.cc
index c4db7a51..631423a9 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -187,7 +187,7 @@ namespace {
}
value_t get_actual(item_t& item) {
- return ! item.has_flags(ITEM_GENERATED);
+ return ! item.has_flags(ITEM_GENERATED | ITEM_TEMP);
}
value_t get_date(item_t& item) {
@@ -224,23 +224,26 @@ namespace {
}
value_t get_pathname(item_t& item) {
- return string_value(item.pathname.string());
+ if (item.pos)
+ return string_value(item.pos->pathname.string());
+ else
+ return string_value(empty_string);
}
value_t get_beg_pos(item_t& item) {
- return long(item.beg_pos);
+ return item.pos ? long(item.pos->beg_pos) : 0L;
}
value_t get_beg_line(item_t& item) {
- return long(item.beg_line);
+ return item.pos ? long(item.pos->beg_line) : 0L;
}
value_t get_end_pos(item_t& item) {
- return long(item.end_pos);
+ return item.pos ? long(item.pos->end_pos) : 0L;
}
value_t get_end_line(item_t& item) {
- return long(item.end_line);
+ return item.pos ? long(item.pos->end_line) : 0L;
}
value_t get_depth(item_t&) {
@@ -397,12 +400,13 @@ bool item_t::valid() const
void print_item(std::ostream& out, const item_t& item, const string& prefix)
{
- out << source_context(item.pathname, item.beg_pos, item.end_pos, prefix);
+ out << source_context(item.pos->pathname, item.pos->beg_pos,
+ item.pos->end_pos, prefix);
}
string item_context(const item_t& item, const string& desc)
{
- std::streamoff len = item.end_pos - item.beg_pos;
+ std::streamoff len = item.pos->end_pos - item.pos->beg_pos;
if (! len)
return _("<no item context>");
@@ -411,18 +415,18 @@ string item_context(const item_t& item, const string& desc)
std::ostringstream out;
- if (item.pathname == path("/dev/stdin")) {
+ if (item.pos->pathname == path("/dev/stdin")) {
out << desc << _(" from standard input:");
return out.str();
}
- out << desc << _(" from \"") << item.pathname.string() << "\"";
+ out << desc << _(" from \"") << item.pos->pathname.string() << "\"";
- if (item.beg_line != item.end_line)
- out << _(", lines ") << item.beg_line << "-"
- << item.end_line << ":\n";
+ if (item.pos->beg_line != item.pos->end_line)
+ out << _(", lines ") << item.pos->beg_line << "-"
+ << item.pos->end_line << ":\n";
else
- out << _(", line ") << item.beg_line << ":\n";
+ out << _(", line ") << item.pos->beg_line << ":\n";
print_item(out, item, "> ");
diff --git a/src/item.h b/src/item.h
index 4d19e36a..5518a063 100644
--- a/src/item.h
+++ b/src/item.h
@@ -50,6 +50,53 @@
namespace ledger {
+struct position_t
+{
+ path pathname;
+ istream_pos_type beg_pos;
+ std::size_t beg_line;
+ istream_pos_type end_pos;
+ std::size_t end_line;
+
+ position_t() : beg_pos(0), beg_line(0), end_pos(0), end_line(0) {
+ TRACE_CTOR(position_t, "");
+ }
+ position_t(const position_t& pos) {
+ TRACE_CTOR(position_t, "copy");
+ *this = pos;
+ }
+ ~position_t() throw() {
+ TRACE_DTOR(position_t);
+ }
+
+ position_t& operator=(const position_t& pos) {
+ if (this != &pos) {
+ pathname = pos.pathname;
+ beg_pos = pos.beg_pos;
+ beg_line = pos.beg_line;
+ end_pos = pos.end_pos;
+ end_line = pos.end_line;
+ }
+ return *this;
+ }
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & pathname;
+ ar & beg_pos;
+ ar & beg_line;
+ ar & end_pos;
+ ar & end_line;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+};
+
/**
* @brief Brief
*
@@ -61,28 +108,21 @@ public:
#define ITEM_NORMAL 0x00 // no flags at all, a basic posting
// jww (2009-10-27): I'm not consistent on the difference between these two.
#define ITEM_GENERATED 0x01 // posting was not found in a journal
-#define ITEM_TEMP 0x02 // posting is a temporary object
+#define ITEM_TEMP 0x02 // posting is a managed temporary
enum state_t { UNCLEARED = 0, CLEARED, PENDING };
- state_t _state;
-
- optional<date_t> _date;
- optional<date_t> _date_eff;
- optional<string> note;
-
typedef std::map<string, optional<string> > string_map;
- optional<string_map> metadata;
- path pathname;
- istream_pos_type beg_pos;
- std::size_t beg_line;
- istream_pos_type end_pos;
- std::size_t end_line;
+ state_t _state;
+ optional<date_t> _date;
+ optional<date_t> _date_eff;
+ optional<string> note;
+ optional<position_t> pos;
+ optional<string_map> metadata;
item_t(flags_t _flags = ITEM_NORMAL, const optional<string>& _note = none)
- : supports_flags<>(_flags), _state(UNCLEARED), note(_note),
- beg_pos(0), beg_line(0), end_pos(0), end_line(0)
+ : supports_flags<>(_flags), _state(UNCLEARED), note(_note)
{
TRACE_CTOR(item_t, "flags_t, const string&");
}
@@ -102,14 +142,8 @@ public:
_date = item._date;
_date_eff = item._date_eff;
-
note = item.note;
-
- pathname = item.pathname;
- beg_pos = item.beg_pos;
- beg_line = item.beg_line;
- end_pos = item.end_pos;
- end_line = item.end_line;
+ pos = item.pos;
}
virtual bool operator==(const item_t& xact) {
@@ -158,6 +192,25 @@ public:
virtual expr_t::ptr_op_t lookup(const string& name);
bool valid() const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<supports_flags<> >(*this);
+ ar & boost::serialization::base_object<scope_t>(*this);
+ ar & _state;
+ ar & _date;
+ ar & _date_eff;
+ ar & note;
+ ar & metadata;
+ ar & pos;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
value_t get_comment(item_t& item);
diff --git a/src/journal.cc b/src/journal.cc
index fdb49e24..7dbc2907 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -32,11 +32,34 @@
#include <system.hh>
#include "journal.h"
+#include "amount.h"
+#include "commodity.h"
+#include "pool.h"
#include "xact.h"
#include "account.h"
namespace ledger {
+journal_t::journal_t()
+ : master(new account_t), was_loaded(false),
+ commodity_pool(new commodity_pool_t)
+{
+ TRACE_CTOR(journal_t, "");
+
+ // Add time commodity conversions, so that timelog's may be parsed
+ // in terms of seconds, but reported as minutes or hours.
+ if (commodity_t * commodity = commodity_pool->create("s"))
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ else
+ assert(false);
+
+ // Add a "percentile" commodity
+ if (commodity_t * commodity = commodity_pool->create("%"))
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ else
+ assert(false);
+}
+
journal_t::~journal_t()
{
TRACE_DTOR(journal_t);
@@ -52,6 +75,9 @@ journal_t::~journal_t()
foreach (period_xact_t * xact, period_xacts)
checked_delete(xact);
+
+ checked_delete(master);
+ commodity_pool.reset();
}
void journal_t::add_account(account_t * acct)
diff --git a/src/journal.h b/src/journal.h
index 43309590..88a225c5 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -48,11 +48,11 @@
#include "utils.h"
#include "hooks.h"
+#include "times.h"
namespace ledger {
-typedef std::list<path> paths_list;
-
+class commodity_pool_t;
class xact_t;
class auto_xact_t;
class xact_finalizer_t;
@@ -72,18 +72,60 @@ typedef std::list<period_xact_t *> period_xacts_list;
class journal_t : public noncopyable
{
public:
- account_t * master;
- account_t * basket;
- xacts_list xacts;
-
- auto_xacts_list auto_xacts;
- period_xacts_list period_xacts;
-
+ struct fileinfo_t
+ {
+ optional<path> filename;
+ uintmax_t size;
+ datetime_t modtime;
+ bool from_stream;
+
+ fileinfo_t() : size(0), from_stream(true) {
+ TRACE_CTOR(journal_t::fileinfo_t, "");
+ }
+ fileinfo_t(const path& _filename)
+ : filename(_filename), from_stream(false) {
+ TRACE_CTOR(journal_t::fileinfo_t, "const path&");
+ size = file_size(*filename);
+ modtime = posix_time::from_time_t(last_write_time(*filename));
+ }
+ fileinfo_t(const fileinfo_t& info)
+ : filename(info.filename), size(info.size),
+ modtime(info.modtime), from_stream(info.from_stream)
+ {
+ TRACE_CTOR(journal_t::fileinfo_t, "copy");
+ }
+ ~fileinfo_t() throw() {
+ TRACE_DTOR(journal_t::fileinfo_t);
+ }
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+ private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & filename;
+ ar & size;
+ ar & modtime;
+ ar & from_stream;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+ };
+
+ account_t * master;
+ account_t * basket;
+ xacts_list xacts;
+ auto_xacts_list auto_xacts;
+ period_xacts_list period_xacts;
+ std::list<fileinfo_t> sources;
+ bool was_loaded;
+
+ shared_ptr<commodity_pool_t> commodity_pool;
hooks_t<xact_finalizer_t, xact_t> xact_finalize_hooks;
- journal_t(account_t * _master = NULL) : master(_master) {
- TRACE_CTOR(journal_t, "");
- }
+ journal_t();
~journal_t();
// These four methods are delegated to the current session, since all
@@ -110,6 +152,23 @@ public:
bool strict = false);
bool valid() const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & master;
+ ar & basket;
+ ar & xacts;
+ ar & auto_xacts;
+ ar & period_xacts;
+ ar & sources;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger
diff --git a/src/mask.h b/src/mask.h
index 065d06a2..011c6f61 100644
--- a/src/mask.h
+++ b/src/mask.h
@@ -94,6 +94,25 @@ public:
}
return true;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ string temp;
+ if (Archive::is_loading::value) {
+ ar & temp;
+ *this = temp;
+ } else {
+ temp = expr.str();
+ ar & temp;
+ }
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const mask_t& mask) {
diff --git a/src/op.cc b/src/op.cc
index 2e098392..67db5136 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -172,12 +172,12 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
left()->left() && left()->left()->is_function()) {
call_scope_t call_args(scope);
if (value_t obj = left()->left()->as_function()(call_args)) {
- if (obj.is_pointer()) {
- if (obj.as_pointer_lval<scope_t>() == NULL) {
+ if (obj.is_scope()) {
+ if (obj.as_scope() == NULL) {
throw_(calc_error,
_("Left operand of . operator is NULL"));
} else {
- scope_t& objscope(obj.as_ref_lval<scope_t>());
+ scope_t& objscope(*obj.as_scope());
if (ptr_op_t member = objscope.lookup(right()->as_ident())) {
result = member->calc(objscope, NULL, depth + 1);
break;
diff --git a/src/op.h b/src/op.h
index c79ed3f6..8d474b80 100644
--- a/src/op.h
+++ b/src/op.h
@@ -192,6 +192,7 @@ public:
}
ptr_op_t& left() {
+ assert(kind > TERMINALS || kind == IDENT);
return left_;
}
const ptr_op_t& left() const {
@@ -289,6 +290,33 @@ public:
static ptr_op_t wrap_value(const value_t& val);
static ptr_op_t wrap_functor(const function_t& fobj);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & refc;
+ ar & kind;
+ if (Archive::is_loading::value || ! left_ || left_->kind != FUNCTION) {
+ ar & left_;
+ } else {
+ ptr_op_t temp_op;
+ ar & temp_op;
+ }
+ if (Archive::is_loading::value || kind == VALUE || kind == IDENT ||
+ (kind > UNARY_OPERATORS &&
+ (! has_right() || ! right()->is_function()))) {
+ ar & data;
+ } else {
+ variant<ptr_op_t, value_t, string, function_t> temp_data;
+ ar & temp_data;
+ }
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline expr_t::ptr_op_t
diff --git a/src/output.cc b/src/output.cc
index 371319bd..e2bbb7ec 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -203,7 +203,7 @@ void format_accounts::flush()
disp_pred.predicate.parse(report.HANDLER(display_).str());
}
- mark_accounts(*report.session.master, report.HANDLED(flat));
+ mark_accounts(*report.session.journal->master, report.HANDLED(flat));
std::size_t displayed = 0;
@@ -212,7 +212,7 @@ void format_accounts::flush()
if (displayed > 1 &&
! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
- bind_scope_t bound_scope(report, *report.session.master);
+ bind_scope_t bound_scope(report, *report.session.journal->master);
separator_format.format(out, bound_scope);
total_line_format.format(out, bound_scope);
}
diff --git a/src/pool.h b/src/pool.h
index 378163e9..6fce0c59 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -134,6 +134,24 @@ public:
parse_price_expression(const std::string& str,
const bool add_prices = true,
const optional<datetime_t>& moment = none);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & commodities;
+ ar & null_commodity;
+ ar & default_commodity;
+ ar & keep_base;
+ ar & price_db;
+ ar & quote_leeway;
+ ar & get_quotes;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger
diff --git a/src/post.h b/src/post.h
index f651d88d..a89ce3bc 100644
--- a/src/post.h
+++ b/src/post.h
@@ -205,6 +205,23 @@ public:
}
friend class xact_t;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<item_t>(*this);
+ ar & xact;
+ ar & account;
+ ar & amount;
+ ar & cost;
+ ar & assigned_amount;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger
diff --git a/src/predicate.h b/src/predicate.h
index 555fac05..5e900234 100644
--- a/src/predicate.h
+++ b/src/predicate.h
@@ -94,6 +94,19 @@ public:
throw;
}
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & predicate;
+ ar & what_to_keep;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
class query_lexer_t
diff --git a/src/py_value.cc b/src/py_value.cc
index 8e579104..9aa4984e 100644
--- a/src/py_value.cc
+++ b/src/py_value.cc
@@ -45,8 +45,8 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(value_overloads, value, 0, 2)
namespace {
expr_t py_value_getattr(const value_t& value, const string& name)
{
- if (value.is_pointer()) {
- if (scope_t * scope = value.as_pointer<scope_t>())
+ if (value.is_scope()) {
+ if (scope_t * scope = value.as_scope())
return expr_t(scope->lookup(name), scope);
}
throw_(value_error, _("Cannot lookup attributes in %1") << value.label());
@@ -283,7 +283,7 @@ void export_value()
.value("BALANCE", value_t::BALANCE)
.value("STRING", value_t::STRING)
.value("SEQUENCE", value_t::SEQUENCE)
- .value("POINTER", value_t::POINTER)
+ .value("SCOPE", value_t::SCOPE)
;
scope().attr("NULL_VALUE") = NULL_VALUE;
diff --git a/src/report.cc b/src/report.cc
index 8628cac7..bc0680d1 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -87,11 +87,11 @@ void report_t::accounts_report(acct_handler_ptr handler)
scoped_ptr<accounts_iterator> iter;
if (! HANDLED(sort_)) {
- iter.reset(new basic_accounts_iterator(*session.master));
+ iter.reset(new basic_accounts_iterator(*session.journal->master));
} else {
expr_t sort_expr(HANDLER(sort_).str());
sort_expr.set_context(this);
- iter.reset(new sorted_accounts_iterator(*session.master.get(),
+ iter.reset(new sorted_accounts_iterator(*session.journal->master,
sort_expr, HANDLED(flat)));
}
diff --git a/src/scope.h b/src/scope.h
index 2539074e..fc330ba0 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -67,6 +67,16 @@ public:
virtual void define(const string&, expr_t::ptr_op_t) {}
virtual expr_t::ptr_op_t lookup(const string& name) = 0;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive &, const unsigned int /* version */) {}
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -100,6 +110,19 @@ public:
return parent->lookup(name);
return NULL;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<scope_t>(*this);
+ ar & parent;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -127,6 +150,19 @@ public:
virtual void define(const string& name, expr_t::ptr_op_t def);
virtual expr_t::ptr_op_t lookup(const string& name);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<child_scope_t>(*this);
+ ar & symbols;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -138,8 +174,6 @@ class call_scope_t : public child_scope_t
{
value_t args;
- call_scope_t();
-
public:
explicit call_scope_t(scope_t& _parent) : child_scope_t(_parent) {
TRACE_CTOR(call_scope_t, "scope_t&");
@@ -182,6 +216,21 @@ public:
bool empty() const {
return args.size() == 0;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ explicit call_scope_t() {}
+
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<child_scope_t>(*this);
+ ar & args;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -215,6 +264,19 @@ public:
return def;
return child_scope_t::lookup(name);
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<child_scope_t>(*this);
+ ar & grandchild;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
diff --git a/src/session.cc b/src/session.cc
index ea9ae180..b7fdf275 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -32,13 +32,12 @@
#include <system.hh>
#include "session.h"
-#include "commodity.h"
-#include "pool.h"
#include "xact.h"
#include "account.h"
#include "journal.h"
#include "iterators.h"
#include "filters.h"
+#include "archive.h"
namespace ledger {
@@ -46,7 +45,7 @@ void set_session_context(session_t * session)
{
if (session) {
times_initialize();
- amount_t::initialize(session->commodity_pool);
+ amount_t::initialize(session->journal->commodity_pool);
// jww (2009-02-04): Is amount_t the right place for parse_conversion to
// happen?
@@ -64,12 +63,8 @@ void set_session_context(session_t * session)
session_t::session_t()
: flush_on_next_data_file(false),
-
current_year(CURRENT_DATE().year()),
-
- commodity_pool(new commodity_pool_t),
- master(new account_t),
- journal(new journal_t(master.get()))
+ journal(new journal_t)
{
TRACE_CTOR(session_t, "");
@@ -77,19 +72,6 @@ session_t::session_t()
HANDLER(price_db_).on(none, (path(home_var) / ".pricedb").string());
else
HANDLER(price_db_).on(none, path("./.pricedb").string());
-
- // Add time commodity conversions, so that timelog's may be parsed
- // in terms of seconds, but reported as minutes or hours.
- if (commodity_t * commodity = commodity_pool->create("s"))
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
- else
- assert(false);
-
- // Add a "percentile" commodity
- if (commodity_t * commodity = commodity_pool->create("%"))
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
- else
- assert(false);
}
std::size_t session_t::read_journal(std::istream& in,
@@ -123,6 +105,9 @@ std::size_t session_t::read_journal(const path& pathname,
std::size_t session_t::read_data(const string& master_account)
{
+ bool populated_data_files = false;
+ bool populated_price_db = false;
+
if (HANDLER(file_).data_files.empty()) {
path file;
if (const char * home_var = std::getenv("HOME"))
@@ -132,6 +117,8 @@ std::size_t session_t::read_data(const string& master_account)
HANDLER(file_).data_files.push_back(file);
else
throw_(parse_error, "No journal file was specified (please use -f)");
+
+ populated_data_files = true;
}
std::size_t xact_count = 0;
@@ -140,43 +127,75 @@ std::size_t session_t::read_data(const string& master_account)
if (! master_account.empty())
acct = journal->find_account(master_account);
- if (HANDLED(price_db_)) {
- path price_db_path = resolve_path(HANDLER(price_db_).str());
- if (exists(price_db_path) && read_journal(price_db_path) > 0)
- throw_(parse_error, _("Transactions not allowed in price history file"));
- }
-
- foreach (const path& pathname, HANDLER(file_).data_files) {
- path filename = resolve_path(pathname);
- if (filename == "-") {
- // To avoid problems with stdin and pipes, etc., we read the entire
- // file in beforehand into a memory buffer, and then parcel it out
- // from there.
- std::ostringstream buffer;
-
- while (std::cin.good() && ! std::cin.eof()) {
- char line[8192];
- std::cin.read(line, 8192);
- std::streamsize count = std::cin.gcount();
- buffer.write(line, count);
- }
- buffer.flush();
+ optional<path> price_db_path;
+ if (HANDLED(price_db_))
+ price_db_path = resolve_path(HANDLER(price_db_).str());
- std::istringstream buf_in(buffer.str());
+ optional<archive_t> cache;
+ if (HANDLED(cache_) && master_account.empty()) {
+ cache = archive_t(HANDLED(cache_).str());
+ cache->read_header();
- xact_count += read_journal(buf_in, "/dev/stdin", acct);
+ if (price_db_path) {
+ HANDLER(file_).data_files.push_back(*price_db_path);
+ populated_price_db = true;
}
- else if (exists(filename)) {
- xact_count += read_journal(filename, acct);
+ }
+
+ if (! (cache &&
+ cache->should_load(HANDLER(file_).data_files) &&
+ cache->load(journal))) {
+ if (price_db_path) {
+ if (exists(*price_db_path) && read_journal(*price_db_path) > 0)
+ throw_(parse_error, _("Transactions not allowed in price history file"));
+ journal->sources.push_back(journal_t::fileinfo_t(*price_db_path));
+ HANDLER(file_).data_files.remove(*price_db_path);
}
- else {
- throw_(parse_error, _("Could not read journal file '%1'") << filename);
+
+ foreach (const path& pathname, HANDLER(file_).data_files) {
+ path filename = resolve_path(pathname);
+ if (filename == "-") {
+ // To avoid problems with stdin and pipes, etc., we read the entire
+ // file in beforehand into a memory buffer, and then parcel it out
+ // from there.
+ std::ostringstream buffer;
+
+ while (std::cin.good() && ! std::cin.eof()) {
+ char line[8192];
+ std::cin.read(line, 8192);
+ std::streamsize count = std::cin.gcount();
+ buffer.write(line, count);
+ }
+ buffer.flush();
+
+ std::istringstream buf_in(buffer.str());
+
+ xact_count += read_journal(buf_in, "/dev/stdin", acct);
+ journal->sources.push_back(journal_t::fileinfo_t());
+ }
+ else if (exists(filename)) {
+ xact_count += read_journal(filename, acct);
+ journal->sources.push_back(journal_t::fileinfo_t(filename));
+ }
+ else {
+ throw_(parse_error, _("Could not read journal file '%1'") << filename);
+ }
}
+
+ assert(xact_count == journal->xacts.size());
+
+ if (cache && cache->should_save(journal))
+ cache->save(journal);
}
+ if (populated_data_files)
+ HANDLER(file_).data_files.clear();
+ else if (populated_price_db)
+ HANDLER(file_).data_files.remove(*price_db_path);
+
VERIFY(journal->valid());
- return xact_count;
+ return journal->xacts.size();
}
void session_t::read_journal_files()
@@ -200,14 +219,10 @@ void session_t::read_journal_files()
void session_t::close_journal_files()
{
journal.reset();
- master.reset();
- commodity_pool.reset();
amount_t::shutdown();
- commodity_pool.reset(new commodity_pool_t);
- amount_t::initialize(commodity_pool);
- master.reset(new account_t);
- journal.reset(new journal_t(master.get()));
+ journal.reset(new journal_t);
+ amount_t::initialize(journal->commodity_pool);
}
void session_t::clean_posts()
@@ -224,9 +239,9 @@ void session_t::clean_posts(xact_t& xact)
void session_t::clean_accounts()
{
- basic_accounts_iterator acct_walker(*master);
+ basic_accounts_iterator acct_walker(*journal->master);
pass_down_accounts(acct_handler_ptr(new clear_account_xdata), acct_walker);
- master->clear_xdata();
+ journal->master->clear_xdata();
}
option_t<session_t> * session_t::lookup_option(const char * p)
@@ -241,6 +256,9 @@ option_t<session_t> * session_t::lookup_option(const char * p)
case 'a':
OPT_(account_); // -a
break;
+ case 'c':
+ OPT(cache_);
+ break;
case 'd':
OPT(download); // -Q
break;
diff --git a/src/session.h b/src/session.h
index 4955053d..c1e0243b 100644
--- a/src/session.h
+++ b/src/session.h
@@ -66,12 +66,9 @@ class session_t : public symbol_scope_t
friend void set_session_context(session_t * session);
public:
- bool flush_on_next_data_file;
- date_t::year_type current_year;
-
- shared_ptr<commodity_pool_t> commodity_pool;
- scoped_ptr<account_t> master;
- scoped_ptr<journal_t> journal;
+ bool flush_on_next_data_file;
+ date_t::year_type current_year;
+ shared_ptr<journal_t> journal;
explicit session_t();
virtual ~session_t() {
@@ -106,6 +103,7 @@ public:
void report_options(std::ostream& out)
{
HANDLER(account_).report(out);
+ HANDLER(cache_).report(out);
HANDLER(download).report(out);
HANDLER(file_).report(out);
HANDLER(input_date_format_).report(out);
@@ -123,6 +121,7 @@ public:
*/
OPTION(session_t, account_); // -a
+ OPTION(session_t, cache_);
OPTION(session_t, download); // -Q
OPTION__
diff --git a/src/stats.cc b/src/stats.cc
index 5bb97fd1..6f0e21f4 100644
--- a/src/stats.cc
+++ b/src/stats.cc
@@ -46,7 +46,7 @@ value_t report_statistics(call_scope_t& args)
std::ostream& out(report.output_stream);
const account_t::xdata_t::details_t&
- statistics(report.session.master->family_details(true));
+ statistics(report.session.journal->master->family_details(true));
if (! is_valid(statistics.earliest_post) &&
! is_valid(statistics.latest_post))
diff --git a/src/system.hh.in b/src/system.hh.in
index 07598173..4a7dc55f 100644
--- a/src/system.hh.in
+++ b/src/system.hh.in
@@ -138,7 +138,6 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
-#include <boost/any.hpp>
#include <boost/bind.hpp>
#include <boost/cast.hpp>
#include <boost/current_function.hpp>
@@ -168,6 +167,74 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/variant.hpp>
#include <boost/version.hpp>
+#if defined(HAVE_BOOST_SERIALIZATION)
+
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/binary_oarchive.hpp>
+
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/binary_object.hpp>
+#include <boost/serialization/optional.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/variant.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/deque.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/serialization/map.hpp>
+
+#include <boost/date_time/posix_time/time_serialize.hpp>
+#include <boost/date_time/gregorian/greg_serialize.hpp>
+
+namespace boost {
+namespace serialization {
+
+template <class Archive>
+void serialize(Archive& ar, boost::filesystem::path& p, const unsigned int)
+{
+ std::string s;
+ if (Archive::is_saving::value)
+ s = p.string();
+
+ ar & s;
+
+ if (Archive::is_loading::value)
+ p = s;
+}
+
+template <class Archive, class T>
+void serialize(Archive& ar, boost::intrusive_ptr<T>& ptr, const unsigned int)
+{
+ if (Archive::is_saving::value) {
+ T * p = ptr.get();
+ ar & p;
+ }
+ else if (Archive::is_loading::value) {
+ T * p;
+ ar & p;
+ ptr.reset(p);
+ }
+}
+
+template <class Archive, class T>
+void serialize(Archive&, boost::function<T>&, const unsigned int)
+{
+}
+
+template <class Archive>
+void serialize(Archive& ar, istream_pos_type& pos, const unsigned int)
+{
+ ar & make_binary_object(&pos, sizeof(istream_pos_type));
+}
+
+} // namespace serialization
+} // namespace boost
+
+#endif // HAVE_BOOST_SERIALIZATION
+
#if defined(HAVE_BOOST_PYTHON)
#include <boost/python.hpp>
diff --git a/src/textual.cc b/src/textual.cc
index f05499df..9375ea4f 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -525,11 +525,12 @@ void instance_t::automated_xact_directive(char * line)
journal.auto_xacts.push_back(ae.get());
- ae->pathname = pathname;
- ae->beg_pos = pos;
- ae->beg_line = lnum;
- ae->end_pos = curr_pos;
- ae->end_line = linenum;
+ ae->pos = position_t();
+ ae->pos->pathname = pathname;
+ ae->pos->beg_pos = pos;
+ ae->pos->beg_line = lnum;
+ ae->pos->end_pos = curr_pos;
+ ae->pos->end_line = linenum;
ae.release();
}
@@ -565,11 +566,12 @@ void instance_t::period_xact_directive(char * line)
journal.period_xacts.push_back(pe.get());
- pe->pathname = pathname;
- pe->beg_pos = pos;
- pe->beg_line = lnum;
- pe->end_pos = curr_pos;
- pe->end_line = linenum;
+ pe->pos = position_t();
+ pe->pos->pathname = pathname;
+ pe->pos->beg_pos = pos;
+ pe->pos->beg_line = lnum;
+ pe->pos->end_pos = curr_pos;
+ pe->pos->end_line = linenum;
pe.release();
} else {
@@ -778,10 +780,11 @@ post_t * instance_t::parse_post(char * line,
std::auto_ptr<post_t> post(new post_t);
- post->xact = xact; // this could be NULL
- post->pathname = pathname;
- post->beg_pos = line_beg_pos;
- post->beg_line = linenum;
+ post->xact = xact; // this could be NULL
+ post->pos = position_t();
+ post->pos->pathname = pathname;
+ post->pos->beg_pos = line_beg_pos;
+ post->pos->beg_line = linenum;
char buf[MAX_LINE + 1];
std::strcpy(buf, line);
@@ -1056,8 +1059,8 @@ post_t * instance_t::parse_post(char * line,
_("Unexpected char '%1' (Note: inline math requires parentheses)")
<< *next);
- post->end_pos = curr_pos;
- post->end_line = linenum;
+ post->pos->end_pos = curr_pos;
+ post->pos->end_line = linenum;
if (! tag_stack.empty()) {
foreach (const string& tag, tag_stack)
@@ -1107,9 +1110,10 @@ xact_t * instance_t::parse_xact(char * line,
std::auto_ptr<xact_t> xact(new xact_t);
- xact->pathname = pathname;
- xact->beg_pos = line_beg_pos;
- xact->beg_line = linenum;
+ xact->pos = position_t();
+ xact->pos->pathname = pathname;
+ xact->pos->beg_pos = line_beg_pos;
+ xact->pos->beg_line = linenum;
bool reveal_context = true;
@@ -1189,8 +1193,8 @@ xact_t * instance_t::parse_xact(char * line,
// This is a trailing note, and possibly a metadata info tag
item->append_note(p + 1, current_year);
- item->end_pos = curr_pos;
- item->end_line++;
+ item->pos->end_pos = curr_pos;
+ item->pos->end_line++;
} else {
reveal_context = false;
@@ -1216,8 +1220,8 @@ xact_t * instance_t::parse_xact(char * line,
}
}
- xact->end_pos = curr_pos;
- xact->end_line = linenum;
+ xact->pos->end_pos = curr_pos;
+ xact->pos->end_line = linenum;
if (! tag_stack.empty()) {
foreach (const string& tag, tag_stack)
@@ -1232,8 +1236,8 @@ xact_t * instance_t::parse_xact(char * line,
catch (const std::exception& err) {
if (reveal_context) {
add_error_context(_("While parsing transaction:"));
- add_error_context(source_context(xact->pathname,
- xact->beg_pos, curr_pos, "> "));
+ add_error_context(source_context(xact->pos->pathname,
+ xact->pos->beg_pos, curr_pos, "> "));
}
throw;
}
diff --git a/src/times.cc b/src/times.cc
index 7b6eb6e8..667f65a3 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -314,50 +314,18 @@ date_t parse_date(const char * str, optional<date_t::year_type> current_year)
return parse_date_mask(str, current_year, saw_year);
}
-date_t date_interval_t::add_duration(const date_t& date,
- const duration_t& duration)
-{
- if (duration.type() == typeid(gregorian::days))
- return date + boost::get<gregorian::days>(duration);
- else if (duration.type() == typeid(gregorian::weeks))
- return date + boost::get<gregorian::weeks>(duration);
- else if (duration.type() == typeid(gregorian::months))
- return date + boost::get<gregorian::months>(duration);
- else
- assert(duration.type() == typeid(gregorian::years));
- return date + boost::get<gregorian::years>(duration);
-}
-
-date_t date_interval_t::subtract_duration(const date_t& date,
- const duration_t& duration)
-{
- if (duration.type() == typeid(gregorian::days))
- return date - boost::get<gregorian::days>(duration);
- else if (duration.type() == typeid(gregorian::weeks))
- return date - boost::get<gregorian::weeks>(duration);
- else if (duration.type() == typeid(gregorian::months))
- return date - boost::get<gregorian::months>(duration);
- else
- assert(duration.type() == typeid(gregorian::years));
- return date - boost::get<gregorian::years>(duration);
-}
-
std::ostream& operator<<(std::ostream& out,
const date_interval_t::duration_t& duration)
{
- if (duration.type() == typeid(gregorian::days))
- out << boost::get<gregorian::days>(duration).days()
- << " day(s)";
- else if (duration.type() == typeid(gregorian::weeks))
- out << (boost::get<gregorian::weeks>(duration).days() / 7)
- << " week(s)";
- else if (duration.type() == typeid(gregorian::months))
- out << boost::get<gregorian::months>(duration).number_of_months()
- << " month(s)";
+ if (duration.quantum == date_interval_t::duration_t::DAYS)
+ out << duration.length << " day(s)";
+ else if (duration.quantum == date_interval_t::duration_t::WEEKS)
+ out << duration.length << " week(s)";
+ else if (duration.quantum == date_interval_t::duration_t::MONTHS)
+ out << duration.length << " month(s)";
else {
- assert(duration.type() == typeid(gregorian::years));
- out << boost::get<gregorian::years>(duration).number_of_years()
- << " year(s)";
+ assert(duration.quantum == date_interval_t::duration_t::YEARS);
+ out << duration.length << " year(s)";
}
return out;
}
@@ -365,7 +333,7 @@ std::ostream& operator<<(std::ostream& out,
void date_interval_t::resolve_end()
{
if (start && ! end_of_duration) {
- end_of_duration = add_duration(*start, *duration);
+ end_of_duration = duration->add(*start);
DEBUG("times.interval",
"stabilize: end_of_duration = " << *end_of_duration);
}
@@ -383,7 +351,7 @@ void date_interval_t::resolve_end()
}
if (start && ! next) {
- next = add_duration(*start, *skip_duration);
+ next = skip_duration->add(*start);
DEBUG("times.interval",
"stabilize: next set to: " << *next);
}
@@ -423,8 +391,8 @@ void date_interval_t::stabilize(const optional<date_t>& date)
date_t when = start ? *start : *date;
- if (duration->type() == typeid(gregorian::months) ||
- duration->type() == typeid(gregorian::years)) {
+ if (duration->quantum == duration_t::MONTHS ||
+ duration->quantum == duration_t::YEARS) {
DEBUG("times.interval", "stabilize: monthly or yearly duration");
start = date_t(when.year(), gregorian::Jan, 1);
@@ -433,7 +401,7 @@ void date_interval_t::stabilize(const optional<date_t>& date)
start = date_t(when - gregorian::days(400));
- if (duration->type() == typeid(gregorian::weeks)) {
+ if (duration->quantum == duration_t::WEEKS) {
// Move it to a Sunday
while (start->day_of_week() != start_of_week)
*start += gregorian::days(1);
@@ -540,8 +508,8 @@ bool date_interval_t::find_period(const date_t& date)
return true;
}
- scan = add_duration(scan, *skip_duration);
- end_of_scan = add_duration(scan, *duration);
+ scan = skip_duration->add(scan);
+ end_of_scan = duration->add(scan);
}
return false;
@@ -565,7 +533,7 @@ date_interval_t& date_interval_t::operator++()
} else {
start = *next;
- end_of_duration = add_duration(*start, *duration);
+ end_of_duration = duration->add(*start);
}
next = none;
@@ -634,15 +602,15 @@ namespace {
assert(look_for_start || look_for_end);
if (word == _("year")) {
- duration = gregorian::years(1);
+ duration = date_interval_t::duration_t(date_interval_t::duration_t::YEARS, 1);
start = gregorian::date(start.year(), 1, 1);
}
else if (word == _("month")) {
- duration = gregorian::months(1);
+ duration = date_interval_t::duration_t(date_interval_t::duration_t::MONTHS, 1);
start = gregorian::date(start.year(), start.month(), 1);
}
else if (word == _("today") || word == _("day")) {
- duration = gregorian::days(1);
+ duration = date_interval_t::duration_t(date_interval_t::duration_t::DAYS, 1);
}
else {
parse_specifier = true;
@@ -651,15 +619,15 @@ namespace {
if (parse_specifier)
parse_inclusion_specifier(word, &start, &end);
else
- end = date_interval_t::add_duration(start, *duration);
+ end = duration->add(start);
if (type == _("last") && duration) {
- start = date_interval_t::subtract_duration(start, *duration);
- end = date_interval_t::subtract_duration(end, *duration);
+ start = duration->subtract(start);
+ end = duration->subtract(end);
}
else if (type == _("next") && duration) {
- start = date_interval_t::add_duration(start, *duration);
- end = date_interval_t::add_duration(end, *duration);
+ start = duration->add(start);
+ end = duration->add(end);
}
if (look_for_start && is_valid(start)) interval.start = start;
@@ -683,41 +651,41 @@ void date_interval_t::parse(std::istream& in)
int quantity = lexical_cast<int>(word);
read_lower_word(in, word);
if (word == _("days"))
- duration = gregorian::days(quantity);
+ duration = duration_t(duration_t::DAYS, quantity);
else if (word == _("weeks"))
- duration = gregorian::weeks(quantity);
+ duration = duration_t(duration_t::WEEKS, quantity);
else if (word == _("months"))
- duration = gregorian::months(quantity);
+ duration = duration_t(duration_t::MONTHS, quantity);
else if (word == _("quarters"))
- duration = gregorian::months(3 * quantity);
+ duration = duration_t(duration_t::MONTHS, 3 * quantity);
else if (word == _("years"))
- duration = gregorian::years(quantity);
+ duration = duration_t(duration_t::YEARS, quantity);
}
else if (word == _("day"))
- duration = gregorian::days(1);
+ duration = duration_t(duration_t::DAYS, 1);
else if (word == _("week"))
- duration = gregorian::weeks(1);
+ duration = duration_t(duration_t::WEEKS, 1);
else if (word == _("month"))
- duration = gregorian::months(1);
+ duration = duration_t(duration_t::MONTHS, 1);
else if (word == _("quarter"))
- duration = gregorian::months(3);
+ duration = duration_t(duration_t::MONTHS, 3);
else if (word == _("year"))
- duration = gregorian::years(1);
+ duration = duration_t(duration_t::YEARS, 1);
}
else if (word == _("daily"))
- duration = gregorian::days(1);
+ duration = duration_t(duration_t::DAYS, 1);
else if (word == _("weekly"))
- duration = gregorian::weeks(1);
+ duration = duration_t(duration_t::WEEKS, 1);
else if (word == _("biweekly"))
- duration = gregorian::weeks(2);
+ duration = duration_t(duration_t::WEEKS, 2);
else if (word == _("monthly"))
- duration = gregorian::months(1);
+ duration = duration_t(duration_t::MONTHS, 1);
else if (word == _("bimonthly"))
- duration = gregorian::months(2);
+ duration = duration_t(duration_t::MONTHS, 2);
else if (word == _("quarterly"))
- duration = gregorian::months(3);
+ duration = duration_t(duration_t::MONTHS, 3);
else if (word == _("yearly"))
- duration = gregorian::years(1);
+ duration = duration_t(duration_t::YEARS, 1);
else if (word == _("this") || word == _("last") || word == _("next") ||
word == _("today")) {
parse_date_words(in, word, *this);
@@ -760,17 +728,17 @@ void date_interval_t::parse(std::istream& in)
if (wday) {
while (start->day_of_week() != *wday)
- *start -= gregorian::days(1);
+ *start = duration_t(duration_t::DAYS, 1).subtract(*start);
if (! end)
- end = *start + gregorian::days(1);
+ end = duration_t(duration_t::DAYS, 1).add(*start);
} else {
bool overwrite_end = false;
if (year) {
start = date_t(*year, 1, 1);
if (! end) {
- end = *start + gregorian::years(1);
+ end = duration_t(duration_t::YEARS, 1).add(*start);
overwrite_end = true;
}
}
@@ -778,7 +746,7 @@ void date_interval_t::parse(std::istream& in)
if (mon) {
start = date_t(start->year(), *mon, 1);
if (! end || overwrite_end)
- end = *start + gregorian::months(1);
+ end = duration_t(duration_t::MONTHS, 1).add(*start);
}
}
}
diff --git a/src/times.h b/src/times.h
index 69e3af51..db83d175 100644
--- a/src/times.h
+++ b/src/times.h
@@ -119,10 +119,71 @@ void set_input_date_format(const char * format);
class date_interval_t : public equality_comparable<date_interval_t>
{
public:
- typedef variant<gregorian::days,
- gregorian::weeks,
- gregorian::months,
- gregorian::years> duration_t;
+ struct duration_t
+ {
+ enum skip_quantum_t {
+ DAYS, WEEKS, MONTHS, YEARS
+ } quantum;
+ int length;
+
+ duration_t() : quantum(DAYS), length(0) {
+ TRACE_CTOR(date_interval_t::duration_t, "");
+ }
+ duration_t(skip_quantum_t _quantum, int _length)
+ : quantum(_quantum), length(_length) {
+ TRACE_CTOR(date_interval_t::duration_t, "skip_quantum_t, int");
+ }
+ duration_t(const duration_t& dur)
+ : quantum(dur.quantum), length(dur.length) {
+ TRACE_CTOR(date_interval_t::duration_t, "copy");
+ }
+ ~duration_t() throw() {
+ TRACE_DTOR(date_interval_t::duration_t);
+ }
+
+ date_t add(const date_t& date) const {
+ switch (quantum) {
+ case DAYS:
+ return date + gregorian::days(length);
+ case WEEKS:
+ return date + gregorian::weeks(length);
+ case MONTHS:
+ return date + gregorian::months(length);
+ case YEARS:
+ return date + gregorian::years(length);
+ default:
+ assert(0); return date_t();
+ }
+ }
+
+ date_t subtract(const date_t& date) const {
+ switch (quantum) {
+ case DAYS:
+ return date - gregorian::days(length);
+ case WEEKS:
+ return date - gregorian::weeks(length);
+ case MONTHS:
+ return date - gregorian::months(length);
+ case YEARS:
+ return date - gregorian::years(length);
+ default:
+ assert(0); return date_t();
+ }
+ }
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+ private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & quantum;
+ ar & length;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+ };
static date_t add_duration(const date_t& date,
const duration_t& duration);
@@ -196,6 +257,25 @@ public:
}
date_interval_t& operator++();
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & start;
+ ar & aligned;
+ ar & skip_duration;
+ ar & factor;
+ ar & next;
+ ar & duration;
+ ar & end_of_duration;
+ ar & end;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
void times_initialize();
diff --git a/src/utils.h b/src/utils.h
index e3ae5dda..c662acbe 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -178,6 +178,18 @@ public:
string(const char * str, size_type x);
string(const char * str, size_type x, size_type y);
~string() throw();
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<std::string>(*this);
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
inline string operator+(const string& __lhs, const string& __rhs)
diff --git a/src/value.cc b/src/value.cc
index a6bbb2fb..a3a05b6c 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -113,8 +113,8 @@ value_t::operator bool() const
}
}
return false;
- case POINTER:
- return ! as_any_pointer().empty();
+ case SCOPE:
+ return as_scope() != NULL;
default:
break;
}
@@ -1206,8 +1206,8 @@ bool value_t::is_realzero() const
case SEQUENCE:
return as_sequence().empty();
- case POINTER:
- return as_any_pointer().empty();
+ case SCOPE:
+ return as_scope() == NULL;
default:
throw_(value_error, _("Cannot determine if %1 is really zero") << label());
@@ -1235,8 +1235,8 @@ bool value_t::is_zero() const
case SEQUENCE:
return as_sequence().empty();
- case POINTER:
- return as_any_pointer().empty();
+ case SCOPE:
+ return as_scope() == NULL;
default:
throw_(value_error, _("Cannot determine if %1 is zero") << label());
@@ -1474,7 +1474,7 @@ value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
case DATE:
case STRING:
case MASK:
- case POINTER:
+ case SCOPE:
return *this;
case SEQUENCE: {
@@ -1579,8 +1579,8 @@ void value_t::print(std::ostream& out,
break;
}
- case POINTER:
- out << "<POINTER>";
+ case SCOPE:
+ out << "<SCOPE>";
break;
default:
@@ -1647,8 +1647,8 @@ void value_t::dump(std::ostream& out, const bool relaxed) const
out << '/' << as_mask() << '/';
break;
- case POINTER:
- out << boost::unsafe_any_cast<const void *>(&as_any_pointer());
+ case SCOPE:
+ out << as_scope();
break;
case SEQUENCE: {
diff --git a/src/value.h b/src/value.h
index 31850894..3c5ce286 100644
--- a/src/value.h
+++ b/src/value.h
@@ -56,6 +56,8 @@ namespace ledger {
DECLARE_EXCEPTION(value_error, std::runtime_error);
+class scope_t;
+
/**
* @class value_t
*
@@ -107,7 +109,7 @@ public:
STRING, // a string object
MASK, // a regular expression mask
SEQUENCE, // a vector of value_t objects
- POINTER // an opaque pointer of any type
+ SCOPE // a pointer to a scope
};
private:
@@ -134,7 +136,7 @@ private:
string, // STRING
mask_t, // MASK
sequence_t *, // SEQUENCE
- boost::any // POINTER
+ scope_t * // SCOPE
> data;
type_t type;
@@ -225,6 +227,20 @@ private:
data = false;
type = VOID;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+ private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & data;
+ ar & type;
+ ar & refc;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -332,10 +348,9 @@ public:
set_sequence(val);
}
- template <typename T>
- explicit value_t(T * item) {
- TRACE_CTOR(value_t, "T *");
- set_pointer(item);
+ explicit value_t(scope_t * item) {
+ TRACE_CTOR(value_t, "scope_t *");
+ set_scope(item);
}
/**
@@ -687,50 +702,19 @@ public:
}
/**
- * Dealing with pointers is bit involved because we actually deal
- * with typed pointers. For example, if you call as_pointer it
- * returns a boost::any object, but if you use as_pointer<void>,
- * then it returns a void *. The latter form only succeeds if the
- * stored pointers was assigned to the value as a void*, otherwise
- * it throws an exception.
+ * Dealing with scope pointers.
*/
- bool is_pointer() const {
- return is_type(POINTER);
- }
- boost::any& as_any_pointer_lval() {
- VERIFY(is_pointer());
- _dup();
- return boost::get<boost::any>(storage->data);
- }
- template <typename T>
- T * as_pointer_lval() {
- return any_cast<T *>(as_any_pointer_lval());
- }
- template <typename T>
- T& as_ref_lval() {
- return *as_pointer_lval<T>();
- }
- const boost::any& as_any_pointer() const {
- VERIFY(is_pointer());
- return boost::get<boost::any>(storage->data);
- }
- template <typename T>
- T * as_pointer() const {
- return any_cast<T *>(as_any_pointer());
+ bool is_scope() const {
+ return is_type(SCOPE);
}
- template <typename T>
- T& as_ref() const {
- return *as_pointer<T>();
+ scope_t * as_scope() const {
+ VERIFY(is_scope());
+ return boost::get<scope_t *>(storage->data);
}
- void set_any_pointer(const boost::any& val) {
- set_type(POINTER);
+ void set_scope(scope_t * val) {
+ set_type(SCOPE);
storage->data = val;
}
- template <typename T>
- void set_pointer(T * val) {
- set_type(POINTER);
- storage->data = boost::any(val);
- }
/**
* Data conversion methods. These methods convert a value object to
@@ -902,8 +886,8 @@ public:
return _("a regexp");
case SEQUENCE:
return _("a sequence");
- case POINTER:
- return _("a pointer");
+ case SCOPE:
+ return _("a scope");
default:
assert(false);
break;
@@ -926,6 +910,20 @@ public:
* Debugging methods.
*/
bool valid() const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & true_value;
+ ar & false_value;
+ ar & storage;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
#define NULL_VALUE (value_t())
diff --git a/src/xact.cc b/src/xact.cc
index 9f118ec2..be8c0214 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -499,7 +499,7 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler)
IF_DEBUG("xact.extend") {
DEBUG("xact.extend",
- "Initial post on line " << initial_post->beg_line << ": "
+ "Initial post on line " << initial_post->pos->beg_line << ": "
<< "amount " << initial_post->amount << " (precision "
<< initial_post->amount.precision() << ")");
@@ -509,7 +509,7 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler)
#endif
DEBUG("xact.extend",
- "Posting on line " << post->beg_line << ": "
+ "Posting on line " << post->pos->beg_line << ": "
<< "amount " << post->amount << ", amt " << amt
<< " (precision " << post->amount.precision()
<< " != " << amt.precision() << ")");
diff --git a/src/xact.h b/src/xact.h
index 74d9f837..98631f65 100644
--- a/src/xact.h
+++ b/src/xact.h
@@ -80,6 +80,20 @@ public:
virtual bool finalize();
virtual bool valid() const = 0;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<item_t>(*this);
+ ar & journal;
+ ar & posts;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -111,6 +125,20 @@ public:
virtual expr_t::ptr_op_t lookup(const string& name);
virtual bool valid() const;
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<xact_base_t>(*this);
+ ar & code;
+ ar & payee;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -154,6 +182,19 @@ public:
virtual bool valid() const {
return true;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<xact_base_t>(*this);
+ ar & predicate;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -180,6 +221,18 @@ struct auto_xact_finalizer_t : public xact_finalizer_t
}
virtual bool operator()(xact_t& xact, bool post);
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & journal;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**
@@ -205,7 +258,7 @@ class period_xact_t : public xact_base_t
TRACE_CTOR(period_xact_t, "const string&");
}
- virtual ~period_xact_t() throw() {
+ virtual ~period_xact_t() {
TRACE_DTOR(period_xact_t);
}
@@ -218,6 +271,20 @@ class period_xact_t : public xact_base_t
#endif
return true;
}
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<xact_base_t>(*this);
+ ar & period;
+ ar & period_string;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
};
/**