Started using boost::optional<T>.

This commit is contained in:
John Wiegley 2007-05-01 04:36:49 +00:00
parent 50a9caf302
commit e92bcf411d
37 changed files with 655 additions and 694 deletions

View file

@ -147,24 +147,24 @@ void amount_t::shutdown()
mpz_clear(divisor); mpz_clear(divisor);
if (commodity_base_t::updater) { if (commodity_base_t::updater) {
delete commodity_base_t::updater; checked_delete(commodity_base_t::updater);
commodity_base_t::updater = NULL; commodity_base_t::updater = NULL;
} }
for (base_commodities_map::iterator i = commodity_base_t::commodities.begin(); for (base_commodities_map::iterator i = commodity_base_t::commodities.begin();
i != commodity_base_t::commodities.end(); i != commodity_base_t::commodities.end();
i++) i++)
delete (*i).second; checked_delete((*i).second);
for (commodities_map::iterator i = commodity_t::commodities.begin(); for (commodities_map::iterator i = commodity_t::commodities.begin();
i != commodity_t::commodities.end(); i != commodity_t::commodities.end();
i++) i++)
delete (*i).second; checked_delete((*i).second);
commodity_base_t::commodities.clear(); commodity_base_t::commodities.clear();
commodity_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::commodities_by_ident = NULL;
commodity_t::null_commodity = NULL; commodity_t::null_commodity = NULL;
@ -172,7 +172,7 @@ void amount_t::shutdown()
true_value->ref--; true_value->ref--;
assert(true_value->ref == 0); assert(true_value->ref == 0);
delete true_value; checked_delete(true_value);
true_value = NULL; true_value = NULL;
} }
@ -318,13 +318,13 @@ namespace {
newbuf[0] = '-'; newbuf[0] = '-';
std::strcpy(&newbuf[1], result ? result : buf); std::strcpy(&newbuf[1], result ? result : buf);
mpz_set_str(dest, newbuf, 10); mpz_set_str(dest, newbuf, 10);
delete[] newbuf; checked_array_delete(newbuf);
} else { } else {
mpz_set_str(dest, result ? result : buf, 10); mpz_set_str(dest, result ? result : buf, 10);
} }
if (result) if (result)
delete[] result; checked_array_delete(result);
freedtoa(buf); freedtoa(buf);
return decpt; return decpt;
@ -346,7 +346,7 @@ void amount_t::_release()
if (--quantity->ref == 0) { if (--quantity->ref == 0) {
if (! (quantity->flags & BIGINT_BULK_ALLOC)) if (! (quantity->flags & BIGINT_BULK_ALLOC))
delete quantity; checked_delete(quantity);
else else
quantity->~bigint_t(); quantity->~bigint_t();
} }
@ -1073,7 +1073,7 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
if (! omit_commodity && comm.annotated) { if (! omit_commodity && comm.annotated) {
annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm)); annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm));
assert(&ann.price != this); assert(&*ann.price != this);
ann.write_annotations(out); ann.write_annotations(out);
} }
@ -1144,11 +1144,11 @@ static void parse_commodity(std::istream& in, string& symbol)
symbol = buf; symbol = buf;
} }
bool parse_annotations(std::istream& in, amount_t& price, void parse_annotations(std::istream& in,
moment_t& date, string& tag) optional<amount_t>& price,
optional<moment_t>& date,
optional<string>& tag)
{ {
bool has_date = false;
do { do {
char buf[256]; char buf[256];
char c = peek_next_nonws(in); char c = peek_next_nonws(in);
@ -1163,19 +1163,22 @@ bool parse_annotations(std::istream& in, amount_t& price,
else else
throw_(amount_error, "Commodity price lacks closing brace"); throw_(amount_error, "Commodity price lacks closing brace");
price.parse(buf, AMOUNT_PARSE_NO_MIGRATE); amount_t temp;
price.in_place_reduce(); temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
temp.in_place_reduce();
// Since this price will maintain its own precision, make sure // Since this price will maintain its own precision, make sure
// it is at least as large as the base commodity, since the user // it is at least as large as the base commodity, since the user
// may have only specified {$1} or something similar. // may have only specified {$1} or something similar.
if (price.has_commodity() && if (temp.has_commodity() &&
price.quantity->prec < price.commodity().precision()) temp.quantity->prec < temp.commodity().precision())
price = price.round(); // no need to retain individual precision temp = temp.round(); // no need to retain individual precision
price = temp;
} }
else if (c == '[') { else if (c == '[') {
if (is_valid_moment(date)) if (date)
throw_(amount_error, "Commodity specifies more than one date"); throw_(amount_error, "Commodity specifies more than one date");
in.get(c); in.get(c);
@ -1186,10 +1189,9 @@ bool parse_annotations(std::istream& in, amount_t& price,
throw_(amount_error, "Commodity date lacks closing bracket"); throw_(amount_error, "Commodity date lacks closing bracket");
date = parse_datetime(buf); date = parse_datetime(buf);
has_date = true;
} }
else if (c == '(') { else if (c == '(') {
if (! tag.empty()) if (tag)
throw_(amount_error, "Commodity specifies more than one tag"); throw_(amount_error, "Commodity specifies more than one tag");
in.get(c); in.get(c);
@ -1208,11 +1210,9 @@ bool parse_annotations(std::istream& in, amount_t& price,
DEBUG("amounts.commodities", DEBUG("amounts.commodities",
"Parsed commodity annotations: " "Parsed commodity annotations: "
<< " price " << price << " " << " price " << (price ? price->to_string() : "NONE") << " "
<< " date " << date << " " << " date " << (date ? *date : moment_t()) << " "
<< " tag " << tag); << " tag " << (tag ? *tag : "NONE"));
return has_date;
} }
void amount_t::parse(std::istream& in, uint8_t flags) void amount_t::parse(std::istream& in, uint8_t flags)
@ -1224,10 +1224,9 @@ void amount_t::parse(std::istream& in, uint8_t flags)
string symbol; string symbol;
string quant; string quant;
amount_t tprice; optional<amount_t> tprice;
moment_t tdate; optional<moment_t> tdate;
bool had_date = false; optional<string> ttag;
string tag;
unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS; unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS;
bool negative = false; bool negative = false;
@ -1252,7 +1251,7 @@ void amount_t::parse(std::istream& in, uint8_t flags)
comm_flags |= COMMODITY_STYLE_SUFFIXED; comm_flags |= COMMODITY_STYLE_SUFFIXED;
if (! in.eof() && ((n = in.peek()) != '\n')) if (! in.eof() && ((n = in.peek()) != '\n'))
had_date = parse_annotations(in, tprice, tdate, tag); parse_annotations(in, tprice, tdate, ttag);
} }
} else { } else {
parse_commodity(in, symbol); parse_commodity(in, symbol);
@ -1264,7 +1263,7 @@ void amount_t::parse(std::istream& in, uint8_t flags)
parse_quantity(in, quant); parse_quantity(in, quant);
if (! quant.empty() && ! in.eof() && ((n = in.peek()) != '\n')) 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_); assert(commodity_);
if (! tprice.realzero() || had_date || ! tag.empty()) if (tprice || tdate || ttag)
commodity_ = commodity_ = annotated_commodity_t::find_or_create
annotated_commodity_t::find_or_create(*commodity_, tprice, tdate, tag); (*commodity_, tprice, tdate, ttag);
} }
// Determine the precision of the amount, based on the usage of // 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'; *t = '\0';
mpz_set_str(MPZ(quantity), buf, 10); mpz_set_str(MPZ(quantity), buf, 10);
delete[] buf; checked_array_delete(buf);
} else { } else {
mpz_set_str(MPZ(quantity), quant.c_str(), 10); mpz_set_str(MPZ(quantity), quant.c_str(), 10);
} }
@ -1564,9 +1563,9 @@ bool amount_t::valid() const
return true; return true;
} }
void amount_t::annotate_commodity(const amount_t& tprice, void amount_t::annotate_commodity(const optional<amount_t>& tprice,
const moment_t& tdate, const optional<moment_t>& tdate,
const string& tag) const optional<string>& ttag)
{ {
const commodity_t * this_base; const commodity_t * this_base;
annotated_commodity_t * this_ann = NULL; annotated_commodity_t * this_ann = NULL;
@ -1581,16 +1580,16 @@ void amount_t::annotate_commodity(const amount_t& tprice,
DEBUG("amounts.commodities", "Annotating commodity for amount " DEBUG("amounts.commodities", "Annotating commodity for amount "
<< *this << std::endl << *this << std::endl
<< " price " << tprice << " " << " price " << (tprice ? tprice->to_string() : "NONE") << " "
<< " date " << tdate << " " << " date " << (tdate ? *tdate : moment_t()) << " "
<< " tag " << tag); << " ttag " << (ttag ? *ttag : "NONE"));
commodity_t * ann_comm = if (commodity_t * ann_comm =
annotated_commodity_t::find_or_create annotated_commodity_t::find_or_create
(*this_base, ! tprice && this_ann ? this_ann->price : tprice, (*this_base,
! is_valid_moment(tdate) && this_ann ? this_ann->date : tdate, ! tprice && this_ann ? this_ann->price : tprice,
tag.empty() && this_ann ? this_ann->tag : tag); ! tdate && this_ann ? this_ann->date : tdate,
if (ann_comm) ! ttag && this_ann ? this_ann->tag : ttag))
set_commodity(*ann_comm); set_commodity(*ann_comm);
DEBUG("amounts.commodities", " Annotated amount is " << *this); DEBUG("amounts.commodities", " Annotated amount is " << *this);
@ -1617,13 +1616,14 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
commodity_t * new_comm; commodity_t * new_comm;
if ((_keep_price && ann_comm.price) || if ((_keep_price && ann_comm.price) ||
(_keep_date && is_valid_moment(ann_comm.date)) || (_keep_date && ann_comm.date) ||
(_keep_tag && ! ann_comm.tag.empty())) (_keep_tag && ann_comm.tag))
{ {
new_comm = annotated_commodity_t::find_or_create new_comm = annotated_commodity_t::find_or_create
(*ann_comm.ptr, _keep_price ? ann_comm.price : amount_t(), (*ann_comm.ptr,
_keep_date ? ann_comm.date : moment_t(), _keep_price ? ann_comm.price : optional<amount_t>(),
_keep_tag ? ann_comm.tag : ""); _keep_date ? ann_comm.date : optional<moment_t>(),
_keep_tag ? ann_comm.tag : optional<string>());
} else { } else {
new_comm = commodity_t::find_or_create(ann_comm.base_symbol()); 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 optional<amount_t> amount_t::price() const
{ {
if (commodity_ && commodity_->annotated) { if (commodity_ && commodity_->annotated &&
amount_t t(((annotated_commodity_t *)commodity_)->price); ((annotated_commodity_t *)commodity_)->price) {
amount_t t(*((annotated_commodity_t *)commodity_)->price);
t *= number(); t *= number();
DEBUG("amounts.commodities", DEBUG("amounts.commodities",
"Returning price of " << *this << " = " << t); "Returning price of " << *this << " = " << t);
@ -1851,12 +1852,12 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
price != static_cast<const annotated_commodity_t&>(comm).price)) price != static_cast<const annotated_commodity_t&>(comm).price))
return false; return false;
if (is_valid_moment(date) && if (date &&
(! comm.annotated || (! comm.annotated ||
date != static_cast<const annotated_commodity_t&>(comm).date)) date != static_cast<const annotated_commodity_t&>(comm).date))
return false; return false;
if (! tag.empty() && if (tag &&
(! comm.annotated || (! comm.annotated ||
tag != static_cast<const annotated_commodity_t&>(comm).tag)) tag != static_cast<const annotated_commodity_t&>(comm).tag))
return false; return false;
@ -1866,25 +1867,25 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
void void
annotated_commodity_t::write_annotations(std::ostream& out, annotated_commodity_t::write_annotations(std::ostream& out,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag) const optional<string>& tag)
{ {
if (price) if (price)
out << " {" << price << '}'; out << " {" << *price << '}';
if (is_valid_moment(date)) if (date)
out << " [" << date << ']'; out << " [" << *date << ']';
if (! tag.empty()) if (tag)
out << " (" << tag << ')'; out << " (" << *tag << ')';
} }
commodity_t * commodity_t *
annotated_commodity_t::create(const commodity_t& comm, annotated_commodity_t::create(const commodity_t& comm,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag, const optional<string>& tag,
const string& mapping_key) const string& mapping_key)
{ {
std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t); std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t);
@ -1904,9 +1905,9 @@ annotated_commodity_t::create(const commodity_t& comm,
DEBUG("amounts.commodities", "Creating annotated commodity " DEBUG("amounts.commodities", "Creating annotated commodity "
<< "symbol " << commodity->symbol() << "symbol " << commodity->symbol()
<< " key " << mapping_key << std::endl << " key " << mapping_key << std::endl
<< " price " << price << " " << " price " << (price ? price->to_string() : "NONE") << " "
<< " date " << date << " " << " date " << (date ? *date : moment_t()) << " "
<< " tag " << tag); << " tag " << (tag ? *tag : "NONE"));
// Add the fully annotated name to the map, so that this symbol may // Add the fully annotated name to the map, so that this symbol may
// quickly be found again. // quickly be found again.
@ -1923,11 +1924,11 @@ annotated_commodity_t::create(const commodity_t& comm,
namespace { namespace {
string make_qualified_name(const commodity_t& comm, string make_qualified_name(const commodity_t& comm,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag) const optional<string>& tag)
{ {
if (price < 0) if (price && *price < 0)
throw_(amount_error, "A commodity's price may not be negative"); throw_(amount_error, "A commodity's price may not be negative");
std::ostringstream name; std::ostringstream name;
@ -1937,9 +1938,9 @@ namespace {
DEBUG("amounts.commodities", "make_qualified_name for " DEBUG("amounts.commodities", "make_qualified_name for "
<< comm.qualified_symbol << std::endl << comm.qualified_symbol << std::endl
<< " price " << price << " " << " price " << (price ? price->to_string() : "NONE") << " "
<< " date " << date << " " << " date " << (date ? *date : moment_t()) << " "
<< " tag " << tag); << " tag " << (tag ? *tag : "NONE"));
DEBUG("amounts.commodities", "qualified_name is " << name.str()); DEBUG("amounts.commodities", "qualified_name is " << name.str());
@ -1949,9 +1950,9 @@ namespace {
commodity_t * commodity_t *
annotated_commodity_t::find_or_create(const commodity_t& comm, annotated_commodity_t::find_or_create(const commodity_t& comm,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag) const optional<string>& tag)
{ {
string name = make_qualified_name(comm, price, date, 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; return false;
if (aleftcomm.price && arightcomm.price) { if (aleftcomm.price && arightcomm.price) {
amount_t leftprice(aleftcomm.price); amount_t leftprice(*aleftcomm.price);
leftprice.in_place_reduce(); leftprice.in_place_reduce();
amount_t rightprice(arightcomm.price); amount_t rightprice(*arightcomm.price);
rightprice.in_place_reduce(); rightprice.in_place_reduce();
if (leftprice.commodity() == rightprice.commodity()) { if (leftprice.commodity() == rightprice.commodity()) {
@ -2013,28 +2014,25 @@ bool compare_amount_commodities::operator()(const amount_t * left,
} }
} }
if (! is_valid_moment(aleftcomm.date) && if (! aleftcomm.date && arightcomm.date)
is_valid_moment(arightcomm.date))
return true; return true;
if (is_valid_moment(aleftcomm.date) && if (aleftcomm.date && ! arightcomm.date)
! is_valid_moment(arightcomm.date))
return false; return false;
if (is_valid_moment(aleftcomm.date) && if (aleftcomm.date && arightcomm.date) {
is_valid_moment(arightcomm.date)) { duration_t diff = *aleftcomm.date - *arightcomm.date;
duration_t diff = aleftcomm.date - arightcomm.date;
return diff.is_negative(); return diff.is_negative();
} }
if (aleftcomm.tag.empty() && ! arightcomm.tag.empty()) if (! aleftcomm.tag && arightcomm.tag)
return true; return true;
if (! aleftcomm.tag.empty() && arightcomm.tag.empty()) if (aleftcomm.tag && ! arightcomm.tag)
return false; return false;
if (! aleftcomm.tag.empty() && ! arightcomm.tag.empty()) if (aleftcomm.tag && arightcomm.tag)
return aleftcomm.tag < arightcomm.tag; return *aleftcomm.tag < *arightcomm.tag;
assert(0); assert(false);
return true; return true;
} }
} }

View file

@ -142,9 +142,9 @@ class amount_t
commodity_t& commodity() const; commodity_t& commodity() const;
void annotate_commodity(const amount_t& price, void annotate_commodity(const optional<amount_t>& tprice,
const moment_t& date = moment_t(), const optional<moment_t>& tdate = optional<moment_t>(),
const string& tag = ""); const optional<string>& ttag = optional<string>());
amount_t strip_annotations(const bool _keep_price = keep_price, amount_t strip_annotations(const bool _keep_price = keep_price,
const bool _keep_date = keep_date, const bool _keep_date = keep_date,
@ -348,8 +348,10 @@ class amount_t
friend void clean_commodity_history(char * item_pool, friend void clean_commodity_history(char * item_pool,
char * item_pool_end); char * item_pool_end);
friend bool parse_annotations(std::istream& in, amount_t& price, friend void parse_annotations(std::istream& in,
moment_t& date, string& tag); optional<amount_t>& price,
optional<moment_t>& date,
optional<string>& tag);
// Streaming interface // Streaming interface
@ -513,9 +515,9 @@ class commodity_base_t
~commodity_base_t() { ~commodity_base_t() {
TRACE_DTOR(commodity_base_t); TRACE_DTOR(commodity_base_t);
if (history) delete history; if (history) checked_delete(history);
if (smaller) delete smaller; if (smaller) checked_delete(smaller);
if (larger) delete larger; if (larger) checked_delete(larger);
} }
static base_commodities_map commodities; static base_commodities_map commodities;
@ -659,7 +661,7 @@ class commodity_t
} }
void set_smaller(const amount_t& arg) { void set_smaller(const amount_t& arg) {
if (base->smaller) if (base->smaller)
delete base->smaller; checked_delete(base->smaller);
base->smaller = new amount_t(arg); base->smaller = new amount_t(arg);
} }
@ -668,7 +670,7 @@ class commodity_t
} }
void set_larger(const amount_t& arg) { void set_larger(const amount_t& arg) {
if (base->larger) if (base->larger)
delete base->larger; checked_delete(base->larger);
base->larger = new amount_t(arg); base->larger = new amount_t(arg);
} }
@ -694,9 +696,9 @@ class annotated_commodity_t : public commodity_t
public: public:
const commodity_t * ptr; const commodity_t * ptr;
amount_t price; optional<amount_t> price;
moment_t date; optional<moment_t> date;
string tag; optional<string> tag;
explicit annotated_commodity_t() { explicit annotated_commodity_t() {
TRACE_CTOR(annotated_commodity_t, ""); TRACE_CTOR(annotated_commodity_t, "");
@ -713,21 +715,21 @@ class annotated_commodity_t : public commodity_t
} }
static void write_annotations(std::ostream& out, static void write_annotations(std::ostream& out,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag); const optional<string>& tag);
private: private:
static commodity_t * create(const commodity_t& comm, static commodity_t * create(const commodity_t& comm,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag, const optional<string>& tag,
const string& mapping_key); const string& mapping_key);
static commodity_t * find_or_create(const commodity_t& comm, static commodity_t * find_or_create(const commodity_t& comm,
const amount_t& price, const optional<amount_t>& price,
const moment_t& date, const optional<moment_t>& date,
const string& tag); const optional<string>& tag);
friend class amount_t; friend class amount_t;
}; };

View file

@ -448,15 +448,12 @@ class balance_t
void write(std::ostream& out, const int first_width, void write(std::ostream& out, const int first_width,
const int latter_width = -1) const; 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 abs() const {
balance_t temp = *this; 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; return temp;
} }
@ -504,80 +501,63 @@ class balance_pair_t
{ {
public: public:
balance_t quantity; balance_t quantity;
balance_t * cost; optional<balance_t> cost;
// constructors // constructors
balance_pair_t() : cost(NULL) { balance_pair_t() {
TRACE_CTOR(balance_pair_t, ""); TRACE_CTOR(balance_pair_t, "");
} }
balance_pair_t(const balance_pair_t& bal_pair) 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"); TRACE_CTOR(balance_pair_t, "copy");
if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost);
} }
balance_pair_t(const balance_t& _quantity) balance_pair_t(const balance_t& _quantity)
: quantity(_quantity), cost(NULL) { : quantity(_quantity) {
TRACE_CTOR(balance_pair_t, "const balance_t&"); TRACE_CTOR(balance_pair_t, "const balance_t&");
} }
balance_pair_t(const amount_t& _quantity) balance_pair_t(const amount_t& _quantity)
: quantity(_quantity), cost(NULL) { : quantity(_quantity) {
TRACE_CTOR(balance_pair_t, "const amount_t&"); TRACE_CTOR(balance_pair_t, "const amount_t&");
} }
template <typename 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"); TRACE_CTOR(balance_pair_t, "T");
} }
// destructor // destructor
~balance_pair_t() { ~balance_pair_t() {
TRACE_DTOR(balance_pair_t); TRACE_DTOR(balance_pair_t);
if (cost) delete cost;
} }
// assignment operator // assignment operator
balance_pair_t& operator=(const balance_pair_t& bal_pair) { balance_pair_t& operator=(const balance_pair_t& bal_pair) {
if (this != &bal_pair) { if (this != &bal_pair) {
if (cost) {
delete cost;
cost = NULL;
}
quantity = bal_pair.quantity; quantity = bal_pair.quantity;
if (bal_pair.cost) cost = bal_pair.cost;
cost = new balance_t(*bal_pair.cost);
} }
return *this; return *this;
} }
balance_pair_t& operator=(const balance_t& bal) { balance_pair_t& operator=(const balance_t& bal) {
if (cost) {
delete cost;
cost = NULL;
}
quantity = bal; quantity = bal;
cost = optional<balance_t>();
return *this; return *this;
} }
balance_pair_t& operator=(const amount_t& amt) { balance_pair_t& operator=(const amount_t& amt) {
if (cost) {
delete cost;
cost = NULL;
}
quantity = amt; quantity = amt;
cost = optional<balance_t>();
return *this; return *this;
} }
template <typename T> template <typename T>
balance_pair_t& operator=(T val) { balance_pair_t& operator=(T val) {
if (cost) {
delete cost;
cost = NULL;
}
quantity = val; quantity = val;
cost = optional<balance_t>();
return *this; return *this;
} }
// in-place arithmetic // in-place arithmetic
balance_pair_t& operator+=(const balance_pair_t& bal_pair) { balance_pair_t& operator+=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost) if (bal_pair.cost && ! cost)
cost = new balance_t(quantity); cost = quantity;
quantity += bal_pair.quantity; quantity += bal_pair.quantity;
if (cost) if (cost)
*cost += bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *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) { balance_pair_t& operator-=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost) if (bal_pair.cost && ! cost)
cost = new balance_t(quantity); cost = quantity;
quantity -= bal_pair.quantity; quantity -= bal_pair.quantity;
if (cost) if (cost)
*cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
@ -673,7 +653,7 @@ class balance_pair_t
// multiplication and division // multiplication and division
balance_pair_t& operator*=(const balance_pair_t& bal_pair) { balance_pair_t& operator*=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost) if (bal_pair.cost && ! cost)
cost = new balance_t(quantity); cost = quantity;
quantity *= bal_pair.quantity; quantity *= bal_pair.quantity;
if (cost) if (cost)
*cost *= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *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) { balance_pair_t& operator/=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost) if (bal_pair.cost && ! cost)
cost = new balance_t(quantity); cost = quantity;
quantity /= bal_pair.quantity; quantity /= bal_pair.quantity;
if (cost) if (cost)
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
@ -852,9 +832,9 @@ class balance_pair_t
// unary negation // unary negation
void in_place_negate() { void in_place_negate() {
quantity = quantity.negate(); quantity.in_place_negate();
if (cost) if (cost)
*cost = cost->negate(); cost->in_place_negate();
} }
balance_pair_t negate() const { balance_pair_t negate() const {
balance_pair_t temp = *this; balance_pair_t temp = *this;
@ -880,14 +860,11 @@ class balance_pair_t
return ((! cost || cost->realzero()) && quantity.realzero()); 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 abs() const {
balance_pair_t temp = *this; balance_pair_t temp = *this;
temp.in_place_abs(); temp.quantity = temp.quantity.abs();
if (temp.cost)
temp.cost = temp.cost->abs();
return temp; return temp;
} }
@ -922,9 +899,9 @@ class balance_pair_t
} }
balance_pair_t& add(const amount_t& amt, 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) if (a_cost && ! cost)
cost = new balance_t(quantity); cost = quantity;
quantity += amt; quantity += amt;
if (cost) if (cost)
*cost += a_cost ? *a_cost : amt; *cost += a_cost ? *a_cost : amt;
@ -948,7 +925,7 @@ class balance_pair_t
void in_place_round() { void in_place_round() {
quantity = quantity.round(); quantity = quantity.round();
if (cost) if (cost)
*cost = cost->round(); cost = cost->round();
} }
balance_pair_t round() const { balance_pair_t round() const {
balance_pair_t temp(*this); balance_pair_t temp(*this);
@ -959,7 +936,7 @@ class balance_pair_t
balance_pair_t unround() { balance_pair_t unround() {
balance_pair_t temp(quantity.unround()); balance_pair_t temp(quantity.unround());
if (cost) if (cost)
temp.cost = new balance_t(cost->unround()); temp.cost = cost->unround();
return temp; return temp;
} }
}; };

View file

@ -59,7 +59,7 @@ void read_binary_string(std::istream& in, string& str)
in.read(buf, slen); in.read(buf, slen);
buf[slen] = '\0'; buf[slen] = '\0';
str = buf; str = buf;
delete[] buf; checked_array_delete(buf);
} }
else if (len) { else if (len) {
char buf[256]; char buf[256];
@ -374,7 +374,7 @@ account_t * read_binary_account(char *& data, journal_t * journal,
// journal's own master account. // journal's own master account.
if (master && acct != master) { if (master && acct != master) {
delete acct; checked_delete(acct);
acct = master; acct = master;
} }
@ -441,7 +441,7 @@ unsigned int read_binary_journal(std::istream& in,
accounts = accounts_next = new account_t *[a_count]; accounts = accounts_next = new account_t *[a_count];
assert(journal->master); assert(journal->master);
delete journal->master; checked_delete(journal->master);
journal->master = read_binary_account(data, journal, master); journal->master = read_binary_account(data, journal, master);
if (read_binary_bool(data)) if (read_binary_bool(data))
@ -501,14 +501,14 @@ unsigned int read_binary_journal(std::istream& in,
(*c).second->precision = commodity->precision; (*c).second->precision = commodity->precision;
(*c).second->flags = commodity->flags; (*c).second->flags = commodity->flags;
if ((*c).second->smaller) if ((*c).second->smaller)
delete (*c).second->smaller; checked_delete((*c).second->smaller);
(*c).second->smaller = commodity->smaller; (*c).second->smaller = commodity->smaller;
if ((*c).second->larger) if ((*c).second->larger)
delete (*c).second->larger; checked_delete((*c).second->larger);
(*c).second->larger = commodity->larger; (*c).second->larger = commodity->larger;
*(base_commodities_next - 1) = (*c).second; *(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()); commodity->symbol());
*(commodities_next - 1) = (*c).second; *(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 // Clean up and return the number of entries read
delete[] accounts; checked_array_delete(accounts);
delete[] commodities; checked_array_delete(commodities);
delete[] data_pool; checked_array_delete(data_pool);
VALIDATE(journal->valid()); VALIDATE(journal->valid());

View file

@ -1,7 +1,7 @@
#ifndef _DERIVE_H #ifndef _DERIVE_H
#define _DERIVE_H #define _DERIVE_H
#include "journal.h" #include "xpath.h"
namespace ledger { namespace ledger {

View file

@ -32,13 +32,13 @@ class format_t
switch (kind) { switch (kind) {
case TEXT: case TEXT:
delete chars; checked_delete(chars);
break; break;
case XPATH: case XPATH:
delete xpath; checked_delete(xpath);
break; break;
case GROUP: case GROUP:
delete format; checked_delete(format);
break; break;
default: default:
assert(! chars); assert(! chars);
@ -75,7 +75,7 @@ class format_t
for (std::list<element_t *>::iterator i = elements.begin(); for (std::list<element_t *>::iterator i = elements.begin();
i != elements.end(); i != elements.end();
i++) i++)
delete *i; checked_delete(*i);
elements.clear(); elements.clear();
} }

View file

@ -77,7 +77,7 @@ void endElement(void *userData, const char *name)
if (! parser->curr_journal->add_entry(parser->curr_entry)) { if (! parser->curr_journal->add_entry(parser->curr_entry)) {
print_entry(std::cerr, *parser->curr_entry); print_entry(std::cerr, *parser->curr_entry);
parser->have_error = "The above entry does not balance"; parser->have_error = "The above entry does not balance";
delete parser->curr_entry; checked_delete(parser->curr_entry);
} else { } else {
parser->curr_entry->src_idx = parser->src_idx; parser->curr_entry->src_idx = parser->src_idx;
parser->curr_entry->beg_pos = parser->beg_pos; 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->state = parser->curr_state;
xact->amount = value; xact->amount = value;
if (value != parser->curr_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_pos = parser->beg_pos;
xact->beg_line = parser->beg_line; xact->beg_line = parser->beg_line;
@ -294,7 +294,7 @@ bool gnucash_parser_t::test(std::istream& in) const
unsigned int gnucash_parser_t::parse(std::istream& in, unsigned int gnucash_parser_t::parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string * original_file) const optional<path>& original_file)
{ {
char buf[BUFSIZ]; char buf[BUFSIZ];
@ -315,7 +315,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
curr_state = transaction_t::UNCLEARED; curr_state = transaction_t::UNCLEARED;
instreamp = &in; instreamp = &in;
path = original_file ? *original_file : "<gnucash>"; pathname = original_file ? *original_file : "<gnucash>";
src_idx = journal->sources.size() - 1; src_idx = journal->sources.size() - 1;
// GnuCash uses the USD commodity without defining it, which really // GnuCash uses the USD commodity without defining it, which really

View file

@ -32,7 +32,7 @@ struct gnucash_parser_t : public parser_t
std::istream * instreamp; std::istream * instreamp;
unsigned int offset; unsigned int offset;
XML_Parser parser; XML_Parser parser;
string path; path pathname;
unsigned int src_idx; unsigned int src_idx;
unsigned long beg_pos; unsigned long beg_pos;
unsigned long beg_line; unsigned long beg_line;
@ -65,7 +65,7 @@ struct gnucash_parser_t : public parser_t
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL); const optional<path>& original = optional<path>());
amount_t convert_number(const string& number, int * precision = NULL); amount_t convert_number(const string& number, int * precision = NULL);
}; };

View file

@ -1,4 +1,5 @@
#include "journal.h" #include "journal.h"
#include "xpath.h"
#include "mask.h" #include "mask.h"
#if 0 #if 0
#ifdef USE_BOOST_PYTHON #ifdef USE_BOOST_PYTHON
@ -15,21 +16,20 @@ bool transaction_t::use_effective_date = false;
transaction_t::~transaction_t() transaction_t::~transaction_t()
{ {
TRACE_DTOR(transaction_t); TRACE_DTOR(transaction_t);
if (cost) delete cost;
} }
moment_t transaction_t::actual_date() const moment_t transaction_t::actual_date() const
{ {
if (! is_valid_moment(_date) && entry) if (! _date && entry)
return entry->actual_date(); return entry->actual_date();
return _date; return *_date;
} }
moment_t transaction_t::effective_date() const moment_t transaction_t::effective_date() const
{ {
if (! is_valid_moment(_date_eff) && entry) if (! _date_eff && entry)
return entry->effective_date(); return entry->effective_date();
return _date_eff; return *_date_eff;
} }
bool transaction_t::valid() const bool transaction_t::valid() const
@ -44,15 +44,10 @@ bool transaction_t::valid() const
return false; return false;
} }
bool found = false; transactions_list::const_iterator i =
for (transactions_list::const_iterator i = entry->transactions.begin(); std::find(entry->transactions.begin(),
i != entry->transactions.end(); entry->transactions.end(), this);
i++) if (i == entry->transactions.end()) {
if (*i == this) {
found = true;
break;
}
if (! found) {
DEBUG("ledger.validate", "transaction_t: ! found"); DEBUG("ledger.validate", "transaction_t: ! found");
return false; return false;
} }
@ -62,7 +57,7 @@ bool transaction_t::valid() const
return false; return false;
} }
if (! amount.valid()) { if (amount && ! amount->valid()) {
DEBUG("ledger.validate", "transaction_t: ! amount.valid()"); DEBUG("ledger.validate", "transaction_t: ! amount.valid()");
return false; return false;
} }
@ -98,16 +93,16 @@ bool entry_base_t::finalize()
// and the per-unit price of unpriced commodities. // and the per-unit price of unpriced commodities.
value_t balance; value_t balance;
bool no_amounts = true; bool no_amounts = true;
bool saw_null = false; bool saw_null = false;
for (transactions_list::const_iterator x = transactions.begin(); for (transactions_list::const_iterator x = transactions.begin();
x != transactions.end(); x != transactions.end();
x++) x++)
if (! ((*x)->flags & TRANSACTION_VIRTUAL) || if (! ((*x)->flags & TRANSACTION_VIRTUAL) ||
((*x)->flags & TRANSACTION_BALANCE)) { ((*x)->flags & TRANSACTION_BALANCE)) {
amount_t * p = (*x)->cost ? (*x)->cost : &(*x)->amount; optional<amount_t>& p((*x)->cost ? (*x)->cost : (*x)->amount);
if (*p) { if (p) {
if (no_amounts) { if (no_amounts) {
balance = *p; balance = *p;
no_amounts = false; no_amounts = false;
@ -115,12 +110,13 @@ bool entry_base_t::finalize()
balance += *p; balance += *p;
} }
if ((*x)->cost && (*x)->amount.commodity().annotated) { assert((*x)->amount);
if ((*x)->cost && (*x)->amount->commodity().annotated) {
annotated_commodity_t& annotated_commodity_t&
ann_comm(static_cast<annotated_commodity_t&> ann_comm(static_cast<annotated_commodity_t&>
((*x)->amount.commodity())); ((*x)->amount->commodity()));
if (ann_comm.price) if (ann_comm.price)
balance += ann_comm.price * (*x)->amount.number() - *((*x)->cost); balance += *ann_comm.price * (*x)->amount->number() - *((*x)->cost);
} }
} else { } else {
saw_null = true; saw_null = true;
@ -151,7 +147,8 @@ bool entry_base_t::finalize()
if (! saw_null && balance && balance.type == value_t::BALANCE && if (! saw_null && balance && balance.type == value_t::BALANCE &&
((balance_t *) balance.data)->amounts.size() == 2) { ((balance_t *) balance.data)->amounts.size() == 2) {
transactions_list::const_iterator x = transactions.begin(); 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 = amounts_map::const_iterator this_bal =
((balance_t *) balance.data)->amounts.find(&this_comm); ((balance_t *) balance.data)->amounts.find(&this_comm);
@ -165,22 +162,22 @@ bool entry_base_t::finalize()
for (; x != transactions.end(); x++) { for (; x != transactions.end(); x++) {
if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL) || if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL) ||
! (*x)->amount || (*x)->amount.commodity() != this_comm) ! (*x)->amount || (*x)->amount->commodity() != this_comm)
continue; continue;
assert((*x)->amount); assert((*x)->amount);
balance -= (*x)->amount; balance -= *(*x)->amount;
entry_t * entry = dynamic_cast<entry_t *>(this); entry_t * entry = dynamic_cast<entry_t *>(this);
if ((*x)->amount.commodity() && if ((*x)->amount->commodity() &&
! (*x)->amount.commodity().annotated) ! (*x)->amount->commodity().annotated)
(*x)->amount.annotate_commodity (*x)->amount->annotate_commodity
(per_unit_cost.abs(), (per_unit_cost.abs(),
entry ? entry->actual_date() : moment_t(), entry ? entry->actual_date() : optional<moment_t>(),
entry ? entry->code : ""); 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; balance += *(*x)->cost;
} }
} }
@ -193,7 +190,7 @@ bool entry_base_t::finalize()
for (transactions_list::const_iterator x = transactions.begin(); for (transactions_list::const_iterator x = transactions.begin();
x != transactions.end(); x != transactions.end();
x++) { x++) {
if (! (*x)->amount.null() || if ((*x)->amount ||
(((*x)->flags & TRANSACTION_VIRTUAL) && (((*x)->flags & TRANSACTION_VIRTUAL) &&
! ((*x)->flags & TRANSACTION_BALANCE))) ! ((*x)->flags & TRANSACTION_BALANCE)))
continue; continue;
@ -246,7 +243,7 @@ bool entry_base_t::finalize()
(*x)->amount = ((amount_t *) balance.data)->negate(); (*x)->amount = ((amount_t *) balance.data)->negate();
(*x)->flags |= TRANSACTION_CALCULATED; (*x)->flags |= TRANSACTION_CALCULATED;
balance += (*x)->amount; balance += *(*x)->amount;
break; break;
default: default:
@ -326,6 +323,21 @@ bool entry_t::valid() const
return true; 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) void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
{ {
transactions_list initial_xacts(entry.transactions.begin(), 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 != initial_xacts.end();
i++) { i++) {
// jww (2006-09-10): Create a scope here based on entry // 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(); for (transactions_list::iterator t = transactions.begin();
t != transactions.end(); t != transactions.end();
t++) { t++) {
amount_t amt; amount_t amt;
if (! (*t)->amount.commodity()) { assert((*t)->amount);
if (! (*t)->amount->commodity()) {
if (! post) if (! post)
continue; continue;
amt = (*i)->amount * (*t)->amount; assert((*i)->amount);
amt = *(*i)->amount * *(*t)->amount;
} else { } else {
if (post) if (post)
continue; continue;
amt = (*t)->amount; amt = *(*t)->amount;
} }
account_t * account = (*t)->account; account_t * account = (*t)->account;
@ -371,7 +385,7 @@ account_t::~account_t()
for (accounts_map::iterator i = accounts.begin(); for (accounts_map::iterator i = accounts.begin();
i != accounts.end(); i != accounts.end();
i++) i++)
delete (*i).second; checked_delete((*i).second);
} }
account_t * account_t::find_account(const string& name, account_t * account_t::find_account(const string& name,
@ -496,10 +510,10 @@ journal_t::~journal_t()
TRACE_DTOR(journal_t); TRACE_DTOR(journal_t);
assert(master); assert(master);
delete master; checked_delete(master);
if (document) if (document)
delete document; checked_delete(document);
// Don't bother unhooking each entry's transactions from the // Don't bother unhooking each entry's transactions from the
// accounts they refer to, because all accounts are about to // accounts they refer to, because all accounts are about to
@ -509,7 +523,7 @@ journal_t::~journal_t()
i++) i++)
if (! item_pool || if (! item_pool ||
((char *) *i) < item_pool || ((char *) *i) >= item_pool_end) ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end)
delete *i; checked_delete(*i);
else else
(*i)->~entry_t(); (*i)->~entry_t();
@ -518,7 +532,7 @@ journal_t::~journal_t()
i++) i++)
if (! item_pool || if (! item_pool ||
((char *) *i) < item_pool || ((char *) *i) >= item_pool_end) ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end)
delete *i; checked_delete(*i);
else else
(*i)->~auto_entry_t(); (*i)->~auto_entry_t();
@ -527,12 +541,12 @@ journal_t::~journal_t()
i++) i++)
if (! item_pool || if (! item_pool ||
((char *) *i) < item_pool || ((char *) *i) >= item_pool_end) ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end)
delete *i; checked_delete(*i);
else else
(*i)->~period_entry_t(); (*i)->~period_entry_t();
if (item_pool) if (item_pool)
delete[] item_pool; checked_array_delete(item_pool);
} }
bool journal_t::add_entry(entry_t * entry) 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(); for (transactions_list::const_iterator i = entry->transactions.begin();
i != entry->transactions.end(); i != entry->transactions.end();
i++) i++)
if ((*i)->cost && (*i)->amount) if ((*i)->cost) {
(*i)->amount.commodity().add_price(entry->date(), assert((*i)->amount);
*(*i)->cost / (*i)->amount.number()); assert(*(*i)->amount);
(*i)->amount->commodity().add_price(entry->date(),
*(*i)->cost / (*i)->amount->number());
}
return true; 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 = else if (const auto_entry_t * entry =
dynamic_cast<const auto_entry_t *>(&entry_base)) { dynamic_cast<const auto_entry_t *>(&entry_base)) {
out << "= " << entry->predicate.expr << '\n'; out << "= " << entry->predicate->expr << '\n';
print_format = prefix + " %-34A %12o\n"; print_format = prefix + " %-34A %12o\n";
} }
else if (const period_entry_t * entry = else if (const period_entry_t * entry =

View file

@ -1,10 +1,20 @@
#ifndef _JOURNAL_H #ifndef _JOURNAL_H
#define _JOURNAL_H #define _JOURNAL_H
#include "xpath.h" #include "amount.h"
namespace ledger { 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 // These flags persist with the object
#define TRANSACTION_NORMAL 0x0000 #define TRANSACTION_NORMAL 0x0000
#define TRANSACTION_VIRTUAL 0x0001 #define TRANSACTION_VIRTUAL 0x0001
@ -22,46 +32,47 @@ class transaction_t
enum state_t { UNCLEARED, CLEARED, PENDING }; enum state_t { UNCLEARED, CLEARED, PENDING };
entry_t * entry; entry_t * entry;
moment_t _date; optional<moment_t> _date;
moment_t _date_eff; optional<moment_t> _date_eff;
account_t * account; account_t * account;
amount_t amount; optional<amount_t> amount;
string amount_expr; optional<string> amount_expr;
amount_t * cost; optional<amount_t> cost;
string cost_expr; optional<string> cost_expr;
state_t state; state_t state;
unsigned short flags; unsigned short flags;
string note; optional<string> note;
unsigned long beg_pos; unsigned long beg_pos;
unsigned long beg_line; unsigned long beg_line;
unsigned long end_pos; unsigned long end_pos;
unsigned long end_line; unsigned long end_line;
mutable void * data; typedef xml::transaction_node_t node_type;
mutable node_type * data;
static bool use_effective_date; static bool use_effective_date;
transaction_t(account_t * _account = NULL) explicit transaction_t(account_t * _account = NULL)
: entry(NULL), account(_account), cost(NULL), : entry(NULL), account(_account), state(UNCLEARED),
state(UNCLEARED), flags(TRANSACTION_NORMAL), flags(TRANSACTION_NORMAL), beg_pos(0), beg_line(0),
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { end_pos(0), end_line(0), data(NULL) {
TRACE_CTOR(transaction_t, "account_t *"); TRACE_CTOR(transaction_t, "account_t *");
} }
transaction_t(account_t * _account, explicit transaction_t(account_t * _account,
const amount_t& _amount, const amount_t& _amount,
unsigned int _flags = TRANSACTION_NORMAL, unsigned int _flags = TRANSACTION_NORMAL,
const string& _note = "") const optional<string> _note = optional<string>())
: entry(NULL), account(_account), amount(_amount), cost(NULL), : entry(NULL), account(_account), amount(_amount),
state(UNCLEARED), flags(_flags), state(UNCLEARED), flags(_flags), note(_note),
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)
: 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) { 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(const transaction_t& xact)
: entry(xact.entry), account(xact.account), amount(xact.amount),
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"); TRACE_CTOR(transaction_t, "copy");
} }
~transaction_t(); ~transaction_t();
@ -75,13 +86,6 @@ class transaction_t
return actual_date(); return actual_date();
} }
bool operator==(const transaction_t& xact) {
return this == &xact;
}
bool operator!=(const transaction_t& xact) {
return ! (*this == xact);
}
bool valid() const; bool valid() const;
}; };
@ -130,7 +134,7 @@ class entry_base_t
i != transactions.end(); i != transactions.end();
i++) i++)
if (! ((*i)->flags & TRANSACTION_BULK_ALLOC)) if (! ((*i)->flags & TRANSACTION_BULK_ALLOC))
delete *i; checked_delete(*i);
else else
(*i)->~transaction_t(); (*i)->~transaction_t();
} }
@ -153,11 +157,12 @@ class entry_t : public entry_base_t
{ {
public: public:
moment_t _date; moment_t _date;
moment_t _date_eff; optional<moment_t> _date_eff;
string code; optional<string> code;
string payee; string payee;
mutable void * data; typedef xml::entry_node_t node_type;
mutable node_type * data;
entry_t() : data(NULL) { entry_t() : data(NULL) {
TRACE_CTOR(entry_t, ""); TRACE_CTOR(entry_t, "");
@ -172,9 +177,7 @@ class entry_t : public entry_base_t
return _date; return _date;
} }
moment_t effective_date() const { moment_t effective_date() const {
if (! is_valid_moment(_date_eff)) return _date_eff ? *_date_eff : _date;
return _date;
return _date_eff;
} }
moment_t date() const { moment_t date() const {
if (transaction_t::use_effective_date) 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 void add_transaction(transaction_t * xact);
virtual bool valid() const; virtual bool valid() const;
bool get_state(transaction_t::state_t * state) 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 class auto_entry_t : public entry_base_t
{ {
public: public:
xml::xpath_t predicate; scoped_ptr<xml::xpath_t> predicate;
auto_entry_t() { auto_entry_t();
TRACE_CTOR(auto_entry_t, ""); auto_entry_t(const string& _predicate);
} virtual ~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);
}
virtual void extend_entry(entry_base_t& entry, bool post); virtual void extend_entry(entry_base_t& entry, bool post);
virtual bool valid() const { virtual bool valid() const {
@ -284,30 +278,28 @@ class account_t
journal_t * journal; journal_t * journal;
account_t * parent; account_t * parent;
string name; string name;
string note; optional<string> note;
unsigned short depth; unsigned short depth;
accounts_map accounts; accounts_map accounts;
mutable void * data; typedef xml::account_node_t node_type;
mutable node_type * data;
mutable ident_t ident; mutable ident_t ident;
mutable string _fullname; mutable string _fullname;
account_t(account_t * _parent = NULL, account_t(account_t * _parent = NULL,
const string& _name = "", const string& _name = "",
const string& _note = "") const optional<string> _note = optional<string>())
: parent(_parent), name(_name), note(_note), : parent(_parent), name(_name), note(_note),
depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) {
TRACE_CTOR(account_t, "account_t *, const string&, const string&"); TRACE_CTOR(account_t, "account_t *, const string&, const string&");
} }
~account_t(); ~account_t();
bool operator==(const account_t& account) { operator string() const {
return this == &account; return fullname();
} }
bool operator!=(const account_t& account) {
return ! (*this == account);
}
string fullname() const; string fullname() const;
void add_account(account_t * acct) { void add_account(account_t * acct) {
@ -322,10 +314,6 @@ class account_t
account_t * find_account(const string& name, bool auto_create = true); account_t * find_account(const string& name, bool auto_create = true);
operator string() const {
return fullname();
}
bool valid() const; bool valid() const;
friend class journal_t; 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<entry_t *> entries_list;
typedef std::list<auto_entry_t *> auto_entries_list; typedef std::list<auto_entry_t *> auto_entries_list;
typedef std::list<period_entry_t *> period_entries_list; typedef std::list<period_entry_t *> period_entries_list;
typedef std::list<path> path_list;
typedef std::list<string> strings_list; typedef std::list<string> strings_list;
class session_t; class session_t;
@ -383,8 +372,8 @@ class journal_t
account_t * master; account_t * master;
account_t * basket; account_t * basket;
entries_list entries; entries_list entries;
strings_list sources; path_list sources;
string price_db; optional<path> price_db;
char * item_pool; char * item_pool;
char * item_pool_end; char * item_pool_end;
@ -393,7 +382,10 @@ class journal_t
// the underlying structures (the transformers modify the XML tree // the underlying structures (the transformers modify the XML tree
// -- perhaps even adding, changing or deleting nodes -- but they do // -- perhaps even adding, changing or deleting nodes -- but they do
// not affect the basic data parsed from the journal file). // 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; auto_entries_list auto_entries;
period_entries_list period_entries; period_entries_list period_entries;
@ -410,13 +402,6 @@ class journal_t
} }
~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) { void add_account(account_t * acct) {
master->add_account(acct); master->add_account(acct);
acct->journal = this; acct->journal = this;

View file

@ -1,15 +1,15 @@
#include "utils.h"
#include "option.h"
#include "gnucash.h"
#include "qif.h"
#include "ofx.h"
#if defined(USE_BOOST_PYTHON) #if defined(USE_BOOST_PYTHON)
#include <pyledger.h> #include <pyledger.h>
#else #else
#include <ledger.h> #include <ledger.h>
#endif #endif
#include "acconf.h"
#include "option.h"
#include "gnucash.h"
#include "qif.h"
#include "ofx.h"
#ifdef HAVE_UNIX_PIPES #ifdef HAVE_UNIX_PIPES
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.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 // Handle the command-line arguments
std::list<string> args; strings_list args;
process_arguments(argc - 1, argv + 1, false, report, args); process_arguments(argc - 1, argv + 1, false, report, args);
if (args.empty()) { 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(); strings_list::iterator arg = args.begin();
if (session.cache_file == "<none>") if (! session.cache_file)
session.use_cache = false; session.use_cache = false;
else 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); 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); TRACE_FINISH(environment, 1);
const char * p = std::getenv("HOME"); const char * p = std::getenv("HOME");
string home = p ? p : ""; path home = p ? p : "";
if (session.init_file.empty()) if (! session.init_file)
session.init_file = home + "/.ledgerrc"; session.init_file = home / ".ledgerrc";
if (session.price_db.empty()) if (! session.price_db)
session.price_db = home + "/.pricedb"; session.price_db = home / ".pricedb";
if (session.cache_file.empty()) if (! session.cache_file)
session.cache_file = home + "/.ledger-cache"; session.cache_file = home / ".ledger-cache";
if (session.data_file == session.cache_file) if (session.data_file == *session.cache_file)
session.use_cache = false; session.use_cache = false;
DEBUG("ledger.session.cache", "2. use_cache = " << session.use_cache); DEBUG("ledger.session.cache", "2. use_cache = " << session.use_cache);
INFO("Initialization file is " << session.init_file); INFO("Initialization file is " << session.init_file->string());
INFO("Price database is " << session.price_db); INFO("Price database is " << session.price_db->string());
INFO("Binary cache is " << session.cache_file); INFO("Binary cache is " << session.cache_file->string());
INFO("Journal file is " << session.data_file); INFO("Journal file is " << session.data_file.string());
if (! session.use_cache) if (! session.use_cache)
INFO("Binary cache mechanism will not be used"); 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 #endif
std::ostream * out = &std::cout; std::ostream * out = &std::cout;
if (! report->output_file.empty()) { if (report->output_file) {
out = new std::ofstream(report->output_file.c_str()); out = new ofstream(*report->output_file);
} }
#ifdef HAVE_UNIX_PIPES #ifdef HAVE_UNIX_PIPES
else if (! report->pager.empty()) { else if (report->pager) {
status = pipe(pfd); status = pipe(pfd);
if (status == -1) if (status == -1)
throw_(std::logic_error, "Failed to create pipe"); 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 // Find command name: its the substring starting right of the
// rightmost '/' character in the pager pathname. See manpage // rightmost '/' character in the pager pathname. See manpage
// for strrchr. // for strrchr.
arg0 = std::strrchr(report->pager.c_str(), '/'); execlp(report->pager->native_file_string().c_str(),
if (arg0) basename(*report->pager).c_str(), (char *)0);
arg0++;
else
arg0 = report->pager.c_str(); // No slashes in pager.
execlp(report->pager.c_str(), arg0, (char *)0);
perror("execl"); perror("execl");
exit(1); 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 // Write out the binary cache, if need be
if (session.use_cache && session.cache_dirty && if (session.use_cache && session.cache_dirty && session.cache_file) {
! session.cache_file.empty()) {
TRACE_START(binary_cache, 1, "Wrote binary journal 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 #if 0
write_binary_journal(stream, journal); write_binary_journal(stream, journal);
#endif #endif
@ -367,15 +361,15 @@ static int read_and_report(report_t * report, int argc, char * argv[],
#if defined(FREE_MEMORY) #if defined(FREE_MEMORY)
// Cleanup memory -- if this is a beta or development build. // Cleanup memory -- if this is a beta or development build.
if (! report->output_file.empty()) if (report->output_file)
delete out; checked_delete(out);
#endif #endif
// If the user specified a pager, wait for it to exit now // If the user specified a pager, wait for it to exit now
#ifdef HAVE_UNIX_PIPES #ifdef HAVE_UNIX_PIPES
if (report->output_file.empty() && ! report->pager.empty()) { if (! report->output_file && report->pager) {
delete out; checked_delete(out);
close(pfd[1]); close(pfd[1]);
// Wait for child to finish // 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->context.push_front(new error_context(""));
err->reveal_context(std::cerr, "Error"); err->reveal_context(std::cerr, "Error");
std::cerr << err->what() << std::endl; std::cerr << err->what() << std::endl;
delete err; checked_delete(err);
} }
catch (fatal * err) { catch (fatal * err) {
std::cout.flush(); std::cout.flush();
@ -467,7 +461,7 @@ int main(int argc, char * argv[], char * envp[])
err->context.push_front(new error_context("")); err->context.push_front(new error_context(""));
err->reveal_context(std::cerr, "Fatal"); err->reveal_context(std::cerr, "Fatal");
std::cerr << err->what() << std::endl; std::cerr << err->what() << std::endl;
delete err; checked_delete(err);
} }
#endif #endif
catch (const std::exception& err) { catch (const std::exception& err) {

View file

@ -111,7 +111,7 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data,
// jww (2005-02-09): uncomment // jww (2005-02-09): uncomment
have_error = "The above entry does not balance"; have_error = "The above entry does not balance";
#endif #endif
delete entry; checked_delete(entry);
return -1; return -1;
} }
return 0; return 0;

View file

@ -207,7 +207,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
} }
process_option(def, scope, value); process_option(def, scope, value);
delete *o; checked_delete(*o);
} }
} }

View file

@ -18,7 +18,7 @@ class parser_t
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL) = 0; const optional<path>& original = optional<path>()) = 0;
}; };
DECLARE_EXCEPTION(parse_error); DECLARE_EXCEPTION(parse_error);

View file

@ -4,6 +4,8 @@
namespace ledger { namespace ledger {
using namespace boost::python;
struct python_run struct python_run
{ {
object result; object result;

View file

@ -12,14 +12,12 @@
namespace ledger { namespace ledger {
using namespace boost::python;
class python_interpreter_t : public xml::xpath_t::scope_t class python_interpreter_t : public xml::xpath_t::scope_t
{ {
handle<> mmodule; boost::python::handle<> mmodule;
public: public:
dict nspace; boost::python::dict nspace;
python_interpreter_t(xml::xpath_t::scope_t * parent); 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(); Py_Finalize();
} }
object import(const string& name); boost::python::object import(const string& name);
enum py_eval_mode_t { enum py_eval_mode_t {
PY_EVAL_EXPR, PY_EVAL_EXPR,
@ -35,18 +33,21 @@ class python_interpreter_t : public xml::xpath_t::scope_t
PY_EVAL_MULTI PY_EVAL_MULTI
}; };
object eval(std::istream& in, py_eval_mode_t mode = PY_EVAL_EXPR); boost::python::object eval(std::istream& in,
object eval(const string& str, py_eval_mode_t mode = PY_EVAL_EXPR); 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(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); string str(c_str);
return eval(str, mode); return eval(str, mode);
} }
class functor_t : public xml::xpath_t::functor_t { class functor_t : public xml::xpath_t::functor_t {
protected: protected:
object func; boost::python::object func;
public: public:
functor_t(const string& name, object _func) functor_t(const string& name, boost::python::object _func)
: xml::xpath_t::functor_t(name), func(_func) {} : xml::xpath_t::functor_t(name), func(_func) {}
virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals); 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) { virtual xml::xpath_t::op_t * lookup(const string& name) {
object func = eval(name); boost::python::object func = eval(name);
if (! func) if (! func)
return parent ? parent->lookup(name) : NULL; return parent ? parent->lookup(name) : NULL;
return xml::xpath_t::wrap_functor(new functor_t(name, func)); 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 { class lambda_t : public functor_t {
public: 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); virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals);
}; };
}; };

View file

@ -6,7 +6,7 @@ namespace ledger {
#define MAX_LINE 1024 #define MAX_LINE 1024
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
static string pathname; static path pathname;
static unsigned int src_idx; static unsigned int src_idx;
static unsigned int linenum; 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, unsigned int qif_parser_t::parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string *) const optional<path>&)
{ {
std::auto_ptr<entry_t> entry; std::auto_ptr<entry_t> entry;
std::auto_ptr<amount_t> amount; std::auto_ptr<amount_t> amount;
@ -104,16 +104,16 @@ unsigned int qif_parser_t::parse(std::istream& in,
case '$': { case '$': {
SET_BEG_POS_AND_LINE(); SET_BEG_POS_AND_LINE();
get_line(in); get_line(in);
xact->amount.parse(line); xact->amount = amount_t(line);
unsigned char flags = xact->amount.commodity().flags(); unsigned char flags = xact->amount->commodity().flags();
unsigned char prec = xact->amount.commodity().precision(); unsigned char prec = xact->amount->commodity().precision();
if (! def_commodity) { if (! def_commodity) {
def_commodity = commodity_t::find_or_create("$"); def_commodity = commodity_t::find_or_create("$");
assert(def_commodity); assert(def_commodity);
} }
xact->amount.set_commodity(*def_commodity); xact->amount->set_commodity(*def_commodity);
def_commodity->add_flags(flags); def_commodity->add_flags(flags);
if (prec > def_commodity->precision()) if (prec > def_commodity->precision())
@ -121,7 +121,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
if (c == '$') { if (c == '$') {
saw_splits = true; saw_splits = true;
xact->amount.in_place_negate(); xact->amount->in_place_negate();
} else { } else {
total = xact; total = xact;
} }
@ -197,7 +197,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
if (total && saw_category) { if (total && saw_category) {
if (! saw_splits) if (! saw_splits)
total->amount.in_place_negate(); // negate, to show correct flow total->amount->in_place_negate(); // negate, to show correct flow
else else
total->account = other; total->account = other;
} }

View file

@ -13,7 +13,7 @@ class qif_parser_t : public parser_t
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL); const optional<path>& original = optional<path>());
}; };
} // namespace ledger } // namespace ledger

View file

@ -117,8 +117,10 @@ static void scan_for_transactions(std::ostream& out, const xml::node_t * node)
<< std::setw(21) << std::left << std::setw(21) << std::left
<< abbreviate(xact->account->fullname(), 21, << abbreviate(xact->account->fullname(), 21,
ABBREVIATE, true) << ' ' ABBREVIATE, true) << ' '
<< std::setw(12) << std::right << std::setw(12) << std::right;
<< xact->amount << '\n'; if (xact->amount)
out << *xact->amount;
out << '\n';
} else { } else {
scan_for_transactions(out, child); scan_for_transactions(out, child);
} }

