A great deal of reorganization to restore the old parsing code (since the

newer XML stuff was pulled).
This commit is contained in:
John Wiegley 2008-07-22 02:23:45 -04:00
parent e41dbc204a
commit 4bc29e1351
24 changed files with 165 additions and 570 deletions

View file

@ -39,7 +39,6 @@ endif
libledger_la_CPPFLAGS = $(libamounts_la_CPPFLAGS) libledger_la_CPPFLAGS = $(libamounts_la_CPPFLAGS)
libledger_la_SOURCES = \ libledger_la_SOURCES = \
binary.cc \ binary.cc \
config.cc \
csv.cc \ csv.cc \
derive.cc \ derive.cc \
emacs.cc \ emacs.cc \
@ -47,13 +46,11 @@ libledger_la_SOURCES = \
journal.cc \ journal.cc \
mask.cc \ mask.cc \
option.cc \ option.cc \
parser.cc \
parsexp.cc \ parsexp.cc \
qif.cc \ qif.cc \
reconcile.cc \ reconcile.cc \
report.cc \ report.cc \
session.cc \ session.cc \
startup.cc \
textual.cc \ textual.cc \
valexpr.cc \ valexpr.cc \
walk.cc \ walk.cc \
@ -83,7 +80,6 @@ pkginclude_HEADERS = \
utils.h \ utils.h \
\ \
binary.h \ binary.h \
config.h \
csv.h \ csv.h \
derive.h \ derive.h \
emacs.h \ emacs.h \
@ -223,7 +219,6 @@ clean-backupfiles:
.\#* .\#*
clean-documentation: clean-documentation:
(cd doc; \
rm -fr *.aux \ rm -fr *.aux \
*.cp \ *.cp \
*.fn \ *.fn \
@ -234,7 +229,7 @@ clean-documentation:
*.pg \ *.pg \
*.toc \ *.toc \
*.tp \ *.tp \
*.vr) *.vr
clean-buildproducts: clean-buildproducts:
rm -fr *.Plo \ rm -fr *.Plo \
@ -284,7 +279,7 @@ clean-autoconf:
texinfo.tex \ texinfo.tex \
ylwrap ylwrap
all-clean: maintainer-clean \ scour: maintainer-clean \
clean-buildproducts \ clean-buildproducts \
clean-backupfiles \ clean-backupfiles \
clean-debugdata \ clean-debugdata \

View file

