Tons of corrections and fixes to value expressions and lot figures.

This commit is contained in:
John Wiegley 2006-03-19 21:11:49 +00:00
parent ab748ed13e
commit 32bdfe20d9
17 changed files with 866 additions and 658 deletions

View file

@ -932,9 +932,41 @@ void parse_quantity(std::istream& in, std::string& value)
char c = peek_next_nonws(in);
READ_INTO(in, buf, 255, c,
std::isdigit(c) || c == '-' || c == '.' || c == ',');
int len = std::strlen(buf);
while (len > 0 && ! std::isdigit(buf[len - 1])) {
buf[--len] = '\0';
in.unget();
}
value = buf;
}
// Invalid commodity characters:
// SPACE, TAB, NEWLINE, RETURN
// 0-9 . , ; - + * / ^ ? : & | ! =
// < > { } [ ] ( ) @
int invalid_chars[256] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
/* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
/* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
void parse_commodity(std::istream& in, std::string& symbol)
{
char buf[256];
@ -947,8 +979,7 @@ void parse_commodity(std::istream& in, std::string& symbol)
else
throw new amount_error("Quoted commodity symbol lacks closing quote");
} else {
READ_INTO(in, buf, 255, c, ! std::isspace(c) && ! std::isdigit(c) &&
c != '-' && c != '.');
READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]);
}
symbol = buf;
}
@ -1041,7 +1072,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
}
char n;
if (std::isdigit(c) || c == '.') {
if (std::isdigit(c)) {
parse_quantity(in, quant);
if (! in.eof() && ((n = in.peek()) != '\n')) {
@ -1065,7 +1096,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
parse_quantity(in, quant);
if (! in.eof() && ((n = in.peek()) != '\n'))
if (! quant.empty() && ! in.eof() && ((n = in.peek()) != '\n'))
parse_annotations(in, price, date, tag);
}
}
@ -1651,6 +1682,9 @@ namespace {
const std::time_t date,
const std::string& tag)
{
if (price < 0)
throw new amount_error("A commodity's price may not be negative");
std::ostringstream name;
comm.write(name);

View file

@ -216,7 +216,15 @@ class balance_t
return true;
}
bool operator<(const amount_t& amt) const {
return amount(amt.commodity()) < amt;
if (amt.commodity())
return amount(amt.commodity()) < amt;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
if ((*i).second < amt)
return true;
return false;
}
template <typename T>
bool operator<(T val) const {
@ -244,7 +252,15 @@ class balance_t
return true;
}
bool operator<=(const amount_t& amt) const {
return amount(amt.commodity()) <= amt;
if (amt.commodity())
return amount(amt.commodity()) <= amt;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
if ((*i).second <= amt)
return true;
return false;
}
template <typename T>
bool operator<=(T val) const {
@ -275,7 +291,15 @@ class balance_t
return true;
}
bool operator>(const amount_t& amt) const {
return amount(amt.commodity()) > amt;
if (amt.commodity())
return amount(amt.commodity()) > amt;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
if ((*i).second > amt)
return true;
return false;
}
template <typename T>
bool operator>(T val) const {
@ -303,7 +327,15 @@ class balance_t
return true;
}
bool operator>=(const amount_t& amt) const {
return amount(amt.commodity()) >= amt;
if (amt.commodity())
return amount(amt.commodity()) >= amt;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
if ((*i).second >= amt)
return true;
return false;
}
template <typename T>
bool operator>=(T val) const {
@ -327,7 +359,15 @@ class balance_t
return i == amounts.end() && j == bal.amounts.end();
}
bool operator==(const amount_t& amt) const {
return amounts.size() == 1 && (*amounts.begin()).second == amt;
if (amt.commodity())
return amounts.size() == 1 && (*amounts.begin()).second == amt;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
if ((*i).second == amt)
return true;
return false;
}
template <typename T>
bool operator==(T val) const {

132
binary.cc
View file

@ -245,6 +245,31 @@ inline void read_binary_amount(char *& data, amount_t& amt)
amt.read_quantity(data);
}
inline void read_binary_value(char *& data, value_t& val)
{
val.type = static_cast<value_t::type_t>(read_binary_long<int>(data));
switch (val.type) {
case value_t::BOOLEAN:
*((bool *) val.data) = read_binary_number<char>(data) == 1;
break;
case value_t::INTEGER:
read_binary_long(data, *((long *) val.data));
break;
case value_t::DATETIME:
read_binary_number(data, ((datetime_t *) val.data)->when);
break;
case value_t::AMOUNT:
read_binary_amount(data, *((amount_t *) val.data));
break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
assert(0);
break;
}
}
inline void read_binary_mask(char *& data, mask_t *& mask)
{
bool exclude;
@ -274,18 +299,13 @@ inline void read_binary_value_expr(char *& data, value_expr_t *& expr)
}
switch (expr->kind) {
case value_expr_t::CONSTANT_T:
read_binary_number(data, expr->constant_t);
case value_expr_t::O_ARG:
case value_expr_t::INDEX:
read_binary_long(data, expr->arg_index);
break;
case value_expr_t::CONSTANT_I:
read_binary_long(data, expr->constant_i);
break;
case value_expr_t::CONSTANT_A:
expr->constant_a = new amount_t();
read_binary_amount(data, *(expr->constant_a));
break;
case value_expr_t::CONSTANT_V:
assert(0);
case value_expr_t::CONSTANT:
expr->value = new value_t;
read_binary_value(data, *expr->value);
break;
case value_expr_t::F_CODE_MASK:
@ -314,16 +334,26 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
read_binary_long(data, xact->_date_eff);
xact->account = accounts[read_binary_long<account_t::ident_t>(data) - 1];
if (read_binary_number<char>(data) == 1) {
read_binary_value_expr(data, xact->amount_expr);
if (xact->amount_expr) xact->amount_expr->acquire();
} else {
char flag = read_binary_number<char>(data);
if (flag == 0) {
read_binary_amount(data, xact->amount);
}
else if (flag == 1) {
read_binary_amount(data, xact->amount);
read_binary_string(data, xact->amount_expr.expr);
}
else {
value_expr_t * ptr = NULL;
read_binary_value_expr(data, ptr);
assert(ptr);
xact->amount_expr.reset(ptr);
read_binary_string(data, xact->amount_expr.expr);
}
if (*data++ == 1) {
xact->cost = new amount_t;
read_binary_amount(data, *xact->cost);
read_binary_string(data, xact->cost_expr);
} else {
xact->cost = NULL;
}
@ -358,7 +388,7 @@ inline void read_binary_entry_base(char *& data, entry_base_t * entry,
for (unsigned long i = 0, count = read_binary_long<unsigned long>(data);
i < count;
i++) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
new(xact_pool) transaction_t;
read_binary_transaction(data, xact_pool);
if (ignore_calculated && xact_pool->flags & TRANSACTION_CALCULATED)
finalize = true;
@ -601,6 +631,9 @@ unsigned int read_binary_journal(std::istream& in,
char * item_pool = new char[pool_size];
journal->item_pool = item_pool;
journal->item_pool_end = item_pool + pool_size;
entry_t * entry_pool = (entry_t *) item_pool;
transaction_t * xact_pool = (transaction_t *) (item_pool +
sizeof(entry_t) * count);
@ -718,9 +751,6 @@ unsigned int read_binary_journal(std::istream& in,
// Clean up and return the number of entries read
journal->item_pool = item_pool;
journal->item_pool_end = item_pool + pool_size;
delete[] accounts;
delete[] commodities;
delete[] data_pool;
@ -822,6 +852,30 @@ void write_binary_amount(std::ostream& out, const amount_t& amt)
amt.write_quantity(out);
}
void write_binary_value(std::ostream& out, const value_t& val)
{
write_binary_long(out, (int)val.type);
switch (val.type) {
case value_t::BOOLEAN:
write_binary_number<char>(out, *((bool *) val.data) ? 1 : 0);
break;
case value_t::INTEGER:
write_binary_long(out, *((long *) val.data));
break;
case value_t::DATETIME:
write_binary_number(out, ((datetime_t *) val.data)->when);
break;
case value_t::AMOUNT:
write_binary_amount(out, *((amount_t *) val.data));
break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
throw new error("Cannot write a balance to the binary cache");
}
}
void write_binary_mask(std::ostream& out, mask_t * mask)
{
write_binary_number(out, mask->exclude);
@ -842,17 +896,12 @@ void write_binary_value_expr(std::ostream& out, const value_expr_t * expr)
write_binary_value_expr(out, expr->left);
switch (expr->kind) {
case value_expr_t::CONSTANT_T:
write_binary_number(out, expr->constant_t);
case value_expr_t::O_ARG:
case value_expr_t::INDEX:
write_binary_long(out, expr->arg_index);
break;
case value_expr_t::CONSTANT_I:
write_binary_long(out, expr->constant_i);
break;
case value_expr_t::CONSTANT_A:
write_binary_amount(out, *(expr->constant_a));
break;
case value_expr_t::CONSTANT_V:
assert(0);
case value_expr_t::CONSTANT:
write_binary_value(out, *expr->value);
break;
case value_expr_t::F_CODE_MASK:
@ -884,21 +933,30 @@ void write_binary_transaction(std::ostream& out, transaction_t * xact,
write_binary_long(out, xact->_date_eff);
write_binary_long(out, xact->account->ident);
if (xact->amount_expr) {
write_binary_number<char>(out, 1);
write_binary_value_expr(out, xact->amount_expr);
} else {
if (ignore_calculated && xact->flags & TRANSACTION_CALCULATED) {
write_binary_number<char>(out, 0);
if (ignore_calculated && xact->flags & TRANSACTION_CALCULATED)
write_binary_amount(out, amount_t());
else
write_binary_amount(out, xact->amount);
write_binary_amount(out, amount_t());
}
else if (xact->amount_expr) {
write_binary_number<char>(out, 2);
write_binary_value_expr(out, xact->amount_expr.get());
write_binary_string(out, xact->amount_expr.expr);
}
else if (! xact->amount_expr.expr.empty()) {
write_binary_number<char>(out, 1);
write_binary_amount(out, xact->amount);
write_binary_string(out, xact->amount_expr.expr);
}
else {
write_binary_number<char>(out, 0);
write_binary_amount(out, xact->amount);
}
if (xact->cost &&
(! (ignore_calculated && xact->flags & TRANSACTION_CALCULATED))) {
write_binary_number<char>(out, 1);
write_binary_amount(out, *xact->cost);
write_binary_string(out, xact->cost_expr);
} else {
write_binary_number<char>(out, 0);
}

View file

@ -31,8 +31,8 @@ namespace {
void xact_amount(value_t& result, const details_t& details, value_expr_t *)
{
if (transaction_has_xdata(*details.xact) &&
transaction_xdata_(*details.xact).dflags & TRANSACTION_COMPOSITE)
result = transaction_xdata_(*details.xact).composite_amount;
transaction_xdata_(*details.xact).dflags & TRANSACTION_COMPOUND)
result = transaction_xdata_(*details.xact).value;
else
result = details.xact->amount;
}
@ -115,8 +115,8 @@ std::string resolve_path(const std::string& path)
void config_t::reset()
{
ledger::amount_expr.reset(new value_expr("a"));
ledger::total_expr.reset(new value_expr("O"));
ledger::amount_expr = "@a";
ledger::total_expr = "@O";
pricing_leeway = 24 * 3600;
budget_flags = BUDGET_NO_BUDGET;
@ -126,8 +126,8 @@ void config_t::reset()
wide_register_format = ("%D %-.35P %-.38A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n");
csv_register_format = "\"%D\",\"%P\",\"%A\",\"%t\",\"%T\"\n";
plot_amount_format = "%D %(S(t))\n";
plot_total_format = "%D %(S(T))\n";
plot_amount_format = "%D %(@S(@t))\n";
plot_total_format = "%D %(@S(@T))\n";
print_format = "\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n";
write_hdr_format = "%d %Y%C%P\n";
write_xact_format = " %-34W %12o%n\n";
@ -315,6 +315,9 @@ void config_t::process_options(const std::string& command,
}
}
if (command != "b" && command != "r")
amount_t::keep_base = true;
// Process remaining command-line arguments
if (command != "e") {
@ -360,9 +363,9 @@ void config_t::process_options(const std::string& command,
// Setup the values of %t and %T, used in format strings
if (! amount_expr.empty())
ledger::amount_expr.reset(new value_expr(amount_expr));
ledger::amount_expr = amount_expr;
if (! total_expr.empty())
ledger::total_expr.reset(new value_expr(total_expr));
ledger::total_expr = total_expr;
// If downloading is to be supported, configure the updater
@ -1097,6 +1100,13 @@ OPT_BEGIN(period_sort, ":") {
config->report_period_sort = optarg;
} OPT_END(period_sort);
OPT_BEGIN(daily, "") {
if (config->report_period.empty())
config->report_period = "daily";
else
config->report_period = std::string("daily ") + config->report_period;
} OPT_END(daily);
OPT_BEGIN(weekly, "W") {
if (config->report_period.empty())
config->report_period = "weekly";
@ -1179,11 +1189,11 @@ OPT_BEGIN(display, "d:") {
} OPT_END(display);
OPT_BEGIN(amount, "t:") {
ledger::amount_expr.reset(new value_expr(optarg));
ledger::amount_expr = optarg;
} OPT_END(amount);
OPT_BEGIN(total, "T:") {
ledger::total_expr.reset(new value_expr(optarg));
ledger::total_expr = optarg;
} OPT_END(total);
OPT_BEGIN(amount_data, "j") {
@ -1225,25 +1235,25 @@ OPT_BEGIN(download, "Q") {
} OPT_END(download);
OPT_BEGIN(quantity, "O") {
ledger::amount_expr.reset(new value_expr("a"));
ledger::total_expr.reset(new value_expr("O"));
ledger::amount_expr = "@a";
ledger::total_expr = "@O";
} OPT_END(quantity);
OPT_BEGIN(basis, "B") {
ledger::amount_expr.reset(new value_expr("b"));
ledger::total_expr.reset(new value_expr("B"));
ledger::amount_expr = "@b";
ledger::total_expr = "@B";
} OPT_END(basis);
OPT_BEGIN(price, "I") {
ledger::amount_expr.reset(new value_expr("i"));
ledger::total_expr.reset(new value_expr("I"));
ledger::amount_expr = "@i";
ledger::total_expr = "@I";
} OPT_END(price);
OPT_BEGIN(market, "V") {
config->show_revalued = true;
ledger::amount_expr.reset(new value_expr("v"));
ledger::total_expr.reset(new value_expr("V"));
ledger::amount_expr = "@v";
ledger::total_expr = "@V";
} OPT_END(market);
namespace {
@ -1279,34 +1289,29 @@ OPT_BEGIN(set_price, ":") {
} OPT_END(set_price);
OPT_BEGIN(performance, "g") {
ledger::amount_expr.reset(new value_expr("P(a,m)-b"));
ledger::total_expr.reset(new value_expr("P(O,m)-B"));
ledger::amount_expr = "@P(@a,@m)-@b";
ledger::total_expr = "@P(@O,@m)-@B";
} OPT_END(performance);
OPT_BEGIN(gain, "G") {
config->show_revalued =
config->show_revalued_only = true;
ledger::amount_expr.reset(new value_expr("a"));
ledger::total_expr.reset(new value_expr("G"));
ledger::amount_expr = "@a";
ledger::total_expr = "@G";
} OPT_END(gain);
OPT_BEGIN(average, "A") {
ledger::total_expr.reset
(new value_expr(expand_value_expr("A(#)", ledger::total_expr->expr)));
ledger::total_expr = expand_value_expr("@A(#)", ledger::total_expr.expr);
} OPT_END(average);
OPT_BEGIN(deviation, "D") {
ledger::total_expr.reset(new value_expr("O"));
ledger::total_expr.reset
(new value_expr(expand_value_expr("t-A(#)", ledger::total_expr->expr)));
ledger::total_expr = expand_value_expr("@t-@A(#)", ledger::total_expr.expr);
} OPT_END(deviation);
OPT_BEGIN(percentage, "%") {
ledger::total_expr.reset(new value_expr("O"));
ledger::total_expr.reset
(new value_expr(expand_value_expr("^#&{100.0%}*(#/^#)",
ledger::total_expr->expr)));
ledger::total_expr = expand_value_expr("^#&{100.0%}*(#/^#)",
ledger::total_expr.expr);
} OPT_END(percentage);
//////////////////////////////////////////////////////////////////////
@ -1332,6 +1337,7 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
{ "comm-as-payee", 'x', false, opt_comm_as_payee, false },
{ "csv-register-format", '\0', true, opt_csv_register_format, false },
{ "current", 'c', false, opt_current, false },
{ "daily", '\0', false, opt_daily, false },
{ "date-format", 'y', true, opt_date_format, false },
{ "debug", '\0', true, opt_debug, false },
{ "descend", '\0', true, opt_descend, false },

View file

@ -107,7 +107,7 @@ class config_t
std::list<item_handler<transaction_t> *>& ptrs);
};
#define CONFIG_OPTIONS_SIZE 90
#define CONFIG_OPTIONS_SIZE 91
extern option_t config_options[CONFIG_OPTIONS_SIZE];
void option_help(std::ostream& out);

View file

@ -167,8 +167,9 @@ entry_t * derive_new_entry(journal_t& journal,
}
done:
if (! run_hooks(journal.entry_finalize_hooks, *added) ||
! added->finalize())
if (! run_hooks(journal.entry_finalize_hooks, *added, false) ||
! added->finalize() ||
! run_hooks(journal.entry_finalize_hooks, *added, true))
throw new error("Failed to finalize derived entry (check commodities)");
return added.release();

View file

@ -172,7 +172,7 @@ element_t * format_t::parse_elements(const std::string& fmt)
current->type = element_t::VALUE_EXPR;
assert(! current->val_expr);
current->val_expr = new value_expr(std::string(b, p));
current->val_expr = std::string(b, p);
break;
}
@ -275,7 +275,7 @@ static bool entry_state(const entry_t * entry, transaction_t::state_t * state)
}
namespace {
void mark_red(std::ostream& out, const element_t * elem) {
inline void mark_red(std::ostream& out, const element_t * elem) {
out.setf(std::ios::left);
out.width(0);
out << "\e[31m";
@ -289,7 +289,7 @@ namespace {
out.width(elem->min_width);
}
void mark_plain(std::ostream& out) {
inline void mark_plain(std::ostream& out) {
out << "\e[0m";
}
}
@ -317,10 +317,10 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
case element_t::AMOUNT:
case element_t::TOTAL:
case element_t::VALUE_EXPR: {
value_expr * calc = NULL;
value_expr calc;
switch (elem->type) {
case element_t::AMOUNT: calc = amount_expr.get(); break;
case element_t::TOTAL: calc = total_expr.get(); break;
case element_t::AMOUNT: calc = amount_expr; break;
case element_t::TOTAL: calc = total_expr; break;
case element_t::VALUE_EXPR: calc = elem->val_expr; break;
default:
assert(0);
@ -348,6 +348,8 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
}
}
bool highlighted = false;
switch (value.type) {
case value_t::BOOLEAN:
out << (*((bool *) value.data) ? "true" : "false");
@ -356,11 +358,15 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
case value_t::INTEGER:
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
if (ansi_invert) {
if (*((long *) value.data) > 0)
if (*((long *) value.data) > 0) {
mark_red(out, elem);
highlighted = true;
}
} else {
if (*((long *) value.data) < 0)
if (*((long *) value.data) < 0) {
mark_red(out, elem);
highlighted = true;
}
}
}
out << *((long *) value.data);
@ -373,11 +379,15 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
case value_t::AMOUNT:
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
if (ansi_invert) {
if (*((amount_t *) value.data) > 0)
if (*((amount_t *) value.data) > 0) {
mark_red(out, elem);
highlighted = true;
}
} else {
if (*((amount_t *) value.data) < 0)
if (*((amount_t *) value.data) < 0) {
mark_red(out, elem);
highlighted = true;
}
}
}
out << *((amount_t *) value.data);
@ -393,11 +403,15 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
if (ansi_invert) {
if (*bal > 0)
if (*bal > 0) {
mark_red(out, elem);
highlighted = true;
}
} else {
if (*bal < 0)
if (*bal < 0) {
mark_red(out, elem);
highlighted = true;
}
}
}
bal->write(out, elem->min_width,
@ -411,7 +425,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
break;
}
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT)
if (highlighted)
mark_plain(out);
break;
}
@ -419,13 +433,20 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
case element_t::OPT_AMOUNT:
if (details.xact) {
std::string disp;
bool use_disp = false;
bool use_disp = false;
if (details.xact->cost && details.xact->amount) {
std::ostringstream stream;
stream << details.xact->amount << " @ "
<< amount_t(*details.xact->cost /
details.xact->amount).unround();
if (! details.xact->amount_expr.expr.empty())
stream << details.xact->amount_expr.expr;
else
stream << details.xact->amount.strip_annotations();
if (! details.xact->cost_expr.empty())
stream << details.xact->cost_expr;
else
stream << " @ " << amount_t(*details.xact->cost /
details.xact->amount).unround();
disp = stream.str();
use_disp = true;
}
@ -450,10 +471,14 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
first->amount == - last->amount);
}
if (! use_disp)
out << details.xact->amount;
else
if (! use_disp) {
if (! details.xact->amount_expr.expr.empty())
out << details.xact->amount_expr.expr;
else
out << details.xact->amount.strip_annotations();
} else {
out << disp;
}
}
break;

View file

@ -53,19 +53,17 @@ struct element_t
std::string chars;
unsigned char min_width;
unsigned char max_width;
value_expr * val_expr;
value_expr val_expr;
struct element_t * next;
element_t() : type(STRING), flags(false),
min_width(0), max_width(0),
val_expr(NULL), next(NULL) {
min_width(0), max_width(0), next(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor element_t");
}
~element_t() {
DEBUG_PRINT("ledger.memory.dtors", "dtor element_t");
if (val_expr) delete val_expr;
if (next) delete next; // recursive, but not too deep
}
};

View file

@ -17,7 +17,6 @@ transaction_t::~transaction_t()
{
DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_t");
if (cost) delete cost;
if (amount_expr) amount_expr->release();
}
std::time_t transaction_t::actual_date() const
@ -74,7 +73,7 @@ bool transaction_t::valid() const
return false;
}
if (flags & ~0x001f) {
if (flags & ~0x003f) {
DEBUG_PRINT("ledger.validate", "transaction_t: flags are bad");
return false;
}
@ -316,35 +315,41 @@ auto_entry_t::~auto_entry_t()
delete predicate;
}
void auto_entry_t::extend_entry(entry_base_t& entry)
void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
{
transactions_list initial_xacts(entry.transactions.begin(),
entry.transactions.end());
for (transactions_list::iterator i = initial_xacts.begin();
i != initial_xacts.end();
i++)
if ((*predicate)(**i))
i++) {
if ((*predicate)(**i)) {
for (transactions_list::iterator t = transactions.begin();
t != transactions.end();
t++) {
amount_t amt;
if (! (*t)->amount.commodity())
if (! (*t)->amount.commodity()) {
if (! post)
continue;
amt = (*i)->amount * (*t)->amount;
else
} else {
if (post)
continue;
amt = (*t)->amount;
}
account_t * account = (*t)->account;
std::string fullname = account->fullname();
assert(! fullname.empty());
if (fullname == "$account")
if (fullname == "$account" || fullname == "@account")
account = (*i)->account;
transaction_t * xact
= new transaction_t(account, amt, (*t)->flags | TRANSACTION_AUTO);
entry.add_transaction(xact);
}
}
}
}
account_t::~account_t()
@ -514,7 +519,9 @@ bool journal_t::add_entry(entry_t * entry)
{
entry->journal = this;
if (! run_hooks(entry_finalize_hooks, *entry) || ! entry->finalize()) {
if (! run_hooks(entry_finalize_hooks, *entry, false) ||
! entry->finalize() ||
! run_hooks(entry_finalize_hooks, *entry, true)) {
entry->journal = NULL;
return false;
}

View file

@ -10,6 +10,7 @@
#include "amount.h"
#include "datetime.h"
#include "value.h"
#include "valexpr.h"
#include "error.h"
#include "debug.h"
#include "util.h"
@ -26,7 +27,6 @@ namespace ledger {
class entry_t;
class account_t;
class value_expr_t;
class transaction_t
{
@ -38,8 +38,9 @@ class transaction_t
std::time_t _date_eff;
account_t * account;
amount_t amount;
value_expr_t * amount_expr;
value_expr amount_expr;
amount_t * cost;
std::string cost_expr;
state_t state;
unsigned short flags;
std::string note;
@ -53,9 +54,8 @@ class transaction_t
transaction_t(account_t * _account = NULL)
: entry(NULL), _date(0), _date_eff(0), account(_account),
amount_expr(NULL), cost(NULL), state(UNCLEARED),
flags(TRANSACTION_NORMAL), beg_pos(0), beg_line(0),
end_pos(0), end_line(0), data(NULL) {
cost(NULL), state(UNCLEARED), flags(TRANSACTION_NORMAL),
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
}
transaction_t(account_t * _account,
@ -63,15 +63,14 @@ class transaction_t
unsigned int _flags = TRANSACTION_NORMAL,
const std::string& _note = "")
: entry(NULL), _date(0), _date_eff(0), account(_account),
amount(_amount), amount_expr(NULL), cost(NULL),
state(UNCLEARED), flags(_flags), note(_note),
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) {
amount(_amount), cost(NULL), state(UNCLEARED), flags(_flags),
note(_note), beg_pos(0), beg_line(0), end_pos(0), end_line(0),
data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
}
transaction_t(const transaction_t& xact)
: entry(xact.entry), _date(0), _date_eff(0), account(xact.account),
amount(xact.amount), amount_expr(NULL),
cost(xact.cost ? new amount_t(*xact.cost) : NULL),
amount(xact.amount), cost(xact.cost ? new amount_t(*xact.cost) : NULL),
state(xact.state), flags(xact.flags), note(xact.note),
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
@ -199,7 +198,7 @@ class entry_t : public entry_base_t
struct entry_finalizer_t {
virtual ~entry_finalizer_t() {}
virtual bool operator()(entry_t& entry) = 0;
virtual bool operator()(entry_t& entry, bool post) = 0;
};
class entry_context : public error_context {
@ -238,7 +237,7 @@ public:
virtual ~auto_entry_t();
virtual void extend_entry(entry_base_t& entry);
virtual void extend_entry(entry_base_t& entry, bool post);
virtual bool valid() const {
return true;
}
@ -248,7 +247,7 @@ class journal_t;
struct auto_entry_finalizer_t : public entry_finalizer_t {
journal_t * journal;
auto_entry_finalizer_t(journal_t * _journal) : journal(_journal) {}
virtual bool operator()(entry_t& entry);
virtual bool operator()(entry_t& entry, bool post);
};
@ -342,12 +341,12 @@ std::ostream& operator<<(std::ostream& out, const account_t& account);
struct func_finalizer_t : public entry_finalizer_t {
typedef bool (*func_t)(entry_t& entry);
typedef bool (*func_t)(entry_t& entry, bool post);
func_t func;
func_finalizer_t(func_t _func) : func(_func) {}
func_finalizer_t(const func_finalizer_t& other) : func(other.func) {}
virtual bool operator()(entry_t& entry) {
return func(entry);
virtual bool operator()(entry_t& entry, bool post) {
return func(entry, post);
}
};
@ -365,11 +364,11 @@ void remove_hook(std::list<T>& list, T obj) {
}
template <typename T, typename Data>
bool run_hooks(std::list<T>& list, Data& item) {
bool run_hooks(std::list<T>& list, Data& item, bool post) {
for (typename std::list<T>::const_iterator i = list.begin();
i != list.end();
i++)
if (! (*(*i))(item))
if (! (*(*i))(item, post))
return false;
return true;
}
@ -446,15 +445,16 @@ class journal_t
bool valid() const;
};
inline void extend_entry_base(journal_t * journal, entry_base_t& entry) {
inline void extend_entry_base(journal_t * journal, entry_base_t& entry,
bool post) {
for (auto_entries_list::iterator i = journal->auto_entries.begin();
i != journal->auto_entries.end();
i++)
(*i)->extend_entry(entry);
(*i)->extend_entry(entry, post);
}
inline bool auto_entry_finalizer_t::operator()(entry_t& entry) {
extend_entry_base(journal, entry);
inline bool auto_entry_finalizer_t::operator()(entry_t& entry, bool post) {
extend_entry_base(journal, entry, post);
return true;
}

View file

@ -100,9 +100,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
command = "p";
else if (command == "output")
command = "w";
else if (command == "emacs")
command = "x";
else if (command == "lisp")
else if (command == "emacs" || command == "lisp")
command = "x";
else if (command == "xml")
command = "X";
@ -119,7 +117,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
command = "r";
}
else if (command == "parse") {
value_auto_ptr expr(ledger::parse_value_expr(*arg));
value_expr expr(ledger::parse_value_expr(*arg));
if (config.verbose_mode) {
std::cout << "Value expression tree:" << std::endl;
ledger::dump_value_expr(std::cout, expr.get());
@ -243,7 +241,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
// Are we handling the parse or expr commands? Do so now.
if (command == "expr") {
value_auto_ptr expr(ledger::parse_value_expr(*arg));
value_expr expr(ledger::parse_value_expr(*arg));
if (config.verbose_mode) {
std::cout << "Value expression tree:" << std::endl;
ledger::dump_value_expr(std::cout, expr.get());

View file

@ -64,6 +64,35 @@ inline char * next_element(char * buf, bool variable = false)
return NULL;
}
value_expr parse_amount_expr(std::istream& in, amount_t& amount,
transaction_t * xact)
{
value_expr expr(parse_value_expr(in, NULL, PARSE_VALEXPR_RELAXED |
PARSE_VALEXPR_PARTIAL)->acquire());
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed an amount expression");
#ifdef DEBUG_ENABLED
DEBUG_IF("ledger.textual.parse") {
if (_debug_stream) {
ledger::dump_value_expr(*_debug_stream, expr);
*_debug_stream << std::endl;
}
}
#endif
if (! compute_amount(expr, amount, xact))
throw new parse_error("Amount expression failed to compute");
if (expr->kind == value_expr_t::CONSTANT)
expr = NULL;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"The transaction amount is " << xact->amount);
return expr;
}
transaction_t * parse_transaction(char * line, account_t * account,
entry_t * entry = NULL)
{
@ -146,53 +175,19 @@ transaction_t * parse_transaction(char * line, account_t * account,
goto finished;
if (p == ';')
goto parse_note;
if (p == '(') {
try {
xact->amount_expr = parse_value_expr(in)->acquire();
}
catch (error * err) {
err_desc = "While parsing transaction amount's value expression:";
throw err;
}
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed an amount expression");
#ifdef DEBUG_ENABLED
DEBUG_IF("ledger.textual.parse") {
if (_debug_stream) {
ledger::dump_value_expr(*_debug_stream, xact->amount_expr);
*_debug_stream << std::endl;
}
}
#endif
if (! compute_amount(xact->amount_expr, xact->amount, xact.get()))
throw new parse_error("Value expression for amount failed to compute");
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"The computed amount is " << xact->amount);
} else {
xact->amount.parse(in, AMOUNT_PARSE_NO_REDUCE);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed amount " << xact->amount);
// Parse any inline math
p = peek_next_nonws(in);
while (in.good() && ! in.eof() && (p == '-' || p == '+')) {
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed inline math operator " << p);
in.get(p);
amount_t temp;
temp.parse(in, AMOUNT_PARSE_NO_REDUCE);
switch (p) {
case '-':
xact->amount -= temp;
break;
case '+':
xact->amount += temp;
break;
}
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Calculated amount is " << xact->amount);
p = peek_next_nonws(in);
}
try {
unsigned long beg = (long)in.tellg();
xact->amount_expr =
parse_amount_expr(in, xact->amount, xact.get());
unsigned long end = (long)in.tellg();
xact->amount_expr.expr = std::string(line, beg, end - beg);
}
catch (error * err) {
err_desc = "While parsing transaction amount:";
throw err;
}
}
@ -215,13 +210,28 @@ transaction_t * parse_transaction(char * line, account_t * account,
if (in.good() && ! in.eof()) {
xact->cost = new amount_t;
p = peek_next_nonws(in);
if (p == '(')
throw new parse_error("A transaction's cost may not be a value expression");
try {
unsigned long beg = (long)in.tellg();
xact->cost->parse(in, AMOUNT_PARSE_NO_MIGRATE);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed cost " << *xact->cost);
if (parse_amount_expr(in, *xact->cost, xact.get()))
throw new parse_error("A transaction's cost must evalute to a constant value");
unsigned long end = (long)in.tellg();
if (per_unit)
xact->cost_expr = (std::string("@") +
std::string(line, beg, end - beg));
else
xact->cost_expr = (std::string("@@") +
std::string(line, beg, end - beg));
}
catch (error * err) {
err_desc = "While parsing transaction cost:";
throw err;
}
if (*xact->cost < 0)
throw new parse_error("A transaction's cost may not be a negative value");
amount_t per_unit_cost(*xact->cost);
if (per_unit)
@ -730,7 +740,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (parse_transactions(in, account_stack.front(), *pe,
"period", end_pos)) {
if (pe->finalize()) {
extend_entry_base(journal, *pe);
extend_entry_base(journal, *pe, true);
journal->period_entries.push_back(pe);
pe->src_idx = src_idx;
pe->beg_pos = beg_pos;

File diff suppressed because it is too large Load diff

183
valexpr.h
View file

@ -1,7 +1,6 @@
#ifndef _VALEXPR_H
#define _VALEXPR_H
#include "journal.h"
#include "value.h"
#include "error.h"
#include "mask.h"
@ -10,6 +9,10 @@
namespace ledger {
class entry_t;
class transaction_t;
class account_t;
struct details_t
{
const entry_t * entry;
@ -37,10 +40,9 @@ struct value_expr_t
{
enum kind_t {
// Constants
CONSTANT_I,
CONSTANT_T,
CONSTANT_A,
CONSTANT_V,
CONSTANT,
ARG_INDEX,
ZERO,
CONSTANTS,
@ -125,11 +127,9 @@ struct value_expr_t
value_expr_t * left;
union {
datetime_t * constant_t;
long constant_i;
amount_t * constant_a;
value_t * constant_v;
value_t * value;
mask_t * mask;
unsigned int arg_index; // used by ARG_INDEX and O_ARG
value_expr_t * right;
};
@ -137,9 +137,6 @@ struct value_expr_t
: kind(_kind), refc(0), left(NULL), right(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t " << this);
}
value_expr_t(const value_expr_t&) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t (copy) " << this);
}
~value_expr_t();
void release() const {
@ -180,12 +177,18 @@ struct value_expr_t
void compute(value_t& result,
const details_t& details = details_t(),
value_expr_t * context = NULL) const;
value_t compute(const details_t& details = details_t(),
value_expr_t * context = NULL) const {
value_t temp;
compute(temp, details, context);
return temp;
}
private:
value_expr_t(const value_expr_t&) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t (copy) " << this);
}
};
class valexpr_context : public error_context {
@ -273,37 +276,21 @@ bool compute_amount(value_expr_t * expr, amount_t& amt,
const transaction_t * xact,
value_expr_t * context = NULL);
struct scope_t;
value_expr_t * parse_boolean_expr(std::istream& in, scope_t * scope);
inline value_expr_t * parse_boolean_expr(const std::string& str,
scope_t * scope = NULL) {
std::istringstream stream(str);
try {
return parse_boolean_expr(stream, scope);
}
catch (error * err) {
err->context.push_back
(new error_context("While parsing value expression: " + str));
throw err;
}
}
inline value_expr_t * parse_boolean_expr(const char * p,
scope_t * scope = NULL) {
return parse_boolean_expr(std::string(p), scope);
}
#define PARSE_VALEXPR_NORMAL 0x00
#define PARSE_VALEXPR_PARTIAL 0x01
#define PARSE_VALEXPR_RELAXED 0x02
value_expr_t * parse_value_expr(std::istream& in,
scope_t * scope = NULL,
const bool partial = false);
const short flags = PARSE_VALEXPR_RELAXED);
inline value_expr_t * parse_value_expr(const std::string& str,
scope_t * scope = NULL,
const bool partial = false) {
inline value_expr_t *
parse_value_expr(const std::string& str,
scope_t * scope = NULL,
const short flags = PARSE_VALEXPR_RELAXED) {
std::istringstream stream(str);
try {
return parse_value_expr(stream, scope, partial);
return parse_value_expr(stream, scope, flags);
}
catch (error * err) {
err->context.push_back
@ -313,10 +300,11 @@ inline value_expr_t * parse_value_expr(const std::string& str,
}
}
inline value_expr_t * parse_value_expr(const char * p,
scope_t * scope = NULL,
const bool partial = false) {
return parse_value_expr(std::string(p), scope, partial);
inline value_expr_t *
parse_value_expr(const char * p,
scope_t * scope = NULL,
const short flags = PARSE_VALEXPR_RELAXED) {
return parse_value_expr(std::string(p), scope, flags);
}
void dump_value_expr(std::ostream& out, const value_expr_t * node,
@ -324,6 +312,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
bool write_value_expr(std::ostream& out,
const value_expr_t * node,
const bool relaxed = true,
const value_expr_t * node_to_find = NULL,
unsigned long * start_pos = NULL,
unsigned long * end_pos = NULL);
@ -359,27 +348,70 @@ inline value_t guarded_compute(const value_expr_t * expr,
}
//////////////////////////////////////////////////////////////////////
//
// This class is used so that during the "in between" stages of value
// expression parsing -- while no one yet holds a reference to the
// value_expr_t object -- we can be assured of deletion should an
// exception happen to whip by.
struct value_auto_ptr {
class value_expr
{
value_expr_t * ptr;
value_auto_ptr() : ptr(NULL) {}
explicit value_auto_ptr(value_expr_t * _ptr)
: ptr(_ptr ? _ptr->acquire() : NULL) {}
~value_auto_ptr() {
public:
std::string expr;
value_expr() : ptr(NULL) {}
value_expr(const std::string& _expr) : expr(_expr) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
if (! _expr.empty())
ptr = parse_value_expr(expr)->acquire();
else
ptr = NULL;
}
value_expr(value_expr_t * _ptr)
: ptr(_ptr ? _ptr->acquire(): NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
}
value_expr(const value_expr& other)
: ptr(other.ptr ? other.ptr->acquire() : NULL),
expr(other.expr) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
}
virtual ~value_expr() {
DEBUG_PRINT("ledger.memory.dtors", "dtor value_expr");
if (ptr)
ptr->release();
}
value_expr& operator=(const std::string& _expr) {
expr = _expr;
reset(parse_value_expr(expr));
return *this;
}
value_expr& operator=(value_expr_t * _expr) {
expr = "";
reset(_expr);
return *this;
}
value_expr& operator=(const value_expr& _expr) {
expr = _expr.expr;
reset(_expr.get());
return *this;
}
operator bool() const throw() {
return ptr != NULL;
}
operator std::string() const throw() {
return expr;
}
operator value_expr_t *() const throw() {
return ptr;
}
value_expr_t& operator*() const throw() {
return *ptr;
}
value_expr_t * operator->() const throw() {
return ptr;
}
value_expr_t * get() const throw() { return ptr; }
value_expr_t * release() throw() {
value_expr_t * tmp = ptr;
@ -390,41 +422,19 @@ struct value_auto_ptr {
if (p != ptr) {
if (ptr)
ptr->release();
ptr = p->acquire();
ptr = p ? p->acquire() : NULL;
}
}
};
//////////////////////////////////////////////////////////////////////
class value_expr
{
value_expr_t * parsed;
public:
std::string expr;
value_expr(const std::string& _expr) : expr(_expr) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
parsed = parse_value_expr(expr)->acquire();
}
value_expr(value_expr_t * _parsed) : parsed(_parsed->acquire()) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
}
virtual ~value_expr() {
DEBUG_PRINT("ledger.memory.dtors", "dtor value_expr");
if (parsed)
parsed->release();
}
virtual void compute(value_t& result,
const details_t& details = details_t(),
value_expr_t * context = NULL) {
guarded_compute(parsed, result, details, context);
guarded_compute(ptr, result, details, context);
}
virtual value_t compute(const details_t& details = details_t(),
value_expr_t * context = NULL) {
value_t temp;
guarded_compute(parsed, temp, details, context);
guarded_compute(ptr, temp, details, context);
return temp;
}
@ -435,35 +445,40 @@ public:
unsigned long * end_pos);
};
extern std::auto_ptr<value_expr> amount_expr;
extern std::auto_ptr<value_expr> total_expr;
extern value_expr amount_expr;
extern value_expr total_expr;
inline void compute_amount(value_t& result,
const details_t& details = details_t()) {
if (amount_expr.get())
if (amount_expr)
amount_expr->compute(result, details);
}
inline value_t compute_amount(const details_t& details = details_t()) {
if (amount_expr.get())
if (amount_expr)
return amount_expr->compute(details);
}
inline void compute_total(value_t& result,
const details_t& details = details_t()) {
if (total_expr.get())
if (total_expr)
total_expr->compute(result, details);
}
inline value_t compute_total(const details_t& details = details_t()) {
if (total_expr.get())
if (total_expr)
return total_expr->compute(details);
}
value_expr_t * parse_boolean_expr(std::istream& in, scope_t * scope,
const short flags);
inline void parse_value_definition(const std::string& str,
scope_t * scope = NULL) {
value_auto_ptr expr
(parse_boolean_expr(str, scope ? scope : global_scope.get()));
std::istringstream def(str);
value_expr expr
(parse_boolean_expr(def, scope ? scope : global_scope.get(),
PARSE_VALEXPR_RELAXED));
}
//////////////////////////////////////////////////////////////////////

48
walk.cc
View file

@ -39,8 +39,8 @@ transaction_xdata_t& transaction_xdata(const transaction_t& xact)
void add_transaction_to(const transaction_t& xact, value_t& value)
{
if (transaction_has_xdata(xact) &&
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) {
value += transaction_xdata_(xact).composite_amount;
transaction_xdata_(xact).dflags & TRANSACTION_COMPOUND) {
value += transaction_xdata_(xact).value;
}
else if (xact.cost || ! value.realzero()) {
value.add(xact.amount, xact.cost);
@ -162,8 +162,8 @@ void calc_transactions::operator()(transaction_t& xact)
void invert_transactions::operator()(transaction_t& xact)
{
if (transaction_has_xdata(xact) &&
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) {
transaction_xdata_(xact).composite_amount.negate();
transaction_xdata_(xact).dflags & TRANSACTION_COMPOUND) {
transaction_xdata_(xact).value.negate();
} else {
xact.amount.negate();
if (xact.cost)
@ -209,29 +209,31 @@ void handle_value(const value_t& value,
transaction_xdata_t& xdata(transaction_xdata(xact));
switch (value.type) {
case value_t::BOOLEAN:
xact.amount = *((bool *) value.data);
break;
case value_t::INTEGER:
xact.amount = *((long *) value.data);
break;
case value_t::AMOUNT:
xact.amount = *((amount_t *) value.data);
break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
xdata.composite_amount = value;
flags |= TRANSACTION_COMPOSITE;
break;
}
if (date)
xdata.date = date;
if (flags)
xdata.dflags |= flags;
value_t temp(value);
switch (value.type) {
case value_t::BOOLEAN:
case value_t::DATETIME:
case value_t::INTEGER:
temp.cast(value_t::AMOUNT);
// fall through...
case value_t::AMOUNT:
xact.amount = *((amount_t *) temp.data);
break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
xdata.value = temp;
flags |= TRANSACTION_COMPOUND;
break;
}
handler(xact);
}
@ -830,7 +832,7 @@ void walk_accounts(account_t& account,
const std::string& sort_string)
{
if (! sort_string.empty()) {
value_auto_ptr sort_order;
value_expr sort_order;
sort_order.reset(parse_value_expr(sort_string));
walk_accounts(account, handler, sort_order.get());
} else {

4
walk.h
View file

@ -80,14 +80,14 @@ bool compare_items<account_t>::operator()(const account_t * left,
#define TRANSACTION_DISPLAYED 0x0008
#define TRANSACTION_NO_TOTAL 0x0010
#define TRANSACTION_SORT_CALC 0x0020
#define TRANSACTION_COMPOSITE 0x0040
#define TRANSACTION_COMPOUND 0x0040
#define TRANSACTION_MATCHES 0x0080
struct transaction_xdata_t
{
value_t total;
value_t sort_value;
value_t composite_amount;
value_t value;
unsigned int index;
unsigned short dflags;
std::time_t date;

4
xml.cc
View file

@ -435,9 +435,9 @@ void format_xml_entries::format_last_entry()
}
output_stream << " <tr:amount>\n";
if (transaction_xdata_(**i).dflags & TRANSACTION_COMPOSITE)
if (transaction_xdata_(**i).dflags & TRANSACTION_COMPOUND)
xml_write_value(output_stream,
transaction_xdata_(**i).composite_amount, 10);
transaction_xdata_(**i).value, 10);
else
xml_write_value(output_stream, value_t((*i)->amount), 10);
output_stream << " </tr:amount>\n";