View file

@ -5,18 +5,14 @@ namespace ledger {
report_t::~report_t() report_t::~report_t()
{ {
TRACE_DTOR(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) 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 != transforms.end();
i++) i++)
(*i)->execute(document); i->execute(document);
} }
void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals) void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals)

View file

@ -11,7 +11,7 @@ typedef std::list<string> strings_list;
class report_t : public xml::xpath_t::scope_t class report_t : public xml::xpath_t::scope_t
{ {
public: public:
string output_file; optional<path> output_file;
string format_string; string format_string;
string amount_expr; string amount_expr;
string total_expr; string total_expr;
@ -20,7 +20,7 @@ class report_t : public xml::xpath_t::scope_t
unsigned long budget_flags; unsigned long budget_flags;
string account; string account;
string pager; optional<path> pager;
bool show_totals; bool show_totals;
bool raw_mode; bool raw_mode;
@ -28,7 +28,7 @@ class report_t : public xml::xpath_t::scope_t
session_t * session; session_t * session;
transform_t * last_transform; transform_t * last_transform;
std::list<transform_t *> transforms; ptr_list<transform_t> transforms;
report_t(session_t * _session) report_t(session_t * _session)
: xml::xpath_t::scope_t(_session), : xml::xpath_t::scope_t(_session),

View file

@ -5,54 +5,55 @@ namespace ledger {
unsigned int session_t::read_journal(std::istream& in, unsigned int session_t::read_journal(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string * original_file) const optional<path>& original)
{ {
if (! master) if (! master)
master = journal->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 != parsers.end();
i++) i++)
if ((*i)->test(in)) if (i->test(in))
return (*i)->parse(in, journal, master, original_file); return i->parse(in, journal, master, original);
return 0; return 0;
} }
unsigned int session_t::read_journal(const string& pathname, unsigned int session_t::read_journal(const path& pathname,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string * original_file) const optional<path>& original)
{ {
journal->sources.push_back(pathname); journal->sources.push_back(pathname);
if (access(pathname.c_str(), R_OK) == -1) if (! exists(pathname))
throw filesystem_error(BOOST_CURRENT_FUNCTION, pathname, throw filesystem_error(BOOST_CURRENT_FUNCTION, pathname,
"Cannot read file"); "Cannot read file");
if (! original_file) ifstream stream(pathname);
original_file = &pathname; return read_journal(stream, journal, master,
original ? original : pathname);
std::ifstream stream(pathname.c_str());
return read_journal(stream, journal, master, original_file);
} }
void session_t::read_init() void session_t::read_init()
{ {
if (init_file.empty()) if (! init_file)
return; return;
if (access(init_file.c_str(), R_OK) == -1) if (! exists(*init_file))
throw filesystem_error(BOOST_CURRENT_FUNCTION, init_file, throw filesystem_error(BOOST_CURRENT_FUNCTION, *init_file,
"Cannot read 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! // jww (2006-09-15): Read initialization options here!
} }
journal_t * session_t::read_data(const string& master_account) 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"); TRACE_START(parser, 1, "Parsing journal file");
journal_t * journal = new_journal(); 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); DEBUG("ledger.cache", "3. use_cache = " << use_cache);
if (use_cache && ! cache_file.empty() && if (use_cache && cache_file) {
! data_file.empty()) { DEBUG("ledger.cache", "using_cache " << cache_file->string());
DEBUG("ledger.cache", "using_cache " << cache_file);
cache_dirty = true; cache_dirty = true;
if (access(cache_file.c_str(), R_OK) != -1) { if (exists(*cache_file)) {
std::ifstream stream(cache_file.c_str()); ifstream stream(*cache_file);
string price_db_orig = journal->price_db; optional<path> price_db_orig = journal->price_db;
try {
journal->price_db = price_db; journal->price_db = price_db;
entry_count += read_journal(stream, journal, NULL,
&data_file); entry_count += read_journal(stream, journal, NULL, data_file);
if (entry_count > 0) if (entry_count > 0)
cache_dirty = false; cache_dirty = false;
else
journal->price_db = price_db_orig; 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; account_t * acct = NULL;
if (! master_account.empty()) if (! master_account.empty())
acct = journal->find_account(master_account); acct = journal->find_account(master_account);
journal->price_db = price_db; journal->price_db = price_db;
if (! journal->price_db.empty() && if (journal->price_db && exists(*journal->price_db)) {
access(journal->price_db.c_str(), R_OK) != -1) { if (read_journal(*journal->price_db, journal)) {
if (read_journal(journal->price_db, journal)) {
throw_(parse_error, "Entries not allowed in price history file"); throw_(parse_error, "Entries not allowed in price history file");
} else { } else {
DEBUG("ledger.cache", "read price database " << journal->price_db); DEBUG("ledger.cache",
"read price database " << journal->price_db->string());
journal->sources.pop_back(); journal->sources.pop_back();
} }
} }
DEBUG("ledger.cache", "rejected cache, parsing " << data_file); DEBUG("ledger.cache", "rejected cache, parsing " << data_file.string());
if (data_file == "-") { if (data_file == "-") {
use_cache = false; use_cache = false;
journal->sources.push_back("<stdin>"); journal->sources.push_back("<stdin>");
entry_count += read_journal(std::cin, journal, acct); 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); entry_count += read_journal(data_file, journal, acct);
if (! journal->price_db.empty()) if (journal->price_db)
journal->sources.push_back(journal->price_db); journal->sources.push_back(*journal->price_db);
} }
} }

View file

@ -10,10 +10,10 @@ namespace ledger {
class session_t : public xml::xpath_t::scope_t class session_t : public xml::xpath_t::scope_t
{ {
public: public:
string init_file; path data_file;
string data_file; optional<path> init_file;
string cache_file; optional<path> cache_file;
string price_db; optional<path> price_db;
string register_format; string register_format;
string wide_register_format; string wide_register_format;
@ -42,8 +42,8 @@ class session_t : public xml::xpath_t::scope_t
bool ansi_codes; bool ansi_codes;
bool ansi_invert; bool ansi_invert;
std::list<journal_t *> journals; ptr_list<journal_t> journals;
std::list<parser_t *> parsers; ptr_list<parser_t> parsers;
session_t(xml::xpath_t::scope_t * _parent = NULL) : session_t(xml::xpath_t::scope_t * _parent = NULL) :
xml::xpath_t::scope_t(_parent), xml::xpath_t::scope_t(_parent),
@ -96,16 +96,6 @@ class session_t : public xml::xpath_t::scope_t
virtual ~session_t() { virtual ~session_t() {
TRACE_DTOR(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() { journal_t * new_journal() {
@ -114,19 +104,26 @@ class session_t : public xml::xpath_t::scope_t
return journal; return journal;
} }
void close_journal(journal_t * journal) { void close_journal(journal_t * journal) {
journals.remove(journal); for (ptr_list<journal_t>::iterator i = journals.begin();
delete journal; i != journals.end();
i++)
if (&*i == journal) {
journals.erase(i);
return;
}
assert(false);
checked_delete(journal);
} }
unsigned int read_journal(std::istream& in, unsigned int read_journal(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL); const optional<path>& original = optional<path>());
unsigned int read_journal(const string& path, unsigned int read_journal(const path& path,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL); const optional<path>& original = optional<path>());
void read_init(); void read_init();
@ -135,17 +132,16 @@ class session_t : public xml::xpath_t::scope_t
void register_parser(parser_t * parser) { void register_parser(parser_t * parser) {
parsers.push_back(parser); parsers.push_back(parser);
} }
bool unregister_parser(parser_t * parser) { void unregister_parser(parser_t * parser) {
std::list<parser_t *>::iterator i; for (ptr_list<parser_t>::iterator i = parsers.begin();
for (i = parsers.begin(); i != parsers.end(); i++) i != parsers.end();
if (*i == parser) i++)
break; if (&*i == parser) {
if (i == parsers.end())
return false;
parsers.erase(i); parsers.erase(i);
return;
return true; }
assert(false);
checked_delete(parser);
} }
// //

View file

@ -101,8 +101,10 @@ extern "C" {
#include <boost/any.hpp> #include <boost/any.hpp>
#include <boost/current_function.hpp> #include <boost/current_function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/exception.hpp> #include <boost/filesystem/exception.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/ptr_container/ptr_list.hpp> #include <boost/ptr_container/ptr_list.hpp>

View file

@ -7,12 +7,12 @@ namespace ledger {
#define MAX_LINE 1024 #define MAX_LINE 1024
static string pathname; static path pathname;
static unsigned int linenum; static unsigned int linenum;
static unsigned int src_idx; static unsigned int src_idx;
static accounts_map account_aliases; 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 #ifdef TIMELOG_SUPPORT
struct time_entry_t { struct time_entry_t {
@ -173,7 +173,9 @@ transaction_t * parse_transaction(char * line,
unsigned long beg = (long)in.tellg(); 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; char c;
if (! in.eof() && (c = peek_next_nonws(in)) != '@' && if (! in.eof() && (c = peek_next_nonws(in)) != '@' &&
@ -192,11 +194,12 @@ transaction_t * parse_transaction(char * line,
xact->entry->data); 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); XPATH_PARSE_NO_REDUCE);
if (xact->entry) { if (xact->entry) {
delete static_cast<xml::transaction_node_t *>(xact->data); checked_delete(xact->data);
xact->data = NULL; xact->data = NULL;
} }
@ -226,13 +229,13 @@ transaction_t * parse_transaction(char * line,
} }
if (in.good() && ! in.eof()) { if (in.good() && ! in.eof()) {
xact->cost = new amount_t;
PUSH_CONTEXT(); PUSH_CONTEXT();
unsigned long beg = (long)in.tellg(); 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(); unsigned long end = (long)in.tellg();
@ -248,15 +251,17 @@ transaction_t * parse_transaction(char * line,
if (*xact->cost < 0) if (*xact->cost < 0)
throw_(parse_error, "A transaction's cost may not be negative"); throw_(parse_error, "A transaction's cost may not be negative");
assert(xact->amount);
amount_t per_unit_cost(*xact->cost); amount_t per_unit_cost(*xact->cost);
if (per_unit) if (per_unit)
*xact->cost *= xact->amount.number(); *xact->cost *= xact->amount->number();
else else
per_unit_cost /= xact->amount.number(); per_unit_cost /= xact->amount->number();
if (xact->amount.commodity() && if (xact->amount->commodity() &&
! xact->amount.commodity().annotated) ! xact->amount->commodity().annotated)
xact->amount.annotate_commodity(per_unit_cost, xact->amount->annotate_commodity(per_unit_cost,
xact->entry->actual_date(), xact->entry->actual_date(),
xact->entry->code); xact->entry->code);
@ -265,17 +270,19 @@ transaction_t * parse_transaction(char * line,
DEBUG("ledger.textual.parse", "line " << linenum << ": " << 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 << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"Annotated amount is " << xact->amount); "Annotated amount is " << *xact->amount);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << 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 << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"Reduced amount is " << xact->amount); "Reduced amount is " << *xact->amount);
}
} }
// Parse the optional note // Parse the optional note
@ -283,10 +290,10 @@ transaction_t * parse_transaction(char * line,
if (note) { if (note) {
xact->note = note; xact->note = note;
DEBUG("ledger.textual.parse", "line " << linenum << ": " << 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 * b = std::strchr(xact->note->c_str(), '['))
if (char * e = std::strchr(xact->note.c_str(), ']')) { if (char * e = std::strchr(xact->note->c_str(), ']')) {
char buf[256]; char buf[256];
std::strncpy(buf, b + 1, e - b - 1); std::strncpy(buf, b + 1, e - b - 1);
buf[e - b - 1] = '\0'; buf[e - b - 1] = '\0';
@ -490,7 +497,7 @@ entry_t * parse_entry(std::istream& in, char * line, journal_t * journal,
} }
if (curr->data) { if (curr->data) {
delete static_cast<xml::entry_node_t *>(curr->data); checked_delete(curr->data);
curr->data = NULL; curr->data = NULL;
} }
@ -615,7 +622,7 @@ static void clock_out_from_timelog(const moment_t& when,
unsigned int textual_parser_t::parse(std::istream& in, unsigned int textual_parser_t::parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string * original_file) const optional<path>& original)
{ {
static bool added_auto_entry_hook = false; static bool added_auto_entry_hook = false;
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
@ -632,11 +639,12 @@ unsigned int textual_parser_t::parse(std::istream& in,
account_stack.push_front(master); 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; src_idx = journal ? journal->sources.size() - 1 : 0;
linenum = 1; linenum = 1;
INFO("Parsing file '" << pathname << "'"); INFO("Parsing file '" << pathname.string() << "'");
unsigned long beg_pos = in.tellg(); unsigned long beg_pos = in.tellg();
unsigned long end_pos; unsigned long end_pos;
@ -825,32 +833,30 @@ unsigned int textual_parser_t::parse(std::istream& in,
char * p = next_element(line); char * p = next_element(line);
string word(line + 1); string word(line + 1);
if (word == "include") { 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 int> save_src_idx(src_idx);
push_var<unsigned long> save_beg_pos(beg_pos); push_var<unsigned long> save_beg_pos(beg_pos);
push_var<unsigned long> save_end_pos(end_pos); push_var<unsigned long> save_end_pos(end_pos);
push_var<unsigned int> save_linenum(linenum); 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); pathname = resolve_path(pathname);
DEBUG("ledger.textual.include", "line " << linenum << ": " << DEBUG("ledger.textual.include", "line " << linenum << ": " <<
"Including path '" << pathname << "'"); "Including path '" << pathname.string() << "'");
include_stack.push_back(std::pair<string, int> include_stack.push_back
(journal->sources.back(), linenum - 1)); (std::pair<path, int>(journal->sources.back(), linenum - 1));
try {
count += journal->session->read_journal(pathname, journal, count += journal->session->read_journal(pathname, journal,
account_stack.front()); account_stack.front());
include_stack.pop_back(); include_stack.pop_back();
} }
catch (...) {
include_stack.pop_back();
throw;
}
}
else if (word == "account") { else if (word == "account") {
if (account_t * acct = account_stack.front()->find_account(p)) if (account_t * acct = account_stack.front()->find_account(p))
account_stack.push_front(acct); account_stack.push_front(acct);

View file

@ -13,7 +13,7 @@ class textual_parser_t : public parser_t
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL); const optional<path>& original = optional<path>());
}; };
#if 0 #if 0

View file

@ -98,7 +98,7 @@ void compact_transform::execute(xml::document_t * document)
account_repitem_t * acct = static_cast<account_repitem_t *>(i); account_repitem_t * acct = static_cast<account_repitem_t *>(i);
acct->parents_elided = p->parents_elided + 1; 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); i->add_total(temp);
if (! temp) { if (! temp) {
repitem_t * next = i->next; repitem_t * next = i->next;
delete i; checked_delete(i);
i = next; i = next;
continue; continue;
} }
@ -125,7 +125,7 @@ void clean_transform::execute(xml::document_t * document)
else if (i->kind == repitem_t::ENTRY && ! i->contents) { else if (i->kind == repitem_t::ENTRY && ! i->contents) {
assert(! i->children); assert(! i->children);
repitem_t * next = i->next; repitem_t * next = i->next;
delete i; checked_delete(i);
i = next; i = next;
continue; continue;
} }
@ -246,7 +246,7 @@ void merge_transform::execute(xml::document_t * document)
j->contents = NULL; j->contents = NULL;
assert(! j->children); assert(! j->children);
delete j; checked_delete(j);
} }
} }
@ -276,14 +276,14 @@ namespace {
class delete_unmarked : public repitem_t::select_callback_t { class delete_unmarked : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t * document) {
if (item->parent && ! (item->flags & REPITEM_FLAGGED)) if (item->parent && ! (item->flags & REPITEM_FLAGGED))
delete item; checked_delete(item);
} }
}; };
class delete_marked : public repitem_t::select_callback_t { class delete_marked : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t * document) {
if (item->flags & REPITEM_FLAGGED) if (item->flags & REPITEM_FLAGGED)
delete item; checked_delete(item);
} }
}; };

View file

@ -113,10 +113,7 @@ class select_transform : public transform_t
select_transform(const string& selection_path) { select_transform(const string& selection_path) {
xpath.parse(selection_path); xpath.parse(selection_path);
} }
virtual ~select_transform() { virtual ~select_transform() {}
if (path)
delete path;
}
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t * document);
}; };

View file

@ -87,14 +87,14 @@ void shutdown_memory_tracing()
report_memory(std::cerr); report_memory(std::cerr);
} }
delete live_memory; live_memory = NULL; checked_delete(live_memory); live_memory = NULL;
delete live_memory_count; live_memory_count = NULL; checked_delete(live_memory_count); live_memory_count = NULL;
delete total_memory_count; total_memory_count = NULL; checked_delete(total_memory_count); total_memory_count = NULL;
delete live_objects; live_objects = NULL; checked_delete(live_objects); live_objects = NULL;
delete live_object_count; live_object_count = NULL; checked_delete(live_object_count); live_object_count = NULL;
delete total_object_count; total_object_count = NULL; checked_delete(total_object_count); total_object_count = NULL;
delete total_ctor_count; total_ctor_count = NULL; checked_delete(total_ctor_count); total_ctor_count = NULL;
} }
inline void add_to_count_map(object_count_map& the_map, inline void add_to_count_map(object_count_map& the_map,
@ -630,15 +630,20 @@ ptr_list<context> context_stack;
namespace ledger { namespace ledger {
string expand_path(const string& path) path expand_path(const path& pathname)
{ {
if (path.length() == 0 || path[0] != '~') if (pathname.empty())
return path; return pathname;
#if 1
return pathname;
#else
// jww (2007-04-30): I need to port this code to use
// boost::filesystem::path
const char * pfx = NULL; const char * pfx = NULL;
string::size_type pos = path.find_first_of('/'); string::size_type pos = pathname.find_first_of('/');
if (path.length() == 1 || pos == 1) { if (pathname.length() == 1 || pos == 1) {
pfx = std::getenv("HOME"); pfx = std::getenv("HOME");
#ifdef HAVE_GETPWUID #ifdef HAVE_GETPWUID
if (! pfx) { if (! pfx) {
@ -651,7 +656,7 @@ string expand_path(const string& path)
} }
#ifdef HAVE_GETPWNAM #ifdef HAVE_GETPWNAM
else { else {
string user(path, 1, pos == string::npos ? string user(pathname, 1, pos == string::npos ?
string::npos : pos - 1); string::npos : pos - 1);
struct passwd * pw = getpwnam(user.c_str()); struct passwd * pw = getpwnam(user.c_str());
if (pw) if (pw)
@ -662,7 +667,7 @@ string expand_path(const string& path)
// if we failed to find an expansion, return the path unchanged. // if we failed to find an expansion, return the path unchanged.
if (! pfx) if (! pfx)
return path; return pathname;
string result(pfx); string result(pfx);
@ -672,16 +677,19 @@ string expand_path(const string& path)
if (result.length() == 0 || result[result.length() - 1] != '/') if (result.length() == 0 || result[result.length() - 1] != '/')
result += '/'; result += '/';
result += path.substr(pos + 1); result += pathname.substr(pos + 1);
return result; return result;
#endif
} }
string resolve_path(const string& path) path resolve_path(const path& pathname)
{ {
if (path[0] == '~') path temp = pathname;
return expand_path(path); if (temp.string()[0] == '~')
return path; temp = expand_path(temp);
temp.normalize();
return temp;
} }
} // namespace ledger } // namespace ledger

View file

@ -447,7 +447,7 @@ inline void throw_unexpected_error(char c, char wanted) {
namespace ledger { namespace ledger {
string resolve_path(const string& path); path resolve_path(const path& pathname);
#ifdef HAVE_REALPATH #ifdef HAVE_REALPATH
extern "C" char * realpath(const char *, char resolved_path[]); extern "C" char * realpath(const char *, char resolved_path[]);

View file

@ -117,10 +117,10 @@ void value_t::destroy()
((balance_pair_t *)data)->~balance_pair_t(); ((balance_pair_t *)data)->~balance_pair_t();
break; break;
case STRING: case STRING:
delete *(string **) data; checked_delete(*(string **) data);
break; break;
case SEQUENCE: case SEQUENCE:
delete *(sequence_t **) data; checked_delete(*(sequence_t **) data);
break; break;
default: default:
break; 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 value_t value_t::value(const moment_t& moment) const
{ {
switch (type) { switch (type) {
@ -2188,7 +2151,7 @@ value_t value_t::cost() const
return value_t(); 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) { switch (type) {
case BOOLEAN: case BOOLEAN:
@ -2337,7 +2300,7 @@ value_context::value_context(const value_t& _bal,
value_context::~value_context() throw() value_context::~value_context() throw()
{ {
delete bal; checked_delete(bal);
} }
void value_context::describe(std::ostream& out) const throw() void value_context::describe(std::ostream& out) const throw()

View file

@ -435,7 +435,6 @@ class value_t
return 0; return 0;
} }
void in_place_abs();
value_t abs() const; value_t abs() const;
void in_place_cast(type_t cast_type); void in_place_cast(type_t cast_type);
value_t cost() const; value_t cost() const;
@ -453,10 +452,11 @@ class value_t
const bool keep_date = amount_t::keep_date, const bool keep_date = amount_t::keep_date,
const bool keep_tag = amount_t::keep_tag) const; 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; value_t value(const moment_t& moment) const;
void in_place_reduce();
void in_place_reduce();
value_t reduce() const { value_t reduce() const {
value_t temp(*this); value_t temp(*this);
temp.in_place_reduce(); temp.in_place_reduce();

View file

@ -29,13 +29,13 @@ document_t::~document_t()
{ {
TRACE_DTOR(xml::document_t); TRACE_DTOR(xml::document_t);
if (top && top != &stub) if (top && top != &stub)
delete top; checked_delete(top);
} }
void document_t::set_top(node_t * _top) void document_t::set_top(node_t * _top)
{ {
if (top && top != &stub) if (top && top != &stub)
delete top; checked_delete(top);
top = _top; top = _top;
} }
@ -191,7 +191,7 @@ void parent_node_t::clear()
node_t * child = _children; node_t * child = _children;
while (child) { while (child) {
node_t * tnext = child->next; node_t * tnext = child->next;
delete child; checked_delete(child);
child = tnext; 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 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 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) { switch (_name_id) {
case document_t::CODE: case document_t::CODE:
if (! entry->code)
return NULL;
// jww (2007-04-20): I have to save this and then delete it later // jww (2007-04-20): I have to save this and then delete it later
terminal_node_t * code_node = terminal_node_t * code_node =
new terminal_node_t(document, const_cast<entry_node_t *>(this)); new terminal_node_t(document, const_cast<entry_node_t *>(this));
code_node->set_name(document_t::CODE); code_node->set_name(document_t::CODE);
code_node->set_text(entry->code); code_node->set_text(*entry->code);
return code_node; return code_node;
case document_t::PAYEE: case document_t::PAYEE:
@ -489,11 +495,11 @@ node_t * account_node_t::children() const
name_node->set_text(account->name); name_node->set_text(account->name);
} }
if (! account->note.empty()) { if (account->note) {
terminal_node_t * note_node = terminal_node_t * note_node =
new terminal_node_t(document, const_cast<account_node_t *>(this)); new terminal_node_t(document, const_cast<account_node_t *>(this));
note_node->set_name(document_t::NOTE); 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(); for (accounts_map::iterator i = account->accounts.begin();

View file

@ -1,6 +1,7 @@
#ifndef _XML_H #ifndef _XML_H
#define _XML_H #define _XML_H
#include "journal.h"
#include "value.h" #include "value.h"
#include "parser.h" #include "parser.h"
@ -45,7 +46,7 @@ public:
virtual ~node_t() { virtual ~node_t() {
TRACE_DTOR(node_t); TRACE_DTOR(node_t);
if (parent) extract(); if (parent) extract();
if (attrs) delete attrs; if (attrs) checked_delete(attrs);
} }
void extract(); // extract this node from its parent's child list void extract(); // extract this node from its parent's child list
@ -252,7 +253,7 @@ class xml_parser_t : public parser_t
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master = NULL, account_t * master = NULL,
const string * original_file = NULL); const optional<path>& original = optional<path>());
}; };
DECLARE_EXCEPTION(parse_error); DECLARE_EXCEPTION(parse_error);
@ -319,7 +320,7 @@ public:
virtual ~transaction_node_t() { virtual ~transaction_node_t() {
TRACE_DTOR(transaction_node_t); TRACE_DTOR(transaction_node_t);
if (payee_virtual_node) if (payee_virtual_node)
delete payee_virtual_node; checked_delete(payee_virtual_node);
} }
virtual node_t * children() const; virtual node_t * children() const;
@ -387,33 +388,33 @@ public:
}; };
template <typename T> template <typename T>
inline parent_node_t * wrap_node(document_t * doc, T * item, inline typename T::node_type *
void * parent_node = NULL) { wrap_node(document_t * doc, T * item, void * parent_node = NULL) {
assert(0); assert(false);
return NULL; return NULL;
} }
template <> template <>
inline parent_node_t * wrap_node(document_t * doc, transaction_t * xact, inline transaction_t::node_type *
void * parent_node) { wrap_node(document_t * doc, transaction_t * xact, void * parent_node) {
return new transaction_node_t(doc, xact, (parent_node_t *)parent_node); return new transaction_node_t(doc, xact, (parent_node_t *)parent_node);
} }
template <> template <>
inline parent_node_t * wrap_node(document_t * doc, entry_t * entry, inline entry_t::node_type *
void * parent_node) { wrap_node(document_t * doc, entry_t * entry, void * parent_node) {
return new entry_node_t(doc, entry, (parent_node_t *)parent_node); return new entry_node_t(doc, entry, (parent_node_t *)parent_node);
} }
template <> template <>
inline parent_node_t * wrap_node(document_t * doc, account_t * account, inline account_t::node_type *
void * parent_node) { wrap_node(document_t * doc, account_t * account, void * parent_node) {
return new account_node_t(doc, account, (parent_node_t *)parent_node); return new account_node_t(doc, account, (parent_node_t *)parent_node);
} }
template <> template <>
inline parent_node_t * wrap_node(document_t * doc, journal_t * journal, inline journal_t::node_type *
void * parent_node) { wrap_node(document_t * doc, journal_t * journal, void * parent_node) {
return new journal_node_t(doc, journal, (parent_node_t *)parent_node); return new journal_node_t(doc, journal, (parent_node_t *)parent_node);
} }

View file

@ -63,7 +63,7 @@ static void endElement(void *userData, const char *name)
if (curr_journal->add_entry(curr_entry)) { if (curr_journal->add_entry(curr_entry)) {
count++; count++;
} else { } else {
delete curr_entry; checked_delete(curr_entry);
have_error = "Entry cannot be balanced"; have_error = "Entry cannot be balanced";
} }
} }
@ -133,7 +133,10 @@ static void endElement(void *userData, const char *name)
} }
#endif #endif
else if (std::strcmp(name, "quantity") == 0) { 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) { if (curr_comm) {
string::size_type i = data.find('.'); string::size_type i = data.find('.');
if (i != string::npos) { if (i != string::npos) {
@ -141,7 +144,7 @@ static void endElement(void *userData, const char *name)
if (precision > curr_comm->precision()) if (precision > curr_comm->precision())
curr_comm->set_precision(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; curr_comm = NULL;
} }
} }
@ -182,7 +185,7 @@ bool xml_parser_t::test(std::istream& in) const
unsigned int xml_parser_t::parse(std::istream& in, unsigned int xml_parser_t::parse(std::istream& in,
journal_t * journal, journal_t * journal,
account_t * master, account_t * master,
const string * original_file) const optional<path>& original)
{ {
char buf[BUFSIZ]; char buf[BUFSIZ];

View file

@ -15,7 +15,7 @@ void xpath_t::initialize()
void xpath_t::shutdown() void xpath_t::shutdown()
{ {
delete lookahead; checked_delete(lookahead);
lookahead = NULL; lookahead = NULL;
} }
@ -555,7 +555,7 @@ xpath_t::op_t::~op_t()
case VALUE: case VALUE:
assert(! left); assert(! left);
assert(valuep); assert(valuep);
delete valuep; checked_delete(valuep);
break; break;
case NODE_NAME: case NODE_NAME:
@ -564,7 +564,7 @@ xpath_t::op_t::~op_t()
case VAR_NAME: case VAR_NAME:
assert(! left); assert(! left);
assert(name); assert(name);
delete name; checked_delete(name);
break; break;
case ARG_INDEX: case ARG_INDEX:
@ -573,14 +573,14 @@ xpath_t::op_t::~op_t()
case FUNCTOR: case FUNCTOR:
assert(! left); assert(! left);
assert(functor); assert(functor);
delete functor; checked_delete(functor);
break; break;
#if 0 #if 0
case MASK: case MASK:
assert(! left); assert(! left);
assert(mask); assert(mask);
delete mask; checked_delete(mask);
break; break;
#endif #endif

View file

@ -428,7 +428,7 @@ public:
"Releasing " << this << ", refc now " << refc - 1); "Releasing " << this << ", refc now " << refc - 1);
assert(refc > 0); assert(refc > 0);
if (--refc == 0) if (--refc == 0)
delete this; checked_delete(this);
} }
op_t * acquire() { op_t * acquire() {
DEBUG("ledger.xpath.memory", DEBUG("ledger.xpath.memory",