diff options
author | John Wiegley <johnw@newartisans.com> | 2005-06-22 23:05:20 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-04-13 02:41:12 -0400 |
commit | f05ef1085a2456d7310a62631d3acbb2e9754d9c (patch) | |
tree | 07a09cf3db1c88538cc7c17b558208966aa02ce6 | |
parent | 6ecec7eb1e670dd31b670287d577980a69c9ce28 (diff) | |
download | fork-ledger-f05ef1085a2456d7310a62631d3acbb2e9754d9c.tar.gz fork-ledger-f05ef1085a2456d7310a62631d3acbb2e9754d9c.tar.bz2 fork-ledger-f05ef1085a2456d7310a62631d3acbb2e9754d9c.zip |
(parse_inline_math): Parse amounts that use any
of ()/*+- as "inline math". This causes "$100.00 * 20" to be
turned into the equivalent value expression "({$100.00} * {20})".
It is a shorthand, at the expense of a little textual parsing
speed.
(parse_amount): Call `parse_inline_math' if appropriate.
(parse_entry): Support transactions that follow immediately after
the payee name, separated by two or more spaces. This makes it
possible -- when a basket account is being used -- to list off
entry transactions one per line.
(parse): Allow a basket account to be specified using the syntax
"A ACCOUNT". From that point on in the file, any single
transactions entries will be balanced against that account.
-rw-r--r-- | textual.cc | 100 |
1 files changed, 95 insertions, 5 deletions
@@ -67,9 +67,80 @@ inline char * next_element(char * buf, bool variable = false) return NULL; } +static inline bool is_mathchr(const char c) { + return (c == '(' || c == ')' || + c == '+' || c == '-' || + c == '*' || c == '/'); +} + +static inline void copy_wsbuf(char *& q, char *& wq, char * wsbuf) { + *wq = '\0'; + std::strcpy(q, wsbuf); + q += std::strlen(wsbuf); + wq = wsbuf; +} + +static char * parse_inline_math(const char * expr) +{ + char * buf = new char[std::strlen(expr) * 2]; + char * q = buf; + char wsbuf[64]; + char * wq = wsbuf; + bool in_math = true; + bool could = true; + + *q++ = '('; + + for (const char * p = expr; *p; p++) { + if (std::isspace(*p)) { + *wq++ = *p; + } else { + bool saw_math = is_mathchr(*p); + if (in_math && ! saw_math) { + copy_wsbuf(q, wq, wsbuf); + *q++ = '{'; + in_math = could = false; + } + else if (! in_math && saw_math && could) { + *q++ = '}'; + copy_wsbuf(q, wq, wsbuf); + in_math = true; + } + else if (wq != wsbuf) { + copy_wsbuf(q, wq, wsbuf); + } + + if (! in_math && std::isdigit(*p)) + could = true; + + *q++ = *p; + } + } + + if (! in_math) + *q++ = '}'; + + *q++ = ')'; + *q++ = '\0'; + + DEBUG_PRINT("ledger.textual.inlinemath", + "Parsed '" << expr << "' as '" << buf << "'"); + + return buf; +} + void parse_amount(const char * text, amount_t& amt, unsigned short flags, transaction_t& xact) { + char * altbuf = NULL; + + if (*text) + for (const char * p = text + 1; *p; p++) + if (is_mathchr(*p)) { + text = altbuf = parse_inline_math(text); + break; + } + if (*text != '(') { amt.parse(text, flags); } else { @@ -89,10 +160,15 @@ void parse_amount(const char * text, amount_t& amt, unsigned short flags, case value_t::BALANCE: case value_t::BALANCE_PAIR: + if (altbuf) + delete[] altbuf; throw parse_error(path, linenum, "Value expression yields a balance"); break; } } + + if (altbuf) + delete[] altbuf; } transaction_t * parse_transaction(char * line, account_t * account) @@ -101,10 +177,10 @@ transaction_t * parse_transaction(char * line, account_t * account) std::auto_ptr<transaction_t> xact(new transaction_t(NULL)); - // The call to `next_element' will skip past the account name, - // and return a pointer to the beginning of the amount. Once - // we know where the amount is, we can strip off any - // transaction note, and parse it. + // The call to `next_element' will skip past the account name, and + // return a pointer to the beginning of the amount. Once we know + // where the amount is, we can strip off any transaction note, and + // parse it. char * p = skip_ws(line); if (char * cost_str = next_element(p, true)) { @@ -253,7 +329,16 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, // Parse the description text - curr->payee = next ? next : "<Unspecified payee>"; + if (next) { + char * first = next_element(next, true); + curr->payee = next; + + if (first) + if (transaction_t * xact = parse_transaction(first, master)) + curr->add_transaction(xact); + } else { + curr->payee = "<Unspecified payee>"; + } TIMER_STOP(entry_details); @@ -450,6 +535,11 @@ unsigned int textual_parser_t::parse(std::istream& in, break; } + case 'A': // a default account for unbalanced xacts + journal->basket = + account_stack.front()->find_account(skip_ws(line + 1)); + break; + case 'C': // a set of conversions if (char * p = std::strchr(line + 1, '=')) { *p++ = '\0'; |