diff options
-rw-r--r-- | Makefile.am | 8 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | amount.cc | 86 | ||||
-rw-r--r-- | amount.h | 10 | ||||
-rw-r--r-- | binary.cc | 2 | ||||
-rw-r--r-- | main.cc | 55 | ||||
-rw-r--r-- | ofx.cc | 7 | ||||
-rw-r--r-- | register.cc | 16 | ||||
-rw-r--r-- | session.cc | 36 | ||||
-rw-r--r-- | session.h | 24 | ||||
-rw-r--r-- | tests/python/corelib/numerics/BasicAmount.py | 4 | ||||
-rw-r--r-- | textual.cc | 38 | ||||
-rw-r--r-- | utils.cc | 367 | ||||
-rw-r--r-- | utils.h | 87 | ||||
-rw-r--r-- | xpath.cc | 21 | ||||
-rw-r--r-- | xpath.h | 27 |
16 files changed, 516 insertions, 276 deletions
diff --git a/Makefile.am b/Makefile.am index 18ce448f..f01256ca 100644 --- a/Makefile.am +++ b/Makefile.am @@ -180,18 +180,11 @@ if HAVE_LIBOFX PYLIBS += ofx endif -if DEBUG -DEBUG_LEVEL = 4 -else -DEBUG_LEVEL = 0 -endif - ledger.so: pyledger.cc libledger.la gdtoa/libgdtoa.la libpyledger.la SRCDIR="$(srcdir)" \ CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \ LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \ PYLIBS="$(PYLIBS)" \ - DEBUG_LEVEL="$(DEBUG_LEVEL)" \ python $(srcdir)/setup.py build --build-lib=. install-exec-hook: @@ -199,7 +192,6 @@ install-exec-hook: CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \ LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \ PYLIBS="$(PYLIBS)" \ - DEBUG_LEVEL="$(DEBUG_LEVEL)" \ python $(srcdir)/setup.py install --prefix=$(prefix) endif diff --git a/Makefile.in b/Makefile.in index 68c1e35e..84f1e89a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -418,8 +418,6 @@ lisp_LISP = ledger.el timeclock.el @HAVE_BOOST_PYTHON_TRUE@ boost_regex boost_python gmp \ @HAVE_BOOST_PYTHON_TRUE@ $(am__append_14) $(am__append_15) \ @HAVE_BOOST_PYTHON_TRUE@ $(am__append_16) -@DEBUG_FALSE@@HAVE_BOOST_PYTHON_TRUE@DEBUG_LEVEL = 0 -@DEBUG_TRUE@@HAVE_BOOST_PYTHON_TRUE@DEBUG_LEVEL = 4 UnitTests_SOURCES = tests/UnitTests.cc \ \ tests/corelib/numerics/BasicAmount.cc \ @@ -1723,7 +1721,6 @@ dist-hook: @HAVE_BOOST_PYTHON_TRUE@ CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \ @HAVE_BOOST_PYTHON_TRUE@ LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \ @HAVE_BOOST_PYTHON_TRUE@ PYLIBS="$(PYLIBS)" \ -@HAVE_BOOST_PYTHON_TRUE@ DEBUG_LEVEL="$(DEBUG_LEVEL)" \ @HAVE_BOOST_PYTHON_TRUE@ python $(srcdir)/setup.py build --build-lib=. @HAVE_BOOST_PYTHON_TRUE@install-exec-hook: @@ -1731,7 +1728,6 @@ dist-hook: @HAVE_BOOST_PYTHON_TRUE@ CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \ @HAVE_BOOST_PYTHON_TRUE@ LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \ @HAVE_BOOST_PYTHON_TRUE@ PYLIBS="$(PYLIBS)" \ -@HAVE_BOOST_PYTHON_TRUE@ DEBUG_LEVEL="$(DEBUG_LEVEL)" \ @HAVE_BOOST_PYTHON_TRUE@ python $(srcdir)/setup.py install --prefix=$(prefix) PyUnitTests: PyUnitTests.py @@ -106,11 +106,11 @@ base_commodities_map commodity_base_t::commodities; commodity_base_t::updater_t * commodity_base_t::updater = NULL; -commodities_map commodity_t::commodities; -commodities_array commodity_t::commodities_by_ident; -bool commodity_t::commodities_sorted = false; -commodity_t * commodity_t::null_commodity; -commodity_t * commodity_t::default_commodity = NULL; +commodities_map commodity_t::commodities; +commodities_array * commodity_t::commodities_by_ident; +bool commodity_t::commodities_sorted = false; +commodity_t * commodity_t::null_commodity; +commodity_t * commodity_t::default_commodity = NULL; #endif void amount_t::initialize() @@ -123,6 +123,8 @@ void amount_t::initialize() commodity_base_t::updater = NULL; + commodity_t::commodities_by_ident = new commodities_array; + commodity_t::default_commodity = NULL; commodity_t::null_commodity = commodity_t::create(""); commodity_t::null_commodity->add_flags(COMMODITY_STYLE_NOMARKET | @@ -159,7 +161,9 @@ void amount_t::shutdown() commodity_base_t::commodities.clear(); commodity_t::commodities.clear(); - commodity_t::commodities_by_ident.clear(); + + delete commodity_t::commodities_by_ident; + commodity_t::commodities_by_ident = NULL; commodity_t::null_commodity = NULL; commodity_t::default_commodity = NULL; @@ -337,7 +341,7 @@ amount_t::amount_t(const double val) void amount_t::_release() { DEBUG_("amounts.refs", - quantity << " ref--, now " << (quantity->ref - 1)); + quantity << " ref--, now " << (quantity->ref - 1)); if (--quantity->ref == 0) { if (! (quantity->flags & BIGINT_BULK_ALLOC)) delete quantity; @@ -379,7 +383,7 @@ void amount_t::_copy(const amount_t& amt) } else { quantity = amt.quantity; DEBUG_("amounts.refs", - quantity << " ref++, now " << (quantity->ref + 1)); + quantity << " ref++, now " << (quantity->ref + 1)); quantity->ref++; } } @@ -1211,10 +1215,10 @@ bool parse_annotations(std::istream& in, amount_t& price, } while (true); DEBUG_("amounts.commodities", - "Parsed commodity annotations: " - << " price " << price << " " - << " date " << date << " " - << " tag " << tag); + "Parsed commodity annotations: " + << " price " << price << " " + << " date " << date << " " + << " tag " << tag); return has_date; } @@ -1401,7 +1405,7 @@ void amount_t::read(std::istream& in) else if (ident == 0) commodity_ = commodity_t::null_commodity; else - commodity_ = commodity_t::commodities_by_ident[ident - 1]; + commodity_ = (*commodity_t::commodities_by_ident)[ident - 1]; read_quantity(in); } @@ -1415,7 +1419,7 @@ void amount_t::read(char *& data) else if (ident == 0) commodity_ = commodity_t::null_commodity; else - commodity_ = commodity_t::commodities_by_ident[ident - 1]; + commodity_ = (*commodity_t::commodities_by_ident)[ident - 1]; read_quantity(data); } @@ -1470,7 +1474,7 @@ void amount_t::read_quantity(char *& data) quantity = (bigint_t *) (bigints + (index - 1) * sizeof(bigint_t)); DEBUG_("amounts.refs", - quantity << " ref++, now " << (quantity->ref + 1)); + quantity << " ref++, now " << (quantity->ref + 1)); quantity->ref++; } } @@ -1585,10 +1589,10 @@ void amount_t::annotate_commodity(const amount_t& tprice, assert(this_base); DEBUG_("amounts.commodities", "Annotating commodity for amount " - << *this << std::endl - << " price " << tprice << " " - << " date " << tdate << " " - << " tag " << tag); + << *this << std::endl + << " price " << tprice << " " + << " date " << tdate << " " + << " tag " << tag); commodity_t * ann_comm = annotated_commodity_t::find_or_create @@ -1610,10 +1614,10 @@ amount_t amount_t::strip_annotations(const bool _keep_price, return *this; DEBUG_("amounts.commodities", "Reducing commodity for amount " - << *this << std::endl - << " keep price " << _keep_price << " " - << " keep date " << _keep_date << " " - << " keep tag " << _keep_tag); + << *this << std::endl + << " keep price " << _keep_price << " " + << " keep date " << _keep_date << " " + << " keep tag " << _keep_tag); annotated_commodity_t& ann_comm(static_cast<annotated_commodity_t&>(commodity())); @@ -1647,7 +1651,7 @@ amount_t amount_t::price() const amount_t t(((annotated_commodity_t *)commodity_)->price); t *= number(); DEBUG_("amounts.commodities", - "Returning price of " << *this << " = " << t); + "Returning price of " << *this << " = " << t); return t; } return *this; @@ -1657,8 +1661,8 @@ moment_t amount_t::date() const { if (commodity_ && commodity_->annotated) { DEBUG_("amounts.commodities", - "Returning date of " << *this << " = " - << ((annotated_commodity_t *)commodity_)->date); + "Returning date of " << *this << " = " + << ((annotated_commodity_t *)commodity_)->date); return ((annotated_commodity_t *)commodity_)->date; } return moment_t(); @@ -1720,7 +1724,7 @@ bool commodity_t::valid() const { if (symbol().empty() && this != null_commodity) { DEBUG_("ledger.validate", - "commodity_t: symbol().empty() && this != null_commodity"); + "commodity_t: symbol().empty() && this != null_commodity"); return false; } @@ -1752,15 +1756,15 @@ commodity_t * commodity_t::create(const string& symbol) } DEBUG_("amounts.commodities", - "Creating commodity " << commodity->qualified_symbol); + "Creating commodity " << commodity->qualified_symbol); std::pair<commodities_map::iterator, bool> result = commodities.insert(commodities_pair(symbol, commodity.get())); if (! result.second) return NULL; - commodity->ident = commodities_by_ident.size(); - commodities_by_ident.push_back(commodity.get()); + commodity->ident = commodities_by_ident->size(); + commodities_by_ident->push_back(commodity.get()); // Start out the new commodity with the default commodity's flags // and precision, if one has been defined. @@ -1896,11 +1900,11 @@ annotated_commodity_t::create(const commodity_t& comm, commodity->qualified_symbol = comm.symbol(); DEBUG_("amounts.commodities", "Creating annotated commodity " - << "symbol " << commodity->symbol() - << " key " << mapping_key << std::endl - << " price " << price << " " - << " date " << date << " " - << " tag " << tag); + << "symbol " << commodity->symbol() + << " key " << mapping_key << std::endl + << " price " << price << " " + << " date " << date << " " + << " tag " << tag); // Add the fully annotated name to the map, so that this symbol may // quickly be found again. @@ -1909,8 +1913,8 @@ annotated_commodity_t::create(const commodity_t& comm, if (! result.second) return NULL; - commodity->ident = commodities_by_ident.size(); - commodities_by_ident.push_back(commodity.get()); + commodity->ident = commodities_by_ident->size(); + commodities_by_ident->push_back(commodity.get()); return commodity.release(); } @@ -1931,10 +1935,10 @@ namespace { annotated_commodity_t::write_annotations(name, price, date, tag); DEBUG_("amounts.commodities", "make_qualified_name for " - << comm.qualified_symbol << std::endl - << " price " << price << " " - << " date " << date << " " - << " tag " << tag); + << comm.qualified_symbol << std::endl + << " price " << price << " " + << " date " << date << " " + << " tag " << tag); DEBUG_("amounts.commodities", "qualified_name is " << name.str()); @@ -554,11 +554,11 @@ class commodity_t public: // This map remembers all commodities that have been defined. - static commodities_map commodities; - static commodities_array commodities_by_ident; - static bool commodities_sorted; - static commodity_t * null_commodity; - static commodity_t * default_commodity; + static commodities_map commodities; + static commodities_array * commodities_by_ident; + static bool commodities_sorted; + static commodity_t * null_commodity; + static commodity_t * default_commodity; static commodity_t * create(const string& symbol); static commodity_t * find(const string& name); @@ -4,7 +4,7 @@ namespace ledger { #if 0 static unsigned long binary_magic_number = 0xFFEED765; -#ifdef DEBUG_ENABLED +#if defined(DEBUG_ON) static unsigned long format_version = 0x00030000; #else static unsigned long format_version = 0x00030000; @@ -67,8 +67,8 @@ static int read_and_report(report_t * report, int argc, char * argv[], TRACE(1, "Binary cache is " << session.cache_file); TRACE(1, "Main journal is " << session.data_file); - TRACE(1, "Based on option settings, binary cache " << - (session.use_cache ? "WILL " : "will NOT ") << "be used"); + if (! session.use_cache) + INFO("The binary cache mechanism will not be used"); // Read the command word and create a command object based on it @@ -134,7 +134,7 @@ static int read_and_report(report_t * report, int argc, char * argv[], else if (verb == "parse") { xml::xpath_t expr(*arg); - if (session.verbose_mode) { + IF_INFO() { std::cout << "Value expression tree:" << std::endl; expr.dump(std::cout); std::cout << std::endl; @@ -231,7 +231,7 @@ static int read_and_report(report_t * report, int argc, char * argv[], if (verb == "expr") { xml::xpath_t expr(*arg); - if (session.verbose_mode) { + IF_INFO() { *out << "Value expression tree:" << std::endl; expr.dump(*out); *out << std::endl; @@ -370,25 +370,46 @@ static int read_and_report(report_t * report, int argc, char * argv[], return 0; } -#ifdef DEBUG_ENABLED -extern int new_calls; -extern unsigned long new_size; -#endif - int main(int argc, char * argv[], char * envp[]) { int status = 1; +#if defined(FULL_DEBUG) + ledger::verify_enabled = true; +#endif + + for (int i = 1; i < argc; i++) + if (argv[i][0] == '-' && argv[i][1] == '-') { +#if defined(VERIFY_ON) + if (std::strcmp(argv[i], "--verify") == 0) + ledger::verify_enabled = true; +#endif +#if defined(DEBUG_ON) + if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) { + ledger::_log_level = LOG_DEBUG; + ledger::_log_category = argv[i + 1]; + i++; + } +#endif +#if defined(TRACING_ON) + if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) { + ledger::_log_level = LOG_TRACE; + ledger::_trace_level = std::atoi(argv[i + 1]); + i++; + } +#endif + } + try { std::ios::sync_with_stdio(false); -#if DEBUG_LEVEL < BETA + ledger::initialize(); + +#if ! defined(FULL_DEBUG) ledger::do_cleanup = false; #endif TRACE(1, "Ledger starting"); - ledger::amount_t::initialize(); - std::auto_ptr<ledger::session_t> session(new ledger::session_t); #if 0 @@ -411,9 +432,6 @@ int main(int argc, char * argv[], char * envp[]) if (! ledger::do_cleanup) { report.release(); session.release(); - ledger::xml::xpath_t::lookahead.clear(); - } else { - ledger::amount_t::shutdown(); } } #if 0 @@ -446,11 +464,8 @@ int main(int argc, char * argv[], char * envp[]) status = _status; } - IF_DEBUG_("ledger.trace.memory") { - report_memory(std::cerr); - std::cerr << "Total calls to new: " << new_calls << std::endl - << "Total memory new'd: " << new_size << std::endl; - } + if (ledger::do_cleanup) + ledger::shutdown(); return status; } @@ -76,12 +76,11 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data, if (data.unitprice_valid && data.unitprice != 1.0) { std::ostringstream cstream; - stream << - data.unitprice; - xact->cost = new amount_t(stream.str() + " " + default_commodity->base_symbol()); + stream << - data.unitprice << " " << default_commodity->base_symbol(); + xact->cost = new amount_t(stream.str()); } - DEBUG_("ledger.ofx.parse", "xact " << xact->amount - << " from " << *xact->account); + DEBUG_("ofx.parse", "xact " << xact->amount << " from " << *xact->account); if (data.date_initiated_valid) entry->_date = data.date_initiated; diff --git a/register.cc b/register.cc index 2633def6..9f33bd0c 100644 --- a/register.cc +++ b/register.cc @@ -127,10 +127,6 @@ static void scan_for_transactions(std::ostream& out, const xml::node_t * node) void register_command::print_document(std::ostream& out, xml::document_t * doc) { -#if DEBUG_LEVEL >= BETA - unsigned long old_new_size = new_size; -#endif - #if 1 scan_for_transactions(out, doc->top); out.flush(); @@ -138,12 +134,6 @@ void register_command::print_document(std::ostream& out, value_t nodelist; xml::xpath_t::eval(nodelist, "//transaction", doc); -#if DEBUG_LEVEL >= BETA - std::cerr << "Memory requested preparing report: " - << (new_size - old_new_size) << std::endl; - old_new_size = new_size; -#endif - const value_t::sequence_t * xact_list = nodelist.to_sequence(); assert(xact_list); @@ -170,12 +160,6 @@ void register_command::print_document(std::ostream& out, << xact->amount << std::endl; } - -#if DEBUG_LEVEL >= BETA - std::cerr << "Memory requested generating report: " - << (new_size - old_new_size) << std::endl; - old_new_size = new_size; -#endif #endif } @@ -62,13 +62,11 @@ journal_t * session_t::read_data(const string& master_account) unsigned int entry_count = 0; - DEBUG_("ledger.cache", - "3. use_cache = " << use_cache); + DEBUG_("ledger.cache", "3. use_cache = " << use_cache); if (use_cache && ! cache_file.empty() && ! data_file.empty()) { - DEBUG_("ledger.cache", - "using_cache " << cache_file); + DEBUG_("ledger.cache", "using_cache " << cache_file); cache_dirty = true; if (access(cache_file.c_str(), R_OK) != -1) { std::ifstream stream(cache_file.c_str()); @@ -95,14 +93,12 @@ journal_t * session_t::read_data(const string& master_account) if (read_journal(journal->price_db, journal)) { throw_(exception, "Entries not allowed in price history file"); } else { - DEBUG_("ledger.cache", - "read price database " << journal->price_db); + DEBUG_("ledger.cache", "read price database " << journal->price_db); journal->sources.pop_back(); } } - DEBUG_("ledger.cache", - "rejected cache, parsing " << data_file); + DEBUG_("ledger.cache", "rejected cache, parsing " << data_file); if (data_file == "-") { use_cache = false; journal->sources.push_back("<stdin>"); @@ -171,14 +167,26 @@ xml::xpath_t::op_t * session_t::lookup(const string& name) if (std::strncmp(p, "option_", 7) == 0) { p = p + 7; switch (*p) { + case 'd': + if (std::strcmp(p, "debug") == 0) + return MAKE_FUNCTOR(session_t, option_debug); + break; + case 'f': if (! *(p + 1) || std::strcmp(p, "file") == 0) return MAKE_FUNCTOR(session_t, option_file); break; + case 't': + if (std::strcmp(p, "trace") == 0) + return MAKE_FUNCTOR(session_t, option_trace); + break; + case 'v': - if (std::strcmp(p, "verbose") == 0) + if (! *(p + 1) || std::strcmp(p, "verbose") == 0) return MAKE_FUNCTOR(session_t, option_verbose); + else if (std::strcmp(p, "verify") == 0) + return MAKE_FUNCTOR(session_t, option_verify); break; } } @@ -192,7 +200,11 @@ xml::xpath_t::op_t * session_t::lookup(const string& name) // session_t object void initialize() { + IF_VERIFY() + initialize_memory_tracing(); + amount_t::initialize(); + xml::xpath_t::initialize(); } void shutdown() @@ -200,7 +212,13 @@ void shutdown() #if defined(USE_BOOST_PYTHON) shutdown_for_python(); #endif + xml::xpath_t::shutdown(); amount_t::shutdown(); + + IF_VERIFY() { + TRACE(1, "Shutting down memory trace"); + shutdown_memory_tracing(); + } } } // namespace ledger @@ -32,10 +32,6 @@ class session_t : public xml::xpath_t::scope_t bool download_quotes; bool use_cache; bool cache_dirty; - bool debug_mode; - bool verbose_mode; - bool trace_alloc_mode; - bool trace_class_mode; moment_t now; @@ -87,10 +83,6 @@ class session_t : public xml::xpath_t::scope_t download_quotes(false), use_cache(false), cache_dirty(false), - debug_mode(false), - verbose_mode(false), - trace_alloc_mode(false), - trace_class_mode(false), now(now), @@ -165,6 +157,18 @@ class session_t : public xml::xpath_t::scope_t virtual xml::xpath_t::op_t * lookup(const string& name); // + // Debug options + // + + void option_verify(value_t&) {} + void option_trace(value_t&, xml::xpath_t::scope_t * locals) {} + void option_debug(value_t&, xml::xpath_t::scope_t * locals) {} + + void option_verbose(value_t&) { + _log_level = LOG_INFO; + } + + // // Option handlers // @@ -172,10 +176,6 @@ class session_t : public xml::xpath_t::scope_t data_file = locals->args.to_string(); } - void option_verbose(value_t&) { - verbose_mode = true; - } - #if 0 #if defined(USE_BOOST_PYTHON) void option_import(value_t&) { diff --git a/tests/python/corelib/numerics/BasicAmount.py b/tests/python/corelib/numerics/BasicAmount.py index 2ce532d9..bdc7dbe9 100644 --- a/tests/python/corelib/numerics/BasicAmount.py +++ b/tests/python/corelib/numerics/BasicAmount.py @@ -1,3 +1,7 @@ +import sys +sys.path.append("/home/johnw/src/ledger") +sys.path.append("/home/johnw/Products/ledger") + import unittest import exceptions @@ -53,10 +53,10 @@ parse_amount_expr(std::istream& in, journal_t *, xml::xpath_t xpath(in, flags | XPATH_PARSE_RELAXED | XPATH_PARSE_PARTIAL); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed an amount expression"); + "Parsed an amount expression"); -#ifdef DEBUG_ENABLED - DEBUG_IF("ledger.textual.parse") { +#if 0 + IF_DEBUG_("ledger.textual.parse") { if (_debug_stream) { xpath.dump(*_debug_stream); *_debug_stream << std::endl; @@ -67,7 +67,7 @@ parse_amount_expr(std::istream& in, journal_t *, amount = xpath.calc(static_cast<xml::transaction_node_t *>(xact.data)).to_amount(); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "The transaction amount is " << amount); + "The transaction amount is " << amount); } transaction_t * parse_transaction(char * line, @@ -125,12 +125,12 @@ transaction_t * parse_transaction(char * line, case '*': xact->state = transaction_t::CLEARED; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed the CLEARED flag"); + "Parsed the CLEARED flag"); break; case '!': xact->state = transaction_t::PENDING; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed the PENDING flag"); + "Parsed the PENDING flag"); break; } @@ -142,18 +142,18 @@ transaction_t * parse_transaction(char * line, (*b == '(' && *e == ')')) { xact->flags |= TRANSACTION_VIRTUAL; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed a virtual account name"); + "Parsed a virtual account name"); if (*b == '[') { xact->flags |= TRANSACTION_BALANCE; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed a balanced virtual account name"); + "Parsed a balanced virtual account name"); } *account_path++ = '\0'; *e = '\0'; } DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed account name " << account_path); + "Parsed account name " << account_path); if (account_aliases.size() > 0) { accounts_map::const_iterator i = account_aliases.find(account_path); if (i != account_aliases.end()) @@ -215,14 +215,14 @@ transaction_t * parse_transaction(char * line, char c = peek_next_nonws(in); if (c == '@') { DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Found a price indicator"); + "Found a price indicator"); bool per_unit = true; in.get(c); if (in.peek() == '@') { in.get(c); per_unit = false; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "And it's for a total price"); + "And it's for a total price"); } if (in.good() && ! in.eof()) { @@ -263,13 +263,13 @@ transaction_t * parse_transaction(char * line, xact->entry->code); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Total cost is " << *xact->cost); + "Total cost is " << *xact->cost); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Per-unit cost is " << per_unit_cost); + "Per-unit cost is " << per_unit_cost); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Annotated amount is " << xact->amount); + "Annotated amount is " << xact->amount); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Bare amount is " << xact->amount.number()); + "Bare amount is " << xact->amount.number()); } } } @@ -277,7 +277,7 @@ transaction_t * parse_transaction(char * line, xact->amount.in_place_reduce(); DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Reduced amount is " << xact->amount); + "Reduced amount is " << xact->amount); } // Parse the optional note @@ -285,7 +285,7 @@ transaction_t * parse_transaction(char * line, if (note) { xact->note = note; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed a note '" << xact->note << "'"); + "Parsed a note '" << xact->note << "'"); if (char * b = std::strchr(xact->note.c_str(), '[')) if (char * e = std::strchr(xact->note.c_str(), ']')) { @@ -294,7 +294,7 @@ transaction_t * parse_transaction(char * line, buf[e - b - 1] = '\0'; DEBUG_("ledger.textual.parse", "line " << linenum << ": " << - "Parsed a transaction date " << buf); + "Parsed a transaction date " << buf); if (char * p = std::strchr(buf, '=')) { *p++ = '\0'; @@ -840,7 +840,7 @@ unsigned int textual_parser_t::parse(std::istream& in, path = resolve_path(path); DEBUG_("ledger.textual.include", "line " << linenum << ": " << - "Including path '" << path << "'"); + "Including path '" << path << "'"); include_stack.push_back(std::pair<string, int> (journal->sources.back(), linenum - 1)); @@ -32,74 +32,190 @@ void debug_assert(const string& reason, #if defined(VERIFY_ON) namespace ledger { + #if defined(FULL_DEBUG) - bool verify_enabled = true; +bool verify_enabled = true; #else - bool verify_enabled = false; +bool verify_enabled = false; #endif - int new_calls = 0; - unsigned long new_size = 0; +typedef std::pair<std::string, std::size_t> allocation_pair; +typedef std::map<void *, allocation_pair> live_memory_map; +typedef std::pair<void *, allocation_pair> live_memory_pair; +typedef std::multimap<void *, allocation_pair> live_objects_map; +typedef std::pair<void *, allocation_pair> live_objects_pair; +typedef std::pair<unsigned int, std::size_t> count_size_pair; +typedef std::map<std::string, count_size_pair> object_count_map; +typedef std::pair<std::string, count_size_pair> object_count_pair; + +static live_memory_map * live_memory = NULL; +static object_count_map * live_memory_count = NULL; +static object_count_map * total_memory_count = NULL; + +static bool memory_tracing_active = false; + +static live_objects_map * live_objects = NULL; +static object_count_map * live_object_count = NULL; +static object_count_map * total_object_count = NULL; +static object_count_map * total_ctor_count = NULL; + +void initialize_memory_tracing() +{ + memory_tracing_active = false; + + live_memory = new live_memory_map; + live_memory_count = new object_count_map; + total_memory_count = new object_count_map; + + live_objects = new live_objects_map; + live_object_count = new object_count_map; + total_object_count = new object_count_map; + total_ctor_count = new object_count_map; + + memory_tracing_active = true; +} + +void shutdown_memory_tracing() +{ + memory_tracing_active = false; + + IF_DEBUG_("memory.counts") + report_memory(std::cerr, true); + else + IF_DEBUG_("memory.counts.live") + report_memory(std::cerr); + + delete live_memory; live_memory = NULL; + delete live_memory_count; live_memory_count = NULL; + delete total_memory_count; total_memory_count = NULL; + + delete live_objects; live_objects = NULL; + delete live_object_count; live_object_count = NULL; + delete total_object_count; total_object_count = NULL; + delete total_ctor_count; total_ctor_count = NULL; +} + +inline void add_to_count_map(object_count_map& the_map, + const char * name, std::size_t size) +{ + object_count_map::iterator k = the_map.find(name); + if (k != the_map.end()) { + (*k).second.first++; + (*k).second.second += size; + } else { + std::pair<object_count_map::iterator, bool> result = + the_map.insert(object_count_pair(name, count_size_pair(1, size))); + VERIFY(result.second); + } +} + +std::size_t current_memory_size() +{ + std::size_t memory_size = 0; + + for (object_count_map::const_iterator i = live_memory_count->begin(); + i != live_memory_count->end(); + i++) + memory_size += (*i).second.second; + + return memory_size; +} + +static void trace_new_func(void * ptr, const char * which, std::size_t size) +{ + memory_tracing_active = false; + + if (! live_memory) return; + + live_memory->insert(live_memory_pair(ptr, allocation_pair(which, size))); + + add_to_count_map(*live_memory_count, which, size); + add_to_count_map(*total_memory_count, which, size); + add_to_count_map(*total_memory_count, "__ALL__", size); + + memory_tracing_active = true; +} + +static void trace_delete_func(void * ptr, const char * which) +{ + memory_tracing_active = false; + + if (! live_memory) return; + + // Ignore deletions of memory not tracked, since it's possible that + // a user (like boost) allocated a block of memory before memory + // tracking began, and then deleted it before memory tracking ended. + // If it really is a double-delete, the malloc library on OS/X will + // notify me. + + live_memory_map::iterator i = live_memory->find(ptr); + if (i == live_memory->end()) + return; + + std::size_t size = (*i).second.second; + VERIFY((*i).second.first == which); + + live_memory->erase(i); + + object_count_map::iterator j = live_memory_count->find(which); + VERIFY(j != live_memory_count->end()); + + (*j).second.second -= size; + if (--(*j).second.first == 0) + live_memory_count->erase(j); + + memory_tracing_active = true; } +} // namespace ledger + void * operator new(std::size_t size) throw (std::bad_alloc) { void * ptr = std::malloc(size); - ledger::new_calls++; - ledger::new_size += size; + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_new_func(ptr, "new", size); return ptr; } -void * operator new[](std::size_t size) throw (std::bad_alloc) { +void * operator new(std::size_t size, const std::nothrow_t&) throw() { void * ptr = std::malloc(size); - ledger::new_calls++; - ledger::new_size += size; + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_new_func(ptr, "new", size); return ptr; } -void * operator new(std::size_t size, const std::nothrow_t&) throw() { +void * operator new[](std::size_t size) throw (std::bad_alloc) { void * ptr = std::malloc(size); - ledger::new_calls++; - ledger::new_size += size; + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_new_func(ptr, "new[]", size); return ptr; } void * operator new[](std::size_t size, const std::nothrow_t&) throw() { void * ptr = std::malloc(size); - ledger::new_calls++; - ledger::new_size += size; + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_new_func(ptr, "new[]", size); return ptr; } void operator delete(void * ptr) throw() { + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_delete_func(ptr, "new"); std::free(ptr); } -void operator delete[](void * ptr) throw() { +void operator delete(void * ptr, const std::nothrow_t&) throw() { + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_delete_func(ptr, "new"); std::free(ptr); } -void operator delete(void * ptr, const std::nothrow_t&) throw() { +void operator delete[](void * ptr) throw() { + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_delete_func(ptr, "new[]"); std::free(ptr); } void operator delete[](void * ptr, const std::nothrow_t&) throw() { + if (DO_VERIFY() && ledger::memory_tracing_active) + ledger::trace_delete_func(ptr, "new[]"); std::free(ptr); } namespace ledger { -live_objects_map live_objects; -object_count_map ctor_count; -object_count_map object_count; -object_count_map live_count; - -inline void add_to_count_map(object_count_map& the_map, - const char * name, std::size_t size) -{ - object_count_map::iterator k = the_map.find(name); - if (k != the_map.end()) { - (*k).second.first++; - (*k).second.second += size; - } else { - std::pair<object_count_map::iterator, bool> result = - the_map.insert(object_count_pair(name, count_size_pair(1, size))); - assert(result.second); - } -} - inline void report_count_map(std::ostream& out, object_count_map& the_map) { for (object_count_map::iterator i = the_map.begin(); @@ -111,88 +227,127 @@ inline void report_count_map(std::ostream& out, object_count_map& the_map) << std::endl; } -bool trace_ctor_func(void * ptr, const char * cls_name, const char * args, +std::size_t current_objects_size() +{ + std::size_t objects_size = 0; + + for (object_count_map::const_iterator i = live_object_count->begin(); + i != live_object_count->end(); + i++) + objects_size += (*i).second.second; + + return objects_size; +} + +void trace_ctor_func(void * ptr, const char * cls_name, const char * args, std::size_t cls_size) { + memory_tracing_active = false; + + if (! live_objects) return; + static char name[1024]; std::strcpy(name, cls_name); std::strcat(name, "("); std::strcat(name, args); std::strcat(name, ")"); - DEBUG_("ledger.trace.debug", "TRACE_CTOR " << ptr << " " << name); + DEBUG_("verify.memory", "TRACE_CTOR " << ptr << " " << name); - live_objects.insert(live_objects_pair(ptr, cls_name)); + live_objects->insert(live_objects_pair(ptr, allocation_pair(cls_name, cls_size))); - add_to_count_map(ctor_count, name, cls_size); - add_to_count_map(object_count, cls_name, cls_size); - add_to_count_map(object_count, "__ALL__", cls_size); - add_to_count_map(live_count, cls_name, cls_size); + add_to_count_map(*live_object_count, cls_name, cls_size); + add_to_count_map(*total_object_count, cls_name, cls_size); + add_to_count_map(*total_object_count, "__ALL__", cls_size); + add_to_count_map(*total_ctor_count, name, cls_size); - return true; + memory_tracing_active = true; } -bool trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size) +void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size) { + memory_tracing_active = false; + + if (! live_objects) return; + DEBUG_("ledger.trace.debug", "TRACE_DTOR " << ptr << " " << cls_name); - live_objects_map::iterator i = live_objects.find(ptr); - if (i == live_objects.end()) { - std::cerr << "Destruction of unknown object of type " << cls_name - << " " << ptr << std::endl; - assert(0); - return false; - } + live_objects_map::iterator i = live_objects->find(ptr); + VERIFY(i != live_objects->end()); - int ptr_count = live_objects.count(ptr); + int ptr_count = live_objects->count(ptr); for (int x = 0; x < ptr_count; x++, i++) { - if ((*i).second == cls_name) { - live_objects.erase(i); + if ((*i).second.first == cls_name) { + live_objects->erase(i); break; } } - object_count_map::iterator k = live_count.find(cls_name); - if (k == live_count.end()) { - std::cerr << "Destruction of unregistered class " << cls_name - << std::endl;; - assert(0); - return false; - } + object_count_map::iterator k = live_object_count->find(cls_name); + VERIFY(k != live_object_count->end()); (*k).second.second -= cls_size; if (--(*k).second.first == 0) - live_count.erase(k); + live_object_count->erase(k); - return true; + memory_tracing_active = true; } -void report_memory(std::ostream& out) +void report_memory(std::ostream& out, bool report_all) { - if (live_count.size() > 0) { - out << "Live object counts:" << std::endl; - report_count_map(out, live_count); + if (! live_memory) return; + + if (live_memory_count->size() > 0) { + out << "NOTE: There may be memory held by Boost " + << "and libstdc++ after ledger::shutdown()" << std::endl; + out << "Live memory count:" << std::endl; + report_count_map(out, *live_memory_count); } - if (live_objects.size() > 0) { - out << "Live objects:" << std::endl; + if (live_memory->size() > 0) { + out << "Live memory:" << std::endl; - for (live_objects_map::iterator i = live_objects.begin(); - i != live_objects.end(); + for (live_memory_map::const_iterator i = live_memory->begin(); + i != live_memory->end(); i++) out << " " << std::right << std::setw(7) << (*i).first - << " " << std::left << (*i).second + << " " << std::right << std::setw(7) << (*i).second.second + << " " << std::left << (*i).second.first << std::endl; } - if (object_count.size() > 0) { - out << "Object counts:" << std::endl; - report_count_map(out, object_count); + if (report_all && total_memory_count->size() > 0) { + out << "Total memory counts:" << std::endl; + report_count_map(out, *total_memory_count); + } + + if (live_object_count->size() > 0) { + out << "Live object count:" << std::endl; + report_count_map(out, *live_object_count); + } + + if (live_objects->size() > 0) { + out << "Live objects:" << std::endl; + + for (live_objects_map::const_iterator i = live_objects->begin(); + i != live_objects->end(); + i++) + out << " " << std::right << std::setw(7) << (*i).first + << " " << std::right << std::setw(7) << (*i).second.second + << " " << std::left << (*i).second.first + << std::endl; } - if (ctor_count.size() > 0) { - out << "Constructor counts:" << std::endl; - report_count_map(out, ctor_count); + if (report_all) { + if (total_object_count->size() > 0) { + out << "Total object counts:" << std::endl; + report_count_map(out, *total_object_count); + } + + if (total_ctor_count->size() > 0) { + out << "Total constructor counts:" << std::endl; + report_count_map(out, *total_ctor_count); + } } } @@ -255,8 +410,64 @@ std::string _log_category; std::ostream * _log_stream = &std::cerr; std::ostringstream _log_buffer; +static inline void stream_memory_size(std::ostream& out, std::size_t size) +{ + if (size < 1024) + out << size << 'b'; + else if (size < (1024 * 1024)) + out << (double(size) / 1024.0) << 'K'; + else if (size < (1024 * 1024 * 1024)) + out << (double(size) / (1024.0 * 1024.0)) << 'M'; + else if (size < (1024 * 1024 * 1024 * 1024)) + out << (double(size) / (1024.0 * 1024.0 * 1024.0)) << 'G'; + else + assert(false); +} + +static bool logger_has_run = false; + bool logger_func(log_level_t level) { + if (! logger_has_run) { + logger_has_run = true; + IF_VERIFY() + *_log_stream << " TIME OBJSZ MEMSZ LEVEL MESSAGE" << std::endl; + else + *_log_stream << " TIME LEVEL MESSAGE" << std::endl; + } + + *_log_stream << std::right << std::setw(6) + << (double(std::clock()) / double(CLOCKS_PER_SEC)); + + IF_VERIFY() { + *_log_stream << std::right << std::setw(6) << std::setprecision(3); + stream_memory_size(*_log_stream, current_objects_size()); + *_log_stream << std::right << std::setw(6) << std::setprecision(3); + stream_memory_size(*_log_stream, current_memory_size()); + } + + *_log_stream << " " << std::left << std::setw(7); + + switch (level) { + case LOG_CRIT: *_log_stream << "[CRIT]"; break; + case LOG_FATAL: *_log_stream << "[FATAL]"; break; + case LOG_ASSERT: *_log_stream << "[ASSRT]"; break; + case LOG_ERROR: *_log_stream << "[ERROR]"; break; + case LOG_VERIFY: *_log_stream << "[VERFY]"; break; + case LOG_WARN: *_log_stream << "[WARN]"; break; + case LOG_INFO: *_log_stream << "[INFO]"; break; + case LOG_EXCEPT: *_log_stream << "[EXCPT]"; break; + case LOG_DEBUG: *_log_stream << "[DEBUG]"; break; + case LOG_TRACE: *_log_stream << "[TRACE]"; break; + + case LOG_OFF: + case LOG_ALL: + assert(false); + break; + } + + *_log_stream << ' ' << _log_buffer.str() << std::endl; + _log_buffer.str(""); } @@ -73,32 +73,26 @@ namespace ledger { extern bool verify_enabled; -#define VERIFY(x) (verify_enabled ? assert(x) : ((void)0)) +#define VERIFY(x) (ledger::verify_enabled ? assert(x) : ((void)0)) +#define DO_VERIFY() ledger::verify_enabled +#define IF_VERIFY() if (DO_VERIFY()) -extern int new_calls; -extern unsigned long new_size; +void initialize_memory_tracing(); +void shutdown_memory_tracing(); -typedef std::multimap<void *, std::string> live_objects_map; -typedef std::pair<void *, std::string> live_objects_pair; -typedef std::pair<unsigned int, std::size_t> count_size_pair; -typedef std::map<std::string, count_size_pair> object_count_map; -typedef std::pair<std::string, count_size_pair> object_count_pair; +std::size_t current_memory_size(); +std::size_t current_objects_size(); -extern live_objects_map live_objects; -extern object_count_map live_count; -extern object_count_map ctor_count; -extern object_count_map object_count; - -bool trace_ctor_func(void * ptr, const char * cls_name, const char * args, +void trace_ctor_func(void * ptr, const char * cls_name, const char * args, std::size_t cls_size); -bool trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size); +void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size); #define TRACE_CTOR(cls, args) \ - VERIFY(trace_ctor_func(this, #cls, args, sizeof(cls))) + (DO_VERIFY() ? trace_ctor_func(this, #cls, args, sizeof(cls)) : ((void)0)) #define TRACE_DTOR(cls) \ - VERIFY(trace_dtor_func(this, #cls, sizeof(cls))) + (DO_VERIFY() ? trace_dtor_func(this, #cls, sizeof(cls)) : ((void)0)) -void report_memory(std::ostream& out); +void report_memory(std::ostream& out, bool report_all = false); #if ! defined(USE_BOOST_PYTHON) @@ -213,20 +207,21 @@ bool logger_func(log_level_t level); static const char * const _this_category = cat #define SHOW_TRACE(lvl) \ - (_log_level >= LOG_TRACE && lvl >= _trace_level) + (_log_level >= LOG_TRACE && lvl <= _trace_level) + +inline bool category_matches(const char * cat) { + return (_log_category == cat || + (std::strlen(cat) > _log_category.size() + 1 && + std::strncmp(cat, _log_category.c_str(), + _log_category.size()) == 0 && + cat[_log_category.size()] == '.')); +} -#define SHOW_DEBUG_(cat) \ - (_log_level >= LOG_DEBUG && \ - (_log_category == cat || \ - _log_category.find(string(cat) + ".") == 0)) +#define SHOW_DEBUG_(cat) \ + (_log_level >= LOG_DEBUG && category_matches(cat)) #define SHOW_DEBUG() SHOW_DEBUG_(_this_category) -#define SHOW_INFO_(cat) \ - (_log_level >= LOG_INFO && \ - (_log_category == cat || \ - _log_category.find(string(cat) + ".") == 0)) -#define SHOW_INFO() SHOW_INFO_(_this_category) - +#define SHOW_INFO() (_log_level >= LOG_INFO) #define SHOW_WARN() (_log_level >= LOG_WARN) #define SHOW_ERROR() (_log_level >= LOG_ERROR) #define SHOW_FATAL() (_log_level >= LOG_FATAL) @@ -248,14 +243,11 @@ bool logger_func(log_level_t level); #define DEBUG(msg) #endif -#define INFO_(cat, msg) \ - (SHOW_INFO(cat) ? ((_log_buffer << msg), logger_func(LOG_INFO)) : false) -#define INFO(msg) INFO_(_this_category, msg) - #define LOG_MACRO(level, msg) \ (_log_level >= level ? \ ((_log_buffer << msg), logger_func(level)) : false) +#define INFO(msg) LOG_MACRO(LOG_INFO, msg) #define WARN(msg) LOG_MACRO(LOG_WARN, msg) #define ERROR(msg) LOG_MACRO(LOG_ERROR, msg) #define FATAL(msg) LOG_MACRO(LOG_FATAL, msg) @@ -271,7 +263,6 @@ bool logger_func(log_level_t level); #define SHOW_TRACE(lvl) false #define SHOW_DEBUG_(cat) false #define SHOW_DEBUG() false -#define SHOW_INFO_(cat) false #define SHOW_INFO() false #define SHOW_WARN() false #define SHOW_ERROR() false @@ -282,7 +273,6 @@ bool logger_func(log_level_t level); #define DEBUG(msg) #define DEBUG_(cat, msg) #define INFO(msg) -#define INFO_(cat, msg) #define WARN(msg) #define ERROR(msg) #define FATAL(msg) @@ -293,7 +283,6 @@ bool logger_func(log_level_t level); #define IF_TRACE(lvl) if (SHOW_TRACE(lvl)) #define IF_DEBUG_(cat) if (SHOW_DEBUG_(cat)) #define IF_DEBUG() if (SHOW_DEBUG()) -#define IF_INFO_(cat) if (SHOW_INFO_(cat)) #define IF_INFO() if (SHOW_INFO()) #define IF_WARN() if (SHOW_WARN()) #define IF_ERROR() if (SHOW_ERROR()) @@ -354,18 +343,12 @@ void finish_timer(const char * name); #define DEBUG_FINISH(name) #endif -#define info_start_(name, cat, msg) \ - (info_(cat, msg) && start_timer(#name)) -#define info_start(name, msg) \ - info_start_(name, _this_category, msg) -#define info_stop_(name, cat) \ - (show_info_(cat) ? stop_timer(#name) : ((void)0)) -#define info_stop(name) \ - info_stop_(name, _this_category) -#define info_finish_(name, cat) \ - (show_info_(cat) ? finish_timer(#name) : ((void)0)) -#define info_finish(name) \ - info_finish_(name, _this_category) +#define INFO_START(name, msg) \ + (INFO(msg) && start_timer(#name)) +#define INFO_STOP(name) \ + (SHOW_INFO() ? stop_timer(#name) : ((void)0)) +#define INFO_FINISH(name) \ + (SHOW_INFO() ? finish_timer(#name) : ((void)0)) } // namespace ledger @@ -380,10 +363,10 @@ void finish_timer(const char * name); #define DEBUG_STOP(name) #define DEBUG_FINISH(name) -#define info_start(name, msg) -#define info_start_(name, cat, msg) -#define info_stop(name) -#define info_finish(name) +#define INFO_START(name, msg) +#define INFO_START_(name, cat, msg) +#define INFO_STOP(name) +#define INFO_FINISH(name) #endif // TIMERS_ON @@ -10,9 +10,20 @@ namespace ledger { namespace xml { #ifndef THREADSAFE -xpath_t::token_t xpath_t::lookahead; +xpath_t::token_t * xpath_t::lookahead = NULL; #endif +void xpath_t::initialize() +{ + lookahead = new xpath_t::token_t; +} + +void xpath_t::shutdown() +{ + delete lookahead; + lookahead = NULL; +} + void xpath_t::token_t::parse_ident(std::istream& in) { if (in.eof()) { @@ -1130,9 +1141,17 @@ xpath_t::parse_expr(std::istream& in, unsigned short tflags) const if (use_lookahead) { use_lookahead = false; +#ifdef THREADSAFE lookahead.rewind(in); +#else + lookahead->rewind(in); +#endif } +#ifdef THREADSAFE lookahead.clear(); +#else + lookahead->clear(); +#endif return node.release(); } @@ -11,6 +11,9 @@ class xpath_t public: struct op_t; + static void initialize(); + static void shutdown(); + DECLARE_EXCEPTION(parse_exception); DECLARE_EXCEPTION(compile_exception); DECLARE_EXCEPTION(calc_exception); @@ -422,21 +425,21 @@ public: void release() const { DEBUG_("ledger.xpath.memory", - "Releasing " << this << ", refc now " << refc - 1); + "Releasing " << this << ", refc now " << refc - 1); assert(refc > 0); if (--refc == 0) delete this; } op_t * acquire() { DEBUG_("ledger.xpath.memory", - "Acquiring " << this << ", refc now " << refc + 1); + "Acquiring " << this << ", refc now " << refc + 1); assert(refc >= 0); refc++; return this; } const op_t * acquire() const { DEBUG_("ledger.xpath.memory", - "Acquiring " << this << ", refc now " << refc + 1); + "Acquiring " << this << ", refc now " << refc + 1); assert(refc >= 0); refc++; return this; @@ -521,21 +524,33 @@ public: } #ifdef THREADSAFE - mutable token_t lookahead; + mutable token_t lookahead; #else - static token_t lookahead; + static token_t * lookahead; #endif - mutable bool use_lookahead; + mutable bool use_lookahead; token_t& next_token(std::istream& in, unsigned short tflags) const { if (use_lookahead) use_lookahead = false; else +#ifdef THREADSAFE lookahead.next(in, tflags); +#else + lookahead->next(in, tflags); +#endif +#ifdef THREADSAFE return lookahead; +#else + return *lookahead; +#endif } void push_token(const token_t& tok) const { +#ifdef THREADSAFE assert(&tok == &lookahead); +#else + assert(&tok == lookahead); +#endif use_lookahead = true; } void push_token() const { |