@ -72,13 +72,13 @@ bool binary_parser_t::test(std::istream& in) const
namespace binary { namespace binary {
unsigned int read_journal(std::istream& in, unsigned int read_journal(std::istream& in,
const path& file, const path& file,
journal_t * journal, journal_t& journal,
account_t * master); account_t * master);
} }
unsigned int binary_parser_t::parse(std::istream& in, unsigned int binary_parser_t::parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master, account_t * master,
const path * original_file) const path * original_file)
{ {
@ -558,13 +558,13 @@ inline commodity_t * read_commodity_annotated(const char *& data)
} }
inline inline
account_t * read_account(const char *& data, journal_t * journal, account_t * read_account(const char *& data, journal_t& journal,
account_t * master = NULL) account_t * master = NULL)
{ {
account_t * acct = new account_t(NULL); account_t * acct = new account_t(NULL);
*accounts_next++ = acct; *accounts_next++ = acct;
acct->journal = journal; acct->journal = &journal;
account_t::ident_t id; account_t::ident_t id;
read_long(data, id); // parent id read_long(data, id); // parent id
@ -601,7 +601,7 @@ account_t * read_account(const char *& data, journal_t * journal,
unsigned int read_journal(std::istream& in, unsigned int read_journal(std::istream& in,
const path& file, const path& file,
journal_t * journal, journal_t& journal,
account_t * master) account_t * master)
{ {
account_index = account_index =
@ -625,7 +625,7 @@ unsigned int read_journal(std::istream& in,
if (std::difftime(info.st_mtime, old_mtime) > 0) if (std::difftime(info.st_mtime, old_mtime) > 0)
return 0; return 0;
journal->sources.push_back(pathname); journal.sources.push_back(pathname);
} }
// Make sure that the cache uses the same price database, // Make sure that the cache uses the same price database,
@ -634,8 +634,8 @@ unsigned int read_journal(std::istream& in,
if (read_bool(in)) { if (read_bool(in)) {
string pathname; string pathname;
read_string(in, pathname); read_string(in, pathname);
if (! journal->price_db || if (! journal.price_db ||
journal->price_db->string() != std::string(pathname)) journal.price_db->string() != std::string(pathname))
return 0; return 0;
} }
} }
@ -655,12 +655,12 @@ unsigned int read_journal(std::istream& in,
account_t::ident_t a_count = read_long<account_t::ident_t>(data); account_t::ident_t a_count = read_long<account_t::ident_t>(data);
accounts = accounts_next = new account_t *[a_count]; accounts = accounts_next = new account_t *[a_count];
assert(journal->master); assert(journal.master);
delete journal->master; delete journal.master;
journal->master = read_account(data, journal, master); journal.master = read_account(data, journal, master);
if (read_bool(data)) if (read_bool(data))
journal->basket = accounts[read_long<account_t::ident_t>(data) - 1]; journal.basket = accounts[read_long<account_t::ident_t>(data) - 1];
// Allocate the memory needed for the entries and transactions in // Allocate the memory needed for the entries and transactions in
// one large block, which is then chopped up and custom constructed // one large block, which is then chopped up and custom constructed
@ -678,8 +678,8 @@ unsigned int read_journal(std::istream& in,
char * item_pool = new char[pool_size]; char * item_pool = new char[pool_size];
journal->item_pool = item_pool; journal.item_pool = item_pool;
journal->item_pool_end = item_pool + pool_size; journal.item_pool_end = item_pool + pool_size;
entry_t * entry_pool = (entry_t *) item_pool; entry_t * entry_pool = (entry_t *) item_pool;
transaction_t * xact_pool = (transaction_t *) (item_pool + transaction_t * xact_pool = (transaction_t *) (item_pool +
@ -777,27 +777,27 @@ unsigned int read_journal(std::istream& in,
new(entry_pool) entry_t; new(entry_pool) entry_t;
bool finalize = false; bool finalize = false;
read_entry(data, entry_pool, xact_pool, finalize); read_entry(data, entry_pool, xact_pool, finalize);
entry_pool->journal = journal; entry_pool->journal = &journal;
if (finalize && ! entry_pool->finalize()) if (finalize && ! entry_pool->finalize())
continue; continue;
journal->entries.push_back(entry_pool++); journal.entries.push_back(entry_pool++);
} }
for (unsigned long i = 0; i < auto_count; i++) { for (unsigned long i = 0; i < auto_count; i++) {
auto_entry_t * auto_entry = new auto_entry_t; auto_entry_t * auto_entry = new auto_entry_t;
read_auto_entry(data, auto_entry, xact_pool); read_auto_entry(data, auto_entry, xact_pool);
auto_entry->journal = journal; auto_entry->journal = &journal;
journal->auto_entries.push_back(auto_entry); journal.auto_entries.push_back(auto_entry);
} }
for (unsigned long i = 0; i < period_count; i++) { for (unsigned long i = 0; i < period_count; i++) {
period_entry_t * period_entry = new period_entry_t; period_entry_t * period_entry = new period_entry_t;
bool finalize = false; bool finalize = false;
read_period_entry(data, period_entry, xact_pool, finalize); read_period_entry(data, period_entry, xact_pool, finalize);
period_entry->journal = journal; period_entry->journal = &journal;
if (finalize && ! period_entry->finalize()) if (finalize && ! period_entry->finalize())
continue; continue;
journal->period_entries.push_back(period_entry); journal.period_entries.push_back(period_entry);
} }
// Clean up and return the number of entries read // Clean up and return the number of entries read
@ -806,7 +806,7 @@ unsigned int read_journal(std::istream& in,
delete[] commodities; delete[] commodities;
delete[] data_pool; delete[] data_pool;
VERIFY(journal->valid()); VERIFY(journal.valid());
return count; return count;
} }
@ -1104,7 +1104,7 @@ void write_account(std::ostream& out, account_t * account)
write_account(out, (*i).second); write_account(out, (*i).second);
} }
void write_journal(std::ostream& out, journal_t * journal) void write_journal(std::ostream& out, journal_t& journal)
{ {
account_index = account_index =
base_commodity_index = base_commodity_index =
@ -1116,12 +1116,12 @@ void write_journal(std::ostream& out, journal_t * journal)
// Write out the files that participated in this journal, so that // Write out the files that participated in this journal, so that
// they can be checked for changes on reading. // they can be checked for changes on reading.
if (journal->sources.empty()) { if (journal.sources.empty()) {
write_number<unsigned short>(out, 0); write_number<unsigned short>(out, 0);
} else { } else {
write_number<unsigned short>(out, journal->sources.size()); write_number<unsigned short>(out, journal.sources.size());
for (paths_list::const_iterator i = journal->sources.begin(); for (paths_list::const_iterator i = journal.sources.begin();
i != journal->sources.end(); i != journal.sources.end();
i++) { i++) {
write_string(out, (*i).string()); write_string(out, (*i).string());
struct stat info; struct stat info;
@ -1131,9 +1131,9 @@ void write_journal(std::ostream& out, journal_t * journal)
// Write out the price database that relates to this data file, so // Write out the price database that relates to this data file, so
// that if it ever changes the cache can be invalidated. // that if it ever changes the cache can be invalidated.
if (journal->price_db) { if (journal.price_db) {
write_bool(out, true); write_bool(out, true);
write_string(out, journal->price_db->string()); write_string(out, journal.price_db->string());
} else { } else {
write_bool(out, false); write_bool(out, false);
} }
@ -1144,21 +1144,21 @@ void write_journal(std::ostream& out, journal_t * journal)
// Write out the accounts // Write out the accounts
write_long<account_t::ident_t>(out, count_accounts(journal->master)); write_long<account_t::ident_t>(out, count_accounts(journal.master));
write_account(out, journal->master); write_account(out, journal.master);
if (journal->basket) { if (journal.basket) {
write_bool(out, true); write_bool(out, true);
write_long(out, journal->basket->ident); write_long(out, journal.basket->ident);
} else { } else {
write_bool(out, false); write_bool(out, false);
} }
// Write out the number of entries, transactions, and amounts // Write out the number of entries, transactions, and amounts
write_long<unsigned long>(out, journal->entries.size()); write_long<unsigned long>(out, journal.entries.size());
write_long<unsigned long>(out, journal->auto_entries.size()); write_long<unsigned long>(out, journal.auto_entries.size());
write_long<unsigned long>(out, journal->period_entries.size()); write_long<unsigned long>(out, journal.period_entries.size());
ostream_pos_type xacts_val = out.tellp(); ostream_pos_type xacts_val = out.tellp();
write_number<unsigned long>(out, 0); write_number<unsigned long>(out, 0);
@ -1222,22 +1222,22 @@ void write_journal(std::ostream& out, journal_t * journal)
unsigned long xact_count = 0; unsigned long xact_count = 0;
for (entries_list::const_iterator i = journal->entries.begin(); for (entries_list::const_iterator i = journal.entries.begin();
i != journal->entries.end(); i != journal.entries.end();
i++) { i++) {
write_entry(out, *i); write_entry(out, *i);
xact_count += (*i)->transactions.size(); xact_count += (*i)->transactions.size();
} }
for (auto_entries_list::const_iterator i = journal->auto_entries.begin(); for (auto_entries_list::const_iterator i = journal.auto_entries.begin();
i != journal->auto_entries.end(); i != journal.auto_entries.end();
i++) { i++) {
write_auto_entry(out, *i); write_auto_entry(out, *i);
xact_count += (*i)->transactions.size(); xact_count += (*i)->transactions.size();
} }
for (period_entries_list::const_iterator i = journal->period_entries.begin(); for (period_entries_list::const_iterator i = journal.period_entries.begin();
i != journal->period_entries.end(); i != journal.period_entries.end();
i++) { i++) {
write_period_entry(out, *i); write_period_entry(out, *i);
xact_count += (*i)->transactions.size(); xact_count += (*i)->transactions.size();

View file

@ -272,7 +272,7 @@ inline void write_object(std::ostream& out, const T& journal) {
assert(false); assert(false);
} }
void write_journal(std::ostream& out, journal_t * journal); void write_journal(std::ostream& out, journal_t& journal);
} // namespace binary } // namespace binary
@ -282,8 +282,8 @@ class binary_parser_t : public parser_t
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
}; };

View file

@ -1,91 +0,0 @@
#include "config.h"
#include "acconf.h"
#include "option.h"
//#include "quotes.h"
#include "valexpr.h"
#include "walk.h"
namespace ledger {
string expand_path(const string& pathname)
{
if (pathname.length() == 0 || pathname[0] != '~')
return pathname;
const char * pfx = NULL;
string::size_type pos = pathname.find_first_of('/');
if (pathname.length() == 1 || pos == 1) {
pfx = std::getenv("HOME");
#ifdef HAVE_GETPWUID
if (! pfx) {
// Punt. We're trying to expand ~/, but HOME isn't set
struct passwd * pw = getpwuid(getuid());
if (pw)
pfx = pw->pw_dir;
}
#endif
}
#ifdef HAVE_GETPWNAM
else {
string user(pathname, 1, pos == string::npos ?
string::npos : pos - 1);
struct passwd * pw = getpwnam(user.c_str());
if (pw)
pfx = pw->pw_dir;
}
#endif
// if we failed to find an expansion, return the pathname unchanged.
if (! pfx)
return pathname;
string result(pfx);
if (pos == string::npos)
return result;
if (result.length() == 0 || result[result.length() - 1] != '/')
result += '/';
result += pathname.substr(pos + 1);
return result;
}
// jww (2008-04-22): This needs to be changed to use boost::filesystem
string resolve_path(const string& pathname)
{
if (pathname[0] == '~')
return expand_path(pathname);
return pathname;
}
config_t::config_t()
{
balance_format = "%20T %2_%-a\n";
register_format = ("%D %-.20P %-.22A %12.67t %!12.80T\n%/"
"%32|%-.22A %12.67t %!12.80T\n");
wide_register_format = ("%D %-.35P %-.38A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\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";
equity_format = "\n%D %Y%C%P\n%/ %-34W %12t\n";
prices_format = "%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n";
pricesdb_format = "P %[%Y/%m/%d %H:%M:%S] %A %t\n";
pricing_leeway = 24 * 3600;
download_quotes = false;
use_cache = false;
cache_dirty = false;
debug_mode = false;
verbose_mode = false;
trace_mode = false;
}
} // namespace ledger

View file

@ -1,47 +0,0 @@
#ifndef _CONFIG_H
#define _CONFIG_H
#include "ledger.h"
namespace ledger {
class config_t
{
public:
path init_file;
path data_file;
path cache_file;
path price_db;
string balance_format;
string register_format;
string wide_register_format;
string plot_amount_format;
string plot_total_format;
string print_format;
string write_hdr_format;
string write_xact_format;
string equity_format;
string prices_format;
string pricesdb_format;
string date_input_format;
string account;
string pager;
unsigned long pricing_leeway;
bool download_quotes;
bool use_cache;
bool cache_dirty;
bool debug_mode;
bool verbose_mode;
bool trace_mode;
config_t();
};
} // namespace ledger
#endif // _CONFIG_H

View file

@ -344,8 +344,8 @@ bool gnucash_parser_t::test(std::istream& in) const
} }
unsigned int gnucash_parser_t::parse(std::istream& in, unsigned int gnucash_parser_t::parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master, account_t * master,
const path * original_file) const path * original_file)
{ {
@ -360,8 +360,8 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
count = 0; count = 0;
action = NO_ACTION; action = NO_ACTION;
curr_journal = journal; curr_journal = &journal;
master_account = master ? master : journal->master; master_account = master ? master : journal.master;
curr_account = NULL; curr_account = NULL;
curr_entry = NULL; curr_entry = NULL;
curr_comm = NULL; curr_comm = NULL;
@ -370,7 +370,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
instreamp = &in; instreamp = &in;
pathname = original_file ? *original_file : "<gnucash>"; pathname = original_file ? *original_file : "<gnucash>";
src_idx = journal->sources.size() - 1; src_idx = journal.sources.size() - 1;
// GnuCash uses the USD commodity without defining it, which really // GnuCash uses the USD commodity without defining it, which really
// means $. // means $.

View file

@ -11,8 +11,8 @@ class gnucash_parser_t : public parser_t
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
}; };

View file

@ -399,9 +399,12 @@ typedef std::list<period_entry_t *> period_entries_list;
typedef std::list<path> paths_list; typedef std::list<path> paths_list;
typedef std::list<string> strings_list; typedef std::list<string> strings_list;
class session_t;
class journal_t class journal_t
{ {
public: public:
session_t * owner;
account_t * master; account_t * master;
account_t * basket; account_t * basket;
entries_list entries; entries_list entries;
@ -416,7 +419,8 @@ class journal_t
std::list<entry_finalizer_t *> entry_finalize_hooks; std::list<entry_finalizer_t *> entry_finalize_hooks;
journal_t() : basket(NULL), item_pool(NULL), item_pool_end(NULL) { journal_t(session_t * _owner) :
owner(_owner), basket(NULL), item_pool(NULL), item_pool_end(NULL) {
TRACE_CTOR(journal_t, ""); TRACE_CTOR(journal_t, "");
master = new account_t(NULL, ""); master = new account_t(NULL, "");
master->journal = this; master->journal = this;

View file

@ -76,7 +76,7 @@ namespace ledger {
extern parser_t * textual_parser_ptr; extern parser_t * textual_parser_ptr;
} }
#include <config.h> #include <session.h>
#include <report.h> #include <report.h>
#endif // _LEDGER_H #endif // _LEDGER_H

View file

@ -199,19 +199,15 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
// Parse the initialization file, which can only be textual; then // Parse the initialization file, which can only be textual; then
// parse the journal data. // parse the journal data.
#if 0
session.read_init(); session.read_init();
#endif
INFO_START(journal, "Read journal file"); INFO_START(journal, "Read journal file");
journal_t * journal = session.create_journal(); journal_t& journal(*session.create_journal());
#if 0 if (! session.read_data(journal, report.account))
if (! session.read_data(builder, journal, report.account))
throw_(parse_error, "Failed to locate any journal entries; " throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?"); "did you specify a valid file with -f?");
#endif
INFO_FINISH(journal); INFO_FINISH(journal);

4
ofx.cc
View file

@ -195,8 +195,8 @@ bool ofx_parser_t::test(std::istream& in) const
} }
unsigned int ofx_parser_t::parse(std::istream& in, unsigned int ofx_parser_t::parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master, account_t * master,
const path * original_file) const path * original_file)
{ {

4
ofx.h
View file

@ -11,8 +11,8 @@ class ofx_parser_t : public parser_t
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
}; };

185
parser.cc
View file

@ -1,185 +0,0 @@
#include "parser.h"
#include "journal.h"
#include "config.h"
namespace ledger {
typedef std::list<parser_t *> parsers_list;
static parsers_list * parsers = NULL;
void initialize_parser_support()
{
parsers = new parsers_list;
}
void shutdown_parser_support()
{
if (parsers) {
delete parsers;
parsers = NULL;
}
}
bool register_parser(parser_t * parser)
{
parsers_list::iterator i;
for (i = parsers->begin(); i != parsers->end(); i++)
if (*i == parser)
break;
if (i != parsers->end())
return false;
parsers->push_back(parser);
return true;
}
bool unregister_parser(parser_t * parser)
{
parsers_list::iterator i;
for (i = parsers->begin(); i != parsers->end(); i++)
if (*i == parser)
break;
if (i == parsers->end())
return false;
parsers->erase(i);
return true;
}
unsigned int parse_journal(std::istream& in,
config_t& config,
journal_t * journal,
account_t * master,
const path * original_file)
{
if (! master)
master = journal->master;
for (parsers_list::iterator i = parsers->begin();
i != parsers->end();
i++)
if ((*i)->test(in))
return (*i)->parse(in, config, journal, master, original_file);
return 0;
}
unsigned int parse_journal_file(const path& pathname,
config_t& config,
journal_t * journal,
account_t * master,
const path * original_file)
{
journal->sources.push_back(pathname);
if (! boost::filesystem::exists(pathname))
throw new error(string("Cannot read file '") +
string(pathname.string()) + "'");
if (! original_file)
original_file = &pathname;
boost::filesystem::ifstream stream(pathname);
return parse_journal(stream, config, journal, master, original_file);
}
extern parser_t * binary_parser_ptr;
extern parser_t * xml_parser_ptr;
extern parser_t * textual_parser_ptr;
unsigned int parse_ledger_data(config_t& config,
journal_t * journal,
parser_t * cache_parser,
parser_t * xml_parser,
parser_t * stdin_parser)
{
unsigned int entry_count = 0;
if (! cache_parser)
cache_parser = binary_parser_ptr;
if (! xml_parser)
xml_parser = xml_parser_ptr;
if (! stdin_parser)
stdin_parser = textual_parser_ptr;
DEBUG("ledger.config.cache",
"3. use_cache = " << config.use_cache);
if (! config.init_file.empty() &&
boost::filesystem::exists(config.init_file)) {
if (parse_journal_file(config.init_file.string(), config, journal) ||
journal->auto_entries.size() > 0 ||
journal->period_entries.size() > 0)
throw new error(string("Entries found in initialization file '") +
string(config.init_file.string()) + "'");
journal->sources.pop_front(); // remove init file
}
if (config.use_cache && ! config.cache_file.empty() &&
! config.data_file.empty()) {
DEBUG("ledger.config.cache",
"using_cache " << config.cache_file);
config.cache_dirty = true;
if (boost::filesystem::exists(config.cache_file)) {
boost::filesystem::ifstream stream(config.cache_file);
if (cache_parser && cache_parser->test(stream)) {
optional<path> price_db_orig = journal->price_db;
journal->price_db = config.price_db;
entry_count += cache_parser->parse(stream, config, journal,
NULL, &config.data_file);
if (entry_count > 0)
config.cache_dirty = false;
else
journal->price_db = price_db_orig;
}
}
}
if (entry_count == 0 && ! config.data_file.empty()) {
account_t * acct = NULL;
if (! config.account.empty())
acct = journal->find_account(config.account);
journal->price_db = config.price_db;
if (journal->price_db &&
boost::filesystem::exists(*journal->price_db)) {
if (parse_journal_file(*journal->price_db, config, journal)) {
throw new error("Entries not allowed in price history file");
} else {
DEBUG("ledger.config.cache",
"read price database " << *journal->price_db);
journal->sources.pop_back();
}
}
DEBUG("ledger.config.cache",
"rejected cache, parsing " << config.data_file);
if (config.data_file == "-") {
config.use_cache = false;
journal->sources.push_back("<stdin>");
#if 0
// jww (2006-03-23): Why doesn't XML work on stdin?
if (xml_parser && std::cin.peek() == '<')
entry_count += xml_parser->parse(std::cin, config, journal, acct);
else if (stdin_parser)
#endif
entry_count += stdin_parser->parse(std::cin, config, journal, acct);
}
else if (boost::filesystem::exists(config.data_file)) {
entry_count += parse_journal_file(config.data_file, config, journal,
acct);
if (journal->price_db)
journal->sources.push_back(*journal->price_db);
}
}
VERIFY(journal->valid());
return entry_count;
}
} // namespace ledger

View file

@ -7,7 +7,7 @@ namespace ledger {
class account_t; class account_t;
class journal_t; class journal_t;
class config_t; class session_t;
class parser_t class parser_t
{ {
@ -17,36 +17,30 @@ class parser_t
virtual bool test(std::istream& in) const = 0; virtual bool test(std::istream& in) const = 0;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL) = 0; const path * original_file = NULL) = 0;
}; };
bool register_parser(parser_t * parser);
bool unregister_parser(parser_t * parser);
unsigned int parse_journal(std::istream& in, unsigned int parse_journal(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
unsigned int parse_journal_file(const path& path, unsigned int parse_journal_file(const path& path,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
unsigned int parse_ledger_data(config_t& config, unsigned int parse_ledger_data(session_t& session,
journal_t * journal, journal_t& journal,
parser_t * cache_parser = NULL, parser_t * cache_parser = NULL,
parser_t * xml_parser = NULL, parser_t * xml_parser = NULL,
parser_t * stdin_parser = NULL); parser_t * stdin_parser = NULL);
void initialize_parser_support();
void shutdown_parser_support();
class parse_error : public error { class parse_error : public error {
public: public:
parse_error(const string& reason, error_context * ctxt = NULL) throw() parse_error(const string& reason, error_context * ctxt = NULL) throw()

14
qif.cc
View file

@ -34,8 +34,8 @@ bool qif_parser_t::test(std::istream& in) const
} }
unsigned int qif_parser_t::parse(std::istream& in, unsigned int qif_parser_t::parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master, account_t * master,
const path * original_file) const path * original_file)
{ {
@ -54,8 +54,8 @@ unsigned int qif_parser_t::parse(std::istream& in,
xact = new transaction_t(master); xact = new transaction_t(master);
entry->add_transaction(xact); entry->add_transaction(xact);
pathname = journal->sources.back(); pathname = journal.sources.back();
src_idx = journal->sources.size() - 1; src_idx = journal.sources.size() - 1;
linenum = 1; linenum = 1;
istream_pos_type beg_pos = 0; istream_pos_type beg_pos = 0;
@ -166,7 +166,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
int len = std::strlen(line); int len = std::strlen(line);
if (line[len - 1] == ']') if (line[len - 1] == ']')
line[len - 1] = '\0'; line[len - 1] = '\0';
xact->account = journal->find_account(line[0] == '[' ? xact->account = journal.find_account(line[0] == '[' ?
line + 1 : line); line + 1 : line);
if (c == 'L') if (c == 'L')
saw_category = true; saw_category = true;
@ -191,7 +191,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
account_t * other; account_t * other;
if (xact->account == master) { if (xact->account == master) {
if (! misc) if (! misc)
misc = journal->find_account("Miscellaneous"); misc = journal.find_account("Miscellaneous");
other = misc; other = misc;
} else { } else {
other = master; other = master;
@ -211,7 +211,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
entry->add_transaction(nxact); entry->add_transaction(nxact);
} }
if (journal->add_entry(entry.get())) { if (journal.add_entry(entry.get())) {
entry->src_idx = src_idx; entry->src_idx = src_idx;
entry->beg_pos = beg_pos; entry->beg_pos = beg_pos;
entry->beg_line = beg_line; entry->beg_line = beg_line;

4
qif.h
View file

@ -11,8 +11,8 @@ class qif_parser_t : public parser_t
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
}; };

View file

@ -118,39 +118,35 @@ session_t::session_t()
ansi_codes(false), ansi_codes(false),
ansi_invert(false) ansi_invert(false)
{ {
TRACE_CTOR(session_t, "xml::xpath_t::scope_t&"); TRACE_CTOR(session_t, "expr::scope_t&");
} }
#if 0 std::size_t session_t::read_journal(journal_t& journal,
std::istream& in,
std::size_t session_t::read_journal(std::istream& in,
const path& pathname, const path& pathname,
xml::builder_t& builder) account_t * master)
{ {
#if 0
if (! master) if (! master)
master = journal->master; master = journal.master;
#endif
foreach (parser_t& parser, parsers) foreach (parser_t& parser, parsers)
if (parser.test(in)) if (parser.test(in))
return parser.parse(in, pathname, builder); return parser.parse(in, *this, journal, master, &pathname);
return 0; return 0;
} }
std::size_t session_t::read_journal(const path& pathname, std::size_t session_t::read_journal(journal_t& journal,
xml::builder_t& builder) const path& pathname,
account_t * master)
{ {
#if 0 journal.sources.push_back(pathname);
journal->sources.push_back(pathname);
#endif
if (! exists(pathname)) if (! exists(pathname))
throw_(std::logic_error, "Cannot read file" << pathname); throw_(std::logic_error, "Cannot read file" << pathname);
ifstream stream(pathname); ifstream stream(pathname);
return read_journal(stream, pathname, builder); return read_journal(journal, stream, pathname, master);
} }
void session_t::read_init() void session_t::read_init()
@ -166,8 +162,7 @@ void session_t::read_init()
// jww (2006-09-15): Read initialization options here! // jww (2006-09-15): Read initialization options here!
} }
std::size_t session_t::read_data(xml::builder_t& builder, std::size_t session_t::read_data(journal_t& journal,
journal_t * journal,
const string& master_account) const string& master_account)
{ {
if (data_file.empty()) if (data_file.empty())
@ -184,9 +179,9 @@ std::size_t session_t::read_data(xml::builder_t& builder,
cache_dirty = true; cache_dirty = true;
if (exists(*cache_file)) { if (exists(*cache_file)) {
push_variable<optional<path> > push_variable<optional<path> >
save_price_db(journal->price_db, price_db); save_price_db(journal.price_db, price_db);
entry_count += read_journal(*cache_file, builder); entry_count += read_journal(journal, *cache_file);
if (entry_count > 0) if (entry_count > 0)
cache_dirty = false; cache_dirty = false;
} }
@ -195,44 +190,41 @@ std::size_t session_t::read_data(xml::builder_t& builder,
if (entry_count == 0) { if (entry_count == 0) {
account_t * acct = NULL; account_t * acct = NULL;
if (! master_account.empty()) if (! master_account.empty())
acct = journal->find_account(master_account); acct = journal.find_account(master_account);
journal->price_db = price_db; journal.price_db = price_db;
if (journal->price_db && exists(*journal->price_db)) { if (journal.price_db && exists(*journal.price_db)) {
if (read_journal(*journal->price_db, builder)) { if (read_journal(journal, *journal.price_db)) {
throw_(parse_error, "Entries not allowed in price history file"); throw_(parse_error, "Entries not allowed in price history file");
} else { } else {
DEBUG("ledger.cache", DEBUG("ledger.cache",
"read price database " << journal->price_db->string()); "read price database " << journal.price_db->string());
journal->sources.pop_back(); journal.sources.pop_back();
} }
} }
DEBUG("ledger.cache", "rejected cache, parsing " << data_file.string()); DEBUG("ledger.cache", "rejected cache, parsing " << data_file.string());
if (data_file == "-") { if (data_file == "-") {
use_cache = false; use_cache = false;
journal->sources.push_back("<stdin>"); journal.sources.push_back("/dev/stdin");
entry_count += read_journal(std::cin, "<stdin>", builder); entry_count += read_journal(journal, std::cin, "/dev/stdin", acct);
} }
else if (exists(data_file)) { else if (exists(data_file)) {
entry_count += read_journal(data_file, builder); entry_count += read_journal(journal, data_file, acct);
if (journal->price_db) if (journal.price_db)
journal->sources.push_back(*journal->price_db); journal.sources.push_back(*journal.price_db);
} }
} }
VERIFY(journal->valid()); VERIFY(journal.valid());
TRACE_STOP(parser, 1); TRACE_STOP(parser, 1);
return entry_count; return entry_count;
} }
#endif
#if 0 #if 0
optional<value_t> value_t session_t::resolve(const string& name, expr::scope_t& locals)
session_t::resolve(const string& name, xml::xpath_t::scope_t& locals)
{ {
const char * p = name.c_str(); const char * p = name.c_str();
switch (*p) { switch (*p) {
@ -259,7 +251,7 @@ session_t::resolve(const string& name, xml::xpath_t::scope_t& locals)
return value_t(register_format, true); return value_t(register_format, true);
break; break;
} }
return xml::xpath_t::scope_t::resolve(name, locals); return expr::scope_t::resolve(name, locals);
} }
#endif #endif

View file

@ -85,7 +85,7 @@ class session_t : public expr::symbol_scope_t
} }
journal_t * create_journal() { journal_t * create_journal() {
journal_t * journal = new journal_t; journal_t * journal = new journal_t(this);
journals.push_back(journal); journals.push_back(journal);
return journal; return journal;
} }
@ -101,19 +101,18 @@ class session_t : public expr::symbol_scope_t
checked_delete(journal); checked_delete(journal);
} }
#if 0 std::size_t read_journal(journal_t& journal,
std::size_t read_journal(std::istream& in, std::istream& in,
const path& pathname, const path& pathname,
xml::builder_t& builder); account_t * master = NULL);
std::size_t read_journal(const path& pathname, std::size_t read_journal(journal_t& journal,
xml::builder_t& builder); const path& pathname,
account_t * master = NULL);
void read_init(); void read_init();
std::size_t read_data(xml::builder_t& builder, std::size_t read_data(journal_t& journal,
journal_t * journal,
const string& master_account = ""); const string& master_account = "");
#endif
void register_parser(parser_t * parser) { void register_parser(parser_t * parser) {
parsers.push_back(parser); parsers.push_back(parser);

View file

@ -1,63 +0,0 @@
#include "ledger.h"
#include "xml.h"
#include "gnucash.h"
#include "qif.h"
#include "ofx.h"
using namespace ledger;
namespace ledger {
parser_t * binary_parser_ptr = NULL;
parser_t * xml_parser_ptr = NULL;
parser_t * gnucash_parser_ptr = NULL;
parser_t * ofx_parser_ptr = NULL;
parser_t * qif_parser_ptr = NULL;
parser_t * textual_parser_ptr = NULL;
}
namespace {
binary_parser_t binary_parser;
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
xml_parser_t xml_parser;
gnucash_parser_t gnucash_parser;
#endif
#ifdef HAVE_LIBOFX
ofx_parser_t ofx_parser;
#endif
qif_parser_t qif_parser;
textual_parser_t textual_parser;
static class startup {
public:
startup();
~startup();
} _startup;
startup::startup()
{
std::ios::sync_with_stdio(false);
initialize_parser_support();
register_parser(&binary_parser); binary_parser_ptr = &binary_parser;
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
register_parser(&xml_parser); xml_parser_ptr = &xml_parser;
register_parser(&gnucash_parser); gnucash_parser_ptr = &gnucash_parser;
#endif
#ifdef HAVE_LIBOFX
register_parser(&ofx_parser); ofx_parser_ptr = &ofx_parser;
#endif
register_parser(&qif_parser); qif_parser_ptr = &qif_parser;
register_parser(&textual_parser); textual_parser_ptr = &textual_parser;
}
startup::~startup()
{
// jww (2008-04-22): What about this?
#if 0
if (! ledger::do_cleanup)
return;
#endif
shutdown_parser_support();
}
}

View file

@ -5,8 +5,7 @@
#include "journal.h" #include "journal.h"
#include "textual.h" #include "textual.h"
#include "valexpr.h" #include "valexpr.h"
#include "option.h" #include "parsexp.h"
#include "config.h"
#include "utils.h" #include "utils.h"
#include "acconf.h" #include "acconf.h"
@ -494,7 +493,7 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
const datetime_t& when, const datetime_t& when,
account_t * account, account_t * account,
const char * desc, const char * desc,
journal_t * journal) journal_t& journal)
{ {
time_entry_t event; time_entry_t event;
@ -551,15 +550,15 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
xact->state = transaction_t::CLEARED; xact->state = transaction_t::CLEARED;
curr->add_transaction(xact); curr->add_transaction(xact);
if (! journal->add_entry(curr.get())) if (! journal.add_entry(curr.get()))
throw new parse_error("Failed to record 'out' timelog entry"); throw new parse_error("Failed to record 'out' timelog entry");
else else
curr.release(); curr.release();
} }
unsigned int textual_parser_t::parse(std::istream& in, unsigned int textual_parser_t::parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master, account_t * master,
const path * original_file) const path * original_file)
{ {
@ -571,16 +570,16 @@ unsigned int textual_parser_t::parse(std::istream& in,
unsigned int errors = 0; unsigned int errors = 0;
std::list<account_t *> account_stack; std::list<account_t *> account_stack;
auto_entry_finalizer_t auto_entry_finalizer(journal); auto_entry_finalizer_t auto_entry_finalizer(&journal);
std::list<time_entry_t> time_entries; std::list<time_entry_t> time_entries;
if (! master) if (! master)
master = journal->master; master = journal.master;
account_stack.push_front(master); account_stack.push_front(master);
pathname = journal->sources.back(); pathname = journal.sources.back();
src_idx = journal->sources.size() - 1; src_idx = journal.sources.size() - 1;
linenum = 1; linenum = 1;
INFO("Parsing file '" << pathname.string() << "'"); INFO("Parsing file '" << pathname.string() << "'");
@ -662,7 +661,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
} }
case 'A': // a default account for unbalanced xacts case 'A': // a default account for unbalanced xacts
journal->basket = journal.basket =
account_stack.front()->find_account(skip_ws(line + 1)); account_stack.front()->find_account(skip_ws(line + 1));
break; break;
@ -742,14 +741,14 @@ unsigned int textual_parser_t::parse(std::istream& in,
case '=': { // automated entry case '=': { // automated entry
if (! added_auto_entry_hook) { if (! added_auto_entry_hook) {
journal->add_entry_finalizer(&auto_entry_finalizer); journal.add_entry_finalizer(&auto_entry_finalizer);
added_auto_entry_hook = true; added_auto_entry_hook = true;
} }
auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1)); auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1));
if (parse_transactions(in, account_stack.front(), *ae, if (parse_transactions(in, account_stack.front(), *ae,
"automated", end_pos)) { "automated", end_pos)) {
journal->auto_entries.push_back(ae); journal.auto_entries.push_back(ae);
ae->src_idx = src_idx; ae->src_idx = src_idx;
ae->beg_pos = beg_pos; ae->beg_pos = beg_pos;
ae->beg_line = beg_line; ae->beg_line = beg_line;
@ -767,8 +766,8 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (parse_transactions(in, account_stack.front(), *pe, if (parse_transactions(in, account_stack.front(), *pe,
"period", end_pos)) { "period", end_pos)) {
if (pe->finalize()) { if (pe->finalize()) {
extend_entry_base(journal, *pe, true); extend_entry_base(&journal, *pe, true);
journal->period_entries.push_back(pe); journal.period_entries.push_back(pe);
pe->src_idx = src_idx; pe->src_idx = src_idx;
pe->beg_pos = beg_pos; pe->beg_pos = beg_pos;
pe->beg_line = beg_line; pe->beg_line = beg_line;
@ -808,11 +807,13 @@ unsigned int textual_parser_t::parse(std::istream& in,
DEBUG("ledger.textual.include", "line " << linenum << ": " << DEBUG("ledger.textual.include", "line " << linenum << ": " <<
"Including path '" << pathname << "'"); "Including path '" << pathname << "'");
#if 0
include_stack.push_back(std::pair<path, int> include_stack.push_back(std::pair<path, int>
(journal->sources.back(), linenum - 1)); (journal.sources.back(), linenum - 1));
count += parse_journal_file(pathname, config, journal, count += parse_journal_file(pathname, config, journal,
account_stack.front()); account_stack.front());
include_stack.pop_back(); include_stack.pop_back();
#endif
} }
else if (word == "account") { else if (word == "account") {
account_t * acct; account_t * acct;
@ -856,7 +857,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
TRACE_START(entries, 1, "Time spent handling entries:"); TRACE_START(entries, 1, "Time spent handling entries:");
if (entry_t * entry = if (entry_t * entry =
parse_entry(in, line, account_stack.front(), *this, pos)) { parse_entry(in, line, account_stack.front(), *this, pos)) {
if (journal->add_entry(entry)) { if (journal.add_entry(entry)) {
entry->src_idx = src_idx; entry->src_idx = src_idx;
entry->beg_pos = beg_pos; entry->beg_pos = beg_pos;
entry->beg_line = beg_line; entry->beg_line = beg_line;
@ -913,7 +914,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
} }
if (added_auto_entry_hook) if (added_auto_entry_hook)
journal->remove_entry_finalizer(&auto_entry_finalizer); journal.remove_entry_finalizer(&auto_entry_finalizer);
if (errors > 0) if (errors > 0)
throw (int)errors; throw (int)errors;

View file

@ -13,8 +13,8 @@ class textual_parser_t : public parser_t
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
}; };

6
walk.h
View file

@ -725,12 +725,12 @@ void walk_accounts(account_t& account,
void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, void walk_commodities(commodity_pool_t::commodities_by_ident& commodities,
item_handler<transaction_t>& handler); item_handler<transaction_t>& handler);
inline void clear_journal_xdata(journal_t * journal) { inline void clear_journal_xdata(journal_t& journal) {
clear_transaction_xdata xact_cleaner; clear_transaction_xdata xact_cleaner;
walk_entries(journal->entries, xact_cleaner); walk_entries(journal.entries, xact_cleaner);
clear_account_xdata acct_cleaner; clear_account_xdata acct_cleaner;
walk_accounts(*journal->master, acct_cleaner); walk_accounts(*journal.master, acct_cleaner);
} }
} // namespace ledger } // namespace ledger

6
xml.cc
View file

@ -180,15 +180,15 @@ bool xml_parser_t::test(std::istream& in) const
} }
unsigned int xml_parser_t::parse(std::istream& in, unsigned int xml_parser_t::parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master, account_t * master,
const path * original_file) const path * original_file)
{ {
char buf[BUFSIZ]; char buf[BUFSIZ];
count = 0; count = 0;
curr_journal = journal; curr_journal = &journal;
curr_entry = NULL; curr_entry = NULL;
curr_comm = NULL; curr_comm = NULL;
ignore = false; ignore = false;

4
xml.h
View file

@ -14,8 +14,8 @@ class xml_parser_t : public parser_t
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual unsigned int parse(std::istream& in,
config_t& config, session_t& session,
journal_t * journal, journal_t& journal,
account_t * master = NULL, account_t * master = NULL,
const path * original_file = NULL); const path * original_file = NULL);
}; };