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