diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cc | 2 | ||||
-rw-r--r-- | src/account.h | 20 | ||||
-rw-r--r-- | src/amount.cc | 101 | ||||
-rw-r--r-- | src/amount.h | 10 | ||||
-rw-r--r-- | src/annotate.h | 46 | ||||
-rw-r--r-- | src/archive.cc | 247 | ||||
-rw-r--r-- | src/archive.h | 105 | ||||
-rw-r--r-- | src/balance.cc | 6 | ||||
-rw-r--r-- | src/balance.h | 14 | ||||
-rw-r--r-- | src/chain.cc | 14 | ||||
-rw-r--r-- | src/commodity.h | 83 | ||||
-rw-r--r-- | src/derive.cc | 4 | ||||
-rw-r--r-- | src/emacs.cc | 6 | ||||
-rw-r--r-- | src/error.cc | 8 | ||||
-rw-r--r-- | src/expr.h | 18 | ||||
-rw-r--r-- | src/flags.h | 22 | ||||
-rw-r--r-- | src/global.cc | 14 | ||||
-rw-r--r-- | src/interactive.cc | 6 | ||||
-rw-r--r-- | src/item.cc | 32 | ||||
-rw-r--r-- | src/item.h | 97 | ||||
-rw-r--r-- | src/journal.cc | 26 | ||||
-rw-r--r-- | src/journal.h | 83 | ||||
-rw-r--r-- | src/mask.h | 19 | ||||
-rw-r--r-- | src/op.cc | 6 | ||||
-rw-r--r-- | src/op.h | 28 | ||||
-rw-r--r-- | src/output.cc | 4 | ||||
-rw-r--r-- | src/pool.h | 18 | ||||
-rw-r--r-- | src/post.h | 17 | ||||
-rw-r--r-- | src/predicate.h | 13 | ||||
-rw-r--r-- | src/py_value.cc | 6 | ||||
-rw-r--r-- | src/report.cc | 4 | ||||
-rw-r--r-- | src/scope.h | 66 | ||||
-rw-r--r-- | src/session.cc | 132 | ||||
-rw-r--r-- | src/session.h | 11 | ||||
-rw-r--r-- | src/stats.cc | 2 | ||||
-rw-r--r-- | src/system.hh.in | 69 | ||||
-rw-r--r-- | src/textual.cc | 54 | ||||
-rw-r--r-- | src/times.cc | 122 | ||||
-rw-r--r-- | src/times.h | 88 | ||||
-rw-r--r-- | src/utils.h | 12 | ||||
-rw-r--r-- | src/value.cc | 22 | ||||
-rw-r--r-- | src/value.h | 92 | ||||
-rw-r--r-- | src/xact.cc | 4 | ||||
-rw-r--r-- | src/xact.h | 69 |
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"); @@ -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, "> "); @@ -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 @@ -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) { @@ -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; @@ -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); } @@ -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 @@ -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() << ")"); @@ -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 }; /** |