diff options
-rw-r--r-- | binary.cc | 33 | ||||
-rw-r--r-- | binary.h | 21 | ||||
-rw-r--r-- | format.cc | 4 | ||||
-rw-r--r-- | format.h | 11 | ||||
-rw-r--r-- | gnucash.cc | 10 | ||||
-rw-r--r-- | ledger.cc | 39 | ||||
-rw-r--r-- | ledger.h | 30 | ||||
-rw-r--r-- | main.cc | 127 | ||||
-rw-r--r-- | textual.cc | 9 | ||||
-rw-r--r-- | textual.h | 13 | ||||
-rw-r--r-- | valexpr.cc | 1 | ||||
-rw-r--r-- | walk.h | 73 |
12 files changed, 201 insertions, 170 deletions
@@ -1,5 +1,4 @@ #include "ledger.h" -#include "textual.h" #include <vector> #include <fstream> @@ -97,7 +96,7 @@ transaction_t * read_binary_transaction(std::istream& in, entry_t * entry) return xact; } -entry_t * read_binary_entry(std::istream& in, ledger_t * ledger) +entry_t * read_binary_entry(std::istream& in, journal_t * journal) { entry_t * entry = new entry_t; @@ -258,7 +257,7 @@ account_t * read_binary_account(std::istream& in, account_t * master = NULL) // If all of the subaccounts will be added to a different master // account, throw away what we've learned about the recorded - // ledger's own master account. + // journal's own master account. if (master) { delete acct; @@ -282,9 +281,9 @@ account_t * read_binary_account(std::istream& in, account_t * master = NULL) return acct; } -unsigned int read_binary_ledger(std::istream& in, +unsigned int read_binary_journal(std::istream& in, const std::string& leader, - ledger_t * ledger, + journal_t * journal, account_t * master) { ident = 0; @@ -325,7 +324,7 @@ unsigned int read_binary_ledger(std::istream& in, in.read(buf, len); buf[len] = '\0'; - ledger->sources.push_back(buf); + journal->sources.push_back(buf); std::time_t old_mtime; struct stat info; @@ -335,7 +334,7 @@ unsigned int read_binary_ledger(std::istream& in, return 0; } - ledger->master = read_binary_account(in, master); + journal->master = read_binary_account(in, master); unsigned long count; in.read((char *)&count, sizeof(count)); @@ -351,8 +350,8 @@ unsigned int read_binary_ledger(std::istream& in, in.read((char *)&count, sizeof(count)); for (int i = count; --i >= 0; ) { - entry_t * entry = read_binary_entry(in, ledger); - ledger->entries.push_back(entry); + entry_t * entry = read_binary_entry(in, journal); + journal->entries.push_back(entry); } #ifdef DEBUG @@ -557,7 +556,7 @@ void write_binary_account(std::ostream& out, account_t * account) #endif } -void write_binary_ledger(std::ostream& out, ledger_t * ledger, +void write_binary_journal(std::ostream& out, journal_t * journal, const std::string& leader) { out.write((char *)&binary_magic_number, sizeof(binary_magic_number)); @@ -576,11 +575,11 @@ void write_binary_ledger(std::ostream& out, ledger_t * ledger, out.write((char *)&len, sizeof(len)); out.write(leader.c_str(), len); - len = ledger->sources.size(); + len = journal->sources.size(); out.write((char *)&len, sizeof(len)); - for (std::list<std::string>::const_iterator i = ledger->sources.begin(); - i != ledger->sources.end(); + for (std::list<std::string>::const_iterator i = journal->sources.begin(); + i != journal->sources.end(); i++) { len = (*i).length(); out.write((char *)&len, sizeof(len)); @@ -591,7 +590,7 @@ void write_binary_ledger(std::ostream& out, ledger_t * ledger, out.write((char *)&info.st_mtime, sizeof(info.st_mtime)); } - write_binary_account(out, ledger->master); + write_binary_account(out, journal->master); unsigned long count = commodity_t::commodities.size(); out.write((char *)&count, sizeof(count)); @@ -601,11 +600,11 @@ void write_binary_ledger(std::ostream& out, ledger_t * ledger, i++) write_binary_commodity(out, (*i).second); - count = ledger->entries.size(); + count = journal->entries.size(); out.write((char *)&count, sizeof(count)); - for (entries_list::const_iterator i = ledger->entries.begin(); - i != ledger->entries.end(); + for (entries_list::const_iterator i = journal->entries.begin(); + i != journal->entries.end(); i++) write_binary_entry(out, *i); diff --git a/binary.h b/binary.h deleted file mode 100644 index e56d2f17..00000000 --- a/binary.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _BINARY_H -#define _BINARY_H - -#include "ledger.h" - -namespace ledger { - -extern unsigned long binary_magic_number; - -extern unsigned int read_binary_ledger(std::istream& in, - const std::string& leader, - ledger_t * journal, - account_t * master = NULL); - -extern void write_binary_ledger(std::ostream& out, - ledger_t * ledger, - const std::string& leader); - -} // namespace ledger - -#endif // _BINARY_H @@ -147,7 +147,7 @@ element_t * format_t::parse_elements(const std::string& fmt) void format_t::format_elements(std::ostream& out, const details_t& details) const { - for (const element_t * elem = elements.get(); elem; elem = elem->next) { + for (const element_t * elem = elements; elem; elem = elem->next) { if (elem->align_left) out << std::left; else @@ -158,7 +158,7 @@ void format_t::format_elements(std::ostream& out, switch (elem->type) { case element_t::STRING: - out << elem->chars;; + out << elem->chars; break; case element_t::VALUE_EXPR: { @@ -49,13 +49,16 @@ struct element_t struct format_t { - std::auto_ptr<element_t> elements; + element_t * elements; - static std::auto_ptr<node_t> value_expr; - static std::auto_ptr<node_t> total_expr; + static std::auto_ptr<node_t> value_expr; + static std::auto_ptr<node_t> total_expr; format_t(const std::string& _format) { - elements.reset(parse_elements(_format)); + elements = parse_elements(_format); + } + ~format_t() { + if (elements) delete elements; } static element_t * parse_elements(const std::string& fmt); @@ -15,7 +15,7 @@ typedef std::pair<const std::string, account_t *> accounts_pair; typedef std::map<account_t *, commodity_t *> account_comm_map; typedef std::pair<account_t *, commodity_t *> account_comm_pair; -static ledger_t * curr_ledger; +static journal_t * curr_journal; static account_t * curr_account; static commodity_t * curr_account_comm; static std::string curr_account_id; @@ -107,7 +107,7 @@ static void endElement(void *userData, const char *name) if (std::strcmp(name, "gnc:account") == 0) { assert(curr_account); if (! curr_account->parent) - curr_ledger->add_account(curr_account); + curr_journal->add_account(curr_account); accounts_by_id.insert(accounts_pair(curr_account_id, curr_account)); curr_account = NULL; } @@ -118,7 +118,7 @@ static void endElement(void *userData, const char *name) } else if (std::strcmp(name, "gnc:transaction") == 0) { assert(curr_entry); - if (! curr_ledger->add_entry(curr_entry)) + if (! curr_journal->add_entry(curr_entry)) assert(0); curr_entry = NULL; } @@ -256,13 +256,13 @@ static void dataHandler(void *userData, const char *s, int len) } } -int parse_gnucash(std::istream& in, ledger_t * ledger, account_t * master) +int parse_gnucash(std::istream& in, journal_t * journal, account_t * master) { char buf[BUFSIZ]; count = 0; action = NO_ACTION; - curr_ledger = ledger; + curr_journal = journal; curr_account = NULL; curr_entry = NULL; curr_comm = NULL; @@ -1,8 +1,6 @@ #include "ledger.h" #include "valexpr.h" #include "datetime.h" -#include "textual.h" -#include "binary.h" #include <fstream> @@ -10,30 +8,7 @@ namespace ledger { const std::string version = "2.0b"; -#if 0 - -struct cmp_items { - const node_t * sort_order; - - cmp_items(const node_t * _sort_order) : sort_order(_sort_order) { - assert(sort_order); - } - - bool operator()(const item_t * left, const item_t * right) const { - assert(left); - assert(right); - return sort_order->compute(left) < sort_order->compute(right); - } -}; - -void item_t::sort(const node_t * sort_order) -{ - std::stable_sort(subitems.begin(), subitems.end(), cmp_items(sort_order)); -} - -#endif - -ledger_t::~ledger_t() +journal_t::~journal_t() { delete master; @@ -46,7 +21,7 @@ ledger_t::~ledger_t() delete *i; } -bool ledger_t::add_entry(entry_t * entry) +bool journal_t::add_entry(entry_t * entry) { entries.push_back(entry); @@ -64,7 +39,7 @@ bool ledger_t::add_entry(entry_t * entry) return true; } -bool ledger_t::remove_entry(entry_t * entry) +bool journal_t::remove_entry(entry_t * entry) { entries.remove(entry); @@ -77,7 +52,7 @@ bool ledger_t::remove_entry(entry_t * entry) return true; } -entry_t * ledger_t::derive_entry(int argc, char **argv) const +entry_t * journal_t::derive_entry(int argc, char **argv) const { entry_t * added = new entry_t; entry_t * matching = NULL; @@ -204,7 +179,7 @@ entry_t * ledger_t::derive_entry(int argc, char **argv) const return added; } -int parse_ledger_file(char * p, ledger_t * journal) +int parse_journal_file(char * p, journal_t * journal) { char * sep = std::strrchr(p, '='); if (sep) *sep++ = '\0'; @@ -225,9 +200,9 @@ int parse_ledger_file(char * p, ledger_t * journal) stream.seekg(start); if (magic == binary_magic_number) - return read_binary_ledger(stream, "", journal, master); + return read_binary_journal(stream, "", journal, master); else - return parse_textual_ledger(stream, journal, master); + return parse_textual_journal(stream, journal, master); } } // namespace ledger @@ -133,14 +133,14 @@ class account_t return fullname(); } - // These functions should only be called from ledger_t::add_entry - // and ledger_t::remove_entry; or from the various parsers. + // These functions should only be called from journal_t::add_entry + // and journal_t::remove_entry; or from the various parsers. void add_transaction(transaction_t * xact) { transactions.push_back(xact); } bool remove_transaction(transaction_t * xact); - friend class ledger_t; + friend class journal_t; }; inline std::ostream& operator<<(std::ostream& out, const account_t& acct) { @@ -151,7 +151,7 @@ inline std::ostream& operator<<(std::ostream& out, const account_t& acct) { typedef std::list<entry_t *> entries_list; -class ledger_t +class journal_t { public: account_t * master; @@ -159,13 +159,13 @@ class ledger_t mutable accounts_map accounts_cache; std::list<std::string> sources; - ledger_t() { + journal_t() { master = new account_t(NULL, ""); master->ident = 0; account_t::next_ident = 1; } - ~ledger_t(); + ~journal_t(); void add_account(account_t * acct) { master->add_account(acct); @@ -186,7 +186,7 @@ class ledger_t account_t * find_account(const std::string& name) const { // With auto_create false, the other `find_account' will not // change the object. - return const_cast<ledger_t *>(this)->find_account(name, false); + return const_cast<journal_t *>(this)->find_account(name, false); } bool add_entry(entry_t * entry); @@ -195,7 +195,21 @@ class ledger_t entry_t * derive_entry(int argc, char **argv) const; }; -int parse_ledger_file(char * p, ledger_t * journal); +int parse_journal_file(char * p, journal_t * journal); + +unsigned int parse_textual_journal(std::istream& in, journal_t * ledger, + account_t * master = NULL); + +extern unsigned long binary_magic_number; + +unsigned int read_binary_journal(std::istream& in, + const std::string& leader, + journal_t * journal, + account_t * master = NULL); + +void write_binary_journal(std::ostream& out, + journal_t * journal, + const std::string& leader); extern const std::string version; @@ -1,7 +1,5 @@ #include "ledger.h" #include "error.h" -#include "textual.h" -#include "binary.h" #include "valexpr.h" #include "format.h" #include "walk.h" @@ -350,11 +348,13 @@ static void show_help(std::ostream& out) int main(int argc, char * argv[]) { - std::auto_ptr<ledger::ledger_t> journal(new ledger::ledger_t); - std::list<std::string> files; - std::auto_ptr<ledger::node_t> predicate; - std::auto_ptr<ledger::node_t> display_predicate; - std::auto_ptr<ledger::node_t> sort_order; + using namespace ledger; + + std::auto_ptr<journal_t> journal(new journal_t); + std::list<std::string> files; + std::auto_ptr<node_t> predicate; + std::auto_ptr<node_t> display_predicate; + std::auto_ptr<node_t> sort_order; std::string predicate_string; std::string display_predicate_string; @@ -376,10 +376,10 @@ int main(int argc, char * argv[]) // Initialize some variables based on environment variable settings if (char * p = std::getenv("PRICE_HIST")) - ledger::price_db = p; + price_db = p; if (char * p = std::getenv("PRICE_EXP")) - ledger::pricing_leeway = std::atol(p) * 60; + pricing_leeway = std::atol(p) * 60; // A ledger data file must be specified @@ -392,18 +392,18 @@ int main(int argc, char * argv[]) break; } - ledger::cache_dirty = true; + cache_dirty = true; if (use_cache) if (const char * p = std::getenv("LEDGER_CACHE")) if (access(p, R_OK) != -1) { std::ifstream instr(p); - if (! ledger::read_binary_ledger(instr, std::getenv("LEDGER"), - journal.get())) { + if (! read_binary_journal(instr, std::getenv("LEDGER"), + journal.get())) { // Throw away what's been read, and create a new journal - journal.reset(new ledger::ledger_t); + journal.reset(new journal_t); } else { - ledger::cache_dirty = false; + cache_dirty = false; } } } @@ -428,7 +428,7 @@ int main(int argc, char * argv[]) case 'v': std::cout - << "Ledger " << ledger::version + << "Ledger " << version << ", the command-line accounting tool" << std::endl << " Copyright (c) 2003-2004, New Artisans LLC. All rights reserved." << std::endl << std::endl @@ -445,7 +445,7 @@ int main(int argc, char * argv[]) break; case 'p': - ledger::set_price_conversion(optarg); + set_price_conversion(optarg); break; case 'b': @@ -536,15 +536,15 @@ int main(int argc, char * argv[]) // Commodity reporting case 'P': - ledger::price_db = optarg; + price_db = optarg; break; case 'L': - ledger::pricing_leeway = std::atol(optarg) * 60; + pricing_leeway = std::atol(optarg) * 60; break; case 'Q': - ledger::commodity_t::updater = ledger::download_price_quote; + commodity_t::updater = download_price_quote; break; case 't': @@ -566,15 +566,15 @@ int main(int argc, char * argv[]) break; case 'V': - ledger::show_commodities_revalued = true; + show_commodities_revalued = true; value_expr = "v"; total_expr = "V"; break; case 'G': - ledger::show_commodities_revalued = - ledger::show_commodities_revalued_only = true; + show_commodities_revalued = + show_commodities_revalued_only = true; value_expr = "c"; total_expr = "G"; @@ -622,36 +622,36 @@ int main(int argc, char * argv[]) // Read the ledger file, unless we already read it from the cache - if (! use_cache || ledger::cache_dirty) { + if (! use_cache || cache_dirty) { int entry_count = 0; try { if (files.empty()) { if (char * p = std::getenv("LEDGER")) for (p = std::strtok(p, ":"); p; p = std::strtok(NULL, ":")) - entry_count += parse_ledger_file(p, journal.get()); + entry_count += parse_journal_file(p, journal.get()); } else { for (std::list<std::string>::iterator i = files.begin(); i != files.end(); i++) { char buf[4096]; char * p = buf; std::strcpy(p, (*i).c_str()); - entry_count += parse_ledger_file(p, journal.get()); + entry_count += parse_journal_file(p, journal.get()); } } // Read prices from their own ledger file, after all others have // been read. - if (! ledger::price_db.empty()) { - const char * path = ledger::price_db.c_str(); + if (! price_db.empty()) { + const char * path = price_db.c_str(); std::ifstream db(path); journal->sources.push_back(path); - entry_count += ledger::parse_textual_ledger(db, journal.get(), + entry_count += parse_textual_journal(db, journal.get(), journal->master); } } - catch (ledger::error& err) { + catch (error& err) { std::cerr << "Fatal: " << err.what() << std::endl; return 1; } @@ -685,7 +685,7 @@ int main(int argc, char * argv[]) // Process the remaining command-line arguments - std::auto_ptr<ledger::entry_t> new_entry; + std::auto_ptr<entry_t> new_entry; if (command == "entry") { new_entry.reset(journal->derive_entry(argc - index, &argv[index])); } else { @@ -770,7 +770,7 @@ int main(int argc, char * argv[]) if (debug) std::cerr << "predicate = " << predicate_string << std::endl; #endif - predicate.reset(ledger::parse_expr(predicate_string)); + predicate.reset(parse_expr(predicate_string)); } if (display_predicate_string.empty() && command == "b" && ! show_empty) @@ -782,18 +782,18 @@ int main(int argc, char * argv[]) std::cerr << "display predicate = " << display_predicate_string << std::endl; #endif - display_predicate.reset(ledger::parse_expr(display_predicate_string)); + display_predicate.reset(parse_expr(display_predicate_string)); } // Compile the sorting string if (! sort_string.empty()) - sort_order.reset(ledger::parse_expr(sort_string)); + sort_order.reset(parse_expr(sort_string)); // Setup the meaning of %t and %T encountered in format strings - ledger::format_t::value_expr.reset(ledger::parse_expr(value_expr)); - ledger::format_t::total_expr.reset(ledger::parse_expr(total_expr)); + format_t::value_expr.reset(parse_expr(value_expr)); + format_t::total_expr.reset(parse_expr(total_expr)); // Now handle the command that was identified above. @@ -812,26 +812,24 @@ int main(int argc, char * argv[]) if (! format_string.empty()) f = format_string.c_str(); else if (command == "b") - f = ledger::bal_fmt.c_str(); + f = bal_fmt.c_str(); else if (command == "r") - f = ledger::reg_fmt.c_str(); + f = reg_fmt.c_str(); else - f = ledger::print_fmt.c_str(); + f = print_fmt.c_str(); if (command == "b") { - std::auto_ptr<ledger::format_t> format(new ledger::format_t(f)); - - ledger::walk_accounts(journal->master, - ledger::format_account(std::cout, *format.get()), - predicate.get(), show_related, show_inverted, - show_subtotals, display_predicate.get()); + format_t format(f); + walk_accounts(journal->master, format_account(std::cout, format), + predicate.get(), show_related, show_inverted, + show_subtotals, display_predicate.get()); if (! display_predicate.get() || - ledger::item_predicate(display_predicate.get())(journal->master)) { + item_predicate(display_predicate.get())(journal->master)) { std::string end_format = "--------------------\n"; end_format += f; - format.get()->elements.reset(ledger::format_t::parse_elements(end_format)); - ledger::format_account(std::cout, *format.get())(journal->master, true); + format.elements = format_t::parse_elements(end_format); + format_account(std::cout, format)(journal->master, true); } } else { std::string first_line_format; @@ -844,27 +842,34 @@ int main(int argc, char * argv[]) first_line_format = next_lines_format = f; } - std::auto_ptr<ledger::format_t> - format(new ledger::format_t(first_line_format)); - std::auto_ptr<ledger::format_t> - nformat(new ledger::format_t(next_lines_format)); - - ledger::walk_entries(journal->entries.begin(), journal->entries.end(), - ledger::format_transaction(std::cout, - first_line_format, - next_lines_format), - predicate.get(), show_related, show_inverted, - display_predicate.get()); + format_t format(first_line_format); + format_t nformat(next_lines_format); + format_transaction formatter(std::cout, format, nformat); + + if (! sort_order.get()) { + walk_entries(journal->entries.begin(), journal->entries.end(), + formatter, predicate.get(), show_related, show_inverted, + display_predicate.get()); + } else { + transactions_deque transactions_pool; + walk_entries(journal->entries.begin(), journal->entries.end(), + collect_transactions(transactions_pool), predicate.get(), + show_related, show_inverted, display_predicate.get()); + std::stable_sort(transactions_pool.begin(), transactions_pool.end(), + compare_transactions(sort_order.get())); + walk_transactions(transactions_pool.begin(), transactions_pool.end(), + formatter, NULL, show_related, show_inverted, + display_predicate.get()); + } } // Save the cache, if need be - if (use_cache && ledger::cache_dirty) + if (use_cache && cache_dirty) if (const char * p = std::getenv("LEDGER_CACHE")) { std::ofstream outstr(p); assert(std::getenv("LEDGER")); - ledger::write_binary_ledger(outstr, journal.get(), - std::getenv("LEDGER")); + write_binary_journal(outstr, journal.get(), std::getenv("LEDGER")); } return 0; @@ -1,4 +1,3 @@ -#include "textual.h" #include "datetime.h" #include "autoxact.h" #include "valexpr.h" @@ -287,8 +286,8 @@ entry_t * parse_entry(std::istream& in, account_t * master) return curr; } -unsigned int parse_textual_ledger(std::istream& in, ledger_t * journal, - account_t * master) +unsigned int parse_textual_journal(std::istream& in, journal_t * journal, + account_t * master) { static char line[MAX_LINE + 1]; char c; @@ -518,8 +517,8 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * journal, unsigned int curr_linenum = linenum; std::string curr_path = path; - count += parse_textual_ledger(stream, journal, - account_stack.front()); + count += parse_textual_journal(stream, journal, + account_stack.front()); linenum = curr_linenum; path = curr_path; diff --git a/textual.h b/textual.h deleted file mode 100644 index 8ae24b83..00000000 --- a/textual.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _TEXTUAL_H -#define _TEXTUAL_H - -#include "ledger.h" - -namespace ledger { - -extern unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger, - account_t * master = NULL); - -} // namespace ledger - -#endif // _TEXTUAL_H @@ -1,7 +1,6 @@ #include "valexpr.h" #include "error.h" #include "datetime.h" -#include "textual.h" #include <pcre.h> @@ -7,6 +7,7 @@ #include "valexpr.h" #include <iostream> +#include <deque> namespace ledger { @@ -84,7 +85,45 @@ class format_transaction void operator()(transaction_t * xact, balance_pair_t * balance, unsigned int * index, - const bool inverted) const; + const bool inverted) const; +}; + +struct compare_transactions { + const node_t * sort_order; + + compare_transactions(const node_t * _sort_order) + : sort_order(_sort_order) { + assert(sort_order); + } + + bool operator()(const transaction_t * left, + const transaction_t * right) const { + assert(left); + assert(right); + balance_t left_result; + sort_order->compute(left_result, details_t(left)); + balance_t right_result; + sort_order->compute(right_result, details_t(right)); + return left_result < right_result; + } +}; + +typedef std::deque<transaction_t *> transactions_deque; + +class collect_transactions +{ + transactions_deque& transactions; + + public: + collect_transactions(transactions_deque& _transactions) + : transactions(_transactions) {} + + void operator()(transaction_t * xact, + balance_pair_t * balance, + unsigned int * index, + const bool inverted) { + transactions.push_back(xact); + } }; class ignore_transaction @@ -153,6 +192,38 @@ void walk_entries(entries_list::iterator begin, related, inverted, &balance, &index); } +template <typename Function> +void walk_transactions(transactions_list::iterator begin, + transactions_list::iterator end, + Function functor, + const node_t * predicate, + const bool related, + const bool inverted, + const node_t * display_predicate = NULL) +{ + balance_pair_t balance; + unsigned int index; + + for (transactions_list::iterator i = begin; i != end; i++) + functor(*i, &balance, &index, inverted); +} + +template <typename Function> +void walk_transactions(transactions_deque::iterator begin, + transactions_deque::iterator end, + Function functor, + const node_t * predicate, + const bool related, + const bool inverted, + const node_t * display_predicate = NULL) +{ + balance_pair_t balance; + unsigned int index; + + for (transactions_deque::iterator i = begin; i != end; i++) + functor(*i, &balance, &index, inverted); +} + class format_account { std::ostream& output_stream; |