diff options
-rw-r--r-- | Makefile.am | 16 | ||||
-rw-r--r-- | amount.cc | 12 | ||||
-rw-r--r-- | amount.h | 9 | ||||
-rw-r--r-- | balance.cc | 5 | ||||
-rw-r--r-- | balance.h | 4 | ||||
-rw-r--r-- | binary.cc | 1057 | ||||
-rw-r--r-- | binary.h | 7 | ||||
-rw-r--r-- | commodity.cc | 10 | ||||
-rw-r--r-- | commodity.h | 38 | ||||
-rw-r--r-- | config.cc | 77 | ||||
-rw-r--r-- | config.h | 74 | ||||
-rw-r--r-- | configure.in | 60 | ||||
-rw-r--r-- | csv.cc | 4 | ||||
-rw-r--r-- | derive.cc | 26 | ||||
-rw-r--r-- | emacs.cc | 5 | ||||
-rw-r--r-- | error.h | 41 | ||||
-rw-r--r-- | format.cc | 165 | ||||
-rw-r--r-- | format.h | 42 | ||||
-rw-r--r-- | gnucash.cc | 69 | ||||
-rw-r--r-- | gnucash.h | 10 | ||||
-rw-r--r-- | journal.cc | 140 | ||||
-rw-r--r-- | journal.h | 115 | ||||
-rw-r--r-- | ledger.h | 3 | ||||
-rw-r--r-- | main.cc | 91 | ||||
-rw-r--r-- | ofx.cc | 28 | ||||
-rw-r--r-- | ofx.h | 10 | ||||
-rw-r--r-- | option.cc | 152 | ||||
-rw-r--r-- | option.h | 20 | ||||
-rw-r--r-- | parser.cc | 78 | ||||
-rw-r--r-- | parser.h | 49 | ||||
-rw-r--r-- | qif.cc | 31 | ||||
-rw-r--r-- | qif.h | 10 | ||||
-rw-r--r-- | quotes.cc | 30 | ||||
-rw-r--r-- | quotes.h | 6 | ||||
-rw-r--r-- | reconcile.cc | 19 | ||||
-rw-r--r-- | report.cc | 52 | ||||
-rw-r--r-- | report.h | 42 | ||||
-rw-r--r-- | startup.cc | 7 | ||||
-rw-r--r-- | system.hh | 10 | ||||
-rw-r--r-- | textual.cc | 253 | ||||
-rw-r--r-- | textual.h | 21 | ||||
-rw-r--r-- | times.cc | 353 | ||||
-rw-r--r-- | times.h | 72 | ||||
-rw-r--r-- | utils.cc | 2 | ||||
-rw-r--r-- | valexpr.cc | 221 | ||||
-rw-r--r-- | valexpr.h | 78 | ||||
-rw-r--r-- | value.cc | 79 | ||||
-rw-r--r-- | value.h | 33 | ||||
-rw-r--r-- | walk.cc | 90 | ||||
-rw-r--r-- | walk.h | 43 | ||||
-rw-r--r-- | xml.cc | 91 | ||||
-rw-r--r-- | xml.h | 10 |
52 files changed, 2745 insertions, 1225 deletions
diff --git a/Makefile.am b/Makefile.am index 7ced6a31..fe7cb3fe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,14 +15,16 @@ lib_LTLIBRARIES = libamounts.la libledger.la libamounts_la_CPPFLAGS = libamounts_la_SOURCES = \ amount.cc \ + commodity.cc \ balance.cc \ - value.cc + value.cc \ + times.cc \ + utils.cc if HAVE_BOOST_PYTHON libamounts_la_CPPFLAGS += -DUSE_BOOST_PYTHON=1 endif if DEBUG libamounts_la_CPPFLAGS += -DDEBUG_MODE -libamounts_la_SOURCES += utils.cc endif libledger_la_CPPFLAGS = @@ -38,7 +40,6 @@ libledger_la_SOURCES = \ option.cc \ parser.cc \ qif.cc \ - quotes.cc \ reconcile.cc \ report.cc \ startup.cc \ @@ -46,6 +47,7 @@ libledger_la_SOURCES = \ valexpr.cc \ walk.cc \ xml.cc +# quotes.cc this is currently not being included if HAVE_EXPAT libledger_la_CPPFLAGS += -DHAVE_EXPAT=1 libledger_la_SOURCES += gnucash.cc @@ -67,11 +69,12 @@ pkginclude_HEADERS = \ acconf.h \ \ amount.h \ + commodity.h \ balance.h \ - datetime.h \ + balpair.h \ value.h \ - debug.h \ - util.h \ + times.h \ + utils.h \ \ binary.h \ config.h \ @@ -91,7 +94,6 @@ pkginclude_HEADERS = \ reconcile.h \ report.h \ textual.h \ - timing.h \ valexpr.h \ walk.h \ xml.h @@ -98,6 +98,11 @@ struct amount_t::bigint_t : public supports_flags<> } }; +uint_fast32_t amount_t::sizeof_bigint_t() +{ + return sizeof(bigint_t); +} + void amount_t::initialize() { mpz_init(temp); @@ -661,7 +666,7 @@ amount_t& amount_t::in_place_unreduce() return *this; } -optional<amount_t> amount_t::value(const optional<moment_t>& moment) const +optional<amount_t> amount_t::value(const optional<datetime_t>& moment) const { if (quantity) { optional<amount_t> amt(commodity().value(moment)); @@ -1213,13 +1218,18 @@ void amount_t::print(std::ostream& _out, bool omit_commodity, } +#if 0 +// jww (2008-05-08): Should these be global? namespace { +#endif char * bigints; char * bigints_next; uint_fast32_t bigints_index; uint_fast32_t bigints_count; char buf[4096]; +#if 0 } +#endif void amount_t::read(std::istream& in) { @@ -139,6 +139,8 @@ public: */ static bool stream_fullstrings; + static uint_fast32_t sizeof_bigint_t(); + protected: void _copy(const amount_t& amt); void _dup(); @@ -148,6 +150,7 @@ protected: struct bigint_t; +public: // needed by binary.cc bigint_t * quantity; commodity_t * commodity_; @@ -312,7 +315,7 @@ public: * compact form greater than 1.0. That is, 3599s will unreduce to * 59.98m, while 3601 unreduces to 1h. * - * value(optional<moment_t>) returns the historical value for an + * value(optional<datetime_t>) returns the historical value for an * amount -- the default moment returns the most recently known * price -- based on the price history of its commodity. For * example, if the amount were 10 AAPL, and on Apr 10, 2000 each @@ -365,7 +368,7 @@ public: } amount_t& in_place_unreduce(); - optional<amount_t> value(const optional<moment_t>& moment = none) const; + optional<amount_t> value(const optional<datetime_t>& moment = none) const; /** * Truth tests. An amount may be truth test in several ways: @@ -504,7 +507,7 @@ public: * purchased for, when it was acquired, or an arbitrary note, * identifying perhaps the lot number of an item. * - * annotate_commodity(amount_t price, [moment_t date, string tag]) + * annotate_commodity(amount_t price, [datetime_t date, string tag]) * sets the annotations for the current amount's commodity. Only * the price argument is required, although it can be passed as * `none' if no price is desired. @@ -166,7 +166,7 @@ balance_t& balance_t::operator/=(const amount_t& amt) } optional<balance_t> -balance_t::value(const optional<moment_t>& moment) const +balance_t::value(const optional<datetime_t>& moment) const { optional<balance_t> temp; @@ -242,8 +242,7 @@ void balance_t::print(std::ostream& out, if (i->second) sorted.push_back(&i->second); - std::stable_sort(sorted.begin(), sorted.end(), - compare_amount_commodities()); + std::stable_sort(sorted.begin(), sorted.end(), compare_amount_commodities()); for (amounts_array::const_iterator i = sorted.begin(); i != sorted.end(); @@ -275,7 +275,7 @@ public: * amount. That is, a balance of 10m and 1799s will unreduce to * 39.98m. * - * value(optional<moment_t>) returns the total historical value for + * value(optional<datetime_t>) returns the total historical value for * a balance -- the default moment returns a value based on the most * recently known price -- based on the price history of its * component commodities. See amount_t::value for an example. @@ -346,7 +346,7 @@ public: return *this = temp; } - optional<balance_t> value(const optional<moment_t>& moment = none) const; + optional<balance_t> value(const optional<datetime_t>& moment = none) const; /** * Truth tests. An balance may be truth test in two ways: @@ -29,9 +29,63 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "utils.h" +#include "binary.h" +#include "journal.h" namespace ledger { + +static unsigned long binary_magic_number = 0xFFEED765; +#ifdef DEBUG_ENABLED +static unsigned long format_version = 0x0002060b; +#else +static unsigned long format_version = 0x0002060a; +#endif + +static account_t ** accounts; +static account_t ** accounts_next; +static unsigned int account_index; + +static commodity_t::base_t ** base_commodities; +static commodity_t::base_t ** base_commodities_next; +static unsigned int base_commodity_index; + +static commodity_t ** commodities; +static commodity_t ** commodities_next; +static unsigned int commodity_index; + +extern char * bigints; +extern char * bigints_next; +extern unsigned int bigints_index; +extern unsigned int bigints_count; + +bool binary_parser_t::test(std::istream& in) const +{ + if (binary::read_number_nocheck<unsigned long>(in) == binary_magic_number && + binary::read_number_nocheck<unsigned long>(in) == format_version) + return true; + + in.clear(); + in.seekg(0, std::ios::beg); + return false; +} + +namespace binary { + unsigned int read_journal(std::istream& in, + const path& file, + journal_t * journal, + account_t * master); +} + +unsigned int binary_parser_t::parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) +{ + return binary::read_journal(in, original_file ? *original_file : "", + journal, master); +} + namespace binary { void read_bool(std::istream& in, bool& num) @@ -153,5 +207,1006 @@ void write_string(std::ostream& out, const string& str) write_guard(out, 0x3002); } +inline void read_amount(const char *& data, amount_t& amt) +{ + commodity_t::ident_t ident; + read_long(data, ident); + if (ident == 0xffffffff) + amt.commodity_ = NULL; + else if (ident == 0) + amt.commodity_ = amount_t::current_pool->null_commodity; + else + amt.commodity_ = commodities[ident - 1]; + + amt.read(data); +} + +inline void read_value(const char *& data, value_t& val) +{ + switch (static_cast<value_t::type_t>(read_long<int>(data))) { + case value_t::BOOLEAN: + val.set_boolean(read_bool(data)); + break; + case value_t::INTEGER: + val.set_long(read_number<unsigned long>(data)); + break; + case value_t::DATETIME: + // jww (2008-04-22): I need to record and read a datetime_t directly + //val.set_datetime(read_long<unsigned long>(data)); + break; + case value_t::AMOUNT: { + amount_t temp; + read_amount(data, temp); + val.set_amount(temp); + break; + } + + //case value_t::BALANCE: + //case value_t::BALANCE_PAIR: + default: + assert(false); + break; + } +} + +inline void read_mask(const char *& data, mask_t *& mask) +{ + bool exclude; + read_number(data, exclude); + string pattern; + read_string(data, pattern); + + mask = new mask_t(pattern); + mask->exclude = exclude; +} + +inline void read_value_expr(const char *& data, value_expr_t *& expr) +{ + if (! read_bool(data)) { + expr = NULL; + return; + } + + value_expr_t::kind_t kind; + read_number(data, kind); + + expr = new value_expr_t(kind); + + if (kind > value_expr_t::TERMINALS) { + read_value_expr(data, expr->left); + if (expr->left) expr->left->acquire(); + } + + switch (expr->kind) { + case value_expr_t::O_ARG: + case value_expr_t::INDEX: + read_long(data, expr->arg_index); + break; + case value_expr_t::CONSTANT: + expr->value = new value_t; + read_value(data, *expr->value); + break; + + case value_expr_t::F_CODE_MASK: + case value_expr_t::F_PAYEE_MASK: + case value_expr_t::F_NOTE_MASK: + case value_expr_t::F_ACCOUNT_MASK: + case value_expr_t::F_SHORT_ACCOUNT_MASK: + case value_expr_t::F_COMMODITY_MASK: + if (read_bool(data)) + read_mask(data, expr->mask); + break; + + default: + if (kind > value_expr_t::TERMINALS) { + read_value_expr(data, expr->right); + if (expr->right) expr->right->acquire(); + } + break; + } +} + + +inline void read_transaction(const char *& data, transaction_t * xact) +{ + read_number(data, xact->_date); + read_number(data, xact->_date_eff); + xact->account = accounts[read_long<account_t::ident_t>(data) - 1]; + + unsigned char flag = read_number<unsigned char>(data); + if (flag == 0) { + read_amount(data, xact->amount); + } + else if (flag == 1) { + read_amount(data, xact->amount); + read_string(data, xact->amount_expr.expr); + } + else { + value_expr_t * ptr = NULL; + read_value_expr(data, ptr); + assert(ptr); + xact->amount_expr.reset(ptr); + read_string(data, xact->amount_expr.expr); + } + + if (read_bool(data)) { + xact->cost = new amount_t; + read_amount(data, *xact->cost); + read_string(data, xact->cost_expr); + } else { + xact->cost = NULL; + } + + read_number(data, xact->state); + read_number(data, xact->flags); + xact->flags |= TRANSACTION_BULK_ALLOC; + read_string(data, &xact->note); + + xact->beg_pos = read_long<unsigned long>(data); + read_long(data, xact->beg_line); + xact->end_pos = read_long<unsigned long>(data); + read_long(data, xact->end_line); + + xact->data = NULL; + + if (xact->amount_expr) + compute_amount(xact->amount_expr, xact->amount, xact); +} + +inline void read_entry_base(const char *& data, entry_base_t * entry, + transaction_t *& xact_pool, bool& finalize) +{ + read_long(data, entry->src_idx); + entry->beg_pos = read_long<unsigned long>(data); + read_long(data, entry->beg_line); + entry->end_pos = read_long<unsigned long>(data); + read_long(data, entry->end_line); + + bool ignore_calculated = read_bool(data); + + for (unsigned long i = 0, count = read_long<unsigned long>(data); + i < count; + i++) { + new(xact_pool) transaction_t; + read_transaction(data, xact_pool); + if (ignore_calculated && xact_pool->flags & TRANSACTION_CALCULATED) + finalize = true; + entry->add_transaction(xact_pool++); + } +} + +inline void read_entry(const char *& data, entry_t * entry, + transaction_t *& xact_pool, bool& finalize) +{ + read_entry_base(data, entry, xact_pool, finalize); + read_number(data, entry->_date); + read_number(data, entry->_date_eff); + read_string(data, &entry->code); + read_string(data, &entry->payee); +} + +inline void read_auto_entry(const char *& data, auto_entry_t * entry, + transaction_t *& xact_pool) +{ + bool ignore; + read_entry_base(data, entry, xact_pool, ignore); + value_expr_t * expr; + read_value_expr(data, expr); + // the item_predicate constructor will acquire the reference + entry->predicate = new item_predicate<transaction_t>(expr); +} + +inline void read_period_entry(const char *& data, period_entry_t * entry, + transaction_t *& xact_pool, bool& finalize) +{ + read_entry_base(data, entry, xact_pool, finalize); + read_string(data, &entry->period_string); + std::istringstream stream(entry->period_string); + entry->period.parse(stream); +} + +inline commodity_t::base_t * read_commodity_base(const char *& data) +{ + string str; + + read_string(data, str); + + commodity_t::base_t * commodity = new commodity_t::base_t(str); + *base_commodities_next++ = commodity; + + read_string(data, str); + if (! str.empty()) + commodity->name = str; + + read_string(data, str); + if (! str.empty()) + commodity->note = str; + + read_number(data, commodity->precision); + unsigned long flags; + read_number(data, flags); + commodity->set_flags(flags); + + return commodity; +} + +inline void read_commodity_base_extra(const char *& data, + commodity_t::ident_t ident) +{ + commodity_t::base_t * commodity = base_commodities[ident]; + + bool read_history = false; + for (unsigned long i = 0, count = read_long<unsigned long>(data); + i < count; + i++) { + datetime_t when; + read_number(data, when); + amount_t amt; + read_amount(data, amt); + + // Upon insertion, amt will be copied, which will cause the amount + // to be duplicated (and thus not lost when the journal's + // item_pool is deleted). + if (! commodity->history) + commodity->history = commodity_t::history_t(); + commodity->history->prices.insert(commodity_t::base_t::history_pair(when, amt)); + + read_history = true; + } + if (read_history) + read_number(data, commodity->history->last_lookup); + + if (read_bool(data)) { + amount_t amt; + read_amount(data, amt); + commodity->smaller = amount_t(amt); + } + + if (read_bool(data)) { + amount_t amt; + read_amount(data, amt); + commodity->larger = amount_t(amt); + } +} + +inline commodity_t * read_commodity(const char *& data) +{ + commodity_t::base_t * base = + base_commodities[read_long<commodity_t::ident_t>(data) - 1]; + + commodity_t * commodity = + new commodity_t(amount_t::current_pool, + shared_ptr<commodity_t::base_t>(base)); + + *commodities_next++ = commodity; + + string str; + read_string(data, str); + if (! str.empty()) + commodity->qualified_symbol = str; + commodity->annotated = false; + + return commodity; +} + +inline commodity_t * read_commodity_annotated(const char *& data) +{ + commodity_t * commodity = + commodities[read_long<commodity_t::ident_t>(data) - 1]; + + annotation_t details; + + string str; + read_string(data, str); + + // This read-and-then-assign causes a new amount to be allocated which does + // not live within the bulk allocation pool, since that pool will be deleted + // *before* the commodities are destroyed. + amount_t amt; + read_amount(data, amt); + details.price = amt; + +#if 0 + // jww (2008-04-22): These are optional members! + read_number(data, details.date); + read_string(data, details.tag); +#endif + + annotated_commodity_t * ann_comm = + new annotated_commodity_t(commodity, details); + *commodities_next++ = ann_comm; + + if (! str.empty()) + ann_comm->qualified_symbol = str; + + return ann_comm; +} + +inline +account_t * read_account(const char *& data, journal_t * journal, + account_t * master = NULL) +{ + account_t * acct = new account_t(NULL); + *accounts_next++ = acct; + + acct->journal = journal; + + account_t::ident_t id; + read_long(data, id); // parent id + if (id == 0xffffffff) + acct->parent = NULL; + else + acct->parent = accounts[id - 1]; + + read_string(data, acct->name); + read_string(data, acct->note); + read_number(data, acct->depth); + + // If all of the subaccounts will be added to a different master + // account, throw away what we've learned about the recorded + // journal's own master account. + + if (master && acct != master) { + delete acct; + acct = master; + } + + for (account_t::ident_t i = 0, + count = read_long<account_t::ident_t>(data); + i < count; + i++) { + account_t * child = read_account(data, journal); + child->parent = acct; + assert(acct != child); + acct->add_account(child); + } + + return acct; +} + +unsigned int read_journal(std::istream& in, + const path& file, + journal_t * journal, + account_t * master) +{ + account_index = + base_commodity_index = + commodity_index = 0; + + // Read in the files that participated in this journal, so that they + // can be checked for changes on reading. + + if (! file.empty()) { + for (unsigned short i = 0, + count = read_number<unsigned short>(in); + i < count; + i++) { + path pathname = read_string(in); + std::time_t old_mtime; + read_number(in, old_mtime); + struct stat info; + // jww (2008-04-22): can this be done differently now? + stat(pathname.string().c_str(), &info); + if (std::difftime(info.st_mtime, old_mtime) > 0) + return 0; + + journal->sources.push_back(pathname); + } + + // Make sure that the cache uses the same price database, + // otherwise it means that LEDGER_PRICE_DB has been changed, and + // we should ignore this cache file. + if (read_string(in) != journal->price_db) + return 0; + } + + // Read all of the data in at once, so that we're just dealing with + // a big data buffer. + + unsigned long data_size = read_number<unsigned long>(in); + + char * data_pool = new char[data_size]; + in.read(data_pool, data_size); + + // Read in the accounts + + const char * data = data_pool; + + account_t::ident_t a_count = read_long<account_t::ident_t>(data); + accounts = accounts_next = new account_t *[a_count]; + + assert(journal->master); + delete journal->master; + journal->master = read_account(data, journal, master); + + if (read_bool(data)) + journal->basket = accounts[read_long<account_t::ident_t>(data) - 1]; + + // Allocate the memory needed for the entries and transactions in + // one large block, which is then chopped up and custom constructed + // as necessary. + + unsigned long count = read_long<unsigned long>(data); + unsigned long auto_count = read_long<unsigned long>(data); + unsigned long period_count = read_long<unsigned long>(data); + unsigned long xact_count = read_number<unsigned long>(data); + unsigned long bigint_count = read_number<unsigned long>(data); + + std::size_t pool_size = (sizeof(entry_t) * count + + sizeof(transaction_t) * xact_count + + amount_t::sizeof_bigint_t() * bigint_count); + + char * item_pool = new char[pool_size]; + + journal->item_pool = item_pool; + journal->item_pool_end = item_pool + pool_size; + + entry_t * entry_pool = (entry_t *) item_pool; + transaction_t * xact_pool = (transaction_t *) (item_pool + + sizeof(entry_t) * count); + bigints_index = 0; + bigints = bigints_next = (item_pool + sizeof(entry_t) * count + + sizeof(transaction_t) * xact_count); + + // Read in the base commodities and then derived commodities + + commodity_t::ident_t bc_count = read_long<commodity_t::ident_t>(data); + base_commodities = base_commodities_next = new commodity_t::base_t *[bc_count]; + + for (commodity_t::ident_t i = 0; i < bc_count; i++) { + commodity_t::base_t * base = read_commodity_base(data); + +#if 0 + // jww (2008-04-22): How does the pool get created here? + amount_t::current_pool->commodities.push_back(commodity); + + // jww (2008-04-22): What about this logic here? + if (! result.second) { + base_commodities_map::iterator c = + commodity_t::base_t::commodities.find(commodity->symbol); + + // It's possible the user might have used a commodity in a value + // expression passed to an option, we'll just override the + // flags, but keep the commodity pointer intact. + if (c == commodity_t::base_t::commodities.end()) + throw new error(string("Failed to read base commodity from cache: ") + + commodity->symbol); + + (*c).second->name = commodity->name; + (*c).second->note = commodity->note; + (*c).second->precision = commodity->precision; + (*c).second->flags = commodity->flags; + if ((*c).second->smaller) + delete (*c).second->smaller; + (*c).second->smaller = commodity->smaller; + if ((*c).second->larger) + delete (*c).second->larger; + (*c).second->larger = commodity->larger; + + *(base_commodities_next - 1) = (*c).second; + delete commodity; + } +#endif + } + + commodity_t::ident_t c_count = read_long<commodity_t::ident_t>(data); + commodities = commodities_next = new commodity_t *[c_count]; + + for (commodity_t::ident_t i = 0; i < c_count; i++) { + commodity_t * commodity; + string mapping_key; + + if (! read_bool(data)) { + commodity = read_commodity(data); + mapping_key = commodity->base->symbol; + } else { + read_string(data, mapping_key); + commodity = read_commodity_annotated(data); + } + + // jww (2008-04-22): What do I do with mapping_key here? + amount_t::current_pool->commodities.push_back(commodity); +#if 0 + // jww (2008-04-22): What about the error case? + if (! result.second) { + commodities_map::iterator c = + commodity_t::commodities.find(mapping_key); + if (c == commodity_t::commodities.end()) + throw new error(string("Failed to read commodity from cache: ") + + commodity->symbol()); + + *(commodities_next - 1) = (*c).second; + delete commodity; + } +#endif + } + + for (commodity_t::ident_t i = 0; i < bc_count; i++) + read_commodity_base_extra(data, i); + + commodity_t::ident_t ident; + read_long(data, ident); + if (ident == 0xffffffff || ident == 0) + amount_t::current_pool->default_commodity = NULL; + else + amount_t::current_pool->default_commodity = commodities[ident - 1]; + + // Read in the entries and transactions + + for (unsigned long i = 0; i < count; i++) { + new(entry_pool) entry_t; + bool finalize = false; + read_entry(data, entry_pool, xact_pool, finalize); + entry_pool->journal = journal; + if (finalize && ! entry_pool->finalize()) + continue; + journal->entries.push_back(entry_pool++); + } + + for (unsigned long i = 0; i < auto_count; i++) { + auto_entry_t * auto_entry = new auto_entry_t; + read_auto_entry(data, auto_entry, xact_pool); + auto_entry->journal = journal; + journal->auto_entries.push_back(auto_entry); + } + + for (unsigned long i = 0; i < period_count; i++) { + period_entry_t * period_entry = new period_entry_t; + bool finalize = false; + read_period_entry(data, period_entry, xact_pool, finalize); + period_entry->journal = journal; + if (finalize && ! period_entry->finalize()) + continue; + journal->period_entries.push_back(period_entry); + } + + // Clean up and return the number of entries read + + delete[] accounts; + delete[] commodities; + delete[] data_pool; + + VERIFY(journal->valid()); + + return count; +} + +void write_amount(std::ostream& out, const amount_t& amt) +{ + if (amt.commodity_) + write_long(out, amt.commodity_->ident); + else + write_long<commodity_t::ident_t>(out, 0xffffffff); + + amt.write(out); +} + +void write_value(std::ostream& out, const value_t& val) +{ + write_long(out, (int)val.type()); + + switch (val.type()) { + case value_t::BOOLEAN: + write_bool(out, const_cast<value_t&>(val).as_boolean_lval()); + break; + case value_t::INTEGER: + write_long(out, const_cast<value_t&>(val).as_long_lval()); + break; + case value_t::DATETIME: + write_number(out, const_cast<value_t&>(val).as_datetime_lval()); + break; + case value_t::AMOUNT: + write_amount(out, const_cast<value_t&>(val).as_amount_lval()); + break; + + //case value_t::BALANCE: + //case value_t::BALANCE_PAIR: + default: + throw new error("Cannot write a balance to the binary cache"); + } +} + +void write_mask(std::ostream& out, mask_t * mask) +{ + write_number(out, mask->exclude); + write_string(out, mask->expr.str()); +} + +void write_value_expr(std::ostream& out, const value_expr_t * expr) +{ + if (! expr) { + write_bool(out, false); + return; + } + write_bool(out, true); + write_number(out, expr->kind); + + if (expr->kind > value_expr_t::TERMINALS) + write_value_expr(out, expr->left); + + switch (expr->kind) { + case value_expr_t::O_ARG: + case value_expr_t::INDEX: + write_long(out, expr->arg_index); + break; + case value_expr_t::CONSTANT: + write_value(out, *expr->value); + break; + + case value_expr_t::F_CODE_MASK: + case value_expr_t::F_PAYEE_MASK: + case value_expr_t::F_NOTE_MASK: + case value_expr_t::F_ACCOUNT_MASK: + case value_expr_t::F_SHORT_ACCOUNT_MASK: + case value_expr_t::F_COMMODITY_MASK: + if (expr->mask) { + write_bool(out, true); + write_mask(out, expr->mask); + } else { + write_bool(out, false); + } + break; + + default: + if (expr->kind > value_expr_t::TERMINALS) + write_value_expr(out, expr->right); + break; + } + +} + +void write_transaction(std::ostream& out, transaction_t * xact, + bool ignore_calculated) +{ + write_number(out, xact->_date); + write_number(out, xact->_date_eff); + write_long(out, xact->account->ident); + + if (ignore_calculated && xact->flags & TRANSACTION_CALCULATED) { + write_number<unsigned char>(out, 0); + write_amount(out, amount_t()); + } + else if (xact->amount_expr) { + write_number<unsigned char>(out, 2); + write_value_expr(out, xact->amount_expr.get()); + write_string(out, xact->amount_expr.expr); + } + else if (! xact->amount_expr.expr.empty()) { + write_number<unsigned char>(out, 1); + write_amount(out, xact->amount); + write_string(out, xact->amount_expr.expr); + } + else { + write_number<unsigned char>(out, 0); + write_amount(out, xact->amount); + } + + if (xact->cost && + (! (ignore_calculated && xact->flags & TRANSACTION_CALCULATED))) { + write_bool(out, true); + write_amount(out, *xact->cost); + write_string(out, xact->cost_expr); + } else { + write_bool(out, false); + } + + write_number(out, xact->state); + write_number(out, xact->flags); + write_string(out, xact->note); + + write_long(out, xact->beg_pos); + write_long(out, xact->beg_line); + write_long(out, xact->end_pos); + write_long(out, xact->end_line); +} + +void write_entry_base(std::ostream& out, entry_base_t * entry) +{ + write_long(out, entry->src_idx); + write_long(out, entry->beg_pos); + write_long(out, entry->beg_line); + write_long(out, entry->end_pos); + write_long(out, entry->end_line); + + bool ignore_calculated = false; + for (transactions_list::const_iterator i = entry->transactions.begin(); + i != entry->transactions.end(); + i++) + if ((*i)->amount_expr) { + ignore_calculated = true; + break; + } + + write_bool(out, ignore_calculated); + + write_long(out, entry->transactions.size()); + for (transactions_list::const_iterator i = entry->transactions.begin(); + i != entry->transactions.end(); + i++) + write_transaction(out, *i, ignore_calculated); +} + +void write_entry(std::ostream& out, entry_t * entry) +{ + write_entry_base(out, entry); + write_number(out, entry->_date); + write_number(out, entry->_date_eff); + write_string(out, entry->code); + write_string(out, entry->payee); +} + +void write_auto_entry(std::ostream& out, auto_entry_t * entry) +{ + write_entry_base(out, entry); + write_value_expr(out, entry->predicate->predicate); +} + +void write_period_entry(std::ostream& out, period_entry_t * entry) +{ + write_entry_base(out, entry); + write_string(out, entry->period_string); +} + +void write_commodity_base(std::ostream& out, commodity_t::base_t * commodity) +{ + // jww (2008-04-22): Not using this anymore? + //commodity->ident = ++base_commodity_index; + + write_string(out, commodity->symbol); + // jww (2008-04-22): What to do with optional members? + write_string(out, *commodity->name); + write_string(out, *commodity->note); + write_number(out, commodity->precision); + write_number(out, commodity->flags()); +} + +void write_commodity_base_extra(std::ostream& out, + commodity_t::base_t * commodity) +{ +#if 0 + // jww (2008-04-22): What did bogus_time used to do? + if (commodity->history && commodity->history->bogus_time) + commodity->remove_price(commodity->history->bogus_time); +#endif + + if (! commodity->history) { + write_long<unsigned long>(out, 0); + } else { + write_long<unsigned long>(out, commodity->history->prices.size()); + for (commodity_t::history_map::const_iterator + i = commodity->history->prices.begin(); + i != commodity->history->prices.end(); + i++) { + write_number(out, (*i).first); + write_amount(out, (*i).second); + } + write_number(out, commodity->history->last_lookup); + } + + if (commodity->smaller) { + write_bool(out, true); + write_amount(out, *commodity->smaller); + } else { + write_bool(out, false); + } + + if (commodity->larger) { + write_bool(out, true); + write_amount(out, *commodity->larger); + } else { + write_bool(out, false); + } +} + +void write_commodity(std::ostream& out, commodity_t * commodity) +{ + commodity->ident = ++commodity_index; + + // jww (2008-04-22): Is this used anymore? + //write_long(out, commodity->base->ident); + // jww (2008-04-22): Optional! + write_string(out, *commodity->qualified_symbol); +} + +void write_commodity_annotated(std::ostream& out, + commodity_t * commodity) +{ + commodity->ident = ++commodity_index; + + // jww (2008-04-22): No longer needed? + //write_long(out, commodity->base->ident); + // jww (2008-04-22): Optional! + write_string(out, *commodity->qualified_symbol); + + annotated_commodity_t * ann_comm = + static_cast<annotated_commodity_t *>(commodity); + + // jww (2008-04-22): No longer needed? + //write_long(out, ann_comm->base->ident); + // jww (2008-04-22): Make a write_annotation_details function; and optional! + write_amount(out, *ann_comm->details.price); + write_number(out, *ann_comm->details.date); + write_string(out, *ann_comm->details.tag); +} + +static inline account_t::ident_t count_accounts(account_t * account) +{ + account_t::ident_t count = 1; + + for (accounts_map::iterator i = account->accounts.begin(); + i != account->accounts.end(); + i++) + count += count_accounts((*i).second); + + return count; +} + +void write_account(std::ostream& out, account_t * account) +{ + account->ident = ++account_index; + + if (account->parent) + write_long(out, account->parent->ident); + else + write_long<account_t::ident_t>(out, 0xffffffff); + + write_string(out, account->name); + write_string(out, account->note); + write_number(out, account->depth); + + write_long<account_t::ident_t>(out, account->accounts.size()); + for (accounts_map::iterator i = account->accounts.begin(); + i != account->accounts.end(); + i++) + write_account(out, (*i).second); +} + +void write_journal(std::ostream& out, journal_t * journal) +{ + account_index = + base_commodity_index = + commodity_index = 0; + + write_number_nocheck(out, binary_magic_number); + write_number_nocheck(out, format_version); + + // Write out the files that participated in this journal, so that + // they can be checked for changes on reading. + + if (journal->sources.empty()) { + write_number<unsigned short>(out, 0); + } else { + write_number<unsigned short>(out, journal->sources.size()); + for (paths_list::const_iterator i = journal->sources.begin(); + i != journal->sources.end(); + i++) { + write_string(out, (*i).string()); + struct stat info; + stat((*i).string().c_str(), &info); + write_number(out, std::time_t(info.st_mtime)); + } + + // Write out the price database that relates to this data file, so + // that if it ever changes the cache can be invalidated. + write_string(out, journal->price_db.string()); + } + + ostream_pos_type data_val = out.tellp(); + write_number<unsigned long>(out, 0); + + // Write out the accounts + + write_long<account_t::ident_t>(out, count_accounts(journal->master)); + write_account(out, journal->master); + + if (journal->basket) { + write_bool(out, true); + write_long(out, journal->basket->ident); + } else { + write_bool(out, false); + } + + // Write out the number of entries, transactions, and amounts + + write_long<unsigned long>(out, journal->entries.size()); + write_long<unsigned long>(out, journal->auto_entries.size()); + write_long<unsigned long>(out, journal->period_entries.size()); + + ostream_pos_type xacts_val = out.tellp(); + write_number<unsigned long>(out, 0); + + ostream_pos_type bigints_val = out.tellp(); + write_number<unsigned long>(out, 0); + + bigints_count = 0; + + // Write out the commodities + // jww (2008-04-22): This whole section needs to be reworked + +#if 0 + write_long<commodity_t::ident_t>(out, amount_t::current_pool->commodities.size()); + + for (base_commodities_map::const_iterator i = + commodity_t::base_t::commodities.begin(); + i != commodity_t::base_t::commodities.end(); + i++) + write_commodity_base(out, (*i).second); + + write_long<commodity_t::ident_t> + (out, commodity_t::commodities.size()); + + for (commodities_map::const_iterator i = commodity_t::commodities.begin(); + i != commodity_t::commodities.end(); + i++) { + if (! (*i).second->annotated) { + write_bool(out, false); + write_commodity(out, (*i).second); + } + } + + for (commodities_map::const_iterator i = commodity_t::commodities.begin(); + i != commodity_t::commodities.end(); + i++) { + if ((*i).second->annotated) { + write_bool(out, true); + write_string(out, (*i).first); // the mapping key + write_commodity_annotated(out, (*i).second); + } + } + + // Write out the history and smaller/larger convertible links after + // both the base and the main commodities have been written, since + // the amounts in both will refer to the mains. + + for (base_commodities_map::const_iterator i = + commodity_t::base_t::commodities.begin(); + i != commodity_t::base_t::commodities.end(); + i++) + write_commodity_base_extra(out, (*i).second); + + if (commodity_t::default_commodity) + write_long(out, commodity_t::default_commodity->ident); + else + write_long<commodity_t::ident_t>(out, 0xffffffff); +#endif + + // Write out the entries and transactions + + unsigned long xact_count = 0; + + for (entries_list::const_iterator i = journal->entries.begin(); + i != journal->entries.end(); + i++) { + write_entry(out, *i); + xact_count += (*i)->transactions.size(); + } + + for (auto_entries_list::const_iterator i = journal->auto_entries.begin(); + i != journal->auto_entries.end(); + i++) { + write_auto_entry(out, *i); + xact_count += (*i)->transactions.size(); + } + + for (period_entries_list::const_iterator i = journal->period_entries.begin(); + i != journal->period_entries.end(); + i++) { + write_period_entry(out, *i); + xact_count += (*i)->transactions.size(); + } + + // Back-patch the count for amounts + + unsigned long data_size = (((unsigned long) out.tellp()) - + ((unsigned long) data_val) - + sizeof(unsigned long)); + out.seekp(data_val); + write_number<unsigned long>(out, data_size); + out.seekp(xacts_val); + write_number<unsigned long>(out, xact_count); + out.seekp(bigints_val); + write_number<unsigned long>(out, bigints_count); +} + } // namespace binary } // namespace ledger @@ -32,7 +32,12 @@ #ifndef BINARY_H #define BINARY_H +#include "parser.h" + namespace ledger { + +class journal_t; + namespace binary { template <typename T> @@ -263,6 +268,8 @@ inline void write_object(std::ostream& out, const T& journal) { assert(false); } +void write_journal(std::ostream& out, journal_t * journal); + } // namespace binary } // namespace ledger diff --git a/commodity.cc b/commodity.cc index 76614f92..3bb3ec72 100644 --- a/commodity.cc +++ b/commodity.cc @@ -44,7 +44,7 @@ namespace ledger { -void commodity_t::add_price(const moment_t& date, +void commodity_t::add_price(const datetime_t& date, const amount_t& price) { if (! base->history) @@ -60,7 +60,7 @@ void commodity_t::add_price(const moment_t& date, } } -bool commodity_t::remove_price(const moment_t& date) +bool commodity_t::remove_price(const datetime_t& date) { if (base->history) { history_map::size_type n = base->history->prices.erase(date); @@ -73,9 +73,9 @@ bool commodity_t::remove_price(const moment_t& date) return false; } -optional<amount_t> commodity_t::value(const optional<moment_t>& moment) +optional<amount_t> commodity_t::value(const optional<datetime_t>& moment) { - optional<moment_t> age; + optional<datetime_t> age; optional<amount_t> price; if (base->history) { @@ -112,7 +112,7 @@ optional<amount_t> commodity_t::value(const optional<moment_t>& moment) if (optional<amount_t> quote = parent().get_quote (*this, age, moment, (base->history && base->history->prices.size() > 0 ? - (*base->history->prices.rbegin()).first : optional<moment_t>()))) + (*base->history->prices.rbegin()).first : optional<datetime_t>()))) return *quote; } return price; diff --git a/commodity.h b/commodity.h index 767023e8..5a8df20b 100644 --- a/commodity.h +++ b/commodity.h @@ -50,10 +50,12 @@ class commodity_t { friend class commodity_pool_t; +public: class base_t : public noncopyable, public supports_flags<> { public: - typedef std::map<const moment_t, amount_t> history_map; + typedef std::map<const datetime_t, amount_t> history_map; + typedef std::pair<const datetime_t, amount_t> history_pair; struct history_t { history_map prices; @@ -178,10 +180,10 @@ public: return base->history; } - void add_price(const moment_t& date, const amount_t& price); - bool remove_price(const moment_t& date); + void add_price(const datetime_t& date, const amount_t& price); + bool remove_price(const datetime_t& date); - optional<amount_t> value(const optional<moment_t>& moment = none); + optional<amount_t> value(const optional<datetime_t>& moment = none); static void parse_symbol(std::istream& in, string& symbol); static void parse_symbol(char *& p, string& symbol); @@ -209,14 +211,14 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) { struct annotation_t : public equality_comparable<annotation_t> { - optional<amount_t> price; - optional<moment_t> date; - optional<string> tag; + optional<amount_t> price; + optional<datetime_t> date; + optional<string> tag; explicit annotation_t - (const optional<amount_t>& _price = none, - const optional<moment_t>& _date = none, - const optional<string>& _tag = none) + (const optional<amount_t>& _price = none, + const optional<datetime_t>& _date = none, + const optional<string>& _tag = none) : price(_price), date(_date), tag(_tag) {} operator bool() const { @@ -232,7 +234,7 @@ struct annotation_t : public equality_comparable<annotation_t> void parse(std::istream& in); void print(std::ostream& out) const { out << "price " << (price ? price->to_string() : "NONE") << " " - << "date " << (date ? *date : moment_t()) << " " + << "date " << (date ? *date : datetime_t()) << " " << "tag " << (tag ? *tag : "NONE"); } @@ -329,9 +331,12 @@ class commodity_pool_t : public noncopyable > > commodities_t; +public: + typedef commodity_pool_t::commodities_t::nth_index<0>::type + commodities_by_ident; + commodities_t commodities; -public: commodity_t * null_commodity; commodity_t * default_commodity; @@ -354,16 +359,13 @@ private: public: boost::function<optional<amount_t> (commodity_t& commodity, - const optional<moment_t>& date, - const optional<moment_t>& moment, - const optional<moment_t>& last)> get_quote; + const optional<datetime_t>& date, + const optional<datetime_t>& moment, + const optional<datetime_t>& last)> get_quote; explicit commodity_pool_t(); ~commodity_pool_t() { - typedef commodity_pool_t::commodities_t::nth_index<0>::type - commodities_by_ident; - commodities_by_ident& ident_index = commodities.get<0>(); for (commodities_by_ident::iterator i = ident_index.begin(); i != ident_index.end(); @@ -1,38 +1,21 @@ #include "config.h" #include "acconf.h" #include "option.h" -#include "datetime.h" -#include "quotes.h" +//#include "quotes.h" #include "valexpr.h" #include "walk.h" -#include <fstream> -#include <cstdlib> -#ifdef WIN32 -#include <io.h> -#else -#include <unistd.h> -#endif - -#ifdef HAVE_REALPATH -extern "C" char *realpath(const char *, char resolved_path[]); -#endif - -#if defined(HAVE_GETPWUID) || defined(HAVE_GETPWNAM) -#include <pwd.h> -#endif - namespace ledger { -std::string expand_path(const std::string& path) +string expand_path(const string& pathname) { - if (path.length() == 0 || path[0] != '~') - return path; + if (pathname.length() == 0 || pathname[0] != '~') + return pathname; const char * pfx = NULL; - std::string::size_type pos = path.find_first_of('/'); + string::size_type pos = pathname.find_first_of('/'); - if (path.length() == 1 || pos == 1) { + if (pathname.length() == 1 || pos == 1) { pfx = std::getenv("HOME"); #ifdef HAVE_GETPWUID if (! pfx) { @@ -45,37 +28,38 @@ std::string expand_path(const std::string& path) } #ifdef HAVE_GETPWNAM else { - std::string user(path, 1, pos == std::string::npos ? - std::string::npos : pos - 1); + string user(pathname, 1, pos == string::npos ? + string::npos : pos - 1); struct passwd * pw = getpwnam(user.c_str()); if (pw) pfx = pw->pw_dir; } #endif - // if we failed to find an expansion, return the path unchanged. + // if we failed to find an expansion, return the pathname unchanged. if (! pfx) - return path; + return pathname; - std::string result(pfx); + string result(pfx); - if (pos == std::string::npos) + if (pos == string::npos) return result; if (result.length() == 0 || result[result.length() - 1] != '/') result += '/'; - result += path.substr(pos + 1); + result += pathname.substr(pos + 1); return result; } -std::string resolve_path(const std::string& path) +// jww (2008-04-22): This needs to be changed to use boost::filesystem +string resolve_path(const string& pathname) { - if (path[0] == '~') - return expand_path(path); - return path; + if (pathname[0] == '~') + return expand_path(pathname); + return pathname; } config_t::config_t() @@ -104,29 +88,4 @@ config_t::config_t() trace_mode = false; } -////////////////////////////////////////////////////////////////////// - -void trace(const std::string& cat, const std::string& str) -{ - char buf[32]; - std::strftime(buf, 31, "%H:%M:%S", datetime_t::now.localtime()); - std::cerr << buf << " " << cat << ": " << str << std::endl; -} - -void trace_push(const std::string& cat, const std::string& str, - timing_t& timer) -{ - timer.start(); - trace(cat, str); -} - -void trace_pop(const std::string& cat, const std::string& str, - timing_t& timer) -{ - timer.stop(); - std::ostringstream out; - out << str << ": " << (double(timer.cumulative) / double(CLOCKS_PER_SEC)) << "s"; - trace(cat, out.str()); -} - } // namespace ledger @@ -2,38 +2,33 @@ #define _CONFIG_H #include "ledger.h" -#include "timing.h" - -#include <iostream> -#include <memory> -#include <list> namespace ledger { class config_t { public: - std::string init_file; - std::string data_file; - std::string cache_file; - std::string price_db; - - std::string balance_format; - std::string register_format; - std::string wide_register_format; - std::string plot_amount_format; - std::string plot_total_format; - std::string print_format; - std::string write_hdr_format; - std::string write_xact_format; - std::string equity_format; - std::string prices_format; - std::string pricesdb_format; - - std::string date_input_format; - - std::string account; - std::string pager; + path init_file; + path data_file; + path cache_file; + path price_db; + + string balance_format; + string register_format; + string wide_register_format; + string plot_amount_format; + string plot_total_format; + string print_format; + string write_hdr_format; + string write_xact_format; + string equity_format; + string prices_format; + string pricesdb_format; + + string date_input_format; + + string account; + string pager; unsigned long pricing_leeway; @@ -47,33 +42,6 @@ class config_t config_t(); }; -////////////////////////////////////////////////////////////////////// - -std::string resolve_path(const std::string& path); - -////////////////////////////////////////////////////////////////////// - -void trace(const std::string& cat, const std::string& str); -void trace_push(const std::string& cat, const std::string& str, - timing_t& timer); -void trace_pop(const std::string& cat, const std::string& str, - timing_t& timer); - -#define TRACE(cat, msg) if (config.trace_mode) trace(#cat, msg) -#define TRACE_(cat, msg) if (trace_mode) trace(#cat, msg) - -#define TRACE_PUSH(cat, msg) \ - timing_t timer_ ## cat(#cat); \ - if (config.trace_mode) trace_push(#cat, msg, timer_ ## cat) -#define TRACE_PUSH_(cat, msg) \ - timing_t timer_ ## cat(#cat); \ - if (trace_mode) trace_push(#cat, msg, timer_ ## cat) - -#define TRACE_POP(cat, msg) \ - if (config.trace_mode) trace_pop(#cat, msg, timer_ ## cat) -#define TRACE_POP_(cat, msg) \ - if (trace_mode) trace_pop(#cat, msg, timer_ ## cat) - } // namespace ledger #endif // _CONFIG_H diff --git a/configure.in b/configure.in index c42a8c0b..98ca5321 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ AC_PREREQ(2.61) -AC_INIT([ledger],[2.7],[johnw@newartisans.com]) +AC_INIT([ledger],[v3.0-merge-back],[johnw@newartisans.com]) AC_CONFIG_SRCDIR(ledger) AM_INIT_AUTOMAKE([dist-bzip2]) @@ -79,8 +79,8 @@ AC_CACHE_CHECK( } else { close(pfd[0]); }]])], - [pipes_avail=true], - [pipes_avail=false]) + [pipes_avail_cv_=true], + [pipes_avail_cv_=false]) AC_LANG_POP]) if [test x$pipes_avail_cv_ = xtrue ]; then @@ -96,11 +96,11 @@ AC_CACHE_CHECK( AC_LANG_PUSH(C++) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <gmp.h>]], [[mpz_t bar; mpz_init(bar); - mpz_clear(bar);]])],[libgmp_avail=true],[libgmp_avail=false]) + mpz_clear(bar);]])],[libgmp_avail_cv_=true],[libgmp_avail_cv_=false]) AC_LANG_POP LIBS=$libgmp_save_libs]) -if [test x$libgmp_avail = xtrue ]; then +if [test x$libgmp_avail_cv_ = xtrue ]; then LIBS="-lgmp $LIBS" else AC_MSG_FAILURE("Could not find gmp library (set CPPFLAGS and LDFLAGS?)") @@ -203,7 +203,7 @@ fi # check for boost_regex AC_CACHE_CHECK( [if boost_regex is available], - [boost_regex_avail], + [boost_regex_avail_cv_], [boost_regex_save_libs=$LIBS LIBS="-lboost_regex$BOOST_SUFFIX $LIBS" AC_LANG_PUSH(C++) @@ -211,12 +211,12 @@ AC_CACHE_CHECK( [AC_LANG_PROGRAM( [[#include <boost/regex.hpp>]], [[boost::regex foo_regexp("Hello, world!");]])], - [boost_regex_avail=true], - [boost_regex_avail=false]) + [boost_regex_avail_cv_=true], + [boost_regex_avail_cv_=false]) AC_LANG_POP LIBS=$boost_regex_save_libs]) -if [test x$boost_regex_avail = xtrue ]; then +if [test x$boost_regex_avail_cv_ = xtrue ]; then LIBS="-lboost_regex$BOOST_SUFFIX $LIBS" else AC_MSG_FAILURE("Could not find boost_regex library (set CPPFLAGS and LDFLAGS?)") @@ -225,7 +225,7 @@ fi # check for boost_date_time AC_CACHE_CHECK( [if boost_date_time is available], - [boost_date_time_cpplib_avail], + [boost_date_time_cpplib_avail_cv_], [boost_date_time_save_libs=$LIBS LIBS="-lboost_date_time$BOOST_SUFFIX $LIBS" AC_LANG_PUSH(C++) @@ -251,12 +251,12 @@ AC_CACHE_CHECK( ptime t12 = time_to_system_local(t10); return t10 != t12;]])], - [boost_date_time_cpplib_avail=true], - [boost_date_time_cpplib_avail=false]) + [boost_date_time_cpplib_avail_cv_=true], + [boost_date_time_cpplib_avail_cv_=false]) AC_LANG_POP LIBS=$boost_date_time_save_libs]) -if [test x$boost_date_time_cpplib_avail = xtrue ]; then +if [test x$boost_date_time_cpplib_avail_cv_ = xtrue ]; then LIBS="-lboost_date_time$BOOST_SUFFIX $LIBS" else AC_MSG_FAILURE("Could not find boost_date_time library (set CPPFLAGS and LDFLAGS?)") @@ -265,7 +265,7 @@ fi # check for boost_filesystem AC_CACHE_CHECK( [if boost_filesystem is available], - [boost_filesystem_cpplib_avail], + [boost_filesystem_cpplib_avail_cv_], [boost_filesystem_save_libs=$LIBS LIBS="-lboost_filesystem$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS" AC_LANG_PUSH(C++) @@ -273,12 +273,12 @@ AC_CACHE_CHECK( [AC_LANG_PROGRAM( [[#include <boost/filesystem/path.hpp>]], [[boost::filesystem::path this_path("Hello");]])], - [boost_filesystem_cpplib_avail=true], - [boost_filesystem_cpplib_avail=false]) + [boost_filesystem_cpplib_avail_cv_=true], + [boost_filesystem_cpplib_avail_cv_=false]) AC_LANG_POP LIBS=$boost_filesystem_save_libs]) -if [test x$boost_filesystem_cpplib_avail = xtrue ]; then +if [test x$boost_filesystem_cpplib_avail_cv_ = xtrue ]; then LIBS="-lboost_filesystem$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS" else AC_MSG_FAILURE("Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)") @@ -287,7 +287,7 @@ fi ## check for boost_signals #AC_CACHE_CHECK( # [if boost_signals is available], -# [boost_signals_cpplib_avail], +# [boost_signals_cpplib_avail_cv_], # [boost_signals_save_libs=$LIBS # LIBS="-lboost_signals$BOOST_SUFFIX $LIBS" # AC_LANG_PUSH(C++) @@ -295,12 +295,12 @@ fi # [AC_LANG_PROGRAM( # [[#include <boost/signal.hpp>]], # [[boost::signal<void (void)> this_signal;]])], -# [boost_signals_cpplib_avail=true], -# [boost_signals_cpplib_avail=false]) +# [boost_signals_cpplib_avail_cv_=true], +# [boost_signals_cpplib_avail_cv_=false]) # AC_LANG_POP # LIBS=$boost_signals_save_libs]) # -#if [test x$boost_signals_cpplib_avail = xtrue ]; then +#if [test x$boost_signals_cpplib_avail_cv_ = xtrue ]; then # LIBS="-lboost_signals$BOOST_SUFFIX $LIBS" #else # AC_MSG_FAILURE("Could not find boost_signals library (set CPPFLAGS and LDFLAGS?)") @@ -328,8 +328,8 @@ if [test x$ofx = xtrue ]; then [AC_LANG_PROGRAM( [[#include <libofx.h>]], [[LibofxContextPtr libofx_context = libofx_get_new_context();]])], - [libofx_avail=true], - [libofx_avail=false]) + [libofx_avail_cv_=true], + [libofx_avail_cv_=false]) AC_LANG_POP LIBS=$libofx_save_libs]) @@ -372,12 +372,12 @@ if [test x$python = xtrue ]; then class_< foo > ("foo") ; }]], [[return 0]])], - [boost_python_cpplib_avail=true], - [boost_python_cpplib_avail=false]) + [boost_python_cpplib_avail_cv_=true], + [boost_python_cpplib_avail_cv_=false]) AC_LANG_POP LIBS=$boost_python_save_libs]) - if [test x$boost_python_cpplib_avail = xtrue ]; then + if [test x$boost_python_cpplib_avail_cv_ = xtrue ]; then AM_CONDITIONAL(HAVE_BOOST_PYTHON, true) LIBS="-lboost_python$BOOST_SUFFIX -lpython$PYTHON_VERSION $LIBS" else @@ -393,7 +393,7 @@ fi # check for CppUnit AC_CACHE_CHECK( [if cppunit is available], - [cppunit_avail], + [cppunit_avail_cv_], [cppunit_save_libs=$LIBS LIBS="-lcppunit $LIBS" AC_LANG_PUSH(C++) @@ -409,12 +409,12 @@ AC_CACHE_CHECK( #include <cppunit/extensions/TestFactoryRegistry.h>]], [[CPPUNIT_NS::TestResult controller; CPPUNIT_NS::TestResultCollector result;]])], - [cppunit_avail=true], - [cppunit_avail=false]) + [cppunit_avail_cv_=true], + [cppunit_avail_cv_=false]) AC_LANG_POP LIBS=$cppunit_save_libs]) -if [test x$cppunit_avail = xtrue ]; then +if [test x$cppunit_avail_cv_ = xtrue ]; then AM_CONDITIONAL(HAVE_CPPUNIT, true) else AM_CONDITIONAL(HAVE_CPPUNIT, false) @@ -3,10 +3,10 @@ namespace ledger { namespace { - inline void write_escaped_string(std::ostream& out, const std::string& xact) + inline void write_escaped_string(std::ostream& out, const string& xact) { out << "\""; - for (std::string::const_iterator i = xact.begin(); i != xact.end(); i++) + for (string::const_iterator i = xact.begin(); i != xact.end(); i++) if (*i == '"') { out << "\\"; out << "\""; @@ -1,11 +1,8 @@ #include "derive.h" -#include "datetime.h" -#include "error.h" +#include "utils.h" #include "mask.h" #include "walk.h" -#include <memory> - namespace ledger { entry_t * derive_new_entry(journal_t& journal, @@ -16,7 +13,9 @@ entry_t * derive_new_entry(journal_t& journal, entry_t * matching = NULL; - added->_date = *i++; + // jww (2008-04-20): Need to parse the string here + //added->_date = *i++; + added->_date = boost::posix_time::time_from_string(*i++); if (i == end) throw new error("Too few arguments to 'entry'"); @@ -31,7 +30,7 @@ entry_t * derive_new_entry(journal_t& journal, break; } - added->payee = matching ? matching->payee : regexp.pattern; + added->payee = matching ? matching->payee : regexp.expr.str(); if (! matching) { account_t * acct; @@ -67,8 +66,8 @@ entry_t * derive_new_entry(journal_t& journal, sum_accounts(*journal.master); value_t total = account_xdata(*acct).total; - if (total.type == value_t::AMOUNT) - xact->amount.set_commodity(((amount_t *) total.data)->commodity()); + if (total.is_type(value_t::AMOUNT)) + xact->amount.set_commodity(total.as_amount_lval().commodity()); } } @@ -114,9 +113,9 @@ entry_t * derive_new_entry(journal_t& journal, } else { while (i != end) { - std::string& re_pat(*i++); - account_t * acct = NULL; - amount_t * amt = NULL; + string& re_pat(*i++); + account_t * acct = NULL; + amount_t * amt = NULL; mask_t acct_regex(re_pat); @@ -152,8 +151,8 @@ entry_t * derive_new_entry(journal_t& journal, if (! xact->amount.commodity()) { if (amt) xact->amount.set_commodity(amt->commodity()); - else if (commodity_t::default_commodity) - xact->amount.set_commodity(*commodity_t::default_commodity); + else if (amount_t::current_pool->default_commodity) + xact->amount.set_commodity(*amount_t::current_pool->default_commodity); } } added->add_transaction(xact); @@ -164,7 +163,6 @@ entry_t * derive_new_entry(journal_t& journal, added->add_transaction(new transaction_t(draw_acct)); } - done: if (! run_hooks(journal.entry_finalize_hooks, *added, false) || ! added->finalize() || ! run_hooks(journal.entry_finalize_hooks, *added, true)) @@ -5,7 +5,7 @@ namespace ledger { void format_emacs_transactions::write_entry(entry_t& entry) { int idx = entry.src_idx; - for (strings_list::iterator i = entry.journal->sources.begin(); + for (paths_list::const_iterator i = entry.journal->sources.begin(); i != entry.journal->sources.end(); i++) if (! idx--) { @@ -15,7 +15,8 @@ void format_emacs_transactions::write_entry(entry_t& entry) out << (((unsigned long)entry.beg_pos) + 1) << " "; - std::time_t date = entry.date(); + tm when = boost::posix_time::to_tm(entry.date()); + std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local? out << "(" << (date / 65536) << " " << (date % 65536) << " 0) "; if (entry.code.empty()) @@ -2,6 +2,7 @@ #define _ERROR_H #include <exception> +#include <stdexcept> #include <string> #include <cstring> #include <sstream> @@ -12,9 +13,9 @@ namespace ledger { class error_context { public: - std::string desc; + string desc; - error_context(const std::string& _desc) throw() : desc(_desc) {} + error_context(const string& _desc) throw() : desc(_desc) {} virtual ~error_context() throw() {} virtual void describe(std::ostream& out) const throw() { if (! desc.empty()) @@ -25,11 +26,11 @@ class error_context class file_context : public error_context { protected: - std::string file; + path file; unsigned long line; public: - file_context(const std::string& _file, unsigned long _line, - const std::string& desc = "") throw() + file_context(const path& _file, unsigned long _line, + const string& desc = "") throw() : error_context(desc), file(_file), line(_line) {} virtual ~file_context() throw() {} @@ -41,13 +42,14 @@ class file_context : public error_context } }; -class line_context : public error_context { - public: - std::string line; +class line_context : public error_context +{ +public: + string line; long pos; - line_context(const std::string& _line, long _pos, - const std::string& desc = "") throw() + line_context(const string& _line, long _pos, + const string& desc = "") throw() : error_context(desc), line(_line), pos(_pos) {} virtual ~line_context() throw() {} @@ -65,11 +67,12 @@ class line_context : public error_context { ////////////////////////////////////////////////////////////////////// -class str_exception : public std::logic_error { - public: +class str_exception : public std::logic_error +{ +public: std::list<error_context *> context; - str_exception(const std::string& why, + str_exception(const string& why, error_context * ctxt = NULL) throw() : std::logic_error(why) { if (ctxt) @@ -84,7 +87,7 @@ class str_exception : public std::logic_error { } virtual void reveal_context(std::ostream& out, - const std::string& kind) const throw() { + const string& kind) const throw() { for (std::list<error_context *>::const_reverse_iterator i = context.rbegin(); i != context.rend(); @@ -100,28 +103,28 @@ class str_exception : public std::logic_error { #define DECLARE_EXCEPTION(kind, name) \ class name : public kind { \ public: \ - name(const std::string& why, error_context * ctxt = NULL) throw() \ + name(const string& why, error_context * ctxt = NULL) throw() \ : kind(why, ctxt) {} \ } class error : public str_exception { public: - error(const std::string& why, error_context * ctxt = NULL) throw() + error(const string& why, error_context * ctxt = NULL) throw() : str_exception(why, ctxt) {} virtual ~error() throw() {} }; class fatal : public str_exception { public: - fatal(const std::string& why, error_context * ctxt = NULL) throw() + fatal(const string& why, error_context * ctxt = NULL) throw() : str_exception(why, ctxt) {} virtual ~fatal() throw() {} }; class fatal_assert : public fatal { public: - fatal_assert(const std::string& why, error_context * ctxt = NULL) throw() - : fatal(std::string("assertion failed '") + why + "'", ctxt) {} + fatal_assert(const string& why, error_context * ctxt = NULL) throw() + : fatal(string("assertion failed '") + why + "'", ctxt) {} virtual ~fatal_assert() throw() {} }; @@ -12,10 +12,10 @@ int format_t::abbrev_length = 2; bool format_t::ansi_codes = false; bool format_t::ansi_invert = false; -std::string format_t::truncate(const std::string& str, unsigned int width, +string format_t::truncate(const string& str, unsigned int width, const bool is_account) { - const int len = str.length(); + const unsigned int len = str.length(); if (len <= width) return str; @@ -43,28 +43,28 @@ std::string format_t::truncate(const std::string& str, unsigned int width, case ABBREVIATE: if (is_account) { - std::list<std::string> parts; - std::string::size_type beg = 0; - for (std::string::size_type pos = str.find(':'); - pos != std::string::npos; + std::list<string> parts; + string::size_type beg = 0; + for (string::size_type pos = str.find(':'); + pos != string::npos; beg = pos + 1, pos = str.find(':', beg)) - parts.push_back(std::string(str, beg, pos - beg)); - parts.push_back(std::string(str, beg)); + parts.push_back(string(str, beg, pos - beg)); + parts.push_back(string(str, beg)); - std::string result; - int newlen = len; - for (std::list<std::string>::iterator i = parts.begin(); + string result; + unsigned int newlen = len; + for (std::list<string>::iterator i = parts.begin(); i != parts.end(); i++) { // Don't contract the last element - std::list<std::string>::iterator x = i; + std::list<string>::iterator x = i; if (++x == parts.end()) { result += *i; break; } if (newlen > width) { - result += std::string(*i, 0, abbrev_length); + result += string(*i, 0, abbrev_length); result += ":"; newlen -= (*i).length() - abbrev_length; } else { @@ -98,9 +98,9 @@ std::string format_t::truncate(const std::string& str, unsigned int width, return buf; } -std::string partial_account_name(const account_t& account) +string partial_account_name(const account_t& account) { - std::string name; + string name; for (const account_t * acct = &account; acct && acct->parent; @@ -118,7 +118,7 @@ std::string partial_account_name(const account_t& account) return name; } -element_t * format_t::parse_elements(const std::string& fmt) +element_t * format_t::parse_elements(const string& fmt) { std::auto_ptr<element_t> result; @@ -143,7 +143,7 @@ element_t * format_t::parse_elements(const std::string& fmt) if (q != buf) { current->type = element_t::STRING; - current->chars = std::string(buf, q); + current->chars = string(buf, q); q = buf; current->next = new element_t; @@ -219,7 +219,7 @@ element_t * format_t::parse_elements(const std::string& fmt) current->type = element_t::VALUE_EXPR; assert(! current->val_expr); - current->val_expr = std::string(b, p); + current->val_expr = string(b, p); break; } @@ -238,7 +238,7 @@ element_t * format_t::parse_elements(const std::string& fmt) throw new format_error("Missing ']'"); current->type = element_t::DATE_STRING; - current->chars = std::string(b, p); + current->chars = string(b, p); break; } @@ -255,11 +255,11 @@ element_t * format_t::parse_elements(const std::string& fmt) case 'd': current->type = element_t::COMPLETE_DATE_STRING; - current->chars = datetime_t::output_format; + current->chars = output_time_format; break; case 'D': current->type = element_t::DATE_STRING; - current->chars = datetime_t::output_format; + current->chars = output_time_format; break; case 'S': current->type = element_t::SOURCE; break; @@ -294,7 +294,7 @@ element_t * format_t::parse_elements(const std::string& fmt) current = current->next; } current->type = element_t::STRING; - current->chars = std::string(buf, q); + current->chars = string(buf, q); } return result.release(); @@ -324,7 +324,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const { for (const element_t * elem = elements; elem; elem = elem->next) { std::ostringstream out; - std::string name; + string name; bool ignore_max_width = false; if (elem->flags & ELEMENT_ALIGN_LEFT) @@ -349,7 +349,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const case element_t::TOTAL: calc = total_expr; break; case element_t::VALUE_EXPR: calc = elem->val_expr; break; default: - assert(0); + assert(false); break; } if (! calc) @@ -363,7 +363,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const if (! amount_t::keep_price || ! amount_t::keep_date || ! amount_t::keep_tag) { - switch (value.type) { + switch (value.type()) { case value_t::AMOUNT: case value_t::BALANCE: case value_t::BALANCE_PAIR: @@ -376,56 +376,56 @@ void format_t::format(std::ostream& out_str, const details_t& details) const bool highlighted = false; - switch (value.type) { + switch (value.type()) { case value_t::BOOLEAN: - out << (*((bool *) value.data) ? "true" : "false"); + out << (value.as_boolean_lval() ? "true" : "false"); break; case value_t::INTEGER: if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) { if (ansi_invert) { - if (*((long *) value.data) > 0) { + if (value.as_long_lval() > 0) { mark_red(out, elem); highlighted = true; } } else { - if (*((long *) value.data) < 0) { + if (value.as_long_lval() < 0) { mark_red(out, elem); highlighted = true; } } } - out << *((long *) value.data); + out << value.as_long_lval(); break; case value_t::DATETIME: - out << *((datetime_t *) value.data); + out << value.as_datetime_lval(); break; case value_t::AMOUNT: if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) { if (ansi_invert) { - if (*((amount_t *) value.data) > 0) { + if (value.as_amount_lval().sign() > 0) { mark_red(out, elem); highlighted = true; } } else { - if (*((amount_t *) value.data) < 0) { + if (value.as_amount_lval().sign() < 0) { mark_red(out, elem); highlighted = true; } } } - out << *((amount_t *) value.data); + out << value.as_amount_lval(); break; case value_t::BALANCE: - bal = (balance_t *) value.data; + bal = &(value.as_balance_lval()); // fall through... case value_t::BALANCE_PAIR: if (! bal) - bal = &((balance_pair_t *) value.data)->quantity; + bal = &(value.as_balance_pair_lval().quantity()); if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) { if (ansi_invert) { @@ -440,14 +440,14 @@ void format_t::format(std::ostream& out_str, const details_t& details) const } } } - bal->write(out, elem->min_width, + bal->print(out, elem->min_width, (elem->max_width > 0 ? elem->max_width : elem->min_width)); ignore_max_width = true; break; default: - assert(0); + assert(false); break; } @@ -458,7 +458,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const case element_t::OPT_AMOUNT: if (details.xact) { - std::string disp; + string disp; bool use_disp = false; if (details.xact->cost && details.xact->amount) { @@ -511,7 +511,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const case element_t::SOURCE: if (details.entry && details.entry->journal) { int idx = details.entry->src_idx; - for (strings_list::iterator i = details.entry->journal->sources.begin(); + for (paths_list::const_iterator i = details.entry->journal->sources.begin(); i != details.entry->journal->sources.end(); i++) if (! idx--) { @@ -568,9 +568,12 @@ void format_t::format(std::ostream& out_str, const details_t& details) const else if (details.entry) date = details.entry->date(); +#if 0 + // jww (2008-04-20): This needs to be rewritten char buf[256]; std::strftime(buf, 255, elem->chars.c_str(), date.localtime()); out << (elem->max_width == 0 ? buf : truncate(buf, elem->max_width)); +#endif break; } @@ -587,13 +590,23 @@ void format_t::format(std::ostream& out_str, const details_t& details) const } char abuf[256]; +#if 0 + // jww (2008-04-20): This needs to be rewritten std::strftime(abuf, 255, elem->chars.c_str(), actual_date.localtime()); +#else + abuf[0] = '\0'; +#endif - if (effective_date && effective_date != actual_date) { + if (is_valid(effective_date) && effective_date != actual_date) { char buf[512]; char ebuf[256]; +#if 0 + // jww (2008-04-20): This needs to be rewritten std::strftime(ebuf, 255, elem->chars.c_str(), effective_date.localtime()); +#else + ebuf[0] = '\0'; +#endif std::strcpy(buf, abuf); std::strcat(buf, "="); @@ -615,6 +628,8 @@ void format_t::format(std::ostream& out_str, const details_t& details) const case transaction_t::PENDING: out << "! "; break; + case transaction_t::UNCLEARED: + break; } } break; @@ -630,12 +645,14 @@ void format_t::format(std::ostream& out_str, const details_t& details) const case transaction_t::PENDING: out << "! "; break; + case transaction_t::UNCLEARED: + break; } } break; case element_t::CODE: { - std::string temp; + string temp; if (details.entry && ! details.entry->code.empty()) { temp += "("; temp += details.entry->code; @@ -675,6 +692,8 @@ void format_t::format(std::ostream& out_str, const details_t& details) const case transaction_t::PENDING: name = "! "; break; + case transaction_t::UNCLEARED: + break; } } // fall through... @@ -691,9 +710,9 @@ void format_t::format(std::ostream& out_str, const details_t& details) const name = truncate(name, elem->max_width - 2, true); if (details.xact->flags & TRANSACTION_BALANCE) - name = "[" + name + "]"; + name = string("[") + name + "]"; else - name = "(" + name + ")"; + name = string("(") + name + ")"; } else if (elem->max_width > 0) name = truncate(name, elem->max_width, true); @@ -722,11 +741,11 @@ void format_t::format(std::ostream& out_str, const details_t& details) const break; default: - assert(0); + assert(false); break; } - std::string temp = out.str(); + string temp = out.str(); if (! ignore_max_width && elem->max_width > 0 && elem->max_width < temp.length()) temp.erase(elem->max_width); @@ -735,13 +754,13 @@ void format_t::format(std::ostream& out_str, const details_t& details) const } format_transactions::format_transactions(std::ostream& _output_stream, - const std::string& format) + const string& format) : output_stream(_output_stream), last_entry(NULL), last_xact(NULL) { const char * f = format.c_str(); if (const char * p = std::strstr(f, "%/")) { - first_line_format.reset(std::string(f, 0, p - f)); - next_lines_format.reset(std::string(p + 2)); + first_line_format.reset(string(f, 0, p - f)); + next_lines_format.reset(string(p + 2)); } else { first_line_format.reset(format); next_lines_format.reset(format); @@ -798,11 +817,11 @@ void format_entries::operator()(transaction_t& xact) } void print_entry(std::ostream& out, const entry_base_t& entry_base, - const std::string& prefix) + const string& prefix) { - std::string print_format; + string print_format; - if (const entry_t * entry = dynamic_cast<const entry_t *>(&entry_base)) { + if (dynamic_cast<const entry_t *>(&entry_base)) { print_format = (prefix + "%D %X%C%P\n" + prefix + " %-34A %12o\n%/" + prefix + " %-34A %12o\n"); @@ -818,7 +837,7 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base, print_format = prefix + " %-34A %12o\n"; } else { - assert(0); + assert(false); } format_entries formatter(out, print_format); @@ -901,15 +920,15 @@ void format_account::operator()(account_t& account) } } -format_equity::format_equity(std::ostream& _output_stream, - const std::string& _format, - const std::string& display_predicate) +format_equity::format_equity(std::ostream& _output_stream, + const string& _format, + const string& display_predicate) : output_stream(_output_stream), disp_pred(display_predicate) { const char * f = _format.c_str(); if (const char * p = std::strstr(f, "%/")) { - first_line_format.reset(std::string(f, 0, p - f)); - next_lines_format.reset(std::string(p + 2)); + first_line_format.reset(string(f, 0, p - f)); + next_lines_format.reset(string(p + 2)); } else { first_line_format.reset(_format); next_lines_format.reset(_format); @@ -917,7 +936,7 @@ format_equity::format_equity(std::ostream& _output_stream, entry_t header_entry; header_entry.payee = "Opening Balances"; - header_entry._date = datetime_t::now; + header_entry._date = current_moment; first_line_format.format(output_stream, details_t(header_entry)); } @@ -929,16 +948,16 @@ void format_equity::flush() account_t summary(NULL, "Equity:Opening Balances"); summary.data = &xdata; - if (total.type >= value_t::BALANCE) { + if (total.type() >= value_t::BALANCE) { balance_t * bal; - if (total.type == value_t::BALANCE) - bal = (balance_t *) total.data; - else if (total.type == value_t::BALANCE_PAIR) - bal = &((balance_pair_t *) total.data)->quantity; + if (total.is_type(value_t::BALANCE)) + bal = &(total.as_balance_lval()); + else if (total.is_type(value_t::BALANCE_PAIR)) + bal = &(total.as_balance_pair_lval().quantity()); else - assert(0); + assert(false); - for (amounts_map::const_iterator i = bal->amounts.begin(); + for (balance_t::amounts_map::const_iterator i = bal->amounts.begin(); i != bal->amounts.end(); i++) { xdata.value = (*i).second; @@ -957,16 +976,16 @@ void format_equity::operator()(account_t& account) if (account_has_xdata(account)) { value_t val = account_xdata_(account).value; - if (val.type >= value_t::BALANCE) { + if (val.type() >= value_t::BALANCE) { balance_t * bal; - if (val.type == value_t::BALANCE) - bal = (balance_t *) val.data; - else if (val.type == value_t::BALANCE_PAIR) - bal = &((balance_pair_t *) val.data)->quantity; + if (val.is_type(value_t::BALANCE)) + bal = &(val.as_balance_lval()); + else if (val.is_type(value_t::BALANCE_PAIR)) + bal = &(val.as_balance_pair_lval().quantity()); else - assert(0); + assert(false); - for (amounts_map::const_iterator i = bal->amounts.begin(); + for (balance_t::amounts_map::const_iterator i = bal->amounts.begin(); i != bal->amounts.end(); i++) { account_xdata_(account).value = (*i).second; @@ -7,10 +7,10 @@ namespace ledger { -std::string truncated(const std::string& str, unsigned int width, +string truncated(const string& str, unsigned int width, const int style = 2); -std::string partial_account_name(const account_t& account, +string partial_account_name(const account_t& account, const unsigned int start_depth); #define ELEMENT_ALIGN_LEFT 0x01 @@ -50,7 +50,7 @@ struct element_t kind_t type; unsigned char flags; - std::string chars; + string chars; unsigned char min_width; unsigned char max_width; value_expr val_expr; @@ -59,18 +59,18 @@ struct element_t element_t() : type(STRING), flags(false), min_width(0), max_width(0), next(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor element_t"); + DEBUG("ledger.memory.ctors", "ctor element_t"); } ~element_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor element_t"); + DEBUG("ledger.memory.dtors", "dtor element_t"); if (next) delete next; // recursive, but not too deep } }; struct format_t { - std::string format_string; + string format_string; element_t * elements; enum elision_style_t { @@ -87,27 +87,27 @@ struct format_t static bool ansi_invert; format_t() : elements(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor format_t"); + DEBUG("ledger.memory.ctors", "ctor format_t"); } - format_t(const std::string& _format) : elements(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor format_t"); + format_t(const string& _format) : elements(NULL) { + DEBUG("ledger.memory.ctors", "ctor format_t"); reset(_format); } ~format_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor format_t"); + DEBUG("ledger.memory.dtors", "dtor format_t"); if (elements) delete elements; } - void reset(const std::string& _format) { + void reset(const string& _format) { if (elements) delete elements; elements = parse_elements(_format); format_string = _format; } - static element_t * parse_elements(const std::string& fmt); + static element_t * parse_elements(const string& fmt); - static std::string truncate(const std::string& str, unsigned int width, + static string truncate(const string& str, unsigned int width, const bool is_account = false); void format(std::ostream& out, const details_t& details) const; @@ -124,7 +124,7 @@ class format_transactions : public item_handler<transaction_t> public: format_transactions(std::ostream& _output_stream, - const std::string& format); + const string& format); virtual void flush() { output_stream.flush(); @@ -135,7 +135,7 @@ class format_transactions : public item_handler<transaction_t> class format_entries : public format_transactions { public: - format_entries(std::ostream& output_stream, const std::string& format) + format_entries(std::ostream& output_stream, const string& format) : format_transactions(output_stream, format) {} virtual void format_last_entry(); @@ -151,7 +151,7 @@ class format_entries : public format_transactions }; void print_entry(std::ostream& out, const entry_base_t& entry, - const std::string& prefix = ""); + const string& prefix = ""); bool disp_subaccounts_p(const account_t& account, const item_predicate<account_t>& disp_pred, @@ -175,8 +175,8 @@ class format_account : public item_handler<account_t> format_t format; format_account(std::ostream& _output_stream, - const std::string& _format, - const std::string& display_predicate = NULL) + const string& _format, + const string& display_predicate = NULL) : output_stream(_output_stream), disp_pred(display_predicate), format(_format) {} @@ -199,8 +199,8 @@ class format_equity : public item_handler<account_t> public: format_equity(std::ostream& _output_stream, - const std::string& _format, - const std::string& display_predicate); + const string& _format, + const string& display_predicate); virtual void flush(); virtual void operator()(account_t& account); @@ -208,7 +208,7 @@ class format_equity : public item_handler<account_t> class format_error : public error { public: - format_error(const std::string& reason, error_context * ctxt = NULL) throw() + format_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~format_error() throw() {} }; @@ -20,8 +20,8 @@ extern "C" { namespace ledger { -typedef std::map<const std::string, account_t *> accounts_map; -typedef std::pair<const std::string, account_t *> accounts_pair; +typedef std::map<const string, account_t *> accounts_map; +typedef std::pair<const string, account_t *> accounts_pair; typedef std::map<account_t *, commodity_t *> account_comm_map; typedef std::pair<account_t *, commodity_t *> account_comm_pair; @@ -29,7 +29,7 @@ typedef std::pair<account_t *, commodity_t *> account_comm_pair; static journal_t * curr_journal; static account_t * master_account; static account_t * curr_account; -static std::string curr_account_id; +static string curr_account_id; static entry_t * curr_entry; static commodity_t * entry_comm; static commodity_t * curr_comm; @@ -39,12 +39,12 @@ static XML_Parser current_parser; static accounts_map accounts_by_id; static account_comm_map account_comms; static unsigned int count; -static std::string have_error; +static string have_error; static std::istream * instreamp; static unsigned int offset; static XML_Parser parser; -static std::string path; +static path pathname; static unsigned int src_idx; static istream_pos_type beg_pos; static unsigned long beg_line; @@ -200,14 +200,14 @@ static void endElement(void *userData, const char *name) } -static amount_t convert_number(const std::string& number, +static amount_t convert_number(const string& number, int * precision = NULL) { const char * num = number.c_str(); if (char * p = std::strchr(num, '/')) { - std::string numer_str(num, p - num); - std::string denom_str(p + 1); + string numer_str(num, p - num); + string denom_str(p + 1); amount_t amt(numer_str); amount_t den(denom_str); @@ -230,15 +230,15 @@ static void dataHandler(void *userData, const char *s, int len) { switch (action) { case ACCOUNT_NAME: - curr_account->name = std::string(s, len); + curr_account->name = string(s, len); break; case ACCOUNT_ID: - curr_account_id = std::string(s, len); + curr_account_id = string(s, len); break; case ACCOUNT_PARENT: { - accounts_map::iterator i = accounts_by_id.find(std::string(s, len)); + accounts_map::iterator i = accounts_by_id.find(string(s, len)); assert(i != accounts_by_id.end()); curr_account->parent = (*i).second; curr_account->depth = curr_account->parent->depth + 1; @@ -247,10 +247,10 @@ static void dataHandler(void *userData, const char *s, int len) } case COMM_SYM: { - std::string symbol(s, len); + string symbol(s, len); if (symbol == "USD") symbol = "$"; - curr_comm = commodity_t::find_or_create(symbol); + curr_comm = amount_t::current_pool->find_or_create(symbol); assert(curr_comm); if (symbol != "$") @@ -264,7 +264,7 @@ static void dataHandler(void *userData, const char *s, int len) } case COMM_NAME: - curr_comm->set_name(std::string(s, len)); + curr_comm->set_name(string(s, len)); break; case COMM_PREC: @@ -272,15 +272,15 @@ static void dataHandler(void *userData, const char *s, int len) break; case ENTRY_NUM: - curr_entry->code = std::string(s, len); + curr_entry->code = string(s, len); break; case ENTRY_DATE: - curr_entry->_date = std::string(s, len); + curr_entry->_date = parse_datetime(string(s, len)); break; case ENTRY_DESC: - curr_entry->payee = std::string(s, len); + curr_entry->payee = string(s, len); break; case XACT_STATE: @@ -295,7 +295,7 @@ static void dataHandler(void *userData, const char *s, int len) case XACT_VALUE: { int precision; assert(entry_comm); - curr_value = convert_number(std::string(s, len), &precision); + curr_value = convert_number(string(s, len), &precision); curr_value.set_commodity(*entry_comm); if (precision > entry_comm->precision()) @@ -304,26 +304,26 @@ static void dataHandler(void *userData, const char *s, int len) } case XACT_QUANTITY: - curr_quant = convert_number(std::string(s, len)); + curr_quant = convert_number(string(s, len)); break; case XACT_ACCOUNT: { transaction_t * xact = curr_entry->transactions.back(); - accounts_map::iterator i = accounts_by_id.find(std::string(s, len)); + accounts_map::iterator i = accounts_by_id.find(string(s, len)); if (i != accounts_by_id.end()) { xact->account = (*i).second; } else { xact->account = curr_journal->find_account("<Unknown>"); - have_error = (std::string("Could not find account ") + - std::string(s, len)); + have_error = (string("Could not find account ") + + string(s, len)); } break; } case XACT_NOTE: - curr_entry->transactions.back()->note = std::string(s, len); + curr_entry->transactions.back()->note = string(s, len); break; case NO_ACTION: @@ -332,7 +332,7 @@ static void dataHandler(void *userData, const char *s, int len) break; default: - assert(0); + assert(false); break; } } @@ -347,17 +347,20 @@ bool gnucash_parser_t::test(std::istream& in) const return std::strncmp(buf, "<?xml", 5) == 0; } -unsigned int gnucash_parser_t::parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int gnucash_parser_t::parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { char buf[BUFSIZ]; +#if 0 + // jww (2008-05-08): Replace this // This is the date format used by Gnucash, so override whatever the // user specified. date_t::input_format = "%Y-%m-%d %H:%M:%S %z"; +#endif count = 0; action = NO_ACTION; @@ -370,12 +373,12 @@ unsigned int gnucash_parser_t::parse(std::istream& in, curr_state = transaction_t::UNCLEARED; instreamp = ∈ - path = original_file ? *original_file : "<gnucash>"; + pathname = original_file ? *original_file : "<gnucash>"; src_idx = journal->sources.size() - 1; // GnuCash uses the USD commodity without defining it, which really // means $. - commodity_t * usd = commodity_t::find_or_create("$"); + commodity_t * usd = amount_t::current_pool->find_or_create("$"); usd->set_precision(2); usd->add_flags(COMMODITY_STYLE_THOUSANDS); @@ -392,14 +395,14 @@ unsigned int gnucash_parser_t::parse(std::istream& in, in.getline(buf, BUFSIZ - 1); std::strcat(buf, "\n"); if (! XML_Parse(parser, buf, std::strlen(buf), in.eof())) { - unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; + //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; const char * msg = XML_ErrorString(XML_GetErrorCode(parser)); XML_ParserFree(parser); throw new parse_error(msg); } if (! have_error.empty()) { - unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; + //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; parse_error err(have_error); std::cerr << "Error: " << err.what() << std::endl; have_error = ""; @@ -10,11 +10,11 @@ class gnucash_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); }; } // namespace ledger @@ -1,34 +1,32 @@ #include "journal.h" -#include "datetime.h" +#include "utils.h" #include "valexpr.h" #include "mask.h" #include "format.h" #include "acconf.h" -#include <fstream> - namespace ledger { -const std::string version = PACKAGE_VERSION; +const string version = PACKAGE_VERSION; bool transaction_t::use_effective_date = false; transaction_t::~transaction_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_t"); + DEBUG("ledger.memory.dtors", "dtor transaction_t"); if (cost) delete cost; } datetime_t transaction_t::actual_date() const { - if (! _date && entry) + if (! is_valid(_date) && entry) return entry->actual_date(); return _date; } datetime_t transaction_t::effective_date() const { - if (! _date_eff && entry) + if (! is_valid(_date_eff) && entry) return entry->effective_date(); return _date_eff; } @@ -36,12 +34,12 @@ datetime_t transaction_t::effective_date() const bool transaction_t::valid() const { if (! entry) { - DEBUG_PRINT("ledger.validate", "transaction_t: ! entry"); + DEBUG("ledger.validate", "transaction_t: ! entry"); return false; } if (state != UNCLEARED && state != CLEARED && state != PENDING) { - DEBUG_PRINT("ledger.validate", "transaction_t: state is bad"); + DEBUG("ledger.validate", "transaction_t: state is bad"); return false; } @@ -54,27 +52,27 @@ bool transaction_t::valid() const break; } if (! found) { - DEBUG_PRINT("ledger.validate", "transaction_t: ! found"); + DEBUG("ledger.validate", "transaction_t: ! found"); return false; } if (! account) { - DEBUG_PRINT("ledger.validate", "transaction_t: ! account"); + DEBUG("ledger.validate", "transaction_t: ! account"); return false; } if (! amount.valid()) { - DEBUG_PRINT("ledger.validate", "transaction_t: ! amount.valid()"); + DEBUG("ledger.validate", "transaction_t: ! amount.valid()"); return false; } if (cost && ! cost->valid()) { - DEBUG_PRINT("ledger.validate", "transaction_t: cost && ! cost->valid()"); + DEBUG("ledger.validate", "transaction_t: cost && ! cost->valid()"); return false; } if (flags & ~0x003f) { - DEBUG_PRINT("ledger.validate", "transaction_t: flags are bad"); + DEBUG("ledger.validate", "transaction_t: flags are bad"); return false; } @@ -92,6 +90,8 @@ bool entry_base_t::remove_transaction(transaction_t * xact) return true; } +// jww (2008-04-20): Migrate the Common Lisp version here! + bool entry_base_t::finalize() { // Scan through and compute the total balance for the entry. This @@ -120,8 +120,9 @@ bool entry_base_t::finalize() annotated_commodity_t& ann_comm(static_cast<annotated_commodity_t&> ((*x)->amount.commodity())); - if (ann_comm.price) - balance += ann_comm.price * (*x)->amount - *((*x)->cost); + if (ann_comm.details.price) + balance += ((*ann_comm.details.price) * (*x)->amount - + *((*x)->cost)); } } else { saw_null = true; @@ -136,7 +137,7 @@ bool entry_base_t::finalize() // account if one has been set. if (journal && journal->basket && transactions.size() == 1) { - assert(balance.type < value_t::BALANCE); + assert(balance.type() < value_t::BALANCE); transaction_t * nxact = new transaction_t(journal->basket); // The amount doesn't need to be set because the code below will // balance this transaction against the other. @@ -149,20 +150,22 @@ bool entry_base_t::finalize() // determine its price by dividing the unit count into the value of // the balance. This is done for the last eligible commodity. - if (! saw_null && balance && balance.type == value_t::BALANCE && - ((balance_t *) balance.data)->amounts.size() == 2) { + if (! saw_null && balance && balance.is_type(value_t::BALANCE) && + balance.as_balance_lval().amounts.size() == 2) { transactions_list::const_iterator x = transactions.begin(); commodity_t& this_comm = (*x)->amount.commodity(); - amounts_map::const_iterator this_bal = - ((balance_t *) balance.data)->amounts.find(&this_comm); - amounts_map::const_iterator other_bal = - ((balance_t *) balance.data)->amounts.begin(); - if (this_bal == other_bal) - other_bal++; + balance_t& bal(balance.as_balance_lval()); + + balance_t::amounts_map::const_iterator this_amt = + bal.amounts.find(&this_comm); + balance_t::amounts_map::const_iterator other_amt = + bal.amounts.begin(); + if (this_amt == other_amt) + other_amt++; amount_t per_unit_cost = - amount_t((*other_bal).second / (*this_bal).second).unround(); + amount_t((*other_amt).second / (*this_amt).second).unround(); for (; x != transactions.end(); x++) { if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL) || @@ -177,9 +180,9 @@ bool entry_base_t::finalize() if ((*x)->amount.commodity() && ! (*x)->amount.commodity().annotated) (*x)->amount.annotate_commodity - (abs(per_unit_cost), - entry ? entry->actual_date() : datetime_t(), - entry ? entry->code : ""); + (annotation_t(per_unit_cost.abs(), + entry ? optional<datetime_t>(entry->actual_date()) : none, + entry ? optional<string>(entry->code) : none)); (*x)->cost = new amount_t(- (per_unit_cost * (*x)->amount)); balance += *(*x)->cost; @@ -194,7 +197,7 @@ bool entry_base_t::finalize() for (transactions_list::const_iterator x = transactions.begin(); x != transactions.end(); x++) { - if (! (*x)->amount.null() || + if (! (*x)->amount.is_null() || (((*x)->flags & TRANSACTION_VIRTUAL) && ! ((*x)->flags & TRANSACTION_BALANCE))) continue; @@ -209,20 +212,20 @@ bool entry_base_t::finalize() // generated to balance them all. balance_t * bal = NULL; - switch (balance.type) { + switch (balance.type()) { case value_t::BALANCE_PAIR: - bal = &((balance_pair_t *) balance.data)->quantity; + bal = &(balance.as_balance_pair_lval().quantity()); // fall through... case value_t::BALANCE: if (! bal) - bal = (balance_t *) balance.data; + bal = &(balance.as_balance_lval()); if (bal->amounts.size() < 2) { balance.cast(value_t::AMOUNT); } else { bool first = true; - for (amounts_map::const_iterator i = bal->amounts.begin(); + for (balance_t::amounts_map::const_iterator i = bal->amounts.begin(); i != bal->amounts.end(); i++) { amount_t amt = (*i).second; @@ -245,7 +248,7 @@ bool entry_base_t::finalize() // fall through... case value_t::AMOUNT: - (*x)->amount = *((amount_t *) balance.data); + (*x)->amount = balance.as_amount_lval(); (*x)->amount.negate(); (*x)->flags |= TRANSACTION_CALCULATED; @@ -273,7 +276,7 @@ entry_t::entry_t(const entry_t& e) : entry_base_t(e), _date(e._date), _date_eff(e._date_eff), code(e.code), payee(e.payee) { - DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t"); + DEBUG("ledger.memory.ctors", "ctor entry_t"); for (transactions_list::const_iterator i = transactions.begin(); i != transactions.end(); @@ -310,8 +313,8 @@ void entry_t::add_transaction(transaction_t * xact) bool entry_t::valid() const { - if (! _date || ! journal) { - DEBUG_PRINT("ledger.validate", "entry_t: ! _date || ! journal"); + if (! is_valid(_date) || ! journal) { + DEBUG("ledger.validate", "entry_t: ! _date || ! journal"); return false; } @@ -319,23 +322,23 @@ bool entry_t::valid() const i != transactions.end(); i++) if ((*i)->entry != this || ! (*i)->valid()) { - DEBUG_PRINT("ledger.validate", "entry_t: transaction not valid"); + DEBUG("ledger.validate", "entry_t: transaction not valid"); return false; } return true; } -auto_entry_t::auto_entry_t(const std::string& _predicate) +auto_entry_t::auto_entry_t(const string& _predicate) : predicate_string(_predicate) { - DEBUG_PRINT("ledger.memory.ctors", "ctor auto_entry_t"); + DEBUG("ledger.memory.ctors", "ctor auto_entry_t"); predicate = new item_predicate<transaction_t>(predicate_string); } auto_entry_t::~auto_entry_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor auto_entry_t"); + DEBUG("ledger.memory.dtors", "dtor auto_entry_t"); if (predicate) delete predicate; } @@ -364,7 +367,7 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post) } account_t * account = (*t)->account; - std::string fullname = account->fullname(); + string fullname = account->fullname(); assert(! fullname.empty()); if (fullname == "$account" || fullname == "@account") account = (*i)->account; @@ -391,7 +394,7 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post) account_t::~account_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor account_t " << this); + DEBUG("ledger.memory.dtors", "dtor account_t " << this); //assert(! data); for (accounts_map::iterator i = accounts.begin(); @@ -400,8 +403,8 @@ account_t::~account_t() delete (*i).second; } -account_t * account_t::find_account(const std::string& name, - const bool auto_create) +account_t * account_t::find_account(const string& name, + const bool auto_create) { accounts_map::const_iterator i = accounts.find(name); if (i != accounts.end()) @@ -409,11 +412,11 @@ account_t * account_t::find_account(const std::string& name, char buf[256]; - std::string::size_type sep = name.find(':'); - assert(sep < 256|| sep == std::string::npos); + string::size_type sep = name.find(':'); + assert(sep < 256|| sep == string::npos); const char * first, * rest; - if (sep == std::string::npos) { + if (sep == string::npos) { first = name.c_str(); rest = NULL; } else { @@ -462,18 +465,18 @@ account_t * find_account_re_(account_t * account, const mask_t& regexp) return NULL; } -account_t * journal_t::find_account_re(const std::string& regexp) +account_t * journal_t::find_account_re(const string& regexp) { return find_account_re_(master, mask_t(regexp)); } -std::string account_t::fullname() const +string account_t::fullname() const { if (! _fullname.empty()) { return _fullname; } else { - const account_t * first = this; - std::string fullname = name; + const account_t * first = this; + string fullname = name; while (first->parent) { first = first->parent; @@ -496,7 +499,7 @@ std::ostream& operator<<(std::ostream& out, const account_t& account) bool account_t::valid() const { if (depth > 256 || ! journal) { - DEBUG_PRINT("ledger.validate", "account_t: depth > 256 || ! journal"); + DEBUG("ledger.validate", "account_t: depth > 256 || ! journal"); return false; } @@ -504,12 +507,12 @@ bool account_t::valid() const i != accounts.end(); i++) { if (this == (*i).second) { - DEBUG_PRINT("ledger.validate", "account_t: parent refers to itself!"); + DEBUG("ledger.validate", "account_t: parent refers to itself!"); return false; } if (! (*i).second->valid()) { - DEBUG_PRINT("ledger.validate", "account_t: child not valid"); + DEBUG("ledger.validate", "account_t: child not valid"); return false; } } @@ -519,7 +522,7 @@ bool account_t::valid() const journal_t::~journal_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor journal_t"); + DEBUG("ledger.memory.dtors", "dtor journal_t"); assert(master); delete master; @@ -602,7 +605,7 @@ bool journal_t::remove_entry(entry_t * entry) bool journal_t::valid() const { if (! master->valid()) { - DEBUG_PRINT("ledger.validate", "journal_t: master not valid"); + DEBUG("ledger.validate", "journal_t: master not valid"); return false; } @@ -610,15 +613,16 @@ bool journal_t::valid() const i != entries.end(); i++) if (! (*i)->valid()) { - DEBUG_PRINT("ledger.validate", "journal_t: entry not valid"); + DEBUG("ledger.validate", "journal_t: entry not valid"); return false; } - for (commodities_map::const_iterator i = commodity_t::commodities.begin(); - i != commodity_t::commodities.end(); + for (commodity_pool_t::commodities_by_ident::const_iterator + i = amount_t::current_pool->commodities.begin(); + i != amount_t::current_pool->commodities.end(); i++) - if (! (*i).second->valid()) { - DEBUG_PRINT("ledger.validate", "journal_t: commodity not valid"); + if (! (*i)->valid()) { + DEBUG("ledger.validate", "journal_t: commodity not valid"); return false; } @@ -634,12 +638,12 @@ void entry_context::describe(std::ostream& out) const throw() } xact_context::xact_context(const ledger::transaction_t& _xact, - const std::string& desc) throw() - : xact(_xact), file_context("", 0, desc) + const string& desc) throw() + : file_context("", 0, desc), xact(_xact) { - const ledger::strings_list& sources(xact.entry->journal->sources); - int x = 0; - for (ledger::strings_list::const_iterator i = sources.begin(); + const ledger::paths_list& sources(xact.entry->journal->sources); + unsigned int x = 0; + for (ledger::paths_list::const_iterator i = sources.begin(); i != sources.end(); i++, x++) if (x == xact.entry->src_idx) { @@ -1,11 +1,6 @@ #ifndef _JOURNAL_H #define _JOURNAL_H -#include <map> -#include <list> -#include <string> -#include <iostream> - #include "amount.h" #include "value.h" #include "valexpr.h" @@ -36,10 +31,10 @@ class transaction_t amount_t amount; value_expr amount_expr; amount_t * cost; - std::string cost_expr; + string cost_expr; state_t state; unsigned short flags; - std::string note; + string note; istream_pos_type beg_pos; unsigned long beg_line; istream_pos_type end_pos; @@ -52,24 +47,24 @@ class transaction_t : entry(NULL), account(_account), cost(NULL), state(UNCLEARED), flags(TRANSACTION_NORMAL), beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); + DEBUG("ledger.memory.ctors", "ctor transaction_t"); } - transaction_t(account_t * _account, - const amount_t& _amount, - unsigned int _flags = TRANSACTION_NORMAL, - const std::string& _note = "") + transaction_t(account_t * _account, + const amount_t& _amount, + unsigned int _flags = TRANSACTION_NORMAL, + const string& _note = "") : entry(NULL), account(_account), amount(_amount), cost(NULL), state(UNCLEARED), flags(_flags), note(_note), beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); + DEBUG("ledger.memory.ctors", "ctor transaction_t"); } transaction_t(const transaction_t& xact) : entry(xact.entry), account(xact.account), amount(xact.amount), cost(xact.cost ? new amount_t(*xact.cost) : NULL), state(xact.state), flags(xact.flags), note(xact.note), beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); + DEBUG("ledger.memory.ctors", "ctor transaction_t"); } ~transaction_t(); @@ -97,7 +92,7 @@ class xact_context : public file_context { const transaction_t& xact; xact_context(const transaction_t& _xact, - const std::string& desc = "") throw(); + const string& desc = "") throw(); virtual ~xact_context() throw() {} }; @@ -109,7 +104,7 @@ class entry_base_t { public: journal_t * journal; - std::string note; + string note; unsigned long src_idx; istream_pos_type beg_pos; unsigned long beg_line; @@ -120,19 +115,19 @@ class entry_base_t entry_base_t() : journal(NULL), beg_pos(0), beg_line(0), end_pos(0), end_line(0) { - DEBUG_PRINT("ledger.memory.ctors", "ctor entry_base_t"); + DEBUG("ledger.memory.ctors", "ctor entry_base_t"); } entry_base_t(const entry_base_t& e) : journal(NULL), beg_pos(0), beg_line(0), end_pos(0), end_line(0) { - DEBUG_PRINT("ledger.memory.ctors", "ctor entry_base_t"); + DEBUG("ledger.memory.ctors", "ctor entry_base_t"); for (transactions_list::const_iterator i = e.transactions.begin(); i != e.transactions.end(); i++) transactions.push_back(new transaction_t(**i)); } virtual ~entry_base_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor entry_base_t"); + DEBUG("ledger.memory.dtors", "dtor entry_base_t"); for (transactions_list::iterator i = transactions.begin(); i != transactions.end(); i++) @@ -159,25 +154,25 @@ class entry_base_t class entry_t : public entry_base_t { public: - datetime_t _date; - datetime_t _date_eff; - std::string code; - std::string payee; + datetime_t _date; + datetime_t _date_eff; + string code; + string payee; entry_t() { - DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t"); + DEBUG("ledger.memory.ctors", "ctor entry_t"); } entry_t(const entry_t& e); virtual ~entry_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor entry_t"); + DEBUG("ledger.memory.dtors", "dtor entry_t"); } datetime_t actual_date() const { return _date; } datetime_t effective_date() const { - if (! _date_eff) + if (! is_valid(_date_eff)) return _date; return _date_eff; } @@ -205,20 +200,13 @@ class entry_context : public error_context { const entry_base_t& entry; entry_context(const entry_base_t& _entry, - const std::string& desc = "") throw() + const string& desc = "") throw() : error_context(desc), entry(_entry) {} virtual ~entry_context() throw() {} virtual void describe(std::ostream& out) const throw(); }; -class balance_error : public error { - public: - balance_error(const std::string& reason, error_context * ctxt = NULL) throw() - : error(reason, ctxt) {} - virtual ~balance_error() throw() {} -}; - template <typename T> class item_predicate; @@ -227,12 +215,12 @@ class auto_entry_t : public entry_base_t { public: item_predicate<transaction_t> * predicate; - std::string predicate_string; + string predicate_string; auto_entry_t() : predicate(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor auto_entry_t"); + DEBUG("ledger.memory.ctors", "ctor auto_entry_t"); } - auto_entry_t(const std::string& _predicate); + auto_entry_t(const string& _predicate); virtual ~auto_entry_t(); @@ -253,23 +241,23 @@ struct auto_entry_finalizer_t : public entry_finalizer_t { class period_entry_t : public entry_base_t { public: - interval_t period; - std::string period_string; + interval_t period; + string period_string; period_entry_t() { - DEBUG_PRINT("ledger.memory.ctors", "ctor period_entry_t"); + DEBUG("ledger.memory.ctors", "ctor period_entry_t"); } - period_entry_t(const std::string& _period) + period_entry_t(const string& _period) : period(_period), period_string(_period) { - DEBUG_PRINT("ledger.memory.ctors", "ctor period_entry_t"); + DEBUG("ledger.memory.ctors", "ctor period_entry_t"); } period_entry_t(const period_entry_t& e) : entry_base_t(e), period(e.period), period_string(e.period_string) { - DEBUG_PRINT("ledger.memory.ctors", "ctor period_entry_t"); + DEBUG("ledger.memory.ctors", "ctor period_entry_t"); } virtual ~period_entry_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor period_entry_t"); + DEBUG("ledger.memory.dtors", "dtor period_entry_t"); } virtual bool valid() const { @@ -278,8 +266,8 @@ class period_entry_t : public entry_base_t }; -typedef std::map<const std::string, account_t *> accounts_map; -typedef std::pair<const std::string, account_t *> accounts_pair; +typedef std::map<const string, account_t *> accounts_map; +typedef std::pair<const string, account_t *> accounts_pair; class account_t { @@ -288,21 +276,21 @@ class account_t journal_t * journal; account_t * parent; - std::string name; - std::string note; + string name; + string note; unsigned short depth; accounts_map accounts; mutable void * data; mutable ident_t ident; - mutable std::string _fullname; + mutable string _fullname; - account_t(account_t * _parent = NULL, - const std::string& _name = "", - const std::string& _note = "") + account_t(account_t * _parent = NULL, + const string& _name = "", + const string& _note = "") : parent(_parent), name(_name), note(_note), depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { - DEBUG_PRINT("ledger.memory.ctors", "ctor account_t " << this); + DEBUG("ledger.memory.ctors", "ctor account_t " << this); } ~account_t(); @@ -313,7 +301,7 @@ class account_t return ! (*this == account); } - std::string fullname() const; + string fullname() const; void add_account(account_t * acct) { accounts.insert(accounts_pair(acct->name, acct)); @@ -325,9 +313,9 @@ class account_t return n > 0; } - account_t * find_account(const std::string& name, bool auto_create = true); + account_t * find_account(const string& name, bool auto_create = true); - operator std::string() const { + operator string() const { return fullname(); } @@ -376,7 +364,8 @@ bool run_hooks(std::list<T>& list, Data& item, bool post) { typedef std::list<entry_t *> entries_list; typedef std::list<auto_entry_t *> auto_entries_list; typedef std::list<period_entry_t *> period_entries_list; -typedef std::list<std::string> strings_list; +typedef std::list<string> strings_list; +typedef std::list<path> paths_list; class journal_t { @@ -384,8 +373,8 @@ class journal_t account_t * master; account_t * basket; entries_list entries; - strings_list sources; - std::string price_db; + paths_list sources; + path price_db; char * item_pool; char * item_pool_end; @@ -396,7 +385,7 @@ class journal_t std::list<entry_finalizer_t *> entry_finalize_hooks; journal_t() : basket(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor journal_t"); + DEBUG("ledger.memory.ctors", "ctor journal_t"); master = new account_t(NULL, ""); master->journal = this; item_pool = item_pool_end = NULL; @@ -419,7 +408,7 @@ class journal_t acct->journal = NULL; } - account_t * find_account(const std::string& name, bool auto_create = true) { + account_t * find_account(const string& name, bool auto_create = true) { accounts_map::iterator c = accounts_cache.find(name); if (c != accounts_cache.end()) return (*c).second; @@ -429,7 +418,7 @@ class journal_t account->journal = this; return account; } - account_t * find_account_re(const std::string& regexp); + account_t * find_account_re(const string& regexp); bool add_entry(entry_t * entry); bool remove_entry(entry_t * entry); @@ -457,7 +446,7 @@ inline bool auto_entry_finalizer_t::operator()(entry_t& entry, bool post) { return true; } -extern const std::string version; +extern const string version; } // namespace ledger @@ -47,11 +47,10 @@ #include <journal.h> -#include <datetime.h> #include <format.h> #include <emacs.h> #include <csv.h> -#include <quotes.h> +//#include <quotes.h> #include <valexpr.h> #include <walk.h> #include <derive.h> @@ -27,11 +27,11 @@ int parse_and_report(config_t& config, report_t& report, { // Configure the terminus for value expressions - ledger::terminus = datetime_t::now; + ledger::terminus = current_moment; // Parse command-line arguments, and those set in the environment - std::list<std::string> args; + std::list<string> args; process_arguments(ledger::config_options, argc - 1, argv + 1, false, args); if (args.empty()) { @@ -44,9 +44,11 @@ int parse_and_report(config_t& config, report_t& report, config.use_cache = false; else config.use_cache = config.data_file.empty() && config.price_db.empty(); - DEBUG_PRINT("ledger.config.cache", "1. use_cache = " << config.use_cache); + DEBUG("ledger.config.cache", "1. use_cache = " << config.use_cache); +#if 0 TRACE(main, "Processing options and environment variables"); +#endif process_environment(ledger::config_options, const_cast<const char **>(envp), "LEDGER_"); @@ -65,7 +67,7 @@ int parse_and_report(config_t& config, report_t& report, #endif const char * p = std::getenv("HOME"); - std::string home = p ? p : ""; + string home = p ? p : ""; if (config.init_file.empty()) config.init_file = home + "/.ledgerrc"; @@ -77,21 +79,23 @@ int parse_and_report(config_t& config, report_t& report, if (config.data_file == config.cache_file) config.use_cache = false; - DEBUG_PRINT("ledger.config.cache", "2. use_cache = " << config.use_cache); + DEBUG("ledger.config.cache", "2. use_cache = " << config.use_cache); - TRACE(main, std::string("Initialization file is ") + config.init_file); - TRACE(main, std::string("Price database is ") + config.price_db); - TRACE(main, std::string("Binary cache is ") + config.cache_file); - TRACE(main, std::string("Main journal is ") + config.data_file); +#if 0 + TRACE(main, string("Initialization file is ") + config.init_file); + TRACE(main, string("Price database is ") + config.price_db); + TRACE(main, string("Binary cache is ") + config.cache_file); + TRACE(main, string("Main journal is ") + config.data_file); - TRACE(main, std::string("Based on option settings, binary cache ") + + TRACE(main, string("Based on option settings, binary cache ") + (config.use_cache ? "WILL " : "will NOT ") + "be used"); +#endif // Read the command word, canonicalize it to its one letter form, // then configure the system based on the kind of report to be // generated - std::string command = *arg++; + string command = *arg++; if (command == "balance" || command == "bal" || command == "b") command = "b"; @@ -125,7 +129,7 @@ int parse_and_report(config_t& config, report_t& report, ledger::dump_value_expr(std::cout, expr.get()); std::cout << std::endl; std::cout << "Value expression parsed was:" << std::endl; - ledger::write_value_expr(std::cout, expr.get()); + ledger::print_value_expr(std::cout, expr.get()); std::cout << std::endl << std::endl; std::cout << "Result of computation: "; } @@ -139,24 +143,28 @@ int parse_and_report(config_t& config, report_t& report, // this gets done below... } else { - throw new error(std::string("Unrecognized command '") + command + "'"); + throw new error(string("Unrecognized command '") + command + "'"); } // Parse initialization files, ledger data, price database, etc. std::auto_ptr<journal_t> journal(new journal_t); +#if 0 { TRACE_PUSH(parser, "Parsing journal file"); +#endif if (parse_ledger_data(config, journal.get()) == 0) throw new error("Please specify ledger file using -f" " or LEDGER_FILE environment variable."); +#if 0 TRACE_POP(parser, "Finished parsing"); } +#endif // process the command word and its following arguments - std::string first_arg; + string first_arg; if (command == "w") { if (arg != args.end()) first_arg = *arg++; @@ -166,17 +174,22 @@ int parse_and_report(config_t& config, report_t& report, throw new error("The 'dump' command requires use of the --output option"); } - TRACE(options, std::string("Post-processing options ") + +#if 0 + TRACE(options, string("Post-processing options ") + "for command \"" + command + "\""); +#endif report.process_options(command, arg, args.end()); +#if 0 + // jww (2008-05-08): Is this disabled now? // If downloading is to be supported, configure the updater if (! commodity_base_t::updater && config.download_quotes) commodity_base_t::updater = new quotes_by_script(config.price_db, config.pricing_leeway, config.cache_dirty); +#endif std::auto_ptr<entry_t> new_entry; if (command == "e") { @@ -223,7 +236,7 @@ appending the output of this command to your Ledger file if you so choose." std::ostream * out = &std::cout; if (! report.output_file.empty()) { - out = new std::ofstream(report.output_file.c_str()); + out = new ofstream(report.output_file); } #ifdef HAVE_UNIX_PIPES else if (! config.pager.empty()) { @@ -279,7 +292,7 @@ appending the output of this command to your Ledger file if you so choose." ledger::dump_value_expr(std::cout, expr.get()); std::cout << std::endl; std::cout << "Value expression parsed was:" << std::endl; - ledger::write_value_expr(std::cout, expr.get()); + ledger::print_value_expr(std::cout, expr.get()); std::cout << std::endl << std::endl; std::cout << "Result of computation: "; } @@ -292,7 +305,7 @@ appending the output of this command to your Ledger file if you so choose." // Compile the format strings - const std::string * format; + const string * format; if (! report.format_string.empty()) format = &report.format_string; @@ -330,39 +343,53 @@ appending the output of this command to your Ledger file if you so choose." formatter = new format_transactions(*out, *format); if (command == "w") { +#if 0 TRACE_PUSH(text_writer, "Writing journal file"); +#endif write_textual_journal(*journal, first_arg, *formatter, config.write_hdr_format, *out); +#if 0 TRACE_POP(text_writer, "Finished writing"); +#endif } else if (command == "W") { +#if 0 TRACE_PUSH(binary_writer, "Writing binary file"); - std::ofstream stream(report.output_file.c_str()); - write_binary_journal(stream, journal.get()); +#endif + ofstream stream(report.output_file); + binary::write_journal(stream, journal.get()); +#if 0 TRACE_POP(binary_writer, "Finished writing"); +#endif } else { +#if 0 TRACE_PUSH(main, "Walking journal entries"); +#endif formatter = report.chain_xact_handlers(command, formatter, journal.get(), journal->master, formatter_ptrs); if (command == "e") walk_transactions(new_entry->transactions, *formatter); else if (command == "P" || command == "D") - walk_commodities(commodity_t::commodities, *formatter); + walk_commodities(amount_t::current_pool->commodities, *formatter); else walk_entries(journal->entries, *formatter); if (command != "P" && command != "D") formatter->flush(); +#if 0 TRACE_POP(main, "Finished entry walk"); +#endif } // For the balance and equity reports, output the sum totals. if (command == "b") { +#if 0 TRACE_PUSH(main, "Walking journal accounts"); +#endif format_account acct_formatter(*out, *format, report.display_predicate); sum_accounts(*journal->master); @@ -377,21 +404,29 @@ appending the output of this command to your Ledger file if you so choose." acct_formatter.format.format(*out, details_t(*journal->master)); } } +#if 0 TRACE_POP(main, "Finished account walk"); +#endif } else if (command == "E") { +#if 0 TRACE_PUSH(main, "Walking journal accounts"); +#endif format_equity acct_formatter(*out, *format, report.display_predicate); sum_accounts(*journal->master); walk_accounts(*journal->master, acct_formatter, report.sort_string); acct_formatter.flush(); +#if 0 TRACE_POP(main, "Finished account walk"); +#endif } #if DEBUG_LEVEL >= BETA +#if 0 { TRACE_PUSH(cleanup, "Cleaning up allocated memory"); +#endif clear_transaction_xdata xact_cleaner; walk_entries(journal->entries, xact_cleaner); @@ -408,19 +443,25 @@ appending the output of this command to your Ledger file if you so choose." i++) delete *i; +#if 0 TRACE_POP(cleanup, "Finished cleaning"); } #endif +#endif // Write out the binary cache, if need be if (config.use_cache && config.cache_dirty && ! config.cache_file.empty()) { +#if 0 TRACE_PUSH(binary_cache, "Writing journal file"); +#endif - std::ofstream stream(config.cache_file.c_str()); - write_binary_journal(stream, journal.get()); + ofstream stream(config.cache_file); + binary::write_journal(stream, journal.get()); +#if 0 TRACE_POP(binary_cache, "Finished writing"); +#endif } #ifdef HAVE_UNIX_PIPES @@ -448,9 +489,13 @@ int main(int argc, char * argv[], char * envp[]) report_t report; ledger::config = &config; ledger::report = &report; +#if 0 TRACE_PUSH(main, "Ledger starting"); +#endif int status = parse_and_report(config, report, argc, argv, envp); +#if 0 TRACE_POP(main, "Ledger done"); +#endif return status; } catch (error * err) { @@ -10,11 +10,11 @@ namespace ledger { -typedef std::map<const std::string, account_t *> accounts_map; -typedef std::pair<const std::string, account_t *> accounts_pair; +typedef std::map<const string, account_t *> accounts_map; +typedef std::pair<const string, account_t *> accounts_pair; -typedef std::map<const std::string, commodity_t *> commodities_map; -typedef std::pair<const std::string, commodity_t *> commodities_pair; +typedef std::map<const string, commodity_t *> commodities_map; +typedef std::pair<const string, commodity_t *> commodities_pair; journal_t * curr_journal; accounts_map ofx_accounts; @@ -31,7 +31,7 @@ int ofx_proc_account_cb(struct OfxAccountData data, void * account_data) if (! data.account_id_valid) return -1; - DEBUG_PRINT("ledger.ofx.parse", "account " << data.account_name); + DEBUG("ledger.ofx.parse", "account " << data.account_name); account_t * account = new account_t(master_account, data.account_name); curr_journal->add_account(account); ofx_accounts.insert(accounts_pair(data.account_id, account)); @@ -88,7 +88,7 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data, xact->cost = new amount_t(stream.str() + " " + default_commodity->base_symbol()); } - DEBUG_PRINT("ledger.ofx.parse", "xact " << xact->amount + DEBUG("ledger.ofx.parse", "xact " << xact->amount << " from " << *xact->account); if (data.date_initiated_valid) @@ -129,7 +129,7 @@ int ofx_proc_security_cb(struct OfxSecurityData data, void * security_data) if (! data.unique_id_valid) return -1; - std::string symbol; + string symbol; if (data.ticker_valid) symbol = data.ticker; else if (data.currency_valid) @@ -148,13 +148,13 @@ int ofx_proc_security_cb(struct OfxSecurityData data, void * security_data) commodities_map::iterator i = ofx_securities.find(data.unique_id); if (i == ofx_securities.end()) { - DEBUG_PRINT("ledger.ofx.parse", "security " << symbol); + DEBUG("ledger.ofx.parse", "security " << symbol); ofx_securities.insert(commodities_pair(data.unique_id, commodity)); } // jww (2005-02-09): What is the commodity for data.unitprice? if (data.date_unitprice_valid && data.unitprice_valid) { - DEBUG_PRINT("ledger.ofx.parse", " price " << data.unitprice); + DEBUG("ledger.ofx.parse", " price " << data.unitprice); commodity->add_price(data.date_unitprice, amount_t(data.unitprice)); } @@ -194,11 +194,11 @@ bool ofx_parser_t::test(std::istream& in) const return true; } -unsigned int ofx_parser_t::parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int ofx_parser_t::parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { if (! original_file) return 0; @@ -10,11 +10,11 @@ class ofx_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); }; } // namespace ledger @@ -1,14 +1,9 @@ #include "option.h" #include "config.h" #include "report.h" -#include "debug.h" -#include "error.h" +#include "utils.h" -#include <iostream> -#include <cstdarg> -#include <unistd.h> - -#include "util.h" +namespace ledger { namespace { inline void process_option(option_t * opt, const char * arg = NULL) { @@ -19,9 +14,9 @@ namespace { catch (error * err) { err->context.push_back (new error_context - (std::string("While parsing option '--") + opt->long_opt + + (string("While parsing option '--") + opt->long_opt + "'" + (opt->short_opt != '\0' ? - (std::string(" (-") + opt->short_opt + "):") : ":"))); + (string(" (-") + opt->short_opt + "):") : ":"))); throw err; } opt->handled = true; @@ -58,7 +53,7 @@ namespace { } } -bool process_option(option_t * options, const std::string& name, +bool process_option(option_t * options, const string& name, const char * arg) { option_t * opt = search_options(options, name.c_str()); @@ -70,9 +65,8 @@ bool process_option(option_t * options, const std::string& name, } void process_arguments(option_t * options, int argc, char ** argv, - const bool anywhere, std::list<std::string>& args) + const bool anywhere, std::list<string>& args) { - int index = 0; for (char ** i = argv; *i; i++) { if ((*i)[0] != '-') { if (anywhere) { @@ -86,7 +80,6 @@ void process_arguments(option_t * options, int argc, char ** argv, } // --long-option or -s - again: if ((*i)[1] == '-') { if ((*i)[2] == '\0') break; @@ -100,18 +93,18 @@ void process_arguments(option_t * options, int argc, char ** argv, option_t * opt = search_options(options, name); if (! opt) - throw new option_error(std::string("illegal option --") + name); + throw new option_error(string("illegal option --") + name); if (opt->wants_arg && value == NULL) { value = *++i; if (value == NULL) - throw new option_error(std::string("missing option argument for --") + + throw new option_error(string("missing option argument for --") + name); } process_option(opt, value); } else if ((*i)[1] == '\0') { - throw new option_error(std::string("illegal option -")); + throw new option_error(string("illegal option -")); } else { std::list<option_t *> opt_queue; @@ -120,7 +113,7 @@ void process_arguments(option_t * options, int argc, char ** argv, for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) { option_t * opt = search_options(options, c); if (! opt) - throw new option_error(std::string("illegal option -") + c); + throw new option_error(string("illegal option -") + c); opt_queue.push_back(opt); } @@ -130,20 +123,17 @@ void process_arguments(option_t * options, int argc, char ** argv, if ((*o)->wants_arg) { value = *++i; if (value == NULL) - throw new option_error(std::string("missing option argument for -") + + throw new option_error(string("missing option argument for -") + (*o)->short_opt); } process_option(*o, value); } } - - next: - ; } } void process_environment(option_t * options, const char ** envp, - const std::string& tag) + const string& tag) { const char * tag_p = tag.c_str(); unsigned int tag_len = tag.length(); @@ -170,7 +160,7 @@ void process_environment(option_t * options, const char ** envp, err->context.pop_back(); err->context.push_back (new error_context - (std::string("While parsing environment variable option '") + + (string("While parsing environment variable option '") + *p + "':")); throw err; } @@ -180,8 +170,6 @@ void process_environment(option_t * options, const char ** envp, ////////////////////////////////////////////////////////////////////// -namespace ledger { - config_t * config = NULL; report_t * report = NULL; @@ -405,23 +393,23 @@ OPT_BEGIN(version, "v") { } OPT_END(version); OPT_BEGIN(init_file, "i:") { - std::string path = resolve_path(optarg); - if (access(path.c_str(), R_OK) != -1) - config->init_file = path; + path pathname = resolve_path(optarg); + if (boost::filesystem::exists(pathname)) + config->init_file = pathname; else - throw new error(std::string("The init file '") + path + + throw new error(string("The init file '") + string(pathname.string()) + "' does not exist or is not readable"); } OPT_END(init_file); OPT_BEGIN(file, "f:") { - if (std::string(optarg) == "-") { + if (string(optarg) == "-") { config->data_file = optarg; } else { - std::string path = resolve_path(optarg); - if (access(path.c_str(), R_OK) != -1) - config->data_file = path; + path pathname = resolve_path(optarg); + if (boost::filesystem::exists(pathname)) + config->data_file = pathname; else - throw new error(std::string("The ledger file '") + path + + throw new error(string("The ledger file '") + string(pathname.string()) + "' does not exist or is not readable"); } } OPT_END(file); @@ -435,10 +423,8 @@ OPT_BEGIN(no_cache, "") { } OPT_END(no_cache); OPT_BEGIN(output, "o:") { - if (std::string(optarg) != "-") { - std::string path = resolve_path(optarg); - report->output_file = path; - } + if (string(optarg) != "-") + report->output_file = resolve_path(optarg); } OPT_END(output); OPT_BEGIN(account, "a:") { @@ -467,30 +453,30 @@ OPT_BEGIN(effective, "") { } OPT_END(effective); OPT_BEGIN(begin, "b:") { - char buf[128]; interval_t interval(optarg); - if (! interval.begin) - throw new error(std::string("Could not determine beginning of period '") + + if (! is_valid(interval.begin)) + throw new error(string("Could not determine beginning of period '") + optarg + "'"); if (! report->predicate.empty()) report->predicate += "&"; report->predicate += "d>=["; - report->predicate += interval.begin.to_string(); + // jww (2008-04-20): fix + //report->predicate += interval.begin.to_string(); report->predicate += "]"; } OPT_END(begin); OPT_BEGIN(end, "e:") { - char buf[128]; interval_t interval(optarg); - if (! interval.end) - throw new error(std::string("Could not determine end of period '") + + if (! is_valid(interval.end)) + throw new error(string("Could not determine end of period '") + optarg + "'"); if (! report->predicate.empty()) report->predicate += "&"; report->predicate += "d<["; - report->predicate += interval.end.to_string(); + // jww (2008-04-20): fix + //report->predicate += interval.end.to_string(); report->predicate += "]"; terminus = interval.end; @@ -617,7 +603,7 @@ OPT_BEGIN(pager, ":") { } OPT_END(pager); OPT_BEGIN(truncate, ":") { - std::string style(optarg); + string style(optarg); if (style == "leading") format_t::elision_style = format_t::TRUNCATE_LEADING; else if (style == "middle") @@ -673,16 +659,16 @@ OPT_BEGIN(related, "r") { } OPT_END(related); OPT_BEGIN(descend, "") { - std::string arg(optarg); - std::string::size_type beg = 0; + string arg(optarg); + string::size_type beg = 0; report->descend_expr = ""; - for (std::string::size_type pos = arg.find(';'); - pos != std::string::npos; + for (string::size_type pos = arg.find(';'); + pos != string::npos; beg = pos + 1, pos = arg.find(';', beg)) - report->descend_expr += (std::string("t=={") + - std::string(arg, beg, pos - beg) + "};"); - report->descend_expr += (std::string("t=={") + - std::string(arg, beg) + "}"); + report->descend_expr += (string("t=={") + + string(arg, beg, pos - beg) + "};"); + report->descend_expr += (string("t=={") + + string(arg, beg) + "}"); } OPT_END(descend); OPT_BEGIN(descend_if, "") { @@ -703,19 +689,21 @@ OPT_BEGIN(period, "p:") { interval_t interval(report->report_period); - if (interval.begin) { + if (is_valid(interval.begin)) { if (! report->predicate.empty()) report->predicate += "&"; report->predicate += "d>=["; - report->predicate += interval.begin.to_string(); + // jww (2008-04-20): fix + //report->predicate += interval.begin.to_string(); report->predicate += "]"; } - if (interval.end) { + if (is_valid(interval.end)) { if (! report->predicate.empty()) report->predicate += "&"; report->predicate += "d<["; - report->predicate += interval.end.to_string(); + // jww (2008-04-20): fix + //report->predicate += interval.end.to_string(); report->predicate += "]"; terminus = interval.end; @@ -726,35 +714,35 @@ OPT_BEGIN(daily, "") { if (report->report_period.empty()) report->report_period = "daily"; else - report->report_period = std::string("daily ") + report->report_period; + report->report_period = string("daily ") + report->report_period; } OPT_END(daily); OPT_BEGIN(weekly, "W") { if (report->report_period.empty()) report->report_period = "weekly"; else - report->report_period = std::string("weekly ") + report->report_period; + report->report_period = string("weekly ") + report->report_period; } OPT_END(weekly); OPT_BEGIN(monthly, "M") { if (report->report_period.empty()) report->report_period = "monthly"; else - report->report_period = std::string("monthly ") + report->report_period; + report->report_period = string("monthly ") + report->report_period; } OPT_END(monthly); OPT_BEGIN(quarterly, "") { if (report->report_period.empty()) report->report_period = "quarterly"; else - report->report_period = std::string("quarterly ") + report->report_period; + report->report_period = string("quarterly ") + report->report_period; } OPT_END(quarterly); OPT_BEGIN(yearly, "Y") { if (report->report_period.empty()) report->report_period = "yearly"; else - report->report_period = std::string("yearly ") + report->report_period; + report->report_period = string("yearly ") + report->report_period; } OPT_END(yearly); OPT_BEGIN(dow, "") { @@ -901,24 +889,26 @@ namespace { while (equals > optarg && std::isspace(*(equals - 1))) equals--; - std::string symbol(optarg, 0, equals - optarg); + string symbol(optarg, 0, equals - optarg); amount_t price(equals + 1); - if (commodity_t * commodity = commodity_t::find_or_create(symbol)) { - commodity->add_price(datetime_t::now, price); - commodity->history()->bogus_time = datetime_t::now; + if (commodity_t * commodity = + amount_t::current_pool->find_or_create(symbol)) { + commodity->add_price(current_moment, price); + // jww (2008-04-20): what was this? + //commodity->history()->bogus_time = current_moment; } } } OPT_BEGIN(set_price, ":") { - std::string arg(optarg); - std::string::size_type beg = 0; - for (std::string::size_type pos = arg.find(';'); - pos != std::string::npos; + string arg(optarg); + string::size_type beg = 0; + for (string::size_type pos = arg.find(';'); + pos != string::npos; beg = pos + 1, pos = arg.find(';', beg)) - parse_price_setting(std::string(arg, beg, pos - beg).c_str()); - parse_price_setting(std::string(arg, beg).c_str()); + parse_price_setting(string(arg, beg, pos - beg).c_str()); + parse_price_setting(string(arg, beg).c_str()); } OPT_END(set_price); OPT_BEGIN(performance, "g") { @@ -934,15 +924,15 @@ OPT_BEGIN(gain, "G") { ledger::total_expr = "@G"; } OPT_END(gain); -static std::string expand_value_expr(const std::string& tmpl, - const std::string& expr) +static string expand_value_expr(const string& tmpl, + const string& expr) { - std::string xp = tmpl; - for (std::string::size_type i = xp.find('#'); - i != std::string::npos; + string xp = tmpl; + for (string::size_type i = xp.find('#'); + i != string::npos; i = xp.find('#')) - xp = (std::string(xp, 0, i) + "(" + expr + ")" + - std::string(xp, i + 1)); + xp = (string(xp, 0, i) + "(" + expr + ")" + + string(xp, i + 1)); return xp; } @@ -1,11 +1,9 @@ #ifndef _OPTION_H #define _OPTION_H -#include <list> -#include <string> -#include <exception> +#include "utils.h" -#include "error.h" +namespace ledger { typedef void (*handler_t)(const char * arg); @@ -17,20 +15,14 @@ struct option_t { bool handled; }; -class option_error : public error { - public: - option_error(const std::string& reason) throw() : error(reason) {} - virtual ~option_error() throw() {} -}; +DECLARE_EXCEPTION(error, option_error); -bool process_option(option_t * options, const std::string& opt, +bool process_option(option_t * options, const string& opt, const char * arg = NULL); void process_arguments(option_t * options, int argc, char ** argv, - const bool anywhere, std::list<std::string>& args); + const bool anywhere, std::list<string>& args); void process_environment(option_t * options, const char ** envp, - const std::string& tag); - -namespace ledger { + const string& tag); class config_t; class report_t; @@ -2,13 +2,6 @@ #include "journal.h" #include "config.h" -#include <fstream> -#ifdef WIN32 -#include <io.h> -#else -#include <unistd.h> -#endif - namespace ledger { typedef std::list<parser_t *> parsers_list; @@ -56,11 +49,11 @@ bool unregister_parser(parser_t * parser) return true; } -unsigned int parse_journal(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int parse_journal(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { if (! master) master = journal->master; @@ -74,21 +67,22 @@ unsigned int parse_journal(std::istream& in, return 0; } -unsigned int parse_journal_file(const std::string& path, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int parse_journal_file(const path& pathname, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { - journal->sources.push_back(path); + journal->sources.push_back(pathname); - if (access(path.c_str(), R_OK) == -1) - throw new error(std::string("Cannot read file '") + path + "'"); + if (! boost::filesystem::exists(pathname)) + throw new error(string("Cannot read file '") + + string(pathname.string()) + "'"); if (! original_file) - original_file = &path; + original_file = &pathname; - std::ifstream stream(path.c_str()); + boost::filesystem::ifstream stream(pathname); return parse_journal(stream, config, journal, master, original_file); } @@ -107,33 +101,33 @@ unsigned int parse_ledger_data(config_t& config, if (! cache_parser) cache_parser = binary_parser_ptr; if (! xml_parser) - xml_parser = xml_parser_ptr; + xml_parser = xml_parser_ptr; if (! stdin_parser) stdin_parser = textual_parser_ptr; - DEBUG_PRINT("ledger.config.cache", + DEBUG("ledger.config.cache", "3. use_cache = " << config.use_cache); if (! config.init_file.empty() && - access(config.init_file.c_str(), R_OK) != -1) { - if (parse_journal_file(config.init_file, config, journal) || + boost::filesystem::exists(config.init_file)) { + if (parse_journal_file(config.init_file.string(), config, journal) || journal->auto_entries.size() > 0 || journal->period_entries.size() > 0) - throw new error(std::string("Entries found in initialization file '") + - config.init_file + "'"); + throw new error(string("Entries found in initialization file '") + + string(config.init_file.string()) + "'"); journal->sources.pop_front(); // remove init file } if (config.use_cache && ! config.cache_file.empty() && ! config.data_file.empty()) { - DEBUG_PRINT("ledger.config.cache", + DEBUG("ledger.config.cache", "using_cache " << config.cache_file); config.cache_dirty = true; - if (access(config.cache_file.c_str(), R_OK) != -1) { - std::ifstream stream(config.cache_file.c_str()); + if (boost::filesystem::exists(config.cache_file)) { + boost::filesystem::ifstream stream(config.cache_file); if (cache_parser && cache_parser->test(stream)) { - std::string price_db_orig = journal->price_db; + path price_db_orig = journal->price_db; journal->price_db = config.price_db; entry_count += cache_parser->parse(stream, config, journal, NULL, &config.data_file); @@ -152,17 +146,17 @@ unsigned int parse_ledger_data(config_t& config, journal->price_db = config.price_db; if (! journal->price_db.empty() && - access(journal->price_db.c_str(), R_OK) != -1) { + boost::filesystem::exists(journal->price_db)) { if (parse_journal_file(journal->price_db, config, journal)) { throw new error("Entries not allowed in price history file"); } else { - DEBUG_PRINT("ledger.config.cache", + DEBUG("ledger.config.cache", "read price database " << journal->price_db); journal->sources.pop_back(); } } - DEBUG_PRINT("ledger.config.cache", + DEBUG("ledger.config.cache", "rejected cache, parsing " << config.data_file); if (config.data_file == "-") { config.use_cache = false; @@ -170,22 +164,20 @@ unsigned int parse_ledger_data(config_t& config, #if 0 // jww (2006-03-23): Why doesn't XML work on stdin? if (xml_parser && std::cin.peek() == '<') - entry_count += xml_parser->parse(std::cin, config, journal, - acct); + entry_count += xml_parser->parse(std::cin, config, journal, acct); else if (stdin_parser) #endif - entry_count += stdin_parser->parse(std::cin, config, - journal, acct); + entry_count += stdin_parser->parse(std::cin, config, journal, acct); } - else if (access(config.data_file.c_str(), R_OK) != -1) { - entry_count += parse_journal_file(config.data_file, config, - journal, acct); + else if (boost::filesystem::exists(config.data_file)) { + entry_count += parse_journal_file(config.data_file, config, journal, + acct); if (! journal->price_db.empty()) journal->sources.push_back(journal->price_db); } } - VALIDATE(journal->valid()); + VERIFY(journal->valid()); return entry_count; } @@ -1,10 +1,7 @@ #ifndef _PARSER_H #define _PARSER_H -#include <iostream> -#include <string> - -#include "error.h" +#include "utils.h" namespace ledger { @@ -19,27 +16,39 @@ class parser_t virtual bool test(std::istream& in) const = 0; - virtual unsigned int parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL) = 0; + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL) = 0; +}; + +class binary_parser_t : public parser_t +{ +public: + virtual bool test(std::istream& in) const; + + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); }; bool register_parser(parser_t * parser); bool unregister_parser(parser_t * parser); -unsigned int parse_journal(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); +unsigned int parse_journal(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); -unsigned int parse_journal_file(const std::string& path, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); +unsigned int parse_journal_file(const path& path, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); unsigned int parse_ledger_data(config_t& config, journal_t * journal, @@ -52,7 +61,7 @@ void shutdown_parser_support(); class parse_error : public error { public: - parse_error(const std::string& reason, error_context * ctxt = NULL) throw() + parse_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~parse_error() throw() {} }; @@ -1,18 +1,13 @@ #include "journal.h" #include "qif.h" -#include "datetime.h" -#include "error.h" -#include "util.h" - -#include <cstring> -#include <memory> +#include "utils.h" namespace ledger { #define MAX_LINE 1024 static char line[MAX_LINE + 1]; -static std::string path; +static path pathname; static unsigned int src_idx; static unsigned int linenum; @@ -38,11 +33,11 @@ bool qif_parser_t::test(std::istream& in) const std::strcmp(magic, "\r\n!T") == 0); } -unsigned int qif_parser_t::parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int qif_parser_t::parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { std::auto_ptr<entry_t> entry; std::auto_ptr<amount_t> amount; @@ -59,9 +54,9 @@ unsigned int qif_parser_t::parse(std::istream& in, xact = new transaction_t(master); entry->add_transaction(xact); - path = journal->sources.back(); - src_idx = journal->sources.size() - 1; - linenum = 1; + pathname = journal->sources.back(); + src_idx = journal->sources.size() - 1; + linenum = 1; istream_pos_type beg_pos = 0; unsigned long beg_line = 0; @@ -97,14 +92,14 @@ unsigned int qif_parser_t::parse(std::istream& in, std::strcmp(line, "Type:Cat") == 0 || std::strcmp(line, "Type:Class") == 0 || std::strcmp(line, "Type:Memorized") == 0) - throw new parse_error(std::string("QIF files of type ") + line + + throw new parse_error(string("QIF files of type ") + line + " are not supported."); break; case 'D': SET_BEG_POS_AND_LINE(); get_line(in); - entry->_date = line; + entry->_date = parse_datetime(line); break; case 'T': @@ -117,7 +112,7 @@ unsigned int qif_parser_t::parse(std::istream& in, unsigned char prec = xact->amount.commodity().precision(); if (! def_commodity) { - def_commodity = commodity_t::find_or_create("$"); + def_commodity = amount_t::current_pool->find_or_create("$"); assert(def_commodity); } xact->amount.set_commodity(*def_commodity); @@ -10,11 +10,11 @@ class qif_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); }; } // namespace ledger @@ -17,24 +17,24 @@ void quotes_by_script::operator()(commodity_base_t& commodity, { DEBUG_CLASS("ledger.quotes.download"); - DEBUG_PRINT_("commodity: " << commodity.symbol); - DEBUG_PRINT_TIME_(datetime_t::now); - DEBUG_PRINT_TIME_(moment); - DEBUG_PRINT_TIME_(date); - DEBUG_PRINT_TIME_(last); + DEBUG_("commodity: " << commodity.symbol); + DEBUG_TIME_(current_moment); + DEBUG_TIME_(moment); + DEBUG_TIME_(date); + DEBUG_TIME_(last); if (commodity.history) - DEBUG_PRINT_TIME_(commodity.history->last_lookup); - DEBUG_PRINT_("pricing_leeway is " << pricing_leeway); + DEBUG_TIME_(commodity.history->last_lookup); + DEBUG_("pricing_leeway is " << pricing_leeway); if ((commodity.history && - (datetime_t::now - commodity.history->last_lookup) < pricing_leeway) || - (datetime_t::now - last) < pricing_leeway || + (current_moment - commodity.history->last_lookup) < pricing_leeway) || + (current_moment - last) < pricing_leeway || (price && moment > date && (moment - date) <= pricing_leeway)) return; using namespace std; - DEBUG_PRINT_("downloading quote for symbol " << commodity.symbol); + DEBUG_("downloading quote for symbol " << commodity.symbol); char buf[256]; buf[0] = '\0'; @@ -55,12 +55,12 @@ void quotes_by_script::operator()(commodity_base_t& commodity, char * p = strchr(buf, '\n'); if (p) *p = '\0'; - DEBUG_PRINT_("downloaded quote: " << buf); + DEBUG_("downloaded quote: " << buf); price.parse(buf); - commodity.add_price(datetime_t::now, price); + commodity.add_price(current_moment, price); - commodity.history->last_lookup = datetime_t::now; + commodity.history->last_lookup = current_moment; cache_dirty = true; if (price && ! price_db.empty()) { @@ -69,11 +69,11 @@ void quotes_by_script::operator()(commodity_base_t& commodity, #else ofstream database(price_db.c_str(), ios_base::out | ios_base::app); #endif - database << "P " << datetime_t::now.to_string("%Y/%m/%d %H:%M:%S") + database << "P " << current_moment.to_string("%Y/%m/%d %H:%M:%S") << " " << commodity.symbol << " " << price << endl; } } else { - throw new error(std::string("Failed to download price for '") + + throw new error(string("Failed to download price for '") + commodity.symbol + "' (command: \"getquote " + commodity.symbol + "\")"); } @@ -5,14 +5,14 @@ namespace ledger { -class quotes_by_script : public commodity_base_t::updater_t +class quotes_by_script : public commodity_t::base_t::updater_t { - std::string price_db; + string price_db; unsigned long pricing_leeway; bool& cache_dirty; public: - quotes_by_script(std::string _price_db, + quotes_by_script(path _price_db, unsigned long _pricing_leeway, bool& _cache_dirty) : price_db(_price_db), pricing_leeway(_pricing_leeway), diff --git a/reconcile.cc b/reconcile.cc index 5b6dba24..b92ff9f1 100644 --- a/reconcile.cc +++ b/reconcile.cc @@ -40,11 +40,10 @@ void reconcile_transactions::flush() transaction_t * first = NULL; transaction_t ** last_ptr = &first; - bool found_pending = false; for (transactions_list::iterator x = xacts.begin(); x != xacts.end(); x++) { - if (! cutoff || (*x)->date() < cutoff) { + if (! is_valid(cutoff) || (*x)->date() < cutoff) { switch ((*x)->state) { case transaction_t::CLEARED: cleared_balance += (*x)->amount; @@ -59,25 +58,25 @@ void reconcile_transactions::flush() } } - if (cleared_balance.type >= value_t::BALANCE) + if (cleared_balance.type() >= value_t::BALANCE) throw new error("Cannot reconcile accounts with multiple commodities"); cleared_balance.cast(value_t::AMOUNT); balance.cast(value_t::AMOUNT); - commodity_t& cb_comm = ((amount_t *) cleared_balance.data)->commodity(); - commodity_t& b_comm = ((amount_t *) balance.data)->commodity(); + commodity_t& cb_comm = cleared_balance.as_amount_lval().commodity(); + commodity_t& b_comm = balance.as_amount_lval().commodity(); balance -= cleared_balance; - if (balance.type >= value_t::BALANCE) - throw new error(std::string("Reconcile balance is not of the same commodity ('") + - b_comm.symbol() + "' != '" + cb_comm.symbol() + "')"); + if (balance.type() >= value_t::BALANCE) + throw new error(string("Reconcile balance is not of the same commodity ('") + + b_comm.symbol() + string("' != '") + cb_comm.symbol() + "')"); // If the amount to reconcile is the same as the pending balance, // then assume an exact match and return the results right away. - amount_t to_reconcile = *((amount_t *) balance.data); + amount_t& to_reconcile(balance.as_amount_lval()); pending_balance.cast(value_t::AMOUNT); - if (to_reconcile == *((amount_t *) pending_balance.data) || + if (to_reconcile == pending_balance.as_amount_lval() || search_for_balance(to_reconcile, &first, first)) { push_to_handler(first); } else { @@ -38,21 +38,21 @@ report_t::report_t() } void -report_t::regexps_to_predicate(const std::string& command, - std::list<std::string>::const_iterator begin, - std::list<std::string>::const_iterator end, +report_t::regexps_to_predicate(const string& command, + std::list<string>::const_iterator begin, + std::list<string>::const_iterator end, const bool account_regexp, const bool add_account_short_masks, const bool logical_and) { - std::string regexps[2]; + string regexps[2]; assert(begin != end); // Treat the remaining command-line arguments as regular // expressions, used for refining report results. - for (std::list<std::string>::const_iterator i = begin; + for (std::list<string>::const_iterator i = begin; i != end; i++) if ((*i)[0] == '-') { @@ -83,12 +83,12 @@ report_t::regexps_to_predicate(const std::string& command, predicate += "!"; } else if (add_account_short_masks) { - if (regexps[i].find(':') != std::string::npos || - regexps[i].find('.') != std::string::npos || - regexps[i].find('*') != std::string::npos || - regexps[i].find('+') != std::string::npos || - regexps[i].find('[') != std::string::npos || - regexps[i].find('(') != std::string::npos) { + if (regexps[i].find(':') != string::npos || + regexps[i].find('.') != string::npos || + regexps[i].find('*') != string::npos || + regexps[i].find('+') != string::npos || + regexps[i].find('[') != string::npos || + regexps[i].find('(') != string::npos) { show_subtotal = true; add_predicate = 1; } else { @@ -127,7 +127,7 @@ report_t::regexps_to_predicate(const std::string& command, } } -void report_t::process_options(const std::string& command, +void report_t::process_options(const string& command, strings_list::iterator arg, strings_list::iterator args_end) { @@ -158,7 +158,7 @@ void report_t::process_options(const std::string& command, // Treat the remaining command-line arguments as regular // expressions, used for refining report results. - std::list<std::string>::iterator i = arg; + std::list<string>::iterator i = arg; for (; i != args_end; i++) if (*i == "--") break; @@ -191,8 +191,8 @@ void report_t::process_options(const std::string& command, } } - DEBUG_PRINT("ledger.config.predicates", "Predicate: " << predicate); - DEBUG_PRINT("ledger.config.predicates", "Display P: " << display_predicate); + DEBUG("ledger.config.predicates", "Predicate: " << predicate); + DEBUG("ledger.config.predicates", "Display P: " << display_predicate); // Setup the values of %t and %T, used in format strings @@ -204,7 +204,7 @@ void report_t::process_options(const std::string& command, // Now setup the various formatting strings if (! date_output_format.empty()) - date_t::output_format = date_output_format; + output_time_format = date_output_format; amount_t::keep_price = keep_price; amount_t::keep_date = keep_date; @@ -215,7 +215,7 @@ void report_t::process_options(const std::string& command, } item_handler<transaction_t> * -report_t::chain_xact_handlers(const std::string& command, +report_t::chain_xact_handlers(const string& command, item_handler<transaction_t> * base_formatter, journal_t * journal, account_t * master, @@ -254,16 +254,16 @@ report_t::chain_xact_handlers(const std::string& command, // transactions which made up the total for that reported // transaction. if (! descend_expr.empty()) { - std::list<std::string> descend_exprs; + std::list<string> descend_exprs; - std::string::size_type beg = 0; - for (std::string::size_type pos = descend_expr.find(';'); - pos != std::string::npos; + string::size_type beg = 0; + for (string::size_type pos = descend_expr.find(';'); + pos != string::npos; beg = pos + 1, pos = descend_expr.find(';', beg)) - descend_exprs.push_back(std::string(descend_expr, beg, pos - beg)); - descend_exprs.push_back(std::string(descend_expr, beg)); + descend_exprs.push_back(string(descend_expr, beg, pos - beg)); + descend_exprs.push_back(string(descend_expr, beg)); - for (std::list<std::string>::reverse_iterator i = + for (std::list<string>::reverse_iterator i = descend_exprs.rbegin(); i != descend_exprs.rend(); i++) @@ -277,9 +277,9 @@ report_t::chain_xact_handlers(const std::string& command, // transactions which can be reconciled to a given balance // (calculated against the transactions which it receives). if (! reconcile_balance.empty()) { - datetime_t cutoff = datetime_t::now; + datetime_t cutoff = current_moment; if (! reconcile_date.empty()) - cutoff = reconcile_date; + cutoff = parse_datetime(reconcile_date); ptrs.push_back(formatter = new reconcile_transactions (formatter, value_t(reconcile_balance), cutoff)); @@ -2,7 +2,6 @@ #define _REPORT_H #include "ledger.h" -#include "timing.h" #include <iostream> #include <memory> @@ -13,21 +12,22 @@ namespace ledger { class report_t { public: - std::string output_file; - std::string predicate; - std::string secondary_predicate; - std::string display_predicate; - std::string report_period; - std::string report_period_sort; - std::string format_string; - std::string sort_string; - std::string amount_expr; - std::string total_expr; - std::string descend_expr; - std::string forecast_limit; - std::string reconcile_balance; - std::string reconcile_date; - std::string date_output_format; + path output_file; + + string predicate; + string secondary_predicate; + string display_predicate; + string report_period; + string report_period_sort; + string format_string; + string sort_string; + string amount_expr; + string total_expr; + string descend_expr; + string forecast_limit; + string reconcile_balance; + string reconcile_date; + string date_output_format; unsigned long budget_flags; @@ -55,19 +55,19 @@ class report_t report_t(); - void regexps_to_predicate(const std::string& command, - std::list<std::string>::const_iterator begin, - std::list<std::string>::const_iterator end, + void regexps_to_predicate(const string& command, + std::list<string>::const_iterator begin, + std::list<string>::const_iterator end, const bool account_regexp = false, const bool add_account_short_masks = false, const bool logical_and = true); - void process_options(const std::string& command, + void process_options(const string& command, strings_list::iterator arg, strings_list::iterator args_end); item_handler<transaction_t> * - chain_xact_handlers(const std::string& command, + chain_xact_handlers(const string& command, item_handler<transaction_t> * base_formatter, journal_t * journal, account_t * master, @@ -1,4 +1,8 @@ #include "ledger.h" +#include "xml.h" +#include "gnucash.h" +#include "qif.h" +#include "ofx.h" using namespace ledger; @@ -49,8 +53,11 @@ namespace { startup::~startup() { + // jww (2008-04-22): What about this? +#if 0 if (! ledger::do_cleanup) return; +#endif shutdown_parser_support(); } } @@ -68,6 +68,7 @@ #include <vector> #if defined(__GNUG__) && __GNUG__ < 3 + namespace std { inline ostream & right (ostream & i) { i.setf(i.right, i.adjustfield); @@ -78,6 +79,15 @@ namespace std { return i; } } + +typedef unsigned long istream_pos_type; +typedef unsigned long ostream_pos_type; + +#else // ! (defined(__GNUG__) && __GNUG__ < 3) + +typedef std::istream::pos_type istream_pos_type; +typedef std::ostream::pos_type ostream_pos_type; + #endif #include <cassert> @@ -4,70 +4,34 @@ #include "journal.h" #include "textual.h" -#include "datetime.h" #include "valexpr.h" -#include "error.h" #include "option.h" #include "config.h" -#include "timing.h" -#include "util.h" +#include "utils.h" #include "acconf.h" -#include <fstream> -#include <sstream> -#include <cstring> -#include <cctype> -#include <cstdio> -#include <cstdlib> - -#ifdef HAVE_REALPATH -extern "C" char *realpath(const char *, char resolved_path[]); -#endif - #define TIMELOG_SUPPORT 1 namespace ledger { #define MAX_LINE 1024 -static std::string path; +static path pathname; static unsigned int linenum; static unsigned int src_idx; static accounts_map account_aliases; -static std::list<std::pair<std::string, int> > include_stack; +static std::list<std::pair<path, int> > include_stack; #ifdef TIMELOG_SUPPORT struct time_entry_t { datetime_t checkin; account_t * account; - std::string desc; + string desc; }; std::list<time_entry_t> time_entries; #endif -inline char * next_element(char * buf, bool variable = false) -{ - for (char * p = buf; *p; p++) { - if (! (*p == ' ' || *p == '\t')) - continue; - - if (! variable) { - *p = '\0'; - return skip_ws(p + 1); - } - else if (*p == '\t') { - *p = '\0'; - return skip_ws(p + 1); - } - else if (*(p + 1) == ' ') { - *p = '\0'; - return skip_ws(p + 2); - } - } - return NULL; -} - static value_expr parse_amount_expr(std::istream& in, amount_t& amount, transaction_t * xact, unsigned short flags = 0) @@ -75,7 +39,7 @@ static value_expr parse_amount_expr(std::istream& in, amount_t& amount, value_expr expr(parse_value_expr(in, NULL, flags | PARSE_VALEXPR_RELAXED | PARSE_VALEXPR_PARTIAL)->acquire()); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed an amount expression"); #ifdef DEBUG_ENABLED @@ -93,7 +57,7 @@ static value_expr parse_amount_expr(std::istream& in, amount_t& amount, if (expr->kind == value_expr_t::CONSTANT) expr = NULL; - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "The transaction amount is " << xact->amount); return expr; } @@ -103,7 +67,7 @@ transaction_t * parse_transaction(char * line, account_t * account, { std::istringstream in(line); - std::string err_desc; + string err_desc; try { // The account will be determined later... @@ -119,14 +83,14 @@ transaction_t * parse_transaction(char * line, account_t * account, xact->state = transaction_t::CLEARED; in.get(p); p = peek_next_nonws(in); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed the CLEARED flag"); break; case '!': xact->state = transaction_t::PENDING; in.get(p); p = peek_next_nonws(in); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed the PENDING flag"); break; } @@ -151,18 +115,18 @@ transaction_t * parse_transaction(char * line, account_t * account, if ((*b == '[' && *(e - 1) == ']') || (*b == '(' && *(e - 1) == ')')) { xact->flags |= TRANSACTION_VIRTUAL; - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed a virtual account name"); if (*b == '[') { xact->flags |= TRANSACTION_BALANCE; - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed a balanced virtual account name"); } b++; e--; } - std::string name(b, e - b); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + string name(b, e - b); + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed account name " << name); if (account_aliases.size() > 0) { accounts_map::const_iterator i = account_aliases.find(name); @@ -189,7 +153,7 @@ transaction_t * parse_transaction(char * line, account_t * account, PARSE_VALEXPR_NO_REDUCE); unsigned long end = (long)in.tellg(); - xact->amount_expr.expr = std::string(line, beg, end - beg); + xact->amount_expr.expr = string(line, beg, end - beg); } catch (error * err) { err_desc = "While parsing transaction amount:"; @@ -202,14 +166,14 @@ transaction_t * parse_transaction(char * line, account_t * account, if (in.good() && ! in.eof()) { p = peek_next_nonws(in); if (p == '@') { - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Found a price indicator"); bool per_unit = true; in.get(p); if (in.peek() == '@') { in.get(p); per_unit = false; - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "And it's for a total price"); } @@ -227,18 +191,18 @@ transaction_t * parse_transaction(char * line, account_t * account, unsigned long end = (long)in.tellg(); if (per_unit) - xact->cost_expr = (std::string("@") + - std::string(line, beg, end - beg)); + xact->cost_expr = (string("@") + + string(line, beg, end - beg)); else - xact->cost_expr = (std::string("@@") + - std::string(line, beg, end - beg)); + xact->cost_expr = (string("@@") + + string(line, beg, end - beg)); } catch (error * err) { err_desc = "While parsing transaction cost:"; throw err; } - if (*xact->cost < 0) + if (xact->cost->sign() < 0) throw new parse_error("A transaction's cost may not be negative"); amount_t per_unit_cost(*xact->cost); @@ -249,22 +213,22 @@ transaction_t * parse_transaction(char * line, account_t * account, if (xact->amount.commodity() && ! xact->amount.commodity().annotated) - xact->amount.annotate_commodity(per_unit_cost, - xact->entry->actual_date(), - xact->entry->code); + xact->amount.annotate_commodity(annotation_t(per_unit_cost, + xact->entry->actual_date(), + xact->entry->code)); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Total cost is " << *xact->cost); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Per-unit cost is " << per_unit_cost); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Annotated amount is " << xact->amount); } } } xact->amount.reduce(); - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Reduced amount is " << xact->amount); // Parse the optional note @@ -276,7 +240,7 @@ transaction_t * parse_transaction(char * line, account_t * account, in.get(p); p = peek_next_nonws(in); xact->note = &line[in.tellg()]; - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << + DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed a note '" << xact->note << "'"); if (char * b = std::strchr(xact->note.c_str(), '[')) @@ -285,15 +249,15 @@ transaction_t * parse_transaction(char * line, account_t * account, std::strncpy(buf, b + 1, e - b - 1); buf[e - b - 1] = '\0'; - DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " << - "Parsed a transaction date " << buf); + DEBUG("ledger.textual.parse", "line " << linenum << ": " << + "Parsed a transaction date " << buf); if (char * p = std::strchr(buf, '=')) { *p++ = '\0'; - xact->_date_eff = p; + xact->_date_eff = parse_datetime(p); } if (buf[0]) - xact->_date = buf; + xact->_date = parse_datetime(buf); } } } @@ -314,7 +278,7 @@ transaction_t * parse_transaction(char * line, account_t * account, bool parse_transactions(std::istream& in, account_t * account, entry_base_t& entry, - const std::string& kind, + const string& kind, unsigned long beg_pos) { static char line[MAX_LINE + 1]; @@ -341,12 +305,14 @@ bool parse_transactions(std::istream& in, return added; } +#if 0 namespace { TIMER_DEF(parsing_total, "total parsing time"); TIMER_DEF(entry_xacts, "parsing transactions"); TIMER_DEF(entry_details, "parsing entry details"); TIMER_DEF(entry_date, "parsing entry date"); } +#endif entry_t * parse_entry(std::istream& in, char * line, account_t * master, textual_parser_t& parser, unsigned long& pos) @@ -355,21 +321,27 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, // Parse the date +#if 0 TIMER_START(entry_date); +#endif char * next = next_element(line); if (char * p = std::strchr(line, '=')) { *p++ = '\0'; - curr->_date_eff = p; + curr->_date_eff = parse_datetime(p); } - curr->_date = line; + curr->_date = parse_datetime(line); +#if 0 TIMER_STOP(entry_date); +#endif // Parse the optional cleared flag: * +#if 0 TIMER_START(entry_details); +#endif transaction_t::state_t state = transaction_t::UNCLEARED; if (next) { @@ -399,11 +371,15 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, curr->payee = next ? next : "<Unspecified payee>"; +#if 0 TIMER_STOP(entry_details); +#endif // Parse all of the transactions associated with this entry +#if 0 TIMER_START(entry_xacts); +#endif unsigned long end_pos; unsigned long beg_line = linenum; @@ -442,7 +418,9 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, break; } +#if 0 TIMER_STOP(entry_xacts); +#endif return curr.release(); } @@ -455,13 +433,13 @@ struct push_var { ~push_var() { var = prev; } }; -static inline void parse_symbol(char *& p, std::string& symbol) +static inline void parse_symbol(char *& p, string& symbol) { if (*p == '"') { char * q = std::strchr(p + 1, '"'); if (! q) throw new parse_error("Quoted commodity symbol lacks closing quote"); - symbol = std::string(p + 1, 0, q - p - 1); + symbol = string(p + 1, 0, q - p - 1); p = q + 2; } else { char * q = next_element(p); @@ -545,7 +523,7 @@ static void clock_out_from_timelog(const datetime_t& when, ("Timelog check-out date less than corresponding check-in"); char buf[32]; - std::sprintf(buf, "%lds", curr->_date - event.checkin); + std::sprintf(buf, "%lds", long((curr->_date - event.checkin).seconds())); amount_t amt; amt.parse(buf); @@ -560,19 +538,20 @@ static void clock_out_from_timelog(const datetime_t& when, curr.release(); } -unsigned int textual_parser_t::parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int textual_parser_t::parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { - static bool added_auto_entry_hook = false; - static char line[MAX_LINE + 1]; - char c; - unsigned int count = 0; - unsigned int errors = 0; + static bool added_auto_entry_hook = false; + static char line[MAX_LINE + 1]; + unsigned int count = 0; + unsigned int errors = 0; +#if 0 TIMER_START(parsing_total); +#endif std::list<account_t *> account_stack; auto_entry_finalizer_t auto_entry_finalizer(journal); @@ -582,7 +561,7 @@ unsigned int textual_parser_t::parse(std::istream& in, account_stack.push_front(master); - path = journal->sources.back(); + pathname = journal->sources.back(); src_idx = journal->sources.size() - 1; linenum = 1; @@ -614,14 +593,14 @@ unsigned int textual_parser_t::parse(std::istream& in, #ifdef TIMELOG_SUPPORT case 'i': case 'I': { - std::string date(line, 2, 19); + string date(line, 2, 19); char * p = skip_ws(line + 22); char * n = next_element(p, true); time_entry_t event; event.desc = n ? n : ""; - event.checkin = date; + event.checkin = parse_datetime(date); event.account = account_stack.front()->find_account(p); if (! time_entries.empty()) @@ -641,14 +620,14 @@ unsigned int textual_parser_t::parse(std::istream& in, if (time_entries.empty()) { throw new parse_error("Timelog check-out event without a check-in"); } else { - std::string date(line, 2, 19); + string date(line, 2, 19); char * p = skip_ws(line + 22); char * n = next_element(p, true); - clock_out_from_timelog - (date, p ? account_stack.front()->find_account(p) : NULL, n, - journal); + clock_out_from_timelog(parse_datetime(date), + p ? account_stack.front()->find_account(p) : NULL, + n, journal); count++; } break; @@ -656,7 +635,7 @@ unsigned int textual_parser_t::parse(std::istream& in, case 'D': { // a default commodity for "entry" amount_t amt(skip_ws(line + 1)); - commodity_t::default_commodity = &amt.commodity(); + amount_t::current_pool->default_commodity = &amt.commodity(); break; } @@ -668,7 +647,10 @@ unsigned int textual_parser_t::parse(std::istream& in, case 'C': // a set of conversions if (char * p = std::strchr(line + 1, '=')) { *p++ = '\0'; + // jww (2008-04-22): NYI! +#if 0 parse_conversion(line + 1, p); +#endif } break; @@ -676,7 +658,7 @@ unsigned int textual_parser_t::parse(std::istream& in, char * date_field_ptr = skip_ws(line + 1); char * time_field_ptr = next_element(date_field_ptr); if (! time_field_ptr) break; - std::string date_field = date_field_ptr; + string date_field = date_field_ptr; char * symbol_and_price; datetime_t datetime; @@ -684,33 +666,35 @@ unsigned int textual_parser_t::parse(std::istream& in, if (std::isdigit(time_field_ptr[0])) { symbol_and_price = next_element(time_field_ptr); if (! symbol_and_price) break; - datetime = date_field + " " + time_field_ptr; + datetime = parse_datetime(date_field + " " + time_field_ptr); } else { symbol_and_price = time_field_ptr; - datetime = date_t(date_field); + datetime = parse_datetime(date_field); } - std::string symbol; + string symbol; parse_symbol(symbol_and_price, symbol); amount_t price(symbol_and_price); - if (commodity_t * commodity = commodity_t::find_or_create(symbol)) + if (commodity_t * commodity = + amount_t::current_pool->find_or_create(symbol)) commodity->add_price(datetime, price); break; } case 'N': { // don't download prices char * p = skip_ws(line + 1); - std::string symbol; + string symbol; parse_symbol(p, symbol); - if (commodity_t * commodity = commodity_t::find_or_create(symbol)) + if (commodity_t * commodity = + amount_t::current_pool->find_or_create(symbol)) commodity->add_flags(COMMODITY_STYLE_NOMARKET); break; } case 'Y': // set the current year - date_t::current_year = std::atoi(skip_ws(line + 1)) - 1900; + current_year = std::atoi(skip_ws(line + 1)) - 1900; break; #ifdef TIMELOG_SUPPORT @@ -754,7 +738,7 @@ unsigned int textual_parser_t::parse(std::istream& in, case '~': { // period entry period_entry_t * pe = new period_entry_t(skip_ws(line + 1)); if (! pe->period) - throw new parse_error(std::string("Parsing time period '") + line + "'"); + throw new parse_error(string("Parsing time period '") + line + "'"); if (parse_transactions(in, account_stack.front(), *pe, "period", end_pos)) { @@ -776,30 +760,33 @@ unsigned int textual_parser_t::parse(std::istream& in, case '@': case '!': { // directive char * p = next_element(line); - std::string word(line + 1); + string word(line + 1); if (word == "include") { - push_var<std::string> save_path(path); + push_var<path> save_pathname(pathname); push_var<unsigned int> save_src_idx(src_idx); push_var<unsigned long> save_beg_pos(beg_pos); push_var<unsigned long> save_end_pos(end_pos); push_var<unsigned int> save_linenum(linenum); - path = p; - if (path[0] != '/' && path[0] != '\\' && path[0] != '~') { - std::string::size_type pos = save_path.prev.rfind('/'); - if (pos == std::string::npos) - pos = save_path.prev.rfind('\\'); - if (pos != std::string::npos) - path = std::string(save_path.prev, 0, pos + 1) + path; + // jww (2008-04-22): Fix this! + pathname = p; +#if 0 + if (pathname[0] != '/' && pathname[0] != '\\' && pathname[0] != '~') { + string::size_type pos = save_pathname.prev.rfind('/'); + if (pos == string::npos) + pos = save_pathname.prev.rfind('\\'); + if (pos != string::npos) + pathname = string(save_pathname.prev, 0, pos + 1) + pathname; } - path = resolve_path(path); + pathname = resolve_path(pathname); +#endif - DEBUG_PRINT("ledger.textual.include", "line " << linenum << ": " << - "Including path '" << path << "'"); + DEBUG("ledger.textual.include", "line " << linenum << ": " << + "Including path '" << pathname << "'"); - include_stack.push_back(std::pair<std::string, int> + include_stack.push_back(std::pair<path, int> (journal->sources.back(), linenum - 1)); - count += parse_journal_file(path, config, journal, + count += parse_journal_file(pathname, config, journal, account_stack.front()); include_stack.pop_back(); } @@ -839,7 +826,6 @@ unsigned int textual_parser_t::parse(std::istream& in, } default: { - unsigned int first_line = linenum; unsigned long pos = beg_pos; if (entry_t * entry = parse_entry(in, line, account_stack.front(), *this, pos)) { @@ -863,13 +849,13 @@ unsigned int textual_parser_t::parse(std::istream& in, } } catch (error * err) { - for (std::list<std::pair<std::string, int> >::reverse_iterator i = + for (std::list<std::pair<path, int> >::reverse_iterator i = include_stack.rbegin(); i != include_stack.rend(); i++) err->context.push_back(new include_context((*i).first, (*i).second, "In file included from")); - err->context.push_front(new file_context(path, linenum - 1)); + err->context.push_front(new file_context(pathname, linenum - 1)); std::cout.flush(); if (errors > 0 && err->context.size() > 1) @@ -882,12 +868,11 @@ unsigned int textual_parser_t::parse(std::istream& in, beg_pos = end_pos; } - done: if (! time_entries.empty()) { for (std::list<time_entry_t>::iterator i = time_entries.begin(); i != time_entries.end(); i++) - clock_out_from_timelog(datetime_t::now, (*i).account, NULL, journal); + clock_out_from_timelog(current_moment, (*i).account, NULL, journal); time_entries.clear(); } @@ -897,20 +882,22 @@ unsigned int textual_parser_t::parse(std::istream& in, if (errors > 0) throw (int)errors; +#if 0 TIMER_STOP(parsing_total); +#endif return count; } -void write_textual_journal(journal_t& journal, std::string path, +void write_textual_journal(journal_t& journal, path pathname, item_handler<transaction_t>& formatter, - const std::string& write_hdr_format, + const string& write_hdr_format, std::ostream& out) { unsigned long index = 0; - std::string found; + path found; - if (path.empty()) { + if (pathname.empty()) { if (! journal.sources.empty()) found = *journal.sources.begin(); } else { @@ -918,12 +905,12 @@ void write_textual_journal(journal_t& journal, std::string path, char buf1[PATH_MAX]; char buf2[PATH_MAX]; - ::realpath(path.c_str(), buf1); + ::realpath(pathname.string().c_str(), buf1); - for (strings_list::iterator i = journal.sources.begin(); + for (paths_list::iterator i = journal.sources.begin(); i != journal.sources.end(); i++) { - ::realpath((*i).c_str(), buf2); + ::realpath((*i).string().c_str(), buf2); if (std::strcmp(buf1, buf2) == 0) { found = *i; break; @@ -931,10 +918,10 @@ void write_textual_journal(journal_t& journal, std::string path, index++; } #else - for (strings_list::iterator i = journal.sources.begin(); + for (paths_list::iterator i = journal.sources.begin(); i != journal.sources.end(); i++) { - if (path == *i) { + if (pathname == *i) { found = *i; break; } @@ -944,8 +931,8 @@ void write_textual_journal(journal_t& journal, std::string path, } if (found.empty()) - throw new error(std::string("Journal does not refer to file '") + - path + "'"); + throw new error(string("Journal does not refer to file '") + + string(pathname.string()) + "'"); entries_list::iterator el = journal.entries.begin(); auto_entries_list::iterator al = journal.auto_entries.begin(); @@ -954,7 +941,7 @@ void write_textual_journal(journal_t& journal, std::string path, unsigned long pos = 0; format_t hdr_fmt(write_hdr_format); - std::ifstream in(found.c_str()); + boost::filesystem::ifstream in(found); while (! in.eof()) { entry_base_t * base = NULL; @@ -12,32 +12,33 @@ class textual_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); }; transaction_t * parse_transaction_text(char * line, account_t * account); transaction_t * parse_transaction(std::istream& in, account_t * account); -void write_textual_journal(journal_t& journal, std::string path, +void write_textual_journal(journal_t& journal, path pathname, item_handler<transaction_t>& formatter, - const std::string& write_hdr_format, + const string& write_hdr_format, std::ostream& out); class include_context : public file_context { public: - include_context(const std::string& file, unsigned long line, - const std::string& desc = "") throw() + include_context(const path& file, unsigned long line, + const string& desc = "") throw() : file_context(file, line, desc) {} virtual ~include_context() throw() {} virtual void describe(std::ostream& out) const throw() { if (! desc.empty()) out << desc << ": "; - out << "\"" << file << "\", line " << line << ":" << std::endl; + out << "\"" << file.string() << "\", line " << line << ":" + << std::endl; } }; @@ -41,15 +41,35 @@ const ptime time_now = boost::posix_time::second_clock::universal_time(); const date date_now = boost::gregorian::day_clock::universal_day(); #ifdef SUPPORT_DATE_AND_TIME -const moment_t& now(time_now); +const datetime_t& current_moment(time_now); #else -const moment_t& now(date_now); +const datetime_t& current_moment(date_now); #endif +int current_year(current_moment.date().year()); + +string input_time_format; +string output_time_format = "%Y/%m/%d"; + +static const char * formats[] = { + "%Y/%m/%d", + "%m/%d", + "%Y.%m.%d", + "%m.%d", + "%Y-%m-%d", + "%m-%d", + "%a", + "%A", + "%b", + "%B", + "%Y", + NULL +}; + bool day_before_month = false; static bool day_before_month_initialized = false; -moment_t parse_datetime(const char * str) +datetime_t parse_datetime(const char * str) { if (! day_before_month_initialized) { #ifdef HAVE_NL_LANGINFO @@ -73,8 +93,333 @@ moment_t parse_datetime(const char * str) int day = ((str[8] - '0') * 10 + (str[9] - '0')); - return moment_t(boost::gregorian::date(year, mon, day)); + return datetime_t(boost::gregorian::date(year, mon, day)); +#endif +} + +datetime_t interval_t::first(const datetime_t& moment) const +{ + datetime_t quant(begin); + +#if 0 + // jww (2008-05-08): Implement + if (is_valid(moment) && moment > quant) { + // Find an efficient starting point for the upcoming while loop. + // We want a date early enough that the range will be correct, but + // late enough that we don't spend hundreds of thousands of loops + // skipping through time. + + struct std::tm * desc = std::localtime(&moment.when); + + if (years) + desc->tm_mon = 0; + desc->tm_mday = 1; + + desc->tm_hour = 0; + desc->tm_min = 0; + desc->tm_sec = 0; + desc->tm_isdst = -1; + + quant = std::mktime(desc); + + datetime_t temp; + while (moment >= (temp = increment(quant))) { + if (quant == temp) + break; + quant = temp; + } + } +#endif + + return quant; +} + +datetime_t interval_t::increment(const datetime_t& moment) const +{ + struct std::tm * desc = NULL; + +#if 0 + struct std::tm * desc = std::localtime(&moment.when); + + // jww (2008-05-08): Implement + if (years) + desc->tm_year += years; + if (months) + desc->tm_mon += months; + if (days) + desc->tm_mday += days; + + desc->tm_hour += hours; + desc->tm_min += minutes; + desc->tm_sec += seconds; + + desc->tm_isdst = -1; + + return std::mktime(desc); +#else + return datetime_t(); +#endif +} + +namespace { + void parse_inclusion_specifier(const string& word, + datetime_t * begin, datetime_t * end) + { +#if 0 + // jww (2008-05-08): Implement! + struct std::tm when; + + if (! parse_date_mask(word.c_str(), &when)) + throw new datetime_error(string("Could not parse date mask: ") + word); + + when.tm_hour = 0; + when.tm_min = 0; + when.tm_sec = 0; + when.tm_isdst = -1; + + bool saw_year = true; + bool saw_mon = true; + bool saw_day = true; + + if (when.tm_year == -1) { + when.tm_year = date_t::current_year; + saw_year = false; + } + if (when.tm_mon == -1) { + when.tm_mon = 0; + saw_mon = false; + } else { + saw_year = false; // don't increment by year if month used + } + if (when.tm_mday == -1) { + when.tm_mday = 1; + saw_day = false; + } else { + saw_mon = false; // don't increment by month if day used + saw_year = false; // don't increment by year if day used + } + + if (begin) { + *begin = std::mktime(&when); + if (end) + *end = interval_t(saw_day ? 86400 : 0, saw_mon ? 1 : 0, + saw_year ? 1 : 0).increment(*begin); + } + else if (end) { + *end = std::mktime(&when); + } +#endif + } + + inline void read_lower_word(std::istream& in, string& word) { + in >> word; + for (int i = 0, l = word.length(); i < l; i++) + word[i] = std::tolower(word[i]); + } + + void parse_date_words(std::istream& in, string& word, + datetime_t * begin, datetime_t * end) + { + string type; + + bool mon_spec = false; + char buf[32]; + + if (word == "this" || word == "last" || word == "next") { + type = word; + if (! in.eof()) + read_lower_word(in, word); + else + word = "month"; + } else { + type = "this"; + } + + if (word == "month") { +#if 0 + // jww (2008-05-08): + std::strftime(buf, 31, "%B", datetime_t::now.localtime()); +#endif + word = buf; + mon_spec = true; + } + else if (word == "year") { +#if 0 + // jww (2008-05-08): + std::strftime(buf, 31, "%Y", datetime_t::now.localtime()); +#endif + word = buf; + } + + parse_inclusion_specifier(word, begin, end); + + if (type == "last") { + if (mon_spec) { + if (begin) + *begin = interval_t(0, -1, 0).increment(*begin); + if (end) + *end = interval_t(0, -1, 0).increment(*end); + } else { + if (begin) + *begin = interval_t(0, 0, -1).increment(*begin); + if (end) + *end = interval_t(0, 0, -1).increment(*end); + } + } + else if (type == "next") { + if (mon_spec) { + if (begin) + *begin = interval_t(0, 1, 0).increment(*begin); + if (end) + *end = interval_t(0, 1, 0).increment(*end); + } else { + if (begin) + *begin = interval_t(0, 0, 1).increment(*begin); + if (end) + *end = interval_t(0, 0, 1).increment(*end); + } + } + } +} + +void interval_t::parse(std::istream& in) +{ + string word; + + while (! in.eof()) { + read_lower_word(in, word); + if (word == "every") { + read_lower_word(in, word); + if (std::isdigit(word[0])) { + int quantity = std::atol(word.c_str()); + read_lower_word(in, word); + if (word == "days") + days = quantity; + else if (word == "weeks") + days = 7 * quantity; + else if (word == "months") + months = quantity; + else if (word == "quarters") + months = 3 * quantity; + else if (word == "years") + years = quantity; + else if (word == "hours") + hours = quantity; + else if (word == "minutes") + minutes = quantity; + else if (word == "seconds") + seconds = quantity; + } + else if (word == "day") + days = 1; + else if (word == "week") + days = 7; + else if (word == "month") + months = 1; + else if (word == "quarter") + months = 3; + else if (word == "year") + years = 1; + else if (word == "hour") + hours = 1; + else if (word == "minute") + minutes = 1; + else if (word == "second") + seconds = 1; + } + else if (word == "daily") + days = 1; + else if (word == "weekly") + days = 7; + else if (word == "biweekly") + days = 14; + else if (word == "monthly") + months = 1; + else if (word == "bimonthly") + months = 2; + else if (word == "quarterly") + months = 3; + else if (word == "yearly") + years = 1; + else if (word == "hourly") + hours = 1; + else if (word == "this" || word == "last" || word == "next") { + parse_date_words(in, word, &begin, &end); + } + else if (word == "in") { + read_lower_word(in, word); + parse_date_words(in, word, &begin, &end); + } + else if (word == "from" || word == "since") { + read_lower_word(in, word); + parse_date_words(in, word, &begin, NULL); + } + else if (word == "to" || word == "until") { + read_lower_word(in, word); + parse_date_words(in, word, NULL, &end); + } + else { + parse_inclusion_specifier(word, &begin, &end); + } + } +} + +namespace { + bool parse_date_mask(const char * date_str, struct std::tm * result) + { +#if 0 + // jww (2008-05-08): + if (! date_t::input_format.empty()) { + std::memset(result, INT_MAX, sizeof(struct std::tm)); + if (strptime(date_str, date_t::input_format.c_str(), result)) + return true; + } + for (const char ** f = formats; *f; f++) { + std::memset(result, INT_MAX, sizeof(struct std::tm)); + if (strptime(date_str, *f, result)) + return true; + } #endif + return false; + } + + bool parse_date(const char * date_str, std::time_t * result, const int year) + { +#if 0 + // jww (2008-05-08): + struct std::tm when; + + if (! parse_date_mask(date_str, &when)) + return false; + + when.tm_hour = 0; + when.tm_min = 0; + when.tm_sec = 0; + + if (when.tm_year == -1) + when.tm_year = ((year == -1) ? date_t::current_year : (year - 1900)); + + if (when.tm_mon == -1) + when.tm_mon = 0; + + if (when.tm_mday == -1) + when.tm_mday = 1; + + *result = std::mktime(&when); +#endif + + return true; + } + + bool quick_parse_date(const char * date_str, std::time_t * result) + { +#if 0 + // jww (2008-05-08): + return parse_date(date_str, result, date_t::current_year + 1900); +#else + return false; +#endif + } } } // namespace ledger @@ -37,65 +37,93 @@ namespace ledger { #define SUPPORT_DATE_AND_TIME 1 #ifdef SUPPORT_DATE_AND_TIME -typedef boost::posix_time::ptime moment_t; -typedef moment_t::time_duration_type duration_t; +typedef boost::posix_time::ptime datetime_t; +typedef datetime_t::time_duration_type duration_t; -inline bool is_valid_moment(const moment_t& moment) { +inline bool is_valid(const datetime_t& moment) { return ! moment.is_not_a_date_time(); } #else // SUPPORT_DATE_AND_TIME -typedef boost::gregorian::date moment_t; +typedef boost::gregorian::date datetime_t; typedef boost::gregorian::date_duration duration_t; -inline bool is_valid_moment(const moment_t& moment) { +inline bool is_valid(const datetime_t& moment) { return ! moment.is_not_a_date(); } #endif // SUPPORT_DATE_AND_TIME -extern const moment_t& now; +extern const datetime_t& current_moment; + +extern int current_year; +extern string input_time_format; +extern string output_time_format; DECLARE_EXCEPTION(error, datetime_error); -class interval_t +struct interval_t { -public: - interval_t() {} - interval_t(const string&) {} + unsigned short years; + unsigned short months; + unsigned short days; + unsigned short hours; + unsigned short minutes; + unsigned short seconds; + + datetime_t begin; + datetime_t end; + + interval_t(int _days = 0, int _months = 0, int _years = 0, + const datetime_t& _begin = datetime_t(), + const datetime_t& _end = datetime_t()) + : years(_years), months(_months), days(_days), + hours(0), minutes(0), seconds(0), + begin(_begin), end(_end) {} + + interval_t(const string& desc) + : years(0), months(0), days(0), + hours(0), minutes(0), seconds(0) { + std::istringstream stream(desc); + parse(stream); + } operator bool() const { - return false; + return (years > 0 || months > 0 || days > 0 || + hours > 0 || minutes > 0 || seconds > 0); } - void start(const moment_t&) {} - moment_t next() const { return moment_t(); } + void start(const datetime_t& moment) { + begin = first(moment); + } + datetime_t first(const datetime_t& moment = datetime_t()) const; + datetime_t increment(const datetime_t&) const; - void parse(std::istream&) {} + void parse(std::istream& in); }; #if 0 -inline moment_t ptime_local_to_utc(const moment_t& when) { +inline datetime_t ptime_local_to_utc(const datetime_t& when) { struct std::tm tm_gmt = to_tm(when); return boost::posix_time::from_time_t(std::mktime(&tm_gmt)); } // jww (2007-04-18): I need to make a general parsing function // instead, and then make these into private methods. -inline moment_t ptime_from_local_date_string(const string& date_string) { - return ptime_local_to_utc(moment_t(boost::gregorian::from_string(date_string), - time_duration())); +inline datetime_t ptime_from_local_date_string(const string& date_string) { + return ptime_local_to_utc(datetime_t(boost::gregorian::from_string(date_string), + time_duration())); } -inline moment_t ptime_from_local_time_string(const string& time_string) { +inline datetime_t ptime_from_local_time_string(const string& time_string) { return ptime_local_to_utc(boost::posix_time::time_from_string(time_string)); } #endif -moment_t parse_datetime(const char * str); +datetime_t parse_datetime(const char * str); -inline moment_t parse_datetime(const string& str) { +inline datetime_t parse_datetime(const string& str) { return parse_datetime(str.c_str()); } @@ -115,7 +143,7 @@ struct intorchar intorchar(const intorchar& o) : ival(o.ival), sval(o.sval) {} }; -ledger::moment_t parse_abs_datetime(std::istream& input); +ledger::datetime_t parse_abs_datetime(std::istream& input); #endif } // namespace ledger @@ -472,7 +472,7 @@ bool logger_func(log_level_t level) IF_VERIFY() *_log_stream << " TIME OBJSZ MEMSZ" << std::endl; - appender = (logger_start - now).total_milliseconds(); + appender = (logger_start - current_moment).total_milliseconds(); } *_log_stream << std::right << std::setw(5) @@ -1,9 +1,6 @@ #include "valexpr.h" #include "walk.h" -#include "error.h" -#include "datetime.h" -#include "debug.h" -#include "util.h" +#include "utils.h" namespace ledger { @@ -16,7 +13,7 @@ datetime_t terminus; details_t::details_t(const transaction_t& _xact) : entry(_xact.entry), xact(&_xact), account(xact_account(_xact)) { - DEBUG_PRINT("ledger.memory.ctors", "ctor details_t"); + DEBUG("ledger.memory.ctors", "ctor details_t"); } bool compute_amount(value_expr_t * expr, amount_t& amt, @@ -26,7 +23,7 @@ bool compute_amount(value_expr_t * expr, amount_t& amt, try { expr->compute(result, xact ? details_t(*xact) : details_t(), context); result.cast(value_t::AMOUNT); - amt = *((amount_t *) result.data); + amt = result.as_amount_lval(); } catch (error * err) { if (err->context.empty() || @@ -44,9 +41,9 @@ bool compute_amount(value_expr_t * expr, amount_t& amt, value_expr_t::~value_expr_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor value_expr_t " << this); + DEBUG("ledger.memory.dtors", "dtor value_expr_t " << this); - DEBUG_PRINT("ledger.valexpr.memory", "Destroying " << this); + DEBUG("ledger.valexpr.memory", "Destroying " << this); assert(refc == 0); if (left) @@ -171,15 +168,20 @@ void value_expr_t::compute(value_t& result, const details_t& details, if (transaction_has_xdata(*details.xact)) { transaction_xdata_t& xdata(transaction_xdata_(*details.xact)); if (xdata.dflags & TRANSACTION_COMPOUND) { - result = xdata.value.price(); + result = xdata.value.value(); set = true; } } - if (! set) - result = details.xact->amount.price(); + if (! set) { + optional<amount_t> value = details.xact->amount.value(); + if (value) + result = *value; + else + result = 0L; + } } else if (details.account && account_has_xdata(*details.account)) { - result = account_xdata(*details.account).value.price(); + result = account_xdata(*details.account).value.value(); } else { result = 0L; @@ -222,9 +224,9 @@ void value_expr_t::compute(value_t& result, const details_t& details, break; case PRICE_TOTAL: if (details.xact && transaction_has_xdata(*details.xact)) - result = transaction_xdata_(*details.xact).total.price(); + result = transaction_xdata_(*details.xact).total.value(); else if (details.account && account_has_xdata(*details.account)) - result = account_xdata(*details.account).total.price(); + result = account_xdata(*details.account).total.value(); else result = 0L; break; @@ -252,7 +254,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, case DATE: if (details.xact && transaction_has_xdata(*details.xact) && - transaction_xdata_(*details.xact).date) + is_valid(transaction_xdata_(*details.xact).date)) result = transaction_xdata_(*details.xact).date; else if (details.xact) result = details.xact->date(); @@ -264,7 +266,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, case ACT_DATE: if (details.xact && transaction_has_xdata(*details.xact) && - transaction_xdata_(*details.xact).date) + is_valid(transaction_xdata_(*details.xact).date)) result = transaction_xdata_(*details.xact).date; else if (details.xact) result = details.xact->actual_date(); @@ -276,7 +278,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, case EFF_DATE: if (details.xact && transaction_has_xdata(*details.xact) && - transaction_xdata_(*details.xact).date) + is_valid(transaction_xdata_(*details.xact).date)) result = transaction_xdata_(*details.xact).date; else if (details.xact) result = details.xact->effective_date(); @@ -342,7 +344,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, int arg_index = 0; value_expr_t * expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - result = result.price(); + result = result.value(); break; } @@ -350,7 +352,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, int arg_index = 0; value_expr_t * expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - result = result.date(); + result = result.as_datetime_lval(); break; } @@ -358,7 +360,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, int arg_index = 0; value_expr_t * expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - result = result.date(); + result = result.as_datetime_lval(); if (! result) break; @@ -366,7 +368,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, expr = find_leaf(context, 1, arg_index); value_t moment; expr->compute(moment, details, context); - if (moment.type == value_t::DATETIME) { + if (moment.is_type(value_t::DATETIME)) { result.cast(value_t::INTEGER); moment.cast(value_t::INTEGER); result -= moment; @@ -384,20 +386,22 @@ void value_expr_t::compute(value_t& result, const details_t& details, value_expr_t * expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - if (result.type != value_t::DATETIME) + if (! result.is_type(value_t::DATETIME)) throw new compute_error("Invalid date passed to year|month|day(date)", new valexpr_context(expr)); - datetime_t& moment(*((datetime_t *)result.data)); + datetime_t& moment(result.as_datetime_lval()); switch (kind) { case F_YEAR: - result = (long)moment.year(); + result = (long)moment.date().year(); break; case F_MONTH: - result = (long)moment.month(); + result = (long)moment.date().month(); break; case F_DAY: - result = (long)moment.day(); + result = (long)moment.date().day(); + break; + default: break; } break; @@ -446,11 +450,11 @@ void value_expr_t::compute(value_t& result, const details_t& details, int arg_index = 0; value_expr_t * expr = find_leaf(context, 0, arg_index); expr->compute(result, details, context); - if (result.type != value_t::AMOUNT) + if (! result.is_type(value_t::AMOUNT)) throw new compute_error("Argument to commodity() must be a commoditized amount", new valexpr_context(expr)); amount_t temp("1"); - temp.set_commodity(((amount_t *) result.data)->commodity()); + temp.set_commodity(result.as_amount_lval().commodity()); result = temp; break; } @@ -464,12 +468,12 @@ void value_expr_t::compute(value_t& result, const details_t& details, arg_index = 0; expr = find_leaf(context, 1, arg_index); expr->compute(result, details, context); - if (result.type != value_t::AMOUNT) + if (! result.is_type(value_t::AMOUNT)) throw new compute_error ("Second argument to set_commodity() must be a commoditized amount", new valexpr_context(expr)); amount_t one("1"); - one.set_commodity(((amount_t *) result.data)->commodity()); + one.set_commodity(result.as_amount_lval().commodity()); result = one; result *= temp; @@ -482,20 +486,20 @@ void value_expr_t::compute(value_t& result, const details_t& details, expr->compute(result, details, context); balance_t * bal = NULL; - switch (result.type) { + switch (result.type()) { case value_t::BALANCE_PAIR: - bal = &((balance_pair_t *) result.data)->quantity; + bal = &(result.as_balance_pair_lval().quantity()); // fall through... case value_t::BALANCE: if (! bal) - bal = (balance_t *) result.data; + bal = &(result.as_balance_lval()); if (bal->amounts.size() < 2) { result.cast(value_t::AMOUNT); } else { value_t temp; - for (amounts_map::const_iterator i = bal->amounts.begin(); + for (balance_t::amounts_map::const_iterator i = bal->amounts.begin(); i != bal->amounts.end(); i++) { amount_t x = (*i).second; @@ -503,12 +507,12 @@ void value_expr_t::compute(value_t& result, const details_t& details, temp += x; } result = temp; - assert(temp.type == value_t::AMOUNT); + assert(temp.is_type(value_t::AMOUNT)); } // fall through... case value_t::AMOUNT: - ((amount_t *) result.data)->clear_commodity(); + result.as_amount_lval().clear_commodity(); break; default: @@ -608,11 +612,11 @@ void value_expr_t::compute(value_t& result, const details_t& details, expr = find_leaf(context, 1, arg_index); value_t moment; expr->compute(moment, details, context); - if (moment.type != value_t::DATETIME) + if (! moment.is_type(value_t::DATETIME)) throw new compute_error("Invalid date passed to P(value,date)", new valexpr_context(expr)); - result = result.value(*((datetime_t *)moment.data)); + result = result.value(moment.as_datetime_lval()); break; } @@ -671,7 +675,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, case O_LTE: result = temp <= result; break; case O_GT: result = temp > result; break; case O_GTE: result = temp >= result; break; - default: assert(0); break; + default: assert(false); break; } break; } @@ -696,7 +700,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, case O_SUB: result -= temp; break; case O_MUL: result *= temp; break; case O_DIV: result /= temp; break; - default: assert(0); break; + default: assert(false); break; } break; } @@ -712,7 +716,7 @@ void value_expr_t::compute(value_t& result, const details_t& details, case LAST: default: - assert(0); + assert(false); break; } } @@ -727,15 +731,15 @@ void value_expr_t::compute(value_t& result, const details_t& details, static inline void unexpected(char c, char wanted = '\0') { if ((unsigned char) c == 0xff) { if (wanted) - throw new value_expr_error(std::string("Missing '") + wanted + "'"); + throw new value_expr_error(string("Missing '") + wanted + "'"); else throw new value_expr_error("Unexpected end"); } else { if (wanted) - throw new value_expr_error(std::string("Invalid char '") + c + + throw new value_expr_error(string("Invalid char '") + c + "' (wanted '" + wanted + "')"); else - throw new value_expr_error(std::string("Invalid char '") + c + "'"); + throw new value_expr_error(string("Invalid char '") + c + "'"); } } @@ -883,7 +887,7 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope, // Define the value associated with the defined identifier value_expr def(parse_boolean_expr(in, params.get(), flags)); if (! def.get()) - throw new value_expr_error(std::string("Definition failed for '") + buf + "'"); + throw new value_expr_error(string("Definition failed for '") + buf + "'"); node.reset(new value_expr_t(value_expr_t::O_DEF)); node->set_left(new value_expr_t(value_expr_t::ARG_INDEX)); @@ -901,14 +905,14 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope, in.unget(); goto find_term; } - throw new value_expr_error(std::string("Unknown identifier '") + + throw new value_expr_error(string("Unknown identifier '") + buf + "'"); } else if (def->kind == value_expr_t::O_DEF) { node.reset(new value_expr_t(value_expr_t::O_REF)); node->set_left(def->right); - int count = 0; + unsigned int count = 0; if (have_args) { in.clear(); in.seekg(beg, std::ios::beg); @@ -1498,7 +1502,7 @@ value_expr_t * parse_value_expr(std::istream& in, scope_t * scope, if (! node.get()) { in.get(c); if (in.eof()) - throw new value_expr_error(std::string("Failed to parse value expression")); + throw new value_expr_error(string("Failed to parse value expression")); else unexpected(c); } else if (! (flags & PARSE_VALEXPR_PARTIAL)) { @@ -1513,8 +1517,8 @@ value_expr_t * parse_value_expr(std::istream& in, scope_t * scope, } valexpr_context::valexpr_context(const ledger::value_expr_t * _expr, - const std::string& desc) throw() - : expr(_expr), error_node(_expr), error_context(desc) + const string& desc) throw() + : error_context(desc), expr(_expr), error_node(_expr) { error_node->acquire(); } @@ -1539,12 +1543,12 @@ void valexpr_context::describe(std::ostream& out) const throw() unsigned long start = (long)out.tellp() - 1; unsigned long begin; unsigned long end; - bool found = ledger::write_value_expr(out, expr, true, + bool found = ledger::print_value_expr(out, expr, true, error_node, &begin, &end); out << std::endl; if (found) { out << " "; - for (int i = 0; i < end - start; i++) { + for (unsigned int i = 0; i < end - start; i++) { if (i >= begin - start) out << "^"; else @@ -1554,23 +1558,21 @@ void valexpr_context::describe(std::ostream& out) const throw() } } -bool write_value_expr(std::ostream& out, +bool print_value_expr(std::ostream& out, const value_expr_t * node, const bool relaxed, const value_expr_t * node_to_find, unsigned long * start_pos, unsigned long * end_pos) { - int arg_index = 0; bool found = false; - value_expr_t * expr; if (start_pos && node == node_to_find) { *start_pos = (long)out.tellp() - 1; found = true; } - std::string symbol; + string symbol; switch (node->kind) { case value_expr_t::ARG_INDEX: @@ -1578,9 +1580,9 @@ bool write_value_expr(std::ostream& out, break; case value_expr_t::CONSTANT: - switch (node->value->type) { + switch (node->value->type()) { case value_t::BOOLEAN: - assert(0); + assert(false); break; case value_t::DATETIME: out << '[' << *(node->value) << ']'; @@ -1593,9 +1595,10 @@ bool write_value_expr(std::ostream& out, if (! relaxed) out << '}'; break; - case value_t::BALANCE: - case value_t::BALANCE_PAIR: - assert(0); + //case value_t::BALANCE: + //case value_t::BALANCE_PAIR: + default: + assert(false); break; } break; @@ -1636,12 +1639,12 @@ bool write_value_expr(std::ostream& out, symbol = "now"; break; case value_expr_t::VALUE_EXPR: - if (write_value_expr(out, amount_expr.get(), relaxed, + if (print_value_expr(out, amount_expr.get(), relaxed, node_to_find, start_pos, end_pos)) found = true; break; case value_expr_t::TOTAL_EXPR: - if (write_value_expr(out, total_expr.get(), relaxed, + if (print_value_expr(out, total_expr.get(), relaxed, node_to_find, start_pos, end_pos)) found = true; break; @@ -1672,37 +1675,37 @@ bool write_value_expr(std::ostream& out, symbol = "dayof"; break; case value_expr_t::F_CODE_MASK: - out << "c/" << node->mask->pattern << "/"; + out << "c/" << node->mask->expr.str() << "/"; break; case value_expr_t::F_PAYEE_MASK: - out << "p/" << node->mask->pattern << "/"; + out << "p/" << node->mask->expr.str() << "/"; break; case value_expr_t::F_NOTE_MASK: - out << "e/" << node->mask->pattern << "/"; + out << "e/" << node->mask->expr.str() << "/"; break; case value_expr_t::F_ACCOUNT_MASK: - out << "W/" << node->mask->pattern << "/"; + out << "W/" << node->mask->expr.str() << "/"; break; case value_expr_t::F_SHORT_ACCOUNT_MASK: - out << "w/" << node->mask->pattern << "/"; + out << "w/" << node->mask->expr.str() << "/"; break; case value_expr_t::F_COMMODITY_MASK: - out << "C/" << node->mask->pattern << "/"; + out << "C/" << node->mask->expr.str() << "/"; break; case value_expr_t::O_NOT: out << "!"; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; break; case value_expr_t::O_NEG: out << "-"; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; break; case value_expr_t::O_PERC: out << "%"; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; break; @@ -1711,168 +1714,168 @@ bool write_value_expr(std::ostream& out, break; case value_expr_t::O_DEF: out << "<def args=\""; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << "\" value=\""; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << "\">"; break; case value_expr_t::O_REF: - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; if (node->right) { out << "("; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; } break; case value_expr_t::O_COM: - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ", "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; break; case value_expr_t::O_QUES: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " ? "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_COL: - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " : "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; break; case value_expr_t::O_AND: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " & "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_OR: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " | "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_NEQ: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " != "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_EQ: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " == "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_LT: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " < "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_LTE: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " <= "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_GT: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " > "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_GTE: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " >= "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_ADD: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " + "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_SUB: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " - "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_MUL: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " * "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::O_DIV: out << "("; - if (write_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->left, relaxed, node_to_find, start_pos, end_pos)) found = true; out << " / "; - if (write_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) + if (print_value_expr(out, node->right, relaxed, node_to_find, start_pos, end_pos)) found = true; out << ")"; break; case value_expr_t::LAST: default: - assert(0); + assert(false); break; } if (! symbol.empty()) { - if (commodity_t::find(symbol)) + if (amount_t::current_pool->find(symbol)) out << '@'; out << symbol; } @@ -1968,7 +1971,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node, case value_expr_t::LAST: default: - assert(0); + assert(false); break; } @@ -2,7 +2,7 @@ #define _VALEXPR_H #include "value.h" -#include "error.h" +#include "utils.h" #include "mask.h" #include <memory> @@ -22,16 +22,16 @@ struct details_t details_t() : entry(NULL), xact(NULL), account(NULL) {} details_t(const entry_t& _entry) : entry(&_entry), xact(NULL), account(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor details_t"); + DEBUG("ledger.memory.ctors", "ctor details_t"); } details_t(const transaction_t& _xact); details_t(const account_t& _account) : entry(NULL), xact(NULL), account(&_account) { - DEBUG_PRINT("ledger.memory.ctors", "ctor details_t"); + DEBUG("ledger.memory.ctors", "ctor details_t"); } #ifdef DEBUG_ENABLED ~details_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor details_t"); + DEBUG("ledger.memory.dtors", "dtor details_t"); } #endif }; @@ -134,26 +134,26 @@ struct value_expr_t value_expr_t(const kind_t _kind) : kind(_kind), refc(0), left(NULL), right(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t " << this); + DEBUG("ledger.memory.ctors", "ctor value_expr_t " << this); } ~value_expr_t(); void release() const { - DEBUG_PRINT("ledger.valexpr.memory", + DEBUG("ledger.valexpr.memory", "Releasing " << this << ", refc now " << refc - 1); assert(refc > 0); if (--refc == 0) delete this; } value_expr_t * acquire() { - DEBUG_PRINT("ledger.valexpr.memory", + DEBUG("ledger.valexpr.memory", "Acquiring " << this << ", refc now " << refc + 1); assert(refc >= 0); refc++; return this; } const value_expr_t * acquire() const { - DEBUG_PRINT("ledger.valexpr.memory", + DEBUG("ledger.valexpr.memory", "Acquiring " << this << ", refc now " << refc + 1); refc++; return this; @@ -186,7 +186,7 @@ struct value_expr_t private: value_expr_t(const value_expr_t&) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t (copy) " << this); + DEBUG("ledger.memory.ctors", "ctor value_expr_t (copy) " << this); } }; @@ -196,7 +196,7 @@ class valexpr_context : public error_context { const ledger::value_expr_t * error_node; valexpr_context(const ledger::value_expr_t * _expr, - const std::string& desc = "") throw(); + const string& desc = "") throw(); virtual ~valexpr_context() throw(); virtual void describe(std::ostream& out) const throw(); @@ -204,14 +204,14 @@ class valexpr_context : public error_context { class compute_error : public error { public: - compute_error(const std::string& reason, error_context * ctxt = NULL) throw() + compute_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~compute_error() throw() {} }; class value_expr_error : public error { public: - value_expr_error(const std::string& reason, + value_expr_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~value_expr_error() throw() {} @@ -221,24 +221,24 @@ struct scope_t { scope_t * parent; - typedef std::map<const std::string, value_expr_t *> symbol_map; - typedef std::pair<const std::string, value_expr_t *> symbol_pair; + typedef std::map<const string, value_expr_t *> symbol_map; + typedef std::pair<const string, value_expr_t *> symbol_pair; symbol_map symbols; scope_t(scope_t * _parent = NULL) : parent(_parent) { - DEBUG_PRINT("ledger.memory.ctors", "ctor scope_t"); + DEBUG("ledger.memory.ctors", "ctor scope_t"); } ~scope_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor scope_t"); + DEBUG("ledger.memory.dtors", "dtor scope_t"); for (symbol_map::iterator i = symbols.begin(); i != symbols.end(); i++) (*i).second->release(); } - void define(const std::string& name, value_expr_t * def) { - DEBUG_PRINT("ledger.valexpr.syms", + void define(const string& name, value_expr_t * def) { + DEBUG("ledger.valexpr.syms", "Defining '" << name << "' = " << def); std::pair<symbol_map::iterator, bool> result = symbols.insert(symbol_pair(name, def)); @@ -248,13 +248,13 @@ struct scope_t = symbols.insert(symbol_pair(name, def)); if (! result.second) { def->release(); - throw new compute_error(std::string("Redefinition of '") + + throw new compute_error(string("Redefinition of '") + name + "' in same scope"); } } def->acquire(); } - value_expr_t * lookup(const std::string& name) { + value_expr_t * lookup(const string& name) { symbol_map::const_iterator i = symbols.find(name); if (i != symbols.end()) return (*i).second; @@ -286,9 +286,9 @@ value_expr_t * parse_value_expr(std::istream& in, const short flags = PARSE_VALEXPR_RELAXED); inline value_expr_t * -parse_value_expr(const std::string& str, - scope_t * scope = NULL, - const short flags = PARSE_VALEXPR_RELAXED) { +parse_value_expr(const string& str, + scope_t * scope = NULL, + const short flags = PARSE_VALEXPR_RELAXED) { std::istringstream stream(str); try { return parse_value_expr(stream, scope, flags); @@ -305,13 +305,13 @@ inline value_expr_t * parse_value_expr(const char * p, scope_t * scope = NULL, const short flags = PARSE_VALEXPR_RELAXED) { - return parse_value_expr(std::string(p), scope, flags); + return parse_value_expr(string(p), scope, flags); } void dump_value_expr(std::ostream& out, const value_expr_t * node, const int depth = 0); -bool write_value_expr(std::ostream& out, +bool print_value_expr(std::ostream& out, const value_expr_t * node, const bool relaxed = true, const value_expr_t * node_to_find = NULL, @@ -354,12 +354,12 @@ class value_expr { value_expr_t * ptr; public: - std::string expr; + string expr; value_expr() : ptr(NULL) {} - value_expr(const std::string& _expr) : expr(_expr) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr"); + value_expr(const string& _expr) : expr(_expr) { + DEBUG("ledger.memory.ctors", "ctor value_expr"); if (! _expr.empty()) ptr = parse_value_expr(expr)->acquire(); else @@ -367,20 +367,20 @@ public: } value_expr(value_expr_t * _ptr) : ptr(_ptr ? _ptr->acquire(): NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr"); + DEBUG("ledger.memory.ctors", "ctor value_expr"); } value_expr(const value_expr& other) : ptr(other.ptr ? other.ptr->acquire() : NULL), expr(other.expr) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr"); + DEBUG("ledger.memory.ctors", "ctor value_expr"); } virtual ~value_expr() { - DEBUG_PRINT("ledger.memory.dtors", "dtor value_expr"); + DEBUG("ledger.memory.dtors", "dtor value_expr"); if (ptr) ptr->release(); } - value_expr& operator=(const std::string& _expr) { + value_expr& operator=(const string& _expr) { expr = _expr; reset(parse_value_expr(expr)); return *this; @@ -399,7 +399,7 @@ public: operator bool() const throw() { return ptr != NULL; } - operator std::string() const throw() { + operator string() const throw() { return expr; } operator value_expr_t *() const throw() { @@ -439,7 +439,7 @@ public: return temp; } - friend bool write_value_expr(std::ostream& out, + friend bool print_value_expr(std::ostream& out, const value_expr_t * node, const value_expr_t * node_to_find, unsigned long * start_pos, @@ -474,7 +474,7 @@ inline value_t compute_total(const details_t& details = details_t()) { value_expr_t * parse_boolean_expr(std::istream& in, scope_t * scope, const short flags); -inline void parse_value_definition(const std::string& str, +inline void parse_value_definition(const string& str, scope_t * scope = NULL) { std::istringstream def(str); value_expr expr @@ -490,18 +490,18 @@ class item_predicate public: const value_expr_t * predicate; - item_predicate(const std::string& _predicate) : predicate(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>"); + item_predicate(const string& _predicate) : predicate(NULL) { + DEBUG("ledger.memory.ctors", "ctor item_predicate<T>"); if (! _predicate.empty()) predicate = parse_value_expr(_predicate)->acquire(); } item_predicate(const value_expr_t * _predicate = NULL) : predicate(_predicate->acquire()) { - DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>"); + DEBUG("ledger.memory.ctors", "ctor item_predicate<T>"); } ~item_predicate() { - DEBUG_PRINT("ledger.memory.dtors", "dtor item_predicate<T>"); + DEBUG("ledger.memory.dtors", "dtor item_predicate<T>"); if (predicate) predicate->release(); } @@ -79,7 +79,7 @@ void value_t::initialize() *reinterpret_cast<bool *>(false_value->data) = false; BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(bool)); - BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(moment_t)); + BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(datetime_t)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(long)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(amount_t)); BOOST_STATIC_ASSERT(sizeof(amount_t) >= sizeof(balance_t *)); @@ -91,8 +91,8 @@ void value_t::initialize() #if 0 DEBUG_(std::setw(3) << std::right << sizeof(bool) << " sizeof(bool)"); - DEBUG_(std::setw(3) << std::right << sizeof(moment_t) - << " sizeof(moment_t)"); + DEBUG_(std::setw(3) << std::right << sizeof(datetime_t) + << " sizeof(datetime_t)"); DEBUG_(std::setw(3) << std::right << sizeof(long) << " sizeof(long)"); DEBUG_(std::setw(3) << std::right << sizeof(amount_t) @@ -151,7 +151,7 @@ value_t::operator bool() const case INTEGER: return as_long(); case DATETIME: - return is_valid_moment(as_datetime()); + return is_valid(as_datetime()); case AMOUNT: return as_amount(); case BALANCE: @@ -194,7 +194,7 @@ long value_t::to_long() const } } -moment_t value_t::to_datetime() const +datetime_t value_t::to_datetime() const { if (is_datetime()) { return as_datetime(); @@ -1119,7 +1119,7 @@ bool value_t::is_realzero() const case INTEGER: return as_long() == 0; case DATETIME: - return ! is_valid_moment(as_datetime()); + return ! is_valid(as_datetime()); case AMOUNT: return as_amount().is_realzero(); case BALANCE: @@ -1142,7 +1142,7 @@ bool value_t::is_realzero() const return true; } -value_t value_t::value(const optional<moment_t>& moment) const +value_t value_t::value(const optional<datetime_t>& moment) const { switch (type()) { case INTEGER: @@ -1194,6 +1194,29 @@ void value_t::in_place_reduce() throw_(value_error, "Cannot reduce " << label()); } +value_t value_t::abs() const +{ + switch (type()) { + case INTEGER: { + long val = const_cast<value_t&>(*this).as_long_lval(); + if (val < 0) + return - val; + return val; + } + case AMOUNT: + return const_cast<value_t&>(*this).as_amount_lval().abs(); + case BALANCE: + return const_cast<value_t&>(*this).as_balance_lval().abs(); + case BALANCE_PAIR: + return const_cast<value_t&>(*this).as_balance_pair_lval().abs(); + default: + break; + } + + throw_(value_error, "Cannot abs " << label()); + return value_t(); +} + value_t value_t::round() const { switch (type()) { @@ -1249,7 +1272,7 @@ value_t value_t::annotated_date() const return *this; case AMOUNT: { - optional<moment_t> temp = as_amount().annotation_details().date; + optional<datetime_t> temp = as_amount().annotation_details().date; if (! temp) return false; return *temp; @@ -1431,4 +1454,44 @@ void value_t::print(std::ostream& out, const int first_width, } } +void value_context::describe(std::ostream& out) const throw() +{ + if (! desc.empty()) + out << desc << std::endl; + + balance_t * ptr = NULL; + + out << std::right; + out.width(20); + + switch (bal.type()) { + case value_t::BOOLEAN: + out << (const_cast<value_t&>(bal).as_boolean_lval() ? "true" : "false"); + break; + case value_t::INTEGER: + out << const_cast<value_t&>(bal).as_long_lval(); + break; + case value_t::DATETIME: + out << const_cast<value_t&>(bal).as_datetime_lval(); + break; + case value_t::AMOUNT: + out << const_cast<value_t&>(bal).as_amount_lval(); + break; + case value_t::BALANCE: + ptr = &(const_cast<value_t&>(bal).as_balance_lval()); + // fall through... + + case value_t::BALANCE_PAIR: + if (! ptr) + ptr = &(const_cast<value_t&>(bal).as_balance_pair_lval().quantity()); + + ptr->print(out, 20); + break; + default: + assert(0); + break; + } + out << std::endl; +} + } // namespace ledger @@ -266,8 +266,8 @@ public: TRACE_CTOR(value_t, "const long"); set_long(val); } - value_t(const moment_t val) { - TRACE_CTOR(value_t, "const moment_t"); + value_t(const datetime_t val) { + TRACE_CTOR(value_t, "const datetime_t"); set_datetime(val); } value_t(const double val) { @@ -366,6 +366,8 @@ public: value_t& operator*=(const value_t& val); value_t& operator/=(const value_t& val); + // jww (2008-04-24): This could be expensive; perhaps it should be + // optional<amount_t&>&? value_t& add(const amount_t& amount, const optional<amount_t>& cost = none); @@ -394,7 +396,7 @@ public: } void in_place_reduce(); - value_t value(const optional<moment_t>& moment = none) const; + value_t value(const optional<datetime_t>& moment = none) const; /** * Truth tests. @@ -500,18 +502,18 @@ public: bool is_datetime() const { return is_type(DATETIME); } - moment_t& as_datetime_lval() { + datetime_t& as_datetime_lval() { assert(is_datetime()); _dup(); - return *(moment_t *) storage->data; + return *(datetime_t *) storage->data; } - const moment_t& as_datetime() const { + const datetime_t& as_datetime() const { assert(is_datetime()); - return *(moment_t *) storage->data; + return *(datetime_t *) storage->data; } - void set_datetime(const moment_t& val) { + void set_datetime(const datetime_t& val) { set_type(DATETIME); - new((moment_t *) storage->data) moment_t(val); + new((datetime_t *) storage->data) datetime_t(val); } bool is_amount() const { @@ -650,7 +652,7 @@ public: */ bool to_boolean() const; long to_long() const; - moment_t to_datetime() const; + datetime_t to_datetime() const; amount_t to_amount() const; balance_t to_balance() const; balance_pair_t to_balance_pair() const; @@ -826,6 +828,17 @@ inline std::ostream& operator<<(std::ostream& out, const value_t& val) { return out; } +class value_context : public error_context +{ + value_t bal; + public: + value_context(const value_t& _bal, const string& desc = "") throw() + : error_context(desc), bal(_bal) {} + virtual ~value_context() throw() {} + + virtual void describe(std::ostream& out) const throw(); +}; + DECLARE_EXCEPTION(error, value_error); } // namespace ledger @@ -44,8 +44,9 @@ void add_transaction_to(const transaction_t& xact, value_t& value) transaction_xdata_(xact).dflags & TRANSACTION_COMPOUND) { value += transaction_xdata_(xact).value; } - else if (xact.cost || ! value.realzero()) { - value.add(xact.amount, xact.cost); + else if (xact.cost || ! value.is_realzero()) { + // jww (2008-04-24): Is this costly? + value.add(xact.amount, xact.cost ? optional<amount_t>(*xact.cost) : none); } else { value = xact.amount; @@ -211,12 +212,12 @@ void handle_value(const value_t& value, transaction_xdata_t& xdata(transaction_xdata(xact)); - if (date) + if (is_valid(date)) xdata.date = date; value_t temp(value); - switch (value.type) { + switch (value.type()) { case value_t::BOOLEAN: case value_t::DATETIME: case value_t::INTEGER: @@ -224,7 +225,7 @@ void handle_value(const value_t& value, // fall through... case value_t::AMOUNT: - xact.amount = *((amount_t *) temp.data); + xact.amount = temp.as_amount_lval(); break; case value_t::BALANCE: @@ -232,6 +233,10 @@ void handle_value(const value_t& value, xdata.value = temp; flags |= TRANSACTION_COMPOUND; break; + + default: + assert(false); // jww (2008-04-24): What to do here? + break; } if (flags) @@ -320,7 +325,10 @@ void changed_value_transactions::output_diff(const datetime_t& current) transaction_xdata(*last_xact).date = current; compute_total(cur_bal, details_t(*last_xact)); cur_bal.round(); + // jww (2008-04-24): What does this do? +#if 0 transaction_xdata(*last_xact).date = 0; +#endif if (value_t diff = cur_bal - last_balance) { entry_temps.push_back(entry_t()); @@ -370,11 +378,16 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt) { std::ostringstream out_date; if (! spec_fmt) { - std::string fmt = "- "; - fmt += date_t::output_format; + string fmt = "- "; + fmt += output_time_format; // jww (2008-04-24): output_date_format? + // jww (2008-04-24): There is no date output function? +#if 0 finish.write(out_date, fmt); +#endif } else { +#if 0 finish.write(out_date, spec_fmt); +#endif } entry_temps.push_back(entry_t()); @@ -393,9 +406,9 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt) void subtotal_transactions::operator()(transaction_t& xact) { - if (! start || xact.date() < start) + if (! is_valid(start) || xact.date() < start) start = xact.date(); - if (! finish || xact.date() > finish) + if (! is_valid(finish) || xact.date() > finish) finish = xact.date(); account_t * acct = xact_account(xact); @@ -434,8 +447,13 @@ void interval_transactions::report_subtotal(const datetime_t& moment) assert(last_xact); start = interval.begin; - if (moment) + if (is_valid(moment)) + // jww (2008-04-24): How to change this back into a datetime? +#if 0 finish = moment - 86400L; +#else + ; +#endif else finish = last_xact->date(); @@ -448,13 +466,13 @@ void interval_transactions::operator()(transaction_t& xact) { const datetime_t date = xact.date(); - if ((interval.begin && date < interval.begin) || - (interval.end && date >= interval.end)) + if ((is_valid(interval.begin) && date < interval.begin) || + (is_valid(interval.end) && date >= interval.end)) return; if (interval) { if (! started) { - if (! interval.begin) + if (! is_valid(interval.begin)) interval.start(date); start = interval.begin; started = true; @@ -572,7 +590,10 @@ void set_code_as_payee::operator()(transaction_t& xact) void dow_transactions::flush() { for (int i = 0; i < 7; i++) { + // jww (2008-04-24): What to use here? +#if 0 start = finish = 0; +#endif for (transactions_list::iterator d = days_of_the_week[i].begin(); d != days_of_the_week[i].end(); d++) @@ -614,19 +635,22 @@ void budget_transactions::report_budget_items(const datetime_t& moment) i != pending_xacts.end(); i++) { datetime_t& begin = (*i).first.begin; - if (! begin) { + if (! is_valid(begin)) { (*i).first.start(moment); begin = (*i).first.begin; } if (begin < moment && - (! (*i).first.end || begin < (*i).first.end)) { + (! is_valid((*i).first.end) || begin < (*i).first.end)) { transaction_t& xact = *(*i).second; - DEBUG_PRINT("ledger.walk.budget", "Reporting budget for " + DEBUG("ledger.walk.budget", "Reporting budget for " << xact_account(xact)->fullname()); - DEBUG_PRINT_TIME("ledger.walk.budget", begin); - DEBUG_PRINT_TIME("ledger.walk.budget", moment); +#if 0 + // jww (2008-04-24): Need a new debug macro here + DEBUG_TIME("ledger.walk.budget", begin); + DEBUG_TIME("ledger.walk.budget", moment); +#endif entry_temps.push_back(entry_t()); entry_t& entry = entry_temps.back(); @@ -686,11 +710,11 @@ void forecast_transactions::add_transaction(const interval_t& period, generate_transactions::add_transaction(period, xact); interval_t& i = pending_xacts.back().first; - if (! i.begin) { - i.start(datetime_t::now); + if (! is_valid(i.begin)) { + i.start(current_moment); i.begin = i.increment(i.begin); } else { - while (i.begin < datetime_t::now) + while (i.begin < current_moment) i.begin = i.increment(i.begin); } } @@ -710,7 +734,7 @@ void forecast_transactions::flush() datetime_t& begin = (*least).first.begin; - if ((*least).first.end && begin >= (*least).first.end) { + if (is_valid((*least).first.end) && begin >= (*least).first.end) { pending_xacts.erase(least); passed.remove((*least).second); continue; @@ -731,8 +755,9 @@ void forecast_transactions::flush() entry.add_transaction(&temp); datetime_t next = (*least).first.increment(begin); + // jww (2008-04-24): Does seconds() here give the total seconds? if (next < begin || // wraparound - (last && (next - last) > 365 * 5 * 24 * 3600)) + (is_valid(last) && (next - last).seconds() > 365 * 5 * 24 * 3600)) break; begin = next; @@ -811,7 +836,7 @@ void sum_accounts(account_t& account) value_t result; compute_amount(result, details_t(account)); - if (! result.realzero()) + if (! result.is_realzero()) xdata.total += result; xdata.total_count += xdata.count; } @@ -854,7 +879,7 @@ void walk_accounts(account_t& account, void walk_accounts(account_t& account, item_handler<account_t>& handler, - const std::string& sort_string) + const string& sort_string) { if (! sort_string.empty()) { value_expr sort_order; @@ -865,25 +890,26 @@ void walk_accounts(account_t& account, } } -void walk_commodities(commodities_map& commodities, +void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, item_handler<transaction_t>& handler) { std::list<transaction_t> xact_temps; std::list<entry_t> entry_temps; std::list<account_t> acct_temps; - for (commodities_map::iterator i = commodities.begin(); + for (commodity_pool_t::commodities_by_ident::iterator + i = commodities.begin(); i != commodities.end(); i++) { - if ((*i).second->flags() & COMMODITY_STYLE_NOMARKET) + if ((*i)->has_flags(COMMODITY_STYLE_NOMARKET)) continue; entry_temps.push_back(entry_t()); - acct_temps.push_back(account_t(NULL, (*i).second->symbol())); + acct_temps.push_back(account_t(NULL, (*i)->symbol())); - if ((*i).second->history()) - for (history_map::iterator j = (*i).second->history()->prices.begin(); - j != (*i).second->history()->prices.end(); + if ((*i)->history()) + for (commodity_t::history_map::iterator j = (*i)->history()->prices.begin(); + j != (*i)->history()->prices.end(); j++) { entry_temps.back()._date = (*j).first; @@ -4,7 +4,6 @@ #include "journal.h" #include "balance.h" #include "valexpr.h" -#include "datetime.h" #include <iostream> #include <fstream> @@ -18,13 +17,13 @@ struct item_handler { public: item_handler() : handler(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor item_handler<T>"); + DEBUG("ledger.memory.ctors", "ctor item_handler<T>"); } item_handler(item_handler * _handler) : handler(_handler) { - DEBUG_PRINT("ledger.memory.ctors", "ctor item_handler<T>"); + DEBUG("ledger.memory.ctors", "ctor item_handler<T>"); } virtual ~item_handler() { - DEBUG_PRINT("ledger.memory.dtors", "dtor item_handler<T>"); + DEBUG("ledger.memory.dtors", "dtor item_handler<T>"); } virtual void flush() { @@ -99,11 +98,11 @@ struct transaction_xdata_t transaction_xdata_t() : index(0), dflags(0), account(NULL), ptr(NULL), component_xacts(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_xdata_t " << this); + DEBUG("ledger.memory.ctors", "ctor transaction_xdata_t " << this); } ~transaction_xdata_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_xdata_t " << this); + DEBUG("ledger.memory.dtors", "dtor transaction_xdata_t " << this); if (component_xacts) delete component_xacts; } @@ -255,7 +254,7 @@ class sort_transactions : public item_handler<transaction_t> sort_order(_sort_order->acquire()) {} sort_transactions(item_handler<transaction_t> * handler, - const std::string& _sort_order) + const string& _sort_order) : item_handler<transaction_t>(handler) { assert(! _sort_order.empty()); sort_order = parse_value_expr(_sort_order)->acquire(); @@ -289,7 +288,7 @@ class sort_entries : public item_handler<transaction_t> : sorter(handler, _sort_order) {} sort_entries(item_handler<transaction_t> * handler, - const std::string& _sort_order) + const string& _sort_order) : sorter(handler, _sort_order) {} virtual void flush() { @@ -317,7 +316,7 @@ class filter_transactions : public item_handler<transaction_t> : item_handler<transaction_t>(handler), pred(predicate) {} filter_transactions(item_handler<transaction_t> * handler, - const std::string& predicate) + const string& predicate) : item_handler<transaction_t>(handler), pred(predicate) {} virtual void operator()(transaction_t& xact) { @@ -397,7 +396,7 @@ class component_transactions : public item_handler<transaction_t> : item_handler<transaction_t>(handler), pred(predicate) {} component_transactions(item_handler<transaction_t> * handler, - const std::string& predicate) + const string& predicate) : item_handler<transaction_t>(handler), pred(predicate) {} virtual void operator()(transaction_t& xact); @@ -445,7 +444,7 @@ class changed_value_transactions : public item_handler<transaction_t> virtual void flush() { if (last_xact) { - output_diff(datetime_t::now); + output_diff(current_moment); last_xact = NULL; } item_handler<transaction_t>::flush(); @@ -470,8 +469,8 @@ class subtotal_transactions : public item_handler<transaction_t> : account(av.account), value(av.value) {} }; - typedef std::map<std::string, acct_value_t> values_map; - typedef std::pair<std::string, acct_value_t> values_pair; + typedef std::map<string, acct_value_t> values_map; + typedef std::pair<string, acct_value_t> values_pair; protected: values_map values; @@ -490,7 +489,7 @@ class subtotal_transactions : public item_handler<transaction_t> remember_components(_remember_components) {} #ifdef DEBUG_ENABLED subtotal_transactions(const subtotal_transactions&) { - assert(0); + assert(false); } #endif virtual ~subtotal_transactions() { @@ -509,7 +508,7 @@ class subtotal_transactions : public item_handler<transaction_t> class interval_expr_error : public error { public: - interval_expr_error(const std::string& reason, + interval_expr_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~interval_expr_error() throw() {} @@ -529,7 +528,7 @@ class interval_transactions : public subtotal_transactions interval(_interval), last_xact(NULL), started(false) {} interval_transactions(item_handler<transaction_t> * _handler, - const std::string& _interval, + const string& _interval, bool remember_components = false) : subtotal_transactions(_handler, remember_components), interval(_interval), last_xact(NULL), started(false) {} @@ -546,8 +545,8 @@ class interval_transactions : public subtotal_transactions class by_payee_transactions : public item_handler<transaction_t> { - typedef std::map<std::string, subtotal_transactions *> payee_subtotals_map; - typedef std::pair<std::string, subtotal_transactions *> payee_subtotals_pair; + typedef std::map<string, subtotal_transactions *> payee_subtotals_map; + typedef std::pair<string, subtotal_transactions *> payee_subtotals_pair; payee_subtotals_map payee_subtotals; bool remember_components; @@ -606,7 +605,7 @@ class dow_transactions : public subtotal_transactions virtual void flush(); virtual void operator()(transaction_t& xact) { - days_of_the_week[xact.date().wday()].push_back(&xact); + days_of_the_week[xact.date().date().day_of_week()].push_back(&xact); } }; @@ -661,7 +660,7 @@ class forecast_transactions : public generate_transactions : generate_transactions(handler), pred(predicate) {} forecast_transactions(item_handler<transaction_t> * handler, - const std::string& predicate) + const string& predicate) : generate_transactions(handler), pred(predicate) {} virtual void add_transaction(const interval_t& period, @@ -729,11 +728,11 @@ void walk_accounts(account_t& account, const value_expr_t * sort_order = NULL); void walk_accounts(account_t& account, item_handler<account_t>& handler, - const std::string& sort_string); + const string& sort_string); ////////////////////////////////////////////////////////////////////// -void walk_commodities(commodities_map& commodities, +void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, item_handler<transaction_t>& handler); inline void clear_journal_xdata(journal_t * journal) { @@ -1,19 +1,6 @@ #include "xml.h" #include "journal.h" -#include "datetime.h" -#include "error.h" - -#include <iostream> -#include <sstream> -#include <cstring> - -extern "C" { -#if defined(HAVE_EXPAT) -#include <expat.h> // expat XML parser -#elif defined(HAVE_XMLPARSE) -#include <xmlparse.h> // expat XML parser -#endif -} +#include "utils.h" namespace ledger { @@ -25,13 +12,13 @@ static unsigned int count; static journal_t * curr_journal; static entry_t * curr_entry; static commodity_t * curr_comm; -static std::string comm_flags; +static string comm_flags; static transaction_t::state_t curr_state; -static std::string data; +static string data; static bool ignore; -static std::string have_error; +static string have_error; static void startElement(void *userData, const char *name, const char **attrs) { @@ -50,7 +37,7 @@ static void startElement(void *userData, const char *name, const char **attrs) curr_entry->transactions.back()->state = curr_state; } else if (std::strcmp(name, "commodity") == 0) { - if (std::string(attrs[0]) == "flags") + if (string(attrs[0]) == "flags") comm_flags = attrs[1]; } else if (std::strcmp(name, "total") == 0) { @@ -83,10 +70,10 @@ static void endElement(void *userData, const char *name) curr_entry = NULL; } else if (std::strcmp(name, "en:date") == 0) { - curr_entry->_date = data; + curr_entry->_date = parse_datetime(data); } else if (std::strcmp(name, "en:date_eff") == 0) { - curr_entry->_date_eff = data; + curr_entry->_date_eff = parse_datetime(data); } else if (std::strcmp(name, "en:code") == 0) { curr_entry->code = data; @@ -117,11 +104,11 @@ static void endElement(void *userData, const char *name) } else if (std::strcmp(name, "symbol") == 0) { assert(! curr_comm); - curr_comm = commodity_t::find_or_create(data); + curr_comm = amount_t::current_pool->find_or_create(data); assert(curr_comm); curr_comm->add_flags(COMMODITY_STYLE_SUFFIXED); if (! comm_flags.empty()) { - for (std::string::size_type i = 0, l = comm_flags.length(); i < l; i++) { + for (string::size_type i = 0, l = comm_flags.length(); i < l; i++) { switch (comm_flags[i]) { case 'P': curr_comm->drop_flags(COMMODITY_STYLE_SUFFIXED); break; case 'S': curr_comm->add_flags(COMMODITY_STYLE_SEPARATED); break; @@ -148,8 +135,8 @@ static void endElement(void *userData, const char *name) else if (std::strcmp(name, "quantity") == 0) { curr_entry->transactions.back()->amount.parse(data); if (curr_comm) { - std::string::size_type i = data.find('.'); - if (i != std::string::npos) { + string::size_type i = data.find('.'); + if (i != string::npos) { int precision = data.length() - i - 1; if (precision > curr_comm->precision()) curr_comm->set_precision(precision); @@ -166,7 +153,7 @@ static void endElement(void *userData, const char *name) static void dataHandler(void *userData, const char *s, int len) { if (! ignore) - data = std::string(s, len); + data = string(s, len); } bool xml_parser_t::test(std::istream& in) const @@ -192,11 +179,11 @@ bool xml_parser_t::test(std::istream& in) const return true; } -unsigned int xml_parser_t::parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master, - const std::string * original_file) +unsigned int xml_parser_t::parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master, + const path * original_file) { char buf[BUFSIZ]; @@ -206,7 +193,6 @@ unsigned int xml_parser_t::parse(std::istream& in, curr_comm = NULL; ignore = false; - unsigned int offset = 2; XML_Parser parser = XML_ParserCreate(NULL); current_parser = parser; @@ -221,20 +207,20 @@ unsigned int xml_parser_t::parse(std::istream& in, result = XML_Parse(parser, buf, std::strlen(buf), in.eof()); } catch (const std::exception& err) { - unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; + //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; XML_ParserFree(parser); throw new parse_error(err.what()); } if (! have_error.empty()) { - unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; + //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; parse_error err(have_error); std::cerr << "Error: " << err.what() << std::endl; have_error = ""; } if (! result) { - unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; + //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; const char * err = XML_ErrorString(XML_GetErrorCode(parser)); XML_ParserFree(parser); throw new parse_error(err); @@ -290,46 +276,49 @@ void xml_write_amount(std::ostream& out, const amount_t& amount, void xml_write_value(std::ostream& out, const value_t& value, const int depth = 0) { - balance_t * bal = NULL; + const balance_t * bal = NULL; for (int i = 0; i < depth; i++) out << ' '; out << "<value type=\""; - switch (value.type) { + switch (value.type()) { case value_t::BOOLEAN: out << "boolean"; break; case value_t::INTEGER: out << "integer"; break; case value_t::AMOUNT: out << "amount"; break; case value_t::BALANCE: case value_t::BALANCE_PAIR: out << "balance"; break; + default: + assert(false); + break; } out << "\">\n"; - switch (value.type) { + switch (value.type()) { case value_t::BOOLEAN: for (int i = 0; i < depth + 2; i++) out << ' '; - out << "<boolean>" << *((bool *) value.data) << "</boolean>\n"; + out << "<boolean>" << value.as_boolean() << "</boolean>\n"; break; case value_t::INTEGER: for (int i = 0; i < depth + 2; i++) out << ' '; - out << "<integer>" << *((long *) value.data) << "</integer>\n"; + out << "<integer>" << value.as_long() << "</integer>\n"; break; case value_t::AMOUNT: - xml_write_amount(out, *((amount_t *) value.data), depth + 2); + xml_write_amount(out, value.as_amount(), depth + 2); break; case value_t::BALANCE: - bal = (balance_t *) value.data; + bal = &(value.as_balance()); // fall through... case value_t::BALANCE_PAIR: if (! bal) - bal = &((balance_pair_t *) value.data)->quantity; + bal = &(value.as_balance_pair().quantity()); for (int i = 0; i < depth + 2; i++) out << ' '; out << "<balance>\n"; - for (amounts_map::const_iterator i = bal->amounts.begin(); + for (balance_t::amounts_map::const_iterator i = bal->amounts.begin(); i != bal->amounts.end(); i++) xml_write_amount(out, (*i).second, depth + 4); @@ -339,7 +328,7 @@ void xml_write_value(std::ostream& out, const value_t& value, break; default: - assert(0); + assert(false); break; } @@ -347,7 +336,7 @@ void xml_write_value(std::ostream& out, const value_t& value, out << "</value>\n"; } -void output_xml_string(std::ostream& out, const std::string& str) +void output_xml_string(std::ostream& out, const string& str) { for (const char * s = str.c_str(); *s; s++) { switch (*s) { @@ -369,14 +358,17 @@ void output_xml_string(std::ostream& out, const std::string& str) void format_xml_entries::format_last_entry() { +#if 0 + // jww (2008-05-08): Need to format these dates output_stream << " <entry>\n" << " <en:date>" << last_entry->_date.to_string("%Y/%m/%d") << "</en:date>\n"; - if (last_entry->_date_eff) + if (is_valid(last_entry->_date_eff)) output_stream << " <en:date_eff>" << last_entry->_date_eff.to_string("%Y/%m/%d") << "</en:date_eff>\n"; +#endif if (! last_entry->code.empty()) { output_stream << " <en:code>"; @@ -403,15 +395,18 @@ void format_xml_entries::format_last_entry() output_stream << " <transaction>\n"; +#if 0 + // jww (2008-05-08): Need to format these if ((*i)->_date) output_stream << " <tr:date>" << (*i)->_date.to_string("%Y/%m/%d") << "</tr:date>\n"; - if ((*i)->_date_eff) + if (is_valid((*i)->_date_eff)) output_stream << " <tr:date_eff>" << (*i)->_date_eff.to_string("%Y/%m/%d") << "</tr:date_eff>\n"; +#endif if ((*i)->state == transaction_t::CLEARED) output_stream << " <tr:cleared/>\n"; @@ -424,7 +419,7 @@ void format_xml_entries::format_last_entry() output_stream << " <tr:generated/>\n"; if ((*i)->account) { - std::string name = (*i)->account->fullname(); + string name = (*i)->account->fullname(); if (name == "<Total>") name = "[TOTAL]"; else if (name == "<Unknown>") @@ -13,11 +13,11 @@ class xml_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - config_t& config, - journal_t * journal, - account_t * master = NULL, - const std::string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + config_t& config, + journal_t * journal, + account_t * master = NULL, + const path * original_file = NULL); }; #endif |