From 88a895a4944efcae0f7dbc7e7d73bef817cd317e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 25 Feb 2006 12:02:11 +0000 Subject: *** no comment *** --- binary.cc | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- journal.h | 16 ++++--- textual.cc | 60 ++++++++++++------------ valexpr.cc | 22 +++++++++ valexpr.h | 2 + 5 files changed, 196 insertions(+), 55 deletions(-) diff --git a/binary.cc b/binary.cc index ba6f497e..5cb4697a 100644 --- a/binary.cc +++ b/binary.cc @@ -13,15 +13,15 @@ namespace ledger { static unsigned long binary_magic_number = 0xFFEED765; #ifdef USE_EDITOR #ifdef DEBUG_ENABLED -static unsigned long format_version = 0x00020585; +static unsigned long format_version = 0x00020587; #else -static unsigned long format_version = 0x00020584; +static unsigned long format_version = 0x00020586; #endif #else #ifdef DEBUG_ENABLED -static unsigned long format_version = 0x00020505; +static unsigned long format_version = 0x00020507; #else -static unsigned long format_version = 0x00020504; +static unsigned long format_version = 0x00020506; #endif #endif @@ -249,16 +249,70 @@ inline void read_binary_amount(char *& data, amount_t& amt) amt.read_quantity(data); } +inline void read_binary_mask(char *& data, mask_t *& mask) +{ + bool exclude; + read_binary_number(data, exclude); + std::string pattern; + read_binary_string(data, pattern); + + mask = new mask_t(pattern); + mask->exclude = exclude; +} + +inline void read_binary_value_expr(char *& data, value_expr_t *& expr) +{ + if (read_binary_number(data) == 0) { + expr = NULL; + return; + } + + value_expr_t::kind_t kind; + read_binary_number(data, kind); + + expr = new value_expr_t(kind); + + read_binary_value_expr(data, expr->left); + read_binary_value_expr(data, expr->right); + + switch (expr->kind) { + case value_expr_t::CONSTANT_T: + read_binary_number(data, expr->constant_t); + break; + case value_expr_t::CONSTANT_I: + read_binary_long(data, expr->constant_i); + break; + case value_expr_t::CONSTANT_A: + read_binary_amount(data, expr->constant_a); + break; + case value_expr_t::F_FUNC: + read_binary_string(data, expr->constant_s); + break; + } + + if (read_binary_number(data) == 1) + read_binary_mask(data, expr->mask); +} + + inline void read_binary_transaction(char *& data, transaction_t * xact) { read_binary_long(data, xact->_date); read_binary_long(data, xact->_date_eff); xact->account = accounts[read_binary_long(data) - 1]; - read_binary_amount(data, xact->amount); + + if (read_binary_number(data) == 1) + read_binary_value_expr(data, xact->amount_expr); + else + read_binary_amount(data, xact->amount); if (*data++ == 1) { xact->cost = new amount_t; - read_binary_amount(data, *xact->cost); + + if (read_binary_number(data) == 1) + read_binary_value_expr(data, xact->cost_expr); + else + read_binary_amount(data, *xact->cost); } else { xact->cost = NULL; } @@ -276,6 +330,11 @@ inline void read_binary_transaction(char *& data, transaction_t * xact) #endif xact->data = NULL; + + if (xact->amount_expr) + compute_amount(xact->amount_expr, xact->amount, *xact); + if (xact->cost_expr) + compute_amount(xact->cost_expr, *xact->cost, *xact); } inline void read_binary_entry_base(char *& data, entry_base_t * entry, @@ -507,9 +566,15 @@ unsigned int read_binary_journal(std::istream& in, for (commodity_t::ident_t i = 0; i < c_count; i++) { commodity_t * commodity = read_binary_commodity(data); if (! (commodity->flags & COMMODITY_STYLE_BUILTIN)) { - std::pair result - = commodity_t::commodities.insert(commodities_pair(commodity->symbol, - commodity)); + if (commodity->symbol == "") { + commodity_t::commodities.erase(commodity->symbol); + delete commodity_t::null_commodity; + commodity_t::null_commodity = commodity; + } + + std::pair result = + commodity_t::commodities.insert(commodities_pair(commodity->symbol, + commodity)); if (! result.second) throw error(std::string("Failed to read commodity from cache: ") + commodity->symbol); @@ -653,16 +718,70 @@ void write_binary_amount(std::ostream& out, const amount_t& amt) amt.write_quantity(out); } +void write_binary_mask(std::ostream& out, mask_t * mask) +{ + write_binary_number(out, mask->exclude); + write_binary_string(out, mask->pattern); +} + +void write_binary_value_expr(std::ostream& out, value_expr_t * expr) +{ + if (expr == NULL) { + write_binary_number(out, 0); + return; + } + write_binary_number(out, 1); + + write_binary_number(out, expr->kind); + write_binary_value_expr(out, expr->left); + write_binary_value_expr(out, expr->right); + + switch (expr->kind) { + case value_expr_t::CONSTANT_T: + write_binary_number(out, expr->constant_t); + 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::F_FUNC: + write_binary_string(out, expr->constant_s); + break; + } + + if (expr->mask) { + write_binary_number(out, 1); + write_binary_mask(out, expr->mask); + } else { + write_binary_number(out, 0); + } +} + void write_binary_transaction(std::ostream& out, transaction_t * xact) { write_binary_long(out, xact->_date); write_binary_long(out, xact->_date_eff); write_binary_long(out, xact->account->ident); - write_binary_amount(out, xact->amount); + + if (xact->amount_expr != NULL) { + write_binary_number(out, 1); + write_binary_value_expr(out, xact->amount_expr); + } else { + write_binary_number(out, 0); + write_binary_amount(out, xact->amount); + } if (xact->cost) { write_binary_number(out, 1); - write_binary_amount(out, *xact->cost); + if (xact->cost_expr != NULL) { + write_binary_number(out, 1); + write_binary_value_expr(out, xact->cost_expr); + } else { + write_binary_number(out, 0); + write_binary_amount(out, *xact->cost); + } } else { write_binary_number(out, 0); } @@ -852,21 +971,17 @@ void write_binary_journal(std::ostream& out, journal_t * journal) // Write out the commodities write_binary_long - (out, commodity_t::commodities.size() - 1); + (out, commodity_t::commodities.size()); for (commodities_map::const_iterator i = commodity_t::commodities.begin(); i != commodity_t::commodities.end(); i++) - if (! (*i).first.empty()) - write_binary_commodity(out, (*i).second); - else - (*i).second->ident = 0; + write_binary_commodity(out, (*i).second); for (commodities_map::const_iterator i = commodity_t::commodities.begin(); i != commodity_t::commodities.end(); i++) - if (! (*i).first.empty()) - write_binary_commodity_extra(out, (*i).second); + write_binary_commodity_extra(out, (*i).second); if (commodity_t::default_commodity) write_binary_long(out, commodity_t::default_commodity->ident); diff --git a/journal.h b/journal.h index 4522723c..a5953921 100644 --- a/journal.h +++ b/journal.h @@ -25,6 +25,7 @@ namespace ledger { class entry_t; class account_t; +class value_expr_t; class transaction_t { @@ -36,7 +37,9 @@ class transaction_t std::time_t _date_eff; account_t * account; amount_t amount; + value_expr_t * amount_expr; amount_t * cost; + value_expr_t * cost_expr; state_t state; unsigned short flags; std::string note; @@ -52,7 +55,8 @@ class transaction_t transaction_t(account_t * _account = NULL) : entry(NULL), _date(0), _date_eff(0), account(_account), - cost(NULL), state(UNCLEARED), flags(TRANSACTION_NORMAL), + amount_expr(NULL), cost(NULL), cost_expr(NULL), + state(UNCLEARED), flags(TRANSACTION_NORMAL), #ifdef USE_EDITOR beg_pos(0), beg_line(0), end_pos(0), end_line(0), #endif @@ -65,8 +69,8 @@ class transaction_t unsigned int _flags = TRANSACTION_NORMAL, const std::string& _note = "") : entry(NULL), _date(0), _date_eff(0), account(_account), - amount(_amount), cost(NULL), state(UNCLEARED), flags(_flags), - note(_note), + amount(_amount), amount_expr(NULL), cost(NULL), cost_expr(NULL), + state(UNCLEARED), flags(_flags), note(_note), #ifdef USE_EDITOR beg_pos(0), beg_line(0), end_pos(0), end_line(0), #endif @@ -75,9 +79,9 @@ class transaction_t } transaction_t(const transaction_t& xact) - : entry(xact.entry), _date(0), _date_eff(0), - account(xact.account), amount(xact.amount), - cost(xact.cost ? new amount_t(*xact.cost) : NULL), + : 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), cost_expr(NULL), state(xact.state), flags(xact.flags), note(xact.note), #ifdef USE_EDITOR beg_pos(0), beg_line(0), end_pos(0), end_line(0), diff --git a/textual.cc b/textual.cc index 43d2e204..f4e25e26 100644 --- a/textual.cc +++ b/textual.cc @@ -126,51 +126,49 @@ static char * parse_inline_math(const char * expr) return buf; } -void parse_amount(const char * text, amount_t& amt, unsigned short flags, - transaction_t& xact) +value_expr_t * parse_amount(const char * text, amount_t& amt, + unsigned short flags, transaction_t& xact) { char * altbuf = NULL; if (*text && *text != '(') { - bool in_quote = false; + bool in_quote = false; + bool seen_digit = false; for (const char * p = text + 1; *p; p++) if (*p == '"') { in_quote = ! in_quote; } - else if (! in_quote && is_mathchr(*p)) { - text = altbuf = parse_inline_math(text); - break; + else if (! in_quote) { + if (is_mathchr(*p)) { + if (*p == '-' && ! seen_digit) + continue; + text = altbuf = parse_inline_math(text); + break; + } + else if (std::isdigit(*p)) { + seen_digit = true; + } } } + value_expr_t * expr = NULL; + if (*text != '(') { amt.parse(text, flags); + + if (altbuf) + delete[] altbuf; } else { - value_expr_t * expr = parse_value_expr(text); - value_t result; - expr->compute(result, details_t(xact)); - switch (result.type) { - case value_t::BOOLEAN: - amt = *((bool *) result.data); - break; - case value_t::INTEGER: - amt = *((long *) result.data); - break; - case value_t::AMOUNT: - amt = *((amount_t *) result.data); - break; + expr = parse_value_expr(text); + + if (altbuf) + delete[] altbuf; - case value_t::BALANCE: - case value_t::BALANCE_PAIR: - if (altbuf) - delete[] altbuf; + if (! compute_amount(expr, amt, xact)) throw parse_error(path, linenum, "Value expression yields a balance"); - break; - } } - if (altbuf) - delete[] altbuf; + return expr; } transaction_t * parse_transaction(char * line, account_t * account) @@ -290,12 +288,12 @@ transaction_t * parse_transaction(char * line, account_t * account) // If an amount (and optional price) were seen, parse them now if (amount) { - parse_amount(amount, xact->amount, AMOUNT_PARSE_NO_REDUCE, *xact); - + xact->amount_expr = parse_amount(amount, xact->amount, + AMOUNT_PARSE_NO_REDUCE, *xact); if (price) { xact->cost = new amount_t; - parse_amount(price, *xact->cost, AMOUNT_PARSE_NO_MIGRATE, *xact); - + xact->cost_expr = parse_amount(price, *xact->cost, + AMOUNT_PARSE_NO_MIGRATE, *xact); if (per_unit) { *xact->cost *= xact->amount; *xact->cost = xact->cost->round(xact->cost->commodity().precision); diff --git a/valexpr.cc b/valexpr.cc index 42e16b63..72ba5f6d 100644 --- a/valexpr.cc +++ b/valexpr.cc @@ -18,6 +18,28 @@ details_t::details_t(const transaction_t& _xact) DEBUG_PRINT("ledger.memory.ctors", "ctor details_t"); } +bool compute_amount(value_expr_t * expr, amount_t& amt, transaction_t& xact) +{ + value_t result; + expr->compute(result, details_t(xact)); + switch (result.type) { + case value_t::BOOLEAN: + amt = *((bool *) result.data); + break; + case value_t::INTEGER: + amt = *((long *) result.data); + break; + case value_t::AMOUNT: + amt = *((amount_t *) result.data); + break; + + case value_t::BALANCE: + case value_t::BALANCE_PAIR: + return false; + } + return true; +} + void value_expr_t::compute(value_t& result, const details_t& details) const { switch (kind) { diff --git a/valexpr.h b/valexpr.h index 820ae04f..73d5113e 100644 --- a/valexpr.h +++ b/valexpr.h @@ -126,6 +126,8 @@ extern std::auto_ptr amount_expr; extern std::auto_ptr total_expr; extern std::time_t terminus; +bool compute_amount(value_expr_t * expr, amount_t& amt, transaction_t& xact); + inline void compute_amount(value_t& result, const details_t& details) { if (amount_expr.get()) amount_expr->compute(result, details); -- cgit v1.2.3