Started using boost::optional<T>.
This commit is contained in:
parent
50a9caf302
commit
e92bcf411d
37 changed files with 655 additions and 694 deletions
186
src/amount.cc
186
src/amount.cc
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
src/amount.h
46
src/amount.h
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 = ∈
|
instreamp = ∈
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
111
src/journal.cc
111
src/journal.cc
|
|
@ -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 =
|
||||||
|
|
|
||||||
135
src/journal.h
135
src/journal.h
|
|
@ -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;
|
||||||
|
|
|
||||||
74
src/main.cc
74
src/main.cc
|
|
@ -1,15 +1,15 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include "option.h"
|
||||||
|
#include "gnucash.h"
|
||||||
|
#include "qif.h"
|
||||||
|
#include "ofx.h"
|
||||||
|
|
||||||
#if defined(USE_BOOST_PYTHON)
|
#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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
using namespace boost::python;
|
||||||
|
|
||||||
struct python_run
|
struct python_run
|
||||||
{
|
{
|
||||||
object result;
|
object result;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
16
src/qif.cc
16
src/qif.cc
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
46
src/utils.cc
46
src/utils.cc
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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[]);
|
||||||
|
|
|
||||||
45
src/value.cc
45
src/value.cc
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
20
src/xml.cc
20
src/xml.cc
|
|
@ -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();
|
||||||
|
|
|
||||||
29
src/xml.h
29
src/xml.h
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
||||||
10
src/xpath.cc
10
src/xpath.cc
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue