diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/amount.cc | 222 | ||||
-rw-r--r-- | src/amount.h | 64 | ||||
-rw-r--r-- | src/balance.h | 79 | ||||
-rw-r--r-- | src/binary.cc | 20 | ||||
-rw-r--r-- | src/derive.h | 2 | ||||
-rw-r--r-- | src/format.h | 8 | ||||
-rw-r--r-- | src/gnucash.cc | 14 | ||||
-rw-r--r-- | src/gnucash.h | 10 | ||||
-rw-r--r-- | src/journal.cc | 113 | ||||
-rw-r--r-- | src/journal.h | 185 | ||||
-rw-r--r-- | src/main.cc | 74 | ||||
-rw-r--r-- | src/ofx.cc | 2 | ||||
-rw-r--r-- | src/option.cc | 2 | ||||
-rw-r--r-- | src/parser.h | 8 | ||||
-rw-r--r-- | src/pyinterp.cc | 2 | ||||
-rw-r--r-- | src/pyinterp.h | 30 | ||||
-rw-r--r-- | src/qif.cc | 16 | ||||
-rw-r--r-- | src/qif.h | 8 | ||||
-rw-r--r-- | src/register.cc | 6 | ||||
-rw-r--r-- | src/report.cc | 8 | ||||
-rw-r--r-- | src/report.h | 14 | ||||
-rw-r--r-- | src/session.cc | 92 | ||||
-rw-r--r-- | src/session.h | 70 | ||||
-rw-r--r-- | src/system.hh | 2 | ||||
-rw-r--r-- | src/textual.cc | 94 | ||||
-rw-r--r-- | src/textual.h | 8 | ||||
-rw-r--r-- | src/transform.cc | 12 | ||||
-rw-r--r-- | src/transform.h | 5 | ||||
-rw-r--r-- | src/utils.cc | 48 | ||||
-rw-r--r-- | src/utils.h | 2 | ||||
-rw-r--r-- | src/value.cc | 45 | ||||
-rw-r--r-- | src/value.h | 6 | ||||
-rw-r--r-- | src/xml.cc | 20 | ||||
-rw-r--r-- | src/xml.h | 35 | ||||
-rw-r--r-- | src/xmlparse.cc | 17 | ||||
-rw-r--r-- | src/xpath.cc | 10 | ||||
-rw-r--r-- | src/xpath.h | 2 |
37 files changed, 658 insertions, 697 deletions
diff --git a/src/amount.cc b/src/amount.cc index 6020a0aa..7a74ef34 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -147,24 +147,24 @@ void amount_t::shutdown() mpz_clear(divisor); if (commodity_base_t::updater) { - delete commodity_base_t::updater; + checked_delete(commodity_base_t::updater); commodity_base_t::updater = NULL; } for (base_commodities_map::iterator i = commodity_base_t::commodities.begin(); i != commodity_base_t::commodities.end(); i++) - delete (*i).second; + checked_delete((*i).second); for (commodities_map::iterator i = commodity_t::commodities.begin(); i != commodity_t::commodities.end(); i++) - delete (*i).second; + checked_delete((*i).second); commodity_base_t::commodities.clear(); commodity_t::commodities.clear(); - delete commodity_t::commodities_by_ident; + checked_delete(commodity_t::commodities_by_ident); commodity_t::commodities_by_ident = NULL; commodity_t::null_commodity = NULL; @@ -172,7 +172,7 @@ void amount_t::shutdown() true_value->ref--; assert(true_value->ref == 0); - delete true_value; + checked_delete(true_value); true_value = NULL; } @@ -318,13 +318,13 @@ namespace { newbuf[0] = '-'; std::strcpy(&newbuf[1], result ? result : buf); mpz_set_str(dest, newbuf, 10); - delete[] newbuf; + checked_array_delete(newbuf); } else { mpz_set_str(dest, result ? result : buf, 10); } if (result) - delete[] result; + checked_array_delete(result); freedtoa(buf); return decpt; @@ -346,7 +346,7 @@ void amount_t::_release() if (--quantity->ref == 0) { if (! (quantity->flags & BIGINT_BULK_ALLOC)) - delete quantity; + checked_delete(quantity); else quantity->~bigint_t(); } @@ -1073,7 +1073,7 @@ void amount_t::print(std::ostream& _out, bool omit_commodity, if (! omit_commodity && comm.annotated) { annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm)); - assert(&ann.price != this); + assert(&*ann.price != this); ann.write_annotations(out); } @@ -1144,11 +1144,11 @@ static void parse_commodity(std::istream& in, string& symbol) symbol = buf; } -bool parse_annotations(std::istream& in, amount_t& price, - moment_t& date, string& tag) +void parse_annotations(std::istream& in, + optional<amount_t>& price, + optional<moment_t>& date, + optional<string>& tag) { - bool has_date = false; - do { char buf[256]; char c = peek_next_nonws(in); @@ -1163,19 +1163,22 @@ bool parse_annotations(std::istream& in, amount_t& price, else throw_(amount_error, "Commodity price lacks closing brace"); - price.parse(buf, AMOUNT_PARSE_NO_MIGRATE); - price.in_place_reduce(); + amount_t temp; + temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE); + temp.in_place_reduce(); // Since this price will maintain its own precision, make sure // it is at least as large as the base commodity, since the user // may have only specified {$1} or something similar. - if (price.has_commodity() && - price.quantity->prec < price.commodity().precision()) - price = price.round(); // no need to retain individual precision + if (temp.has_commodity() && + temp.quantity->prec < temp.commodity().precision()) + temp = temp.round(); // no need to retain individual precision + + price = temp; } else if (c == '[') { - if (is_valid_moment(date)) + if (date) throw_(amount_error, "Commodity specifies more than one date"); in.get(c); @@ -1186,10 +1189,9 @@ bool parse_annotations(std::istream& in, amount_t& price, throw_(amount_error, "Commodity date lacks closing bracket"); date = parse_datetime(buf); - has_date = true; } else if (c == '(') { - if (! tag.empty()) + if (tag) throw_(amount_error, "Commodity specifies more than one tag"); in.get(c); @@ -1207,12 +1209,10 @@ bool parse_annotations(std::istream& in, amount_t& price, } while (true); DEBUG("amounts.commodities", - "Parsed commodity annotations: " - << " price " << price << " " - << " date " << date << " " - << " tag " << tag); - - return has_date; + "Parsed commodity annotations: " + << " price " << (price ? price->to_string() : "NONE") << " " + << " date " << (date ? *date : moment_t()) << " " + << " tag " << (tag ? *tag : "NONE")); } void amount_t::parse(std::istream& in, uint8_t flags) @@ -1222,14 +1222,13 @@ void amount_t::parse(std::istream& in, uint8_t flags) // [-]NUM[ ]SYM [@ AMOUNT] // SYM[ ][-]NUM [@ AMOUNT] - string symbol; - string quant; - amount_t tprice; - moment_t tdate; - bool had_date = false; - string tag; - unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS; - bool negative = false; + string symbol; + string quant; + optional<amount_t> tprice; + optional<moment_t> tdate; + optional<string> ttag; + unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS; + bool negative = false; char c = peek_next_nonws(in); if (c == '-') { @@ -1252,7 +1251,7 @@ void amount_t::parse(std::istream& in, uint8_t flags) comm_flags |= COMMODITY_STYLE_SUFFIXED; if (! in.eof() && ((n = in.peek()) != '\n')) - had_date = parse_annotations(in, tprice, tdate, tag); + parse_annotations(in, tprice, tdate, ttag); } } else { parse_commodity(in, symbol); @@ -1264,7 +1263,7 @@ void amount_t::parse(std::istream& in, uint8_t flags) parse_quantity(in, quant); if (! quant.empty() && ! in.eof() && ((n = in.peek()) != '\n')) - had_date = parse_annotations(in, tprice, tdate, tag); + parse_annotations(in, tprice, tdate, ttag); } } @@ -1288,9 +1287,9 @@ void amount_t::parse(std::istream& in, uint8_t flags) } assert(commodity_); - if (! tprice.realzero() || had_date || ! tag.empty()) - commodity_ = - annotated_commodity_t::find_or_create(*commodity_, tprice, tdate, tag); + if (tprice || tdate || ttag) + commodity_ = annotated_commodity_t::find_or_create + (*commodity_, tprice, tdate, ttag); } // Determine the precision of the amount, based on the usage of @@ -1348,7 +1347,7 @@ void amount_t::parse(std::istream& in, uint8_t flags) *t = '\0'; mpz_set_str(MPZ(quantity), buf, 10); - delete[] buf; + checked_array_delete(buf); } else { mpz_set_str(MPZ(quantity), quant.c_str(), 10); } @@ -1564,9 +1563,9 @@ bool amount_t::valid() const return true; } -void amount_t::annotate_commodity(const amount_t& tprice, - const moment_t& tdate, - const string& tag) +void amount_t::annotate_commodity(const optional<amount_t>& tprice, + const optional<moment_t>& tdate, + const optional<string>& ttag) { const commodity_t * this_base; annotated_commodity_t * this_ann = NULL; @@ -1580,17 +1579,17 @@ 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); - - commodity_t * ann_comm = - annotated_commodity_t::find_or_create - (*this_base, ! tprice && this_ann ? this_ann->price : tprice, - ! is_valid_moment(tdate) && this_ann ? this_ann->date : tdate, - tag.empty() && this_ann ? this_ann->tag : tag); - if (ann_comm) + << *this << std::endl + << " price " << (tprice ? tprice->to_string() : "NONE") << " " + << " date " << (tdate ? *tdate : moment_t()) << " " + << " ttag " << (ttag ? *ttag : "NONE")); + + if (commodity_t * ann_comm = + annotated_commodity_t::find_or_create + (*this_base, + ! tprice && this_ann ? this_ann->price : tprice, + ! tdate && this_ann ? this_ann->date : tdate, + ! ttag && this_ann ? this_ann->tag : ttag)) set_commodity(*ann_comm); DEBUG("amounts.commodities", " Annotated amount is " << *this); @@ -1607,8 +1606,8 @@ amount_t amount_t::strip_annotations(const bool _keep_price, DEBUG("amounts.commodities", "Reducing commodity for amount " << *this << std::endl << " keep price " << _keep_price << " " - << " keep date " << _keep_date << " " - << " keep tag " << _keep_tag); + << " keep date " << _keep_date << " " + << " keep tag " << _keep_tag); annotated_commodity_t& ann_comm(static_cast<annotated_commodity_t&>(commodity())); @@ -1617,13 +1616,14 @@ amount_t amount_t::strip_annotations(const bool _keep_price, commodity_t * new_comm; if ((_keep_price && ann_comm.price) || - (_keep_date && is_valid_moment(ann_comm.date)) || - (_keep_tag && ! ann_comm.tag.empty())) + (_keep_date && ann_comm.date) || + (_keep_tag && ann_comm.tag)) { new_comm = annotated_commodity_t::find_or_create - (*ann_comm.ptr, _keep_price ? ann_comm.price : amount_t(), - _keep_date ? ann_comm.date : moment_t(), - _keep_tag ? ann_comm.tag : ""); + (*ann_comm.ptr, + _keep_price ? ann_comm.price : optional<amount_t>(), + _keep_date ? ann_comm.date : optional<moment_t>(), + _keep_tag ? ann_comm.tag : optional<string>()); } else { new_comm = commodity_t::find_or_create(ann_comm.base_symbol()); } @@ -1638,8 +1638,9 @@ amount_t amount_t::strip_annotations(const bool _keep_price, optional<amount_t> amount_t::price() const { - if (commodity_ && commodity_->annotated) { - amount_t t(((annotated_commodity_t *)commodity_)->price); + if (commodity_ && commodity_->annotated && + ((annotated_commodity_t *)commodity_)->price) { + amount_t t(*((annotated_commodity_t *)commodity_)->price); t *= number(); DEBUG("amounts.commodities", "Returning price of " << *this << " = " << t); @@ -1800,7 +1801,7 @@ commodity_t * commodity_t::find(const string& symbol) amount_t commodity_base_t::value(const moment_t& moment) { moment_t age; - amount_t price; + amount_t price; if (history) { assert(history->prices.size() > 0); @@ -1851,12 +1852,12 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const price != static_cast<const annotated_commodity_t&>(comm).price)) return false; - if (is_valid_moment(date) && + if (date && (! comm.annotated || date != static_cast<const annotated_commodity_t&>(comm).date)) return false; - if (! tag.empty() && + if (tag && (! comm.annotated || tag != static_cast<const annotated_commodity_t&>(comm).tag)) return false; @@ -1865,27 +1866,27 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const } void -annotated_commodity_t::write_annotations(std::ostream& out, - const amount_t& price, - const moment_t& date, - const string& tag) +annotated_commodity_t::write_annotations(std::ostream& out, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag) { if (price) - out << " {" << price << '}'; + out << " {" << *price << '}'; - if (is_valid_moment(date)) - out << " [" << date << ']'; + if (date) + out << " [" << *date << ']'; - if (! tag.empty()) - out << " (" << tag << ')'; + if (tag) + out << " (" << *tag << ')'; } commodity_t * -annotated_commodity_t::create(const commodity_t& comm, - const amount_t& price, - const moment_t& date, - const string& tag, - const string& mapping_key) +annotated_commodity_t::create(const commodity_t& comm, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag, + const string& mapping_key) { std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t); @@ -1902,11 +1903,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 ? price->to_string() : "NONE") << " " + << " date " << (date ? *date : moment_t()) << " " + << " tag " << (tag ? *tag : "NONE")); // Add the fully annotated name to the map, so that this symbol may // quickly be found again. @@ -1922,12 +1923,12 @@ annotated_commodity_t::create(const commodity_t& comm, } namespace { - string make_qualified_name(const commodity_t& comm, - const amount_t& price, - const moment_t& date, - const string& tag) + string make_qualified_name(const commodity_t& comm, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag) { - if (price < 0) + if (price && *price < 0) throw_(amount_error, "A commodity's price may not be negative"); std::ostringstream name; @@ -1937,9 +1938,9 @@ namespace { DEBUG("amounts.commodities", "make_qualified_name for " << comm.qualified_symbol << std::endl - << " price " << price << " " - << " date " << date << " " - << " tag " << tag); + << " price " << (price ? price->to_string() : "NONE") << " " + << " date " << (date ? *date : moment_t()) << " " + << " tag " << (tag ? *tag : "NONE")); DEBUG("amounts.commodities", "qualified_name is " << name.str()); @@ -1948,10 +1949,10 @@ namespace { } commodity_t * -annotated_commodity_t::find_or_create(const commodity_t& comm, - const amount_t& price, - const moment_t& date, - const string& tag) +annotated_commodity_t::find_or_create(const commodity_t& comm, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag) { string name = make_qualified_name(comm, price, date, tag); @@ -1991,9 +1992,9 @@ bool compare_amount_commodities::operator()(const amount_t * left, return false; if (aleftcomm.price && arightcomm.price) { - amount_t leftprice(aleftcomm.price); + amount_t leftprice(*aleftcomm.price); leftprice.in_place_reduce(); - amount_t rightprice(arightcomm.price); + amount_t rightprice(*arightcomm.price); rightprice.in_place_reduce(); if (leftprice.commodity() == rightprice.commodity()) { @@ -2013,28 +2014,25 @@ bool compare_amount_commodities::operator()(const amount_t * left, } } - if (! is_valid_moment(aleftcomm.date) && - is_valid_moment(arightcomm.date)) + if (! aleftcomm.date && arightcomm.date) return true; - if (is_valid_moment(aleftcomm.date) && - ! is_valid_moment(arightcomm.date)) + if (aleftcomm.date && ! arightcomm.date) return false; - if (is_valid_moment(aleftcomm.date) && - is_valid_moment(arightcomm.date)) { - duration_t diff = aleftcomm.date - arightcomm.date; + if (aleftcomm.date && arightcomm.date) { + duration_t diff = *aleftcomm.date - *arightcomm.date; return diff.is_negative(); } - if (aleftcomm.tag.empty() && ! arightcomm.tag.empty()) + if (! aleftcomm.tag && arightcomm.tag) return true; - if (! aleftcomm.tag.empty() && arightcomm.tag.empty()) + if (aleftcomm.tag && ! arightcomm.tag) return false; - if (! aleftcomm.tag.empty() && ! arightcomm.tag.empty()) - return aleftcomm.tag < arightcomm.tag; + if (aleftcomm.tag && arightcomm.tag) + return *aleftcomm.tag < *arightcomm.tag; - assert(0); + assert(false); return true; } } diff --git a/src/amount.h b/src/amount.h index 84be02b3..e1f7d6ef 100644 --- a/src/amount.h +++ b/src/amount.h @@ -142,9 +142,9 @@ class amount_t commodity_t& commodity() const; - void annotate_commodity(const amount_t& price, - const moment_t& date = moment_t(), - const string& tag = ""); + void annotate_commodity(const optional<amount_t>& tprice, + const optional<moment_t>& tdate = optional<moment_t>(), + const optional<string>& ttag = optional<string>()); amount_t strip_annotations(const bool _keep_price = keep_price, const bool _keep_date = keep_date, @@ -348,8 +348,10 @@ class amount_t friend void clean_commodity_history(char * item_pool, char * item_pool_end); - friend bool parse_annotations(std::istream& in, amount_t& price, - moment_t& date, string& tag); + friend void parse_annotations(std::istream& in, + optional<amount_t>& price, + optional<moment_t>& date, + optional<string>& tag); // Streaming interface @@ -513,9 +515,9 @@ class commodity_base_t ~commodity_base_t() { TRACE_DTOR(commodity_base_t); - if (history) delete history; - if (smaller) delete smaller; - if (larger) delete larger; + if (history) checked_delete(history); + if (smaller) checked_delete(smaller); + if (larger) checked_delete(larger); } static base_commodities_map commodities; @@ -538,10 +540,10 @@ class commodity_base_t public: virtual ~updater_t() {} virtual void operator()(commodity_base_t& commodity, - const moment_t& moment, - const moment_t& date, - const moment_t& last, - amount_t& price) = 0; + const moment_t& moment, + const moment_t& date, + const moment_t& last, + amount_t& price) = 0; }; friend class updater_t; @@ -659,7 +661,7 @@ class commodity_t } void set_smaller(const amount_t& arg) { if (base->smaller) - delete base->smaller; + checked_delete(base->smaller); base->smaller = new amount_t(arg); } @@ -668,7 +670,7 @@ class commodity_t } void set_larger(const amount_t& arg) { if (base->larger) - delete base->larger; + checked_delete(base->larger); base->larger = new amount_t(arg); } @@ -694,9 +696,9 @@ class annotated_commodity_t : public commodity_t public: const commodity_t * ptr; - amount_t price; - moment_t date; - string tag; + optional<amount_t> price; + optional<moment_t> date; + optional<string> tag; explicit annotated_commodity_t() { TRACE_CTOR(annotated_commodity_t, ""); @@ -712,22 +714,22 @@ class annotated_commodity_t : public commodity_t annotated_commodity_t::write_annotations(out, price, date, tag); } - static void write_annotations(std::ostream& out, - const amount_t& price, - const moment_t& date, - const string& tag); + static void write_annotations(std::ostream& out, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag); private: - static commodity_t * create(const commodity_t& comm, - const amount_t& price, - const moment_t& date, - const string& tag, - const string& mapping_key); - - static commodity_t * find_or_create(const commodity_t& comm, - const amount_t& price, - const moment_t& date, - const string& tag); + static commodity_t * create(const commodity_t& comm, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag, + const string& mapping_key); + + static commodity_t * find_or_create(const commodity_t& comm, + const optional<amount_t>& price, + const optional<moment_t>& date, + const optional<string>& tag); friend class amount_t; }; diff --git a/src/balance.h b/src/balance.h index e8665335..463191b7 100644 --- a/src/balance.h +++ b/src/balance.h @@ -448,15 +448,12 @@ class balance_t void write(std::ostream& out, const int first_width, const int latter_width = -1) const; - void in_place_abs() { - for (amounts_map::iterator i = amounts.begin(); - i != amounts.end(); - i++) - (*i).second = (*i).second.abs(); - } balance_t abs() const { balance_t temp = *this; - temp.in_place_abs(); + for (amounts_map::iterator i = temp.amounts.begin(); + i != temp.amounts.end(); + i++) + (*i).second = (*i).second.abs(); return temp; } @@ -503,81 +500,64 @@ inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) { class balance_pair_t { public: - balance_t quantity; - balance_t * cost; + balance_t quantity; + optional<balance_t> cost; // constructors - balance_pair_t() : cost(NULL) { + balance_pair_t() { TRACE_CTOR(balance_pair_t, ""); } balance_pair_t(const balance_pair_t& bal_pair) - : quantity(bal_pair.quantity), cost(NULL) { + : quantity(bal_pair.quantity), cost(bal_pair.cost) { TRACE_CTOR(balance_pair_t, "copy"); - if (bal_pair.cost) - cost = new balance_t(*bal_pair.cost); } balance_pair_t(const balance_t& _quantity) - : quantity(_quantity), cost(NULL) { + : quantity(_quantity) { TRACE_CTOR(balance_pair_t, "const balance_t&"); } balance_pair_t(const amount_t& _quantity) - : quantity(_quantity), cost(NULL) { + : quantity(_quantity) { TRACE_CTOR(balance_pair_t, "const amount_t&"); } template <typename T> - balance_pair_t(T val) : quantity(val), cost(NULL) { + balance_pair_t(T val) : quantity(val) { TRACE_CTOR(balance_pair_t, "T"); } // destructor ~balance_pair_t() { TRACE_DTOR(balance_pair_t); - if (cost) delete cost; } // assignment operator balance_pair_t& operator=(const balance_pair_t& bal_pair) { if (this != &bal_pair) { - if (cost) { - delete cost; - cost = NULL; - } quantity = bal_pair.quantity; - if (bal_pair.cost) - cost = new balance_t(*bal_pair.cost); + cost = bal_pair.cost; } return *this; } balance_pair_t& operator=(const balance_t& bal) { - if (cost) { - delete cost; - cost = NULL; - } quantity = bal; + cost = optional<balance_t>(); return *this; } balance_pair_t& operator=(const amount_t& amt) { - if (cost) { - delete cost; - cost = NULL; - } quantity = amt; + cost = optional<balance_t>(); return *this; } template <typename T> balance_pair_t& operator=(T val) { - if (cost) { - delete cost; - cost = NULL; - } quantity = val; + cost = optional<balance_t>(); return *this; } // in-place arithmetic balance_pair_t& operator+=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) - cost = new balance_t(quantity); + cost = quantity; quantity += bal_pair.quantity; if (cost) *cost += bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; @@ -602,7 +582,7 @@ class balance_pair_t balance_pair_t& operator-=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) - cost = new balance_t(quantity); + cost = quantity; quantity -= bal_pair.quantity; if (cost) *cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; @@ -673,7 +653,7 @@ class balance_pair_t // multiplication and division balance_pair_t& operator*=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) - cost = new balance_t(quantity); + cost = quantity; quantity *= bal_pair.quantity; if (cost) *cost *= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; @@ -698,7 +678,7 @@ class balance_pair_t balance_pair_t& operator/=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) - cost = new balance_t(quantity); + cost = quantity; quantity /= bal_pair.quantity; if (cost) *cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; @@ -852,9 +832,9 @@ class balance_pair_t // unary negation void in_place_negate() { - quantity = quantity.negate(); + quantity.in_place_negate(); if (cost) - *cost = cost->negate(); + cost->in_place_negate(); } balance_pair_t negate() const { balance_pair_t temp = *this; @@ -880,14 +860,11 @@ class balance_pair_t return ((! cost || cost->realzero()) && quantity.realzero()); } - void in_place_abs() { - quantity = quantity.abs(); - if (cost) - *cost = cost->abs(); - } balance_pair_t abs() const { balance_pair_t temp = *this; - temp.in_place_abs(); + temp.quantity = temp.quantity.abs(); + if (temp.cost) + temp.cost = temp.cost->abs(); return temp; } @@ -922,9 +899,9 @@ class balance_pair_t } balance_pair_t& add(const amount_t& amt, - const amount_t * a_cost = NULL) { + const optional<amount_t>& a_cost = optional<amount_t>()) { if (a_cost && ! cost) - cost = new balance_t(quantity); + cost = quantity; quantity += amt; if (cost) *cost += a_cost ? *a_cost : amt; @@ -948,7 +925,7 @@ class balance_pair_t void in_place_round() { quantity = quantity.round(); if (cost) - *cost = cost->round(); + cost = cost->round(); } balance_pair_t round() const { balance_pair_t temp(*this); @@ -959,7 +936,7 @@ class balance_pair_t balance_pair_t unround() { balance_pair_t temp(quantity.unround()); if (cost) - temp.cost = new balance_t(cost->unround()); + temp.cost = cost->unround(); return temp; } }; diff --git a/src/binary.cc b/src/binary.cc index d3238b5a..55d8e03a 100644 --- a/src/binary.cc +++ b/src/binary.cc @@ -59,7 +59,7 @@ void read_binary_string(std::istream& in, string& str) in.read(buf, slen); buf[slen] = '\0'; str = buf; - delete[] buf; + checked_array_delete(buf); } else if (len) { char buf[256]; @@ -374,7 +374,7 @@ account_t * read_binary_account(char *& data, journal_t * journal, // journal's own master account. if (master && acct != master) { - delete acct; + checked_delete(acct); acct = master; } @@ -441,7 +441,7 @@ unsigned int read_binary_journal(std::istream& in, accounts = accounts_next = new account_t *[a_count]; assert(journal->master); - delete journal->master; + checked_delete(journal->master); journal->master = read_binary_account(data, journal, master); if (read_binary_bool(data)) @@ -501,14 +501,14 @@ unsigned int read_binary_journal(std::istream& in, (*c).second->precision = commodity->precision; (*c).second->flags = commodity->flags; if ((*c).second->smaller) - delete (*c).second->smaller; + checked_delete((*c).second->smaller); (*c).second->smaller = commodity->smaller; if ((*c).second->larger) - delete (*c).second->larger; + checked_delete((*c).second->larger); (*c).second->larger = commodity->larger; *(base_commodities_next - 1) = (*c).second; - delete commodity; + checked_delete(commodity); } } @@ -538,7 +538,7 @@ unsigned int read_binary_journal(std::istream& in, commodity->symbol()); *(commodities_next - 1) = (*c).second; - delete commodity; + checked_delete(commodity); } } @@ -583,9 +583,9 @@ unsigned int read_binary_journal(std::istream& in, // Clean up and return the number of entries read - delete[] accounts; - delete[] commodities; - delete[] data_pool; + checked_array_delete(accounts); + checked_array_delete(commodities); + checked_array_delete(data_pool); VALIDATE(journal->valid()); diff --git a/src/derive.h b/src/derive.h index c0607fc2..dfc65c00 100644 --- a/src/derive.h +++ b/src/derive.h @@ -1,7 +1,7 @@ #ifndef _DERIVE_H #define _DERIVE_H -#include "journal.h" +#include "xpath.h" namespace ledger { diff --git a/src/format.h b/src/format.h index e271fcf7..e169011f 100644 --- a/src/format.h +++ b/src/format.h @@ -32,13 +32,13 @@ class format_t switch (kind) { case TEXT: - delete chars; + checked_delete(chars); break; case XPATH: - delete xpath; + checked_delete(xpath); break; case GROUP: - delete format; + checked_delete(format); break; default: assert(! chars); @@ -75,7 +75,7 @@ class format_t for (std::list<element_t *>::iterator i = elements.begin(); i != elements.end(); i++) - delete *i; + checked_delete(*i); elements.clear(); } diff --git a/src/gnucash.cc b/src/gnucash.cc index 3859ebb4..0fb62bf0 100644 --- a/src/gnucash.cc +++ b/src/gnucash.cc @@ -77,7 +77,7 @@ void endElement(void *userData, const char *name) if (! parser->curr_journal->add_entry(parser->curr_entry)) { print_entry(std::cerr, *parser->curr_entry); parser->have_error = "The above entry does not balance"; - delete parser->curr_entry; + checked_delete(parser->curr_entry); } else { parser->curr_entry->src_idx = parser->src_idx; parser->curr_entry->beg_pos = parser->beg_pos; @@ -122,7 +122,7 @@ void endElement(void *userData, const char *name) xact->state = parser->curr_state; xact->amount = value; if (value != parser->curr_value) - xact->cost = new amount_t(parser->curr_value); + xact->cost = amount_t(parser->curr_value); xact->beg_pos = parser->beg_pos; xact->beg_line = parser->beg_line; @@ -291,10 +291,10 @@ 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, - journal_t * journal, - account_t * master, - const string * original_file) +unsigned int gnucash_parser_t::parse(std::istream& in, + journal_t * journal, + account_t * master, + const optional<path>& original_file) { char buf[BUFSIZ]; @@ -315,7 +315,7 @@ 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 diff --git a/src/gnucash.h b/src/gnucash.h index a0d9fb18..cddf9df9 100644 --- a/src/gnucash.h +++ b/src/gnucash.h @@ -32,7 +32,7 @@ struct gnucash_parser_t : public parser_t std::istream * instreamp; unsigned int offset; XML_Parser parser; - string path; + path pathname; unsigned int src_idx; unsigned long beg_pos; unsigned long beg_line; @@ -62,10 +62,10 @@ struct gnucash_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()); amount_t convert_number(const string& number, int * precision = NULL); }; diff --git a/src/journal.cc b/src/journal.cc index 9bb453ef..6d50f50e 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -1,4 +1,5 @@ #include "journal.h" +#include "xpath.h" #include "mask.h" #if 0 #ifdef USE_BOOST_PYTHON @@ -15,21 +16,20 @@ bool transaction_t::use_effective_date = false; transaction_t::~transaction_t() { TRACE_DTOR(transaction_t); - if (cost) delete cost; } moment_t transaction_t::actual_date() const { - if (! is_valid_moment(_date) && entry) + if (! _date && entry) return entry->actual_date(); - return _date; + return *_date; } moment_t transaction_t::effective_date() const { - if (! is_valid_moment(_date_eff) && entry) + if (! _date_eff && entry) return entry->effective_date(); - return _date_eff; + return *_date_eff; } bool transaction_t::valid() const @@ -44,15 +44,10 @@ bool transaction_t::valid() const return false; } - bool found = false; - for (transactions_list::const_iterator i = entry->transactions.begin(); - i != entry->transactions.end(); - i++) - if (*i == this) { - found = true; - break; - } - if (! found) { + transactions_list::const_iterator i = + std::find(entry->transactions.begin(), + entry->transactions.end(), this); + if (i == entry->transactions.end()) { DEBUG("ledger.validate", "transaction_t: ! found"); return false; } @@ -62,7 +57,7 @@ bool transaction_t::valid() const return false; } - if (! amount.valid()) { + if (amount && ! amount->valid()) { DEBUG("ledger.validate", "transaction_t: ! amount.valid()"); return false; } @@ -98,16 +93,16 @@ bool entry_base_t::finalize() // and the per-unit price of unpriced commodities. value_t balance; + bool no_amounts = true; + bool saw_null = false; - bool no_amounts = true; - bool saw_null = false; for (transactions_list::const_iterator x = transactions.begin(); x != transactions.end(); x++) if (! ((*x)->flags & TRANSACTION_VIRTUAL) || ((*x)->flags & TRANSACTION_BALANCE)) { - amount_t * p = (*x)->cost ? (*x)->cost : &(*x)->amount; - if (*p) { + optional<amount_t>& p((*x)->cost ? (*x)->cost : (*x)->amount); + if (p) { if (no_amounts) { balance = *p; no_amounts = false; @@ -115,12 +110,13 @@ bool entry_base_t::finalize() balance += *p; } - if ((*x)->cost && (*x)->amount.commodity().annotated) { + assert((*x)->amount); + if ((*x)->cost && (*x)->amount->commodity().annotated) { annotated_commodity_t& ann_comm(static_cast<annotated_commodity_t&> - ((*x)->amount.commodity())); + ((*x)->amount->commodity())); if (ann_comm.price) - balance += ann_comm.price * (*x)->amount.number() - *((*x)->cost); + balance += *ann_comm.price * (*x)->amount->number() - *((*x)->cost); } } else { saw_null = true; @@ -151,7 +147,8 @@ bool entry_base_t::finalize() if (! saw_null && balance && balance.type == value_t::BALANCE && ((balance_t *) balance.data)->amounts.size() == 2) { transactions_list::const_iterator x = transactions.begin(); - commodity_t& this_comm = (*x)->amount.commodity(); + assert((*x)->amount); + commodity_t& this_comm = (*x)->amount->commodity(); amounts_map::const_iterator this_bal = ((balance_t *) balance.data)->amounts.find(&this_comm); @@ -165,22 +162,22 @@ bool entry_base_t::finalize() for (; x != transactions.end(); x++) { if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL) || - ! (*x)->amount || (*x)->amount.commodity() != this_comm) + ! (*x)->amount || (*x)->amount->commodity() != this_comm) continue; assert((*x)->amount); - balance -= (*x)->amount; + balance -= *(*x)->amount; entry_t * entry = dynamic_cast<entry_t *>(this); - if ((*x)->amount.commodity() && - ! (*x)->amount.commodity().annotated) - (*x)->amount.annotate_commodity + if ((*x)->amount->commodity() && + ! (*x)->amount->commodity().annotated) + (*x)->amount->annotate_commodity (per_unit_cost.abs(), - entry ? entry->actual_date() : moment_t(), - entry ? entry->code : ""); + entry ? entry->actual_date() : optional<moment_t>(), + entry ? entry->code : optional<string>()); - (*x)->cost = new amount_t(- (per_unit_cost * (*x)->amount.number())); + (*x)->cost = - (per_unit_cost * (*x)->amount->number()); balance += *(*x)->cost; } } @@ -193,7 +190,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 || (((*x)->flags & TRANSACTION_VIRTUAL) && ! ((*x)->flags & TRANSACTION_BALANCE))) continue; @@ -246,7 +243,7 @@ bool entry_base_t::finalize() (*x)->amount = ((amount_t *) balance.data)->negate(); (*x)->flags |= TRANSACTION_CALCULATED; - balance += (*x)->amount; + balance += *(*x)->amount; break; default: @@ -326,6 +323,21 @@ bool entry_t::valid() const return true; } +auto_entry_t::auto_entry_t() +{ + TRACE_CTOR(auto_entry_t, ""); +} + +auto_entry_t::auto_entry_t(const string& _predicate) + : predicate(new xml::xpath_t(_predicate)) +{ + TRACE_CTOR(auto_entry_t, "const string&"); +} + +auto_entry_t::~auto_entry_t() { + TRACE_DTOR(auto_entry_t); +} + void auto_entry_t::extend_entry(entry_base_t& entry, bool post) { transactions_list initial_xacts(entry.transactions.begin(), @@ -335,19 +347,21 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post) i != initial_xacts.end(); i++) { // jww (2006-09-10): Create a scope here based on entry - if (predicate.calc((xml::node_t *) NULL)) { + if (predicate->calc((xml::node_t *) NULL)) { for (transactions_list::iterator t = transactions.begin(); t != transactions.end(); t++) { amount_t amt; - if (! (*t)->amount.commodity()) { + assert((*t)->amount); + if (! (*t)->amount->commodity()) { if (! post) continue; - amt = (*i)->amount * (*t)->amount; + assert((*i)->amount); + amt = *(*i)->amount * *(*t)->amount; } else { if (post) continue; - amt = (*t)->amount; + amt = *(*t)->amount; } account_t * account = (*t)->account; @@ -371,7 +385,7 @@ account_t::~account_t() for (accounts_map::iterator i = accounts.begin(); i != accounts.end(); i++) - delete (*i).second; + checked_delete((*i).second); } account_t * account_t::find_account(const string& name, @@ -496,10 +510,10 @@ journal_t::~journal_t() TRACE_DTOR(journal_t); assert(master); - delete master; + checked_delete(master); if (document) - delete document; + checked_delete(document); // Don't bother unhooking each entry's transactions from the // accounts they refer to, because all accounts are about to @@ -509,7 +523,7 @@ journal_t::~journal_t() i++) if (! item_pool || ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end) - delete *i; + checked_delete(*i); else (*i)->~entry_t(); @@ -518,7 +532,7 @@ journal_t::~journal_t() i++) if (! item_pool || ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end) - delete *i; + checked_delete(*i); else (*i)->~auto_entry_t(); @@ -527,12 +541,12 @@ journal_t::~journal_t() i++) if (! item_pool || ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end) - delete *i; + checked_delete(*i); else (*i)->~period_entry_t(); if (item_pool) - delete[] item_pool; + checked_array_delete(item_pool); } bool journal_t::add_entry(entry_t * entry) @@ -551,9 +565,12 @@ bool journal_t::add_entry(entry_t * entry) for (transactions_list::const_iterator i = entry->transactions.begin(); i != entry->transactions.end(); i++) - if ((*i)->cost && (*i)->amount) - (*i)->amount.commodity().add_price(entry->date(), - *(*i)->cost / (*i)->amount.number()); + if ((*i)->cost) { + assert((*i)->amount); + assert(*(*i)->amount); + (*i)->amount->commodity().add_price(entry->date(), + *(*i)->cost / (*i)->amount->number()); + } return true; } @@ -614,7 +631,7 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base, } else if (const auto_entry_t * entry = dynamic_cast<const auto_entry_t *>(&entry_base)) { - out << "= " << entry->predicate.expr << '\n'; + out << "= " << entry->predicate->expr << '\n'; print_format = prefix + " %-34A %12o\n"; } else if (const period_entry_t * entry = diff --git a/src/journal.h b/src/journal.h index a2490efc..711cac19 100644 --- a/src/journal.h +++ b/src/journal.h @@ -1,10 +1,20 @@ #ifndef _JOURNAL_H #define _JOURNAL_H -#include "xpath.h" +#include "amount.h" namespace ledger { +namespace xml { + class document_t; + class xpath_t; + + class transaction_node_t; + class entry_node_t; + class account_node_t; + class journal_node_t; +}; + // These flags persist with the object #define TRANSACTION_NORMAL 0x0000 #define TRANSACTION_VIRTUAL 0x0001 @@ -21,47 +31,48 @@ class transaction_t public: enum state_t { UNCLEARED, CLEARED, PENDING }; - entry_t * entry; - moment_t _date; - moment_t _date_eff; - account_t * account; - amount_t amount; - string amount_expr; - amount_t * cost; - string cost_expr; - state_t state; - unsigned short flags; - string note; - unsigned long beg_pos; - unsigned long beg_line; - unsigned long end_pos; - unsigned long end_line; - - mutable void * data; + entry_t * entry; + optional<moment_t> _date; + optional<moment_t> _date_eff; + account_t * account; + optional<amount_t> amount; + optional<string> amount_expr; + optional<amount_t> cost; + optional<string> cost_expr; + state_t state; + unsigned short flags; + optional<string> note; + unsigned long beg_pos; + unsigned long beg_line; + unsigned long end_pos; + unsigned long end_line; + + typedef xml::transaction_node_t node_type; + mutable node_type * data; static bool use_effective_date; - transaction_t(account_t * _account = NULL) - : 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) { + explicit transaction_t(account_t * _account = NULL) + : entry(NULL), account(_account), state(UNCLEARED), + flags(TRANSACTION_NORMAL), beg_pos(0), beg_line(0), + end_pos(0), end_line(0), data(NULL) { TRACE_CTOR(transaction_t, "account_t *"); } - 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) { - TRACE_CTOR(transaction_t, "account_t *, const amount_t&, unsigned int, const string&"); + explicit transaction_t(account_t * _account, + const amount_t& _amount, + unsigned int _flags = TRANSACTION_NORMAL, + const optional<string> _note = optional<string>()) + : entry(NULL), account(_account), amount(_amount), + state(UNCLEARED), flags(_flags), note(_note), + beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { + TRACE_CTOR(transaction_t, + "account_t *, const amount_t&, unsigned int, const string&"); } - transaction_t(const transaction_t& xact) + explicit 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) { + cost(xact.cost), state(xact.state), flags(xact.flags), note(xact.note), + beg_pos(xact.beg_pos), beg_line(xact.beg_line), + end_pos(xact.end_pos), end_line(xact.end_line), data(NULL) { TRACE_CTOR(transaction_t, "copy"); } ~transaction_t(); @@ -75,13 +86,6 @@ class transaction_t return actual_date(); } - bool operator==(const transaction_t& xact) { - return this == &xact; - } - bool operator!=(const transaction_t& xact) { - return ! (*this == xact); - } - bool valid() const; }; @@ -130,7 +134,7 @@ class entry_base_t i != transactions.end(); i++) if (! ((*i)->flags & TRANSACTION_BULK_ALLOC)) - delete *i; + checked_delete(*i); else (*i)->~transaction_t(); } @@ -152,12 +156,13 @@ class entry_base_t class entry_t : public entry_base_t { public: - moment_t _date; - moment_t _date_eff; - string code; - string payee; + moment_t _date; + optional<moment_t> _date_eff; + optional<string> code; + string payee; - mutable void * data; + typedef xml::entry_node_t node_type; + mutable node_type * data; entry_t() : data(NULL) { TRACE_CTOR(entry_t, ""); @@ -172,9 +177,7 @@ class entry_t : public entry_base_t return _date; } moment_t effective_date() const { - if (! is_valid_moment(_date_eff)) - return _date; - return _date_eff; + return _date_eff ? *_date_eff : _date; } moment_t date() const { if (transaction_t::use_effective_date) @@ -184,7 +187,6 @@ class entry_t : public entry_base_t } virtual void add_transaction(transaction_t * xact); - virtual bool valid() const; bool get_state(transaction_t::state_t * state) const; @@ -218,19 +220,11 @@ DECLARE_EXCEPTION(balance_error); class auto_entry_t : public entry_base_t { public: - xml::xpath_t predicate; + scoped_ptr<xml::xpath_t> predicate; - auto_entry_t() { - TRACE_CTOR(auto_entry_t, ""); - } - auto_entry_t(const string& _predicate) - : predicate(_predicate) { - TRACE_CTOR(auto_entry_t, "const string&"); - } - - virtual ~auto_entry_t() { - TRACE_DTOR(auto_entry_t); - } + auto_entry_t(); + auto_entry_t(const string& _predicate); + virtual ~auto_entry_t(); virtual void extend_entry(entry_base_t& entry, bool post); virtual bool valid() const { @@ -248,8 +242,8 @@ struct auto_entry_finalizer_t : public entry_finalizer_t { class period_entry_t : public entry_base_t { public: - interval_t period; - string period_string; + interval_t period; + string period_string; period_entry_t() { TRACE_CTOR(period_entry_t, ""); @@ -281,33 +275,31 @@ class account_t public: typedef unsigned long ident_t; - journal_t * journal; - account_t * parent; - string name; - string note; - unsigned short depth; - accounts_map accounts; + journal_t * journal; + account_t * parent; + string name; + optional<string> note; + unsigned short depth; + accounts_map accounts; + + typedef xml::account_node_t node_type; + mutable node_type * data; - mutable void * data; mutable ident_t ident; mutable string _fullname; account_t(account_t * _parent = NULL, const string& _name = "", - const string& _note = "") + const optional<string> _note = optional<string>()) : parent(_parent), name(_name), note(_note), depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { TRACE_CTOR(account_t, "account_t *, const string&, const string&"); } ~account_t(); - bool operator==(const account_t& account) { - return this == &account; - } - bool operator!=(const account_t& account) { - return ! (*this == account); + operator string() const { + return fullname(); } - string fullname() const; void add_account(account_t * acct) { @@ -322,10 +314,6 @@ class account_t account_t * find_account(const string& name, bool auto_create = true); - operator string() const { - return fullname(); - } - bool valid() const; friend class journal_t; @@ -372,6 +360,7 @@ 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<path> path_list; typedef std::list<string> strings_list; class session_t; @@ -379,21 +368,24 @@ class session_t; class journal_t { public: - session_t * session; - account_t * master; - account_t * basket; - entries_list entries; - strings_list sources; - string price_db; - char * item_pool; - char * item_pool_end; + session_t * session; + account_t * master; + account_t * basket; + entries_list entries; + path_list sources; + optional<path> price_db; + char * item_pool; + char * item_pool_end; // This is used for dynamically representing the journal data as an // XML tree, to facilitate transformations without modifying any of // the underlying structures (the transformers modify the XML tree // -- perhaps even adding, changing or deleting nodes -- but they do // not affect the basic data parsed from the journal file). - xml::document_t * document; + mutable xml::document_t * document; + + typedef xml::journal_node_t node_type; + mutable node_type * data; auto_entries_list auto_entries; period_entries_list period_entries; @@ -410,13 +402,6 @@ class journal_t } ~journal_t(); - bool operator==(const journal_t& journal) { - return this == &journal; - } - bool operator!=(const journal_t& journal) { - return ! (*this == journal); - } - void add_account(account_t * acct) { master->add_account(acct); acct->journal = this; diff --git a/src/main.cc b/src/main.cc index 0af4da0d..f70d0bd9 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,15 +1,15 @@ +#include "utils.h" +#include "option.h" +#include "gnucash.h" +#include "qif.h" +#include "ofx.h" + #if defined(USE_BOOST_PYTHON) #include <pyledger.h> #else #include <ledger.h> #endif -#include "acconf.h" -#include "option.h" -#include "gnucash.h" -#include "qif.h" -#include "ofx.h" - #ifdef HAVE_UNIX_PIPES #include <sys/types.h> #include <sys/wait.h> @@ -33,7 +33,7 @@ static int read_and_report(report_t * report, int argc, char * argv[], // Handle the command-line arguments - std::list<string> args; + strings_list args; process_arguments(argc - 1, argv + 1, false, report, args); if (args.empty()) { @@ -44,10 +44,10 @@ static int read_and_report(report_t * report, int argc, char * argv[], } strings_list::iterator arg = args.begin(); - if (session.cache_file == "<none>") + if (! session.cache_file) session.use_cache = false; else - session.use_cache = session.data_file.empty() && session.price_db.empty(); + session.use_cache = ! session.data_file.empty() && session.price_db; DEBUG("ledger.session.cache", "1. use_cache = " << session.use_cache); @@ -58,25 +58,25 @@ static int read_and_report(report_t * report, int argc, char * argv[], TRACE_FINISH(environment, 1); const char * p = std::getenv("HOME"); - string home = p ? p : ""; + path home = p ? p : ""; - if (session.init_file.empty()) - session.init_file = home + "/.ledgerrc"; - if (session.price_db.empty()) - session.price_db = home + "/.pricedb"; + if (! session.init_file) + session.init_file = home / ".ledgerrc"; + if (! session.price_db) + session.price_db = home / ".pricedb"; - if (session.cache_file.empty()) - session.cache_file = home + "/.ledger-cache"; + if (! session.cache_file) + session.cache_file = home / ".ledger-cache"; - if (session.data_file == session.cache_file) + if (session.data_file == *session.cache_file) session.use_cache = false; DEBUG("ledger.session.cache", "2. use_cache = " << session.use_cache); - INFO("Initialization file is " << session.init_file); - INFO("Price database is " << session.price_db); - INFO("Binary cache is " << session.cache_file); - INFO("Journal file is " << session.data_file); + INFO("Initialization file is " << session.init_file->string()); + INFO("Price database is " << session.price_db->string()); + INFO("Binary cache is " << session.cache_file->string()); + INFO("Journal file is " << session.data_file.string()); if (! session.use_cache) INFO("Binary cache mechanism will not be used"); @@ -197,11 +197,11 @@ static int read_and_report(report_t * report, int argc, char * argv[], #endif std::ostream * out = &std::cout; - if (! report->output_file.empty()) { - out = new std::ofstream(report->output_file.c_str()); + if (report->output_file) { + out = new ofstream(*report->output_file); } #ifdef HAVE_UNIX_PIPES - else if (! report->pager.empty()) { + else if (report->pager) { status = pipe(pfd); if (status == -1) throw_(std::logic_error, "Failed to create pipe"); @@ -227,13 +227,8 @@ static int read_and_report(report_t * report, int argc, char * argv[], // Find command name: its the substring starting right of the // rightmost '/' character in the pager pathname. See manpage // for strrchr. - arg0 = std::strrchr(report->pager.c_str(), '/'); - if (arg0) - arg0++; - else - arg0 = report->pager.c_str(); // No slashes in pager. - - execlp(report->pager.c_str(), arg0, (char *)0); + execlp(report->pager->native_file_string().c_str(), + basename(*report->pager).c_str(), (char *)0); perror("execl"); exit(1); } @@ -352,11 +347,10 @@ static int read_and_report(report_t * report, int argc, char * argv[], // Write out the binary cache, if need be - if (session.use_cache && session.cache_dirty && - ! session.cache_file.empty()) { + if (session.use_cache && session.cache_dirty && session.cache_file) { TRACE_START(binary_cache, 1, "Wrote binary journal file"); - std::ofstream stream(session.cache_file.c_str()); + ofstream stream(*session.cache_file); #if 0 write_binary_journal(stream, journal); #endif @@ -367,15 +361,15 @@ static int read_and_report(report_t * report, int argc, char * argv[], #if defined(FREE_MEMORY) // Cleanup memory -- if this is a beta or development build. - if (! report->output_file.empty()) - delete out; + if (report->output_file) + checked_delete(out); #endif // If the user specified a pager, wait for it to exit now #ifdef HAVE_UNIX_PIPES - if (report->output_file.empty() && ! report->pager.empty()) { - delete out; + if (! report->output_file && report->pager) { + checked_delete(out); close(pfd[1]); // Wait for child to finish @@ -457,7 +451,7 @@ int main(int argc, char * argv[], char * envp[]) err->context.push_front(new error_context("")); err->reveal_context(std::cerr, "Error"); std::cerr << err->what() << std::endl; - delete err; + checked_delete(err); } catch (fatal * err) { std::cout.flush(); @@ -467,7 +461,7 @@ int main(int argc, char * argv[], char * envp[]) err->context.push_front(new error_context("")); err->reveal_context(std::cerr, "Fatal"); std::cerr << err->what() << std::endl; - delete err; + checked_delete(err); } #endif catch (const std::exception& err) { @@ -111,7 +111,7 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data, // jww (2005-02-09): uncomment have_error = "The above entry does not balance"; #endif - delete entry; + checked_delete(entry); return -1; } return 0; diff --git a/src/option.cc b/src/option.cc index 64672211..0773030c 100644 --- a/src/option.cc +++ b/src/option.cc @@ -207,7 +207,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere, } process_option(def, scope, value); - delete *o; + checked_delete(*o); } } diff --git a/src/parser.h b/src/parser.h index c1289b47..a95a9e21 100644 --- a/src/parser.h +++ b/src/parser.h @@ -15,10 +15,10 @@ class parser_t virtual bool test(std::istream& in) const = 0; - virtual unsigned int parse(std::istream& in, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL) = 0; + virtual unsigned int parse(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()) = 0; }; DECLARE_EXCEPTION(parse_error); diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 21363450..0ab25cc3 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -4,6 +4,8 @@ namespace ledger { +using namespace boost::python; + struct python_run { object result; diff --git a/src/pyinterp.h b/src/pyinterp.h index 9c801a48..f32f4811 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -12,14 +12,12 @@ namespace ledger { -using namespace boost::python; - class python_interpreter_t : public xml::xpath_t::scope_t { - handle<> mmodule; + boost::python::handle<> mmodule; public: - dict nspace; + boost::python::dict nspace; python_interpreter_t(xml::xpath_t::scope_t * parent); @@ -27,7 +25,7 @@ class python_interpreter_t : public xml::xpath_t::scope_t Py_Finalize(); } - object import(const string& name); + boost::python::object import(const string& name); enum py_eval_mode_t { PY_EVAL_EXPR, @@ -35,18 +33,21 @@ class python_interpreter_t : public xml::xpath_t::scope_t PY_EVAL_MULTI }; - object eval(std::istream& in, py_eval_mode_t mode = PY_EVAL_EXPR); - object eval(const string& str, py_eval_mode_t mode = PY_EVAL_EXPR); - object eval(const char * c_str, py_eval_mode_t mode = PY_EVAL_EXPR) { + boost::python::object eval(std::istream& in, + py_eval_mode_t mode = PY_EVAL_EXPR); + boost::python::object eval(const string& str, + py_eval_mode_t mode = PY_EVAL_EXPR); + boost::python::object eval(const char * c_str, + py_eval_mode_t mode = PY_EVAL_EXPR) { string str(c_str); return eval(str, mode); } class functor_t : public xml::xpath_t::functor_t { - protected: - object func; - public: - functor_t(const string& name, object _func) + protected: + boost::python::object func; + public: + functor_t(const string& name, boost::python::object _func) : xml::xpath_t::functor_t(name), func(_func) {} virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals); @@ -58,7 +59,7 @@ class python_interpreter_t : public xml::xpath_t::scope_t } virtual xml::xpath_t::op_t * lookup(const string& name) { - object func = eval(name); + boost::python::object func = eval(name); if (! func) return parent ? parent->lookup(name) : NULL; return xml::xpath_t::wrap_functor(new functor_t(name, func)); @@ -66,8 +67,7 @@ class python_interpreter_t : public xml::xpath_t::scope_t class lambda_t : public functor_t { public: - lambda_t(object code) : functor_t("<lambda>", code) {} - + lambda_t(boost::python::object code) : functor_t("<lambda>", code) {} virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals); }; }; @@ -6,7 +6,7 @@ namespace ledger { #define MAX_LINE 1024 static char line[MAX_LINE + 1]; -static string pathname; +static path pathname; static unsigned int src_idx; static unsigned int linenum; @@ -35,7 +35,7 @@ bool qif_parser_t::test(std::istream& in) const unsigned int qif_parser_t::parse(std::istream& in, journal_t * journal, account_t * master, - const string *) + const optional<path>&) { std::auto_ptr<entry_t> entry; std::auto_ptr<amount_t> amount; @@ -104,16 +104,16 @@ unsigned int qif_parser_t::parse(std::istream& in, case '$': { SET_BEG_POS_AND_LINE(); get_line(in); - xact->amount.parse(line); + xact->amount = amount_t(line); - unsigned char flags = xact->amount.commodity().flags(); - unsigned char prec = xact->amount.commodity().precision(); + unsigned char flags = xact->amount->commodity().flags(); + unsigned char prec = xact->amount->commodity().precision(); if (! def_commodity) { def_commodity = commodity_t::find_or_create("$"); assert(def_commodity); } - xact->amount.set_commodity(*def_commodity); + xact->amount->set_commodity(*def_commodity); def_commodity->add_flags(flags); if (prec > def_commodity->precision()) @@ -121,7 +121,7 @@ unsigned int qif_parser_t::parse(std::istream& in, if (c == '$') { saw_splits = true; - xact->amount.in_place_negate(); + xact->amount->in_place_negate(); } else { total = xact; } @@ -197,7 +197,7 @@ unsigned int qif_parser_t::parse(std::istream& in, if (total && saw_category) { if (! saw_splits) - total->amount.in_place_negate(); // negate, to show correct flow + total->amount->in_place_negate(); // negate, to show correct flow else total->account = other; } @@ -10,10 +10,10 @@ class qif_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()); }; } // namespace ledger diff --git a/src/register.cc b/src/register.cc index 9f33bd0c..de0344de 100644 --- a/src/register.cc +++ b/src/register.cc @@ -117,8 +117,10 @@ static void scan_for_transactions(std::ostream& out, const xml::node_t * node) << std::setw(21) << std::left << abbreviate(xact->account->fullname(), 21, ABBREVIATE, true) << ' ' - << std::setw(12) << std::right - << xact->amount << '\n'; + << std::setw(12) << std::right; + if (xact->amount) + out << *xact->amount; + out << '\n'; } else { scan_for_transactions(out, child); } diff --git a/src/report.cc b/src/report.cc index 072d0d8b..2d49b62b 100644 --- a/src/report.cc +++ b/src/report.cc @@ -5,18 +5,14 @@ namespace ledger { report_t::~report_t() { TRACE_DTOR(report_t); - for (std::list<transform_t *>::const_iterator i = transforms.begin(); - i != transforms.end(); - i++) - delete *i; } void report_t::apply_transforms(xml::document_t * document) { - for (std::list<transform_t *>::const_iterator i = transforms.begin(); + for (ptr_list<transform_t>::iterator i = transforms.begin(); i != transforms.end(); i++) - (*i)->execute(document); + i->execute(document); } void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals) diff --git a/src/report.h b/src/report.h index 11a0b759..ca066566 100644 --- a/src/report.h +++ b/src/report.h @@ -11,16 +11,16 @@ typedef std::list<string> strings_list; class report_t : public xml::xpath_t::scope_t { public: - string output_file; - string format_string; - string amount_expr; - string total_expr; - string date_output_format; + optional<path> output_file; + string format_string; + string amount_expr; + string total_expr; + string date_output_format; unsigned long budget_flags; string account; - string pager; + optional<path> pager; bool show_totals; bool raw_mode; @@ -28,7 +28,7 @@ class report_t : public xml::xpath_t::scope_t session_t * session; transform_t * last_transform; - std::list<transform_t *> transforms; + ptr_list<transform_t> transforms; report_t(session_t * _session) : xml::xpath_t::scope_t(_session), diff --git a/src/session.cc b/src/session.cc index 65490b38..ecbc929f 100644 --- a/src/session.cc +++ b/src/session.cc @@ -2,57 +2,58 @@ namespace ledger { -unsigned int session_t::read_journal(std::istream& in, - journal_t * journal, - account_t * master, - const string * original_file) +unsigned int session_t::read_journal(std::istream& in, + journal_t * journal, + account_t * master, + const optional<path>& original) { if (! master) master = journal->master; - for (std::list<parser_t *>::iterator i = parsers.begin(); + for (ptr_list<parser_t>::iterator i = parsers.begin(); i != parsers.end(); i++) - if ((*i)->test(in)) - return (*i)->parse(in, journal, master, original_file); + if (i->test(in)) + return i->parse(in, journal, master, original); return 0; } -unsigned int session_t::read_journal(const string& pathname, - journal_t * journal, - account_t * master, - const string * original_file) +unsigned int session_t::read_journal(const path& pathname, + journal_t * journal, + account_t * master, + const optional<path>& original) { journal->sources.push_back(pathname); - if (access(pathname.c_str(), R_OK) == -1) + if (! exists(pathname)) throw filesystem_error(BOOST_CURRENT_FUNCTION, pathname, "Cannot read file"); - if (! original_file) - original_file = &pathname; - - std::ifstream stream(pathname.c_str()); - return read_journal(stream, journal, master, original_file); + ifstream stream(pathname); + return read_journal(stream, journal, master, + original ? original : pathname); } void session_t::read_init() { - if (init_file.empty()) + if (! init_file) return; - if (access(init_file.c_str(), R_OK) == -1) - throw filesystem_error(BOOST_CURRENT_FUNCTION, init_file, + if (! exists(*init_file)) + throw filesystem_error(BOOST_CURRENT_FUNCTION, *init_file, "Cannot read init file"); - std::ifstream init(init_file.c_str()); + ifstream init(*init_file); // jww (2006-09-15): Read initialization options here! } journal_t * session_t::read_data(const string& master_account) { + if (data_file.empty()) + throw_(parse_error, "No journal file was specified (please use -f)"); + TRACE_START(parser, 1, "Parsing journal file"); journal_t * journal = new_journal(); @@ -63,50 +64,55 @@ journal_t * session_t::read_data(const string& master_account) DEBUG("ledger.cache", "3. use_cache = " << use_cache); - if (use_cache && ! cache_file.empty() && - ! data_file.empty()) { - DEBUG("ledger.cache", "using_cache " << cache_file); + if (use_cache && cache_file) { + DEBUG("ledger.cache", "using_cache " << cache_file->string()); cache_dirty = true; - if (access(cache_file.c_str(), R_OK) != -1) { - std::ifstream stream(cache_file.c_str()); - - string price_db_orig = journal->price_db; - journal->price_db = price_db; - entry_count += read_journal(stream, journal, NULL, - &data_file); - if (entry_count > 0) - cache_dirty = false; - else + if (exists(*cache_file)) { + ifstream stream(*cache_file); + + optional<path> price_db_orig = journal->price_db; + try { + journal->price_db = price_db; + + entry_count += read_journal(stream, journal, NULL, data_file); + if (entry_count > 0) + cache_dirty = false; + + journal->price_db = price_db_orig; + } + catch (...) { journal->price_db = price_db_orig; + throw; + } } } - if (entry_count == 0 && ! data_file.empty()) { + if (entry_count == 0) { account_t * acct = NULL; if (! master_account.empty()) acct = journal->find_account(master_account); journal->price_db = price_db; - if (! journal->price_db.empty() && - access(journal->price_db.c_str(), R_OK) != -1) { - if (read_journal(journal->price_db, journal)) { + if (journal->price_db && exists(*journal->price_db)) { + if (read_journal(*journal->price_db, journal)) { throw_(parse_error, "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->string()); journal->sources.pop_back(); } } - DEBUG("ledger.cache", "rejected cache, parsing " << data_file); + DEBUG("ledger.cache", "rejected cache, parsing " << data_file.string()); if (data_file == "-") { use_cache = false; journal->sources.push_back("<stdin>"); entry_count += read_journal(std::cin, journal, acct); } - else if (access(data_file.c_str(), R_OK) != -1) { + else if (exists(data_file)) { entry_count += read_journal(data_file, journal, acct); - if (! journal->price_db.empty()) - journal->sources.push_back(journal->price_db); + if (journal->price_db) + journal->sources.push_back(*journal->price_db); } } diff --git a/src/session.h b/src/session.h index a1fd304b..1a28e6ee 100644 --- a/src/session.h +++ b/src/session.h @@ -10,10 +10,10 @@ namespace ledger { class session_t : public xml::xpath_t::scope_t { public: - string init_file; - string data_file; - string cache_file; - string price_db; + path data_file; + optional<path> init_file; + optional<path> cache_file; + optional<path> price_db; string register_format; string wide_register_format; @@ -42,8 +42,8 @@ class session_t : public xml::xpath_t::scope_t bool ansi_codes; bool ansi_invert; - std::list<journal_t *> journals; - std::list<parser_t *> parsers; + ptr_list<journal_t> journals; + ptr_list<parser_t> parsers; session_t(xml::xpath_t::scope_t * _parent = NULL) : xml::xpath_t::scope_t(_parent), @@ -96,16 +96,6 @@ class session_t : public xml::xpath_t::scope_t virtual ~session_t() { TRACE_DTOR(session_t); - - for (std::list<journal_t *>::iterator i = journals.begin(); - i != journals.end(); - i++) - delete *i; - - for (std::list<parser_t *>::iterator i = parsers.begin(); - i != parsers.end(); - i++) - delete *i; } journal_t * new_journal() { @@ -114,19 +104,26 @@ class session_t : public xml::xpath_t::scope_t return journal; } void close_journal(journal_t * journal) { - journals.remove(journal); - delete journal; + for (ptr_list<journal_t>::iterator i = journals.begin(); + i != journals.end(); + i++) + if (&*i == journal) { + journals.erase(i); + return; + } + assert(false); + checked_delete(journal); } - unsigned int read_journal(std::istream& in, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL); + unsigned int read_journal(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()); - unsigned int read_journal(const string& path, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL); + unsigned int read_journal(const path& path, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()); void read_init(); @@ -135,17 +132,16 @@ class session_t : public xml::xpath_t::scope_t void register_parser(parser_t * parser) { parsers.push_back(parser); } - bool unregister_parser(parser_t * parser) { - std::list<parser_t *>::iterator i; - for (i = parsers.begin(); i != parsers.end(); i++) - if (*i == parser) - break; - if (i == parsers.end()) - return false; - - parsers.erase(i); - - return true; + void unregister_parser(parser_t * parser) { + for (ptr_list<parser_t>::iterator i = parsers.begin(); + i != parsers.end(); + i++) + if (&*i == parser) { + parsers.erase(i); + return; + } + assert(false); + checked_delete(parser); } // diff --git a/src/system.hh b/src/system.hh index ce7a71be..55e64734 100644 --- a/src/system.hh +++ b/src/system.hh @@ -101,8 +101,10 @@ extern "C" { #include <boost/any.hpp> #include <boost/current_function.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/filesystem/convenience.hpp> #include <boost/filesystem/exception.hpp> #include <boost/filesystem/fstream.hpp> +#include <boost/filesystem/operations.hpp> #include <boost/filesystem/path.hpp> #include <boost/optional.hpp> #include <boost/ptr_container/ptr_list.hpp> diff --git a/src/textual.cc b/src/textual.cc index 9bbf3dbc..7d1d224e 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -7,12 +7,12 @@ namespace ledger { #define MAX_LINE 1024 -static string pathname; +static path pathname; static unsigned int linenum; static unsigned int src_idx; static accounts_map account_aliases; -static std::list<std::pair<string, int> > include_stack; +static std::list<std::pair<path, int> > include_stack; #ifdef TIMELOG_SUPPORT struct time_entry_t { @@ -173,7 +173,9 @@ transaction_t * parse_transaction(char * line, unsigned long beg = (long)in.tellg(); - xact->amount.parse(in, AMOUNT_PARSE_NO_REDUCE); + amount_t temp; + temp.parse(in, AMOUNT_PARSE_NO_REDUCE); + xact->amount = temp; char c; if (! in.eof() && (c = peek_next_nonws(in)) != '@' && @@ -192,11 +194,12 @@ transaction_t * parse_transaction(char * line, xact->entry->data); } - parse_amount_expr(in, journal, *xact, xact->amount, + assert(xact->amount); + parse_amount_expr(in, journal, *xact, *xact->amount, XPATH_PARSE_NO_REDUCE); if (xact->entry) { - delete static_cast<xml::transaction_node_t *>(xact->data); + checked_delete(xact->data); xact->data = NULL; } @@ -226,13 +229,13 @@ transaction_t * parse_transaction(char * line, } if (in.good() && ! in.eof()) { - xact->cost = new amount_t; - PUSH_CONTEXT(); unsigned long beg = (long)in.tellg(); - xact->cost->parse(in); + amount_t temp; + temp.parse(in); + xact->cost = temp; unsigned long end = (long)in.tellg(); @@ -248,15 +251,17 @@ transaction_t * parse_transaction(char * line, if (*xact->cost < 0) throw_(parse_error, "A transaction's cost may not be negative"); + assert(xact->amount); + amount_t per_unit_cost(*xact->cost); if (per_unit) - *xact->cost *= xact->amount.number(); + *xact->cost *= xact->amount->number(); else - per_unit_cost /= xact->amount.number(); + per_unit_cost /= xact->amount->number(); - if (xact->amount.commodity() && - ! xact->amount.commodity().annotated) - xact->amount.annotate_commodity(per_unit_cost, + if (xact->amount->commodity() && + ! xact->amount->commodity().annotated) + xact->amount->annotate_commodity(per_unit_cost, xact->entry->actual_date(), xact->entry->code); @@ -265,17 +270,19 @@ transaction_t * parse_transaction(char * line, DEBUG("ledger.textual.parse", "line " << linenum << ": " << "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()); } } } - xact->amount.in_place_reduce(); + if (xact->amount) { + xact->amount->in_place_reduce(); - DEBUG("ledger.textual.parse", "line " << linenum << ": " << - "Reduced amount is " << xact->amount); + DEBUG("ledger.textual.parse", "line " << linenum << ": " << + "Reduced amount is " << *xact->amount); + } } // Parse the optional note @@ -283,10 +290,10 @@ 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(), ']')) { + if (char * b = std::strchr(xact->note->c_str(), '[')) + if (char * e = std::strchr(xact->note->c_str(), ']')) { char buf[256]; std::strncpy(buf, b + 1, e - b - 1); buf[e - b - 1] = '\0'; @@ -490,7 +497,7 @@ entry_t * parse_entry(std::istream& in, char * line, journal_t * journal, } if (curr->data) { - delete static_cast<xml::entry_node_t *>(curr->data); + checked_delete(curr->data); curr->data = NULL; } @@ -612,10 +619,10 @@ static void clock_out_from_timelog(const moment_t& when, curr.release(); } -unsigned int textual_parser_t::parse(std::istream& in, - journal_t * journal, - account_t * master, - const string * original_file) +unsigned int textual_parser_t::parse(std::istream& in, + journal_t * journal, + account_t * master, + const optional<path>& original) { static bool added_auto_entry_hook = false; static char line[MAX_LINE + 1]; @@ -632,11 +639,12 @@ unsigned int textual_parser_t::parse(std::istream& in, account_stack.push_front(master); - pathname = journal ? journal->sources.back() : *original_file; + pathname = (journal ? journal->sources.back() : + (assert(original), *original)); src_idx = journal ? journal->sources.size() - 1 : 0; linenum = 1; - INFO("Parsing file '" << pathname << "'"); + INFO("Parsing file '" << pathname.string() << "'"); unsigned long beg_pos = in.tellg(); unsigned long end_pos; @@ -825,31 +833,29 @@ unsigned int textual_parser_t::parse(std::istream& in, char * p = next_element(line); string word(line + 1); if (word == "include") { - push_var<string> save_path(pathname); + push_var<path> save_path(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); - pathname = p; - if (pathname[0] != '/' && pathname[0] != '\\' && - pathname[0] != '~') { - string::size_type pos = save_path.prev.rfind('/'); - if (pos == string::npos) - pos = save_path.prev.rfind('\\'); - if (pos != string::npos) - pathname = string(save_path.prev, 0, pos + 1) + pathname; - } pathname = resolve_path(pathname); DEBUG("ledger.textual.include", "line " << linenum << ": " << - "Including path '" << pathname << "'"); + "Including path '" << pathname.string() << "'"); + + include_stack.push_back + (std::pair<path, int>(journal->sources.back(), linenum - 1)); - include_stack.push_back(std::pair<string, int> - (journal->sources.back(), linenum - 1)); - count += journal->session->read_journal(pathname, journal, - account_stack.front()); - include_stack.pop_back(); + try { + count += journal->session->read_journal(pathname, journal, + account_stack.front()); + include_stack.pop_back(); + } + catch (...) { + include_stack.pop_back(); + throw; + } } else if (word == "account") { if (account_t * acct = account_stack.front()->find_account(p)) diff --git a/src/textual.h b/src/textual.h index bf05b1fc..bcdaee1c 100644 --- a/src/textual.h +++ b/src/textual.h @@ -10,10 +10,10 @@ class textual_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()); }; #if 0 diff --git a/src/transform.cc b/src/transform.cc index b6a25cee..7e2405fb 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -98,7 +98,7 @@ void compact_transform::execute(xml::document_t * document) account_repitem_t * acct = static_cast<account_repitem_t *>(i); acct->parents_elided = p->parents_elided + 1; - delete p; + checked_delete(p); } } @@ -116,7 +116,7 @@ void clean_transform::execute(xml::document_t * document) i->add_total(temp); if (! temp) { repitem_t * next = i->next; - delete i; + checked_delete(i); i = next; continue; } @@ -125,7 +125,7 @@ void clean_transform::execute(xml::document_t * document) else if (i->kind == repitem_t::ENTRY && ! i->contents) { assert(! i->children); repitem_t * next = i->next; - delete i; + checked_delete(i); i = next; continue; } @@ -246,7 +246,7 @@ void merge_transform::execute(xml::document_t * document) j->contents = NULL; assert(! j->children); - delete j; + checked_delete(j); } } @@ -276,14 +276,14 @@ namespace { class delete_unmarked : public repitem_t::select_callback_t { virtual void operator()(xml::document_t * document) { if (item->parent && ! (item->flags & REPITEM_FLAGGED)) - delete item; + checked_delete(item); } }; class delete_marked : public repitem_t::select_callback_t { virtual void operator()(xml::document_t * document) { if (item->flags & REPITEM_FLAGGED) - delete item; + checked_delete(item); } }; diff --git a/src/transform.h b/src/transform.h index 1a5286a1..d54ab499 100644 --- a/src/transform.h +++ b/src/transform.h @@ -113,10 +113,7 @@ class select_transform : public transform_t select_transform(const string& selection_path) { xpath.parse(selection_path); } - virtual ~select_transform() { - if (path) - delete path; - } + virtual ~select_transform() {} virtual void execute(xml::document_t * document); }; diff --git a/src/utils.cc b/src/utils.cc index 41bca6be..f18ccca1 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -87,14 +87,14 @@ void shutdown_memory_tracing() 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; + checked_delete(live_memory); live_memory = NULL; + checked_delete(live_memory_count); live_memory_count = NULL; + checked_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; + checked_delete(live_objects); live_objects = NULL; + checked_delete(live_object_count); live_object_count = NULL; + checked_delete(total_object_count); total_object_count = NULL; + checked_delete(total_ctor_count); total_ctor_count = NULL; } inline void add_to_count_map(object_count_map& the_map, @@ -630,15 +630,20 @@ ptr_list<context> context_stack; namespace ledger { -string expand_path(const string& path) +path expand_path(const path& pathname) { - if (path.length() == 0 || path[0] != '~') - return path; + if (pathname.empty()) + return pathname; - const char * pfx = NULL; - string::size_type pos = path.find_first_of('/'); +#if 1 + return pathname; +#else + // jww (2007-04-30): I need to port this code to use + // boost::filesystem::path + const char * pfx = NULL; + 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) { @@ -651,7 +656,7 @@ string expand_path(const string& path) } #ifdef HAVE_GETPWNAM else { - string user(path, 1, pos == string::npos ? + string user(pathname, 1, pos == string::npos ? string::npos : pos - 1); struct passwd * pw = getpwnam(user.c_str()); if (pw) @@ -662,7 +667,7 @@ string expand_path(const string& path) // if we failed to find an expansion, return the path unchanged. if (! pfx) - return path; + return pathname; string result(pfx); @@ -672,16 +677,19 @@ string expand_path(const string& path) if (result.length() == 0 || result[result.length() - 1] != '/') result += '/'; - result += path.substr(pos + 1); + result += pathname.substr(pos + 1); return result; +#endif } -string resolve_path(const string& path) +path resolve_path(const path& pathname) { - if (path[0] == '~') - return expand_path(path); - return path; + path temp = pathname; + if (temp.string()[0] == '~') + temp = expand_path(temp); + temp.normalize(); + return temp; } } // namespace ledger diff --git a/src/utils.h b/src/utils.h index da6aaa27..89b9a2d0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -447,7 +447,7 @@ inline void throw_unexpected_error(char c, char wanted) { namespace ledger { -string resolve_path(const string& path); +path resolve_path(const path& pathname); #ifdef HAVE_REALPATH extern "C" char * realpath(const char *, char resolved_path[]); diff --git a/src/value.cc b/src/value.cc index 74a3bd8f..7956af12 100644 --- a/src/value.cc +++ b/src/value.cc @@ -117,10 +117,10 @@ void value_t::destroy() ((balance_pair_t *)data)->~balance_pair_t(); break; case STRING: - delete *(string **) data; + checked_delete(*(string **) data); break; case SEQUENCE: - delete *(sequence_t **) data; + checked_delete(*(sequence_t **) data); break; default: break; @@ -1820,43 +1820,6 @@ void value_t::in_place_negate() } } -void value_t::in_place_abs() -{ - switch (type) { - case BOOLEAN: - break; - case INTEGER: - if (*((long *) data) < 0) - *((long *) data) = - *((long *) data); - break; - case DATETIME: - break; - case AMOUNT: - ((amount_t *) data)->abs(); - break; - case BALANCE: - ((balance_t *) data)->abs(); - break; - case BALANCE_PAIR: - ((balance_pair_t *) data)->abs(); - break; - case STRING: - throw_(value_error, "Cannot take the absolute value of a string"); - case XML_NODE: - *this = (*(xml::node_t **) data)->to_value(); - in_place_abs(); - break; - case POINTER: - throw_(value_error, "Cannot take the absolute value of a pointer"); - case SEQUENCE: - throw_(value_error, "Cannot take the absolute value of a sequence"); - - default: - assert(0); - break; - } -} - value_t value_t::value(const moment_t& moment) const { switch (type) { @@ -2188,7 +2151,7 @@ value_t value_t::cost() const return value_t(); } -value_t& value_t::add(const amount_t& amount, const amount_t * tcost) +value_t& value_t::add(const amount_t& amount, const optional<amount_t>& tcost) { switch (type) { case BOOLEAN: @@ -2337,7 +2300,7 @@ value_context::value_context(const value_t& _bal, value_context::~value_context() throw() { - delete bal; + checked_delete(bal); } void value_context::describe(std::ostream& out) const throw() diff --git a/src/value.h b/src/value.h index 0737fac1..4c6e0f18 100644 --- a/src/value.h +++ b/src/value.h @@ -435,7 +435,6 @@ class value_t return 0; } - void in_place_abs(); value_t abs() const; void in_place_cast(type_t cast_type); value_t cost() const; @@ -453,10 +452,11 @@ class value_t const bool keep_date = amount_t::keep_date, const bool keep_tag = amount_t::keep_tag) const; - value_t& add(const amount_t& amount, const amount_t * cost = NULL); + value_t& add(const amount_t& amount, + const optional<amount_t>& cost = optional<amount_t>()); value_t value(const moment_t& moment) const; - void in_place_reduce(); + void in_place_reduce(); value_t reduce() const { value_t temp(*this); temp.in_place_reduce(); @@ -29,13 +29,13 @@ document_t::~document_t() { TRACE_DTOR(xml::document_t); if (top && top != &stub) - delete top; + checked_delete(top); } void document_t::set_top(node_t * _top) { if (top && top != &stub) - delete top; + checked_delete(top); top = _top; } @@ -191,7 +191,7 @@ void parent_node_t::clear() node_t * child = _children; while (child) { node_t * tnext = child->next; - delete child; + checked_delete(child); child = tnext; } } @@ -443,7 +443,10 @@ node_t * transaction_node_t::lookup_child(int _name_id) const value_t transaction_node_t::to_value() const { - return transaction->amount; + if (transaction->amount) + return *transaction->amount; + else + return value_t(); } node_t * entry_node_t::children() const @@ -461,11 +464,14 @@ node_t * entry_node_t::lookup_child(int _name_id) const { switch (_name_id) { case document_t::CODE: + if (! entry->code) + return NULL; + // jww (2007-04-20): I have to save this and then delete it later terminal_node_t * code_node = new terminal_node_t(document, const_cast<entry_node_t *>(this)); code_node->set_name(document_t::CODE); - code_node->set_text(entry->code); + code_node->set_text(*entry->code); return code_node; case document_t::PAYEE: @@ -489,11 +495,11 @@ node_t * account_node_t::children() const name_node->set_text(account->name); } - if (! account->note.empty()) { + if (account->note) { terminal_node_t * note_node = new terminal_node_t(document, const_cast<account_node_t *>(this)); note_node->set_name(document_t::NOTE); - note_node->set_text(account->note); + note_node->set_text(*account->note); } for (accounts_map::iterator i = account->accounts.begin(); @@ -1,6 +1,7 @@ #ifndef _XML_H #define _XML_H +#include "journal.h" #include "value.h" #include "parser.h" @@ -45,7 +46,7 @@ public: virtual ~node_t() { TRACE_DTOR(node_t); if (parent) extract(); - if (attrs) delete attrs; + if (attrs) checked_delete(attrs); } void extract(); // extract this node from its parent's child list @@ -249,10 +250,10 @@ class xml_parser_t : public parser_t public: virtual bool test(std::istream& in) const; - virtual unsigned int parse(std::istream& in, - journal_t * journal, - account_t * master = NULL, - const string * original_file = NULL); + virtual unsigned int parse(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = optional<path>()); }; DECLARE_EXCEPTION(parse_error); @@ -319,7 +320,7 @@ public: virtual ~transaction_node_t() { TRACE_DTOR(transaction_node_t); if (payee_virtual_node) - delete payee_virtual_node; + checked_delete(payee_virtual_node); } virtual node_t * children() const; @@ -387,33 +388,33 @@ public: }; template <typename T> -inline parent_node_t * wrap_node(document_t * doc, T * item, - void * parent_node = NULL) { - assert(0); +inline typename T::node_type * +wrap_node(document_t * doc, T * item, void * parent_node = NULL) { + assert(false); return NULL; } template <> -inline parent_node_t * wrap_node(document_t * doc, transaction_t * xact, - void * parent_node) { +inline transaction_t::node_type * +wrap_node(document_t * doc, transaction_t * xact, void * parent_node) { return new transaction_node_t(doc, xact, (parent_node_t *)parent_node); } template <> -inline parent_node_t * wrap_node(document_t * doc, entry_t * entry, - void * parent_node) { +inline entry_t::node_type * +wrap_node(document_t * doc, entry_t * entry, void * parent_node) { return new entry_node_t(doc, entry, (parent_node_t *)parent_node); } template <> -inline parent_node_t * wrap_node(document_t * doc, account_t * account, - void * parent_node) { +inline account_t::node_type * +wrap_node(document_t * doc, account_t * account, void * parent_node) { return new account_node_t(doc, account, (parent_node_t *)parent_node); } template <> -inline parent_node_t * wrap_node(document_t * doc, journal_t * journal, - void * parent_node) { +inline journal_t::node_type * +wrap_node(document_t * doc, journal_t * journal, void * parent_node) { return new journal_node_t(doc, journal, (parent_node_t *)parent_node); } diff --git a/src/xmlparse.cc b/src/xmlparse.cc index 1b9e9a45..51da13f4 100644 --- a/src/xmlparse.cc +++ b/src/xmlparse.cc @@ -63,7 +63,7 @@ static void endElement(void *userData, const char *name) if (curr_journal->add_entry(curr_entry)) { count++; } else { - delete curr_entry; + checked_delete(curr_entry); have_error = "Entry cannot be balanced"; } } @@ -133,7 +133,10 @@ static void endElement(void *userData, const char *name) } #endif else if (std::strcmp(name, "quantity") == 0) { - curr_entry->transactions.back()->amount.parse(data); + amount_t temp; + temp.parse(data); + curr_entry->transactions.back()->amount = temp; + if (curr_comm) { string::size_type i = data.find('.'); if (i != string::npos) { @@ -141,7 +144,7 @@ static void endElement(void *userData, const char *name) if (precision > curr_comm->precision()) curr_comm->set_precision(precision); } - curr_entry->transactions.back()->amount.set_commodity(*curr_comm); + curr_entry->transactions.back()->amount->set_commodity(*curr_comm); curr_comm = NULL; } } @@ -179,10 +182,10 @@ bool xml_parser_t::test(std::istream& in) const return true; } -unsigned int xml_parser_t::parse(std::istream& in, - journal_t * journal, - account_t * master, - const string * original_file) +unsigned int xml_parser_t::parse(std::istream& in, + journal_t * journal, + account_t * master, + const optional<path>& original) { char buf[BUFSIZ]; diff --git a/src/xpath.cc b/src/xpath.cc index b7927cb4..53d337ea 100644 --- a/src/xpath.cc +++ b/src/xpath.cc @@ -15,7 +15,7 @@ void xpath_t::initialize() void xpath_t::shutdown() { - delete lookahead; + checked_delete(lookahead); lookahead = NULL; } @@ -555,7 +555,7 @@ xpath_t::op_t::~op_t() case VALUE: assert(! left); assert(valuep); - delete valuep; + checked_delete(valuep); break; case NODE_NAME: @@ -564,7 +564,7 @@ xpath_t::op_t::~op_t() case VAR_NAME: assert(! left); assert(name); - delete name; + checked_delete(name); break; case ARG_INDEX: @@ -573,14 +573,14 @@ xpath_t::op_t::~op_t() case FUNCTOR: assert(! left); assert(functor); - delete functor; + checked_delete(functor); break; #if 0 case MASK: assert(! left); assert(mask); - delete mask; + checked_delete(mask); break; #endif diff --git a/src/xpath.h b/src/xpath.h index 76625436..638ec482 100644 --- a/src/xpath.h +++ b/src/xpath.h @@ -428,7 +428,7 @@ public: "Releasing " << this << ", refc now " << refc - 1); assert(refc > 0); if (--refc == 0) - delete this; + checked_delete(this); } op_t * acquire() { DEBUG("ledger.xpath.memory", |