summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-07 17:45:48 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-07 17:45:48 -0400
commit589eabd8e60636b7b250b75a5a2966034e8ba911 (patch)
treef9db5c14df14dbc2db3ba0c96dff34c8e670a311
parent9380d73646bcd79c4f24581b2212f684cea70138 (diff)
downloadfork-ledger-589eabd8e60636b7b250b75a5a2966034e8ba911.tar.gz
fork-ledger-589eabd8e60636b7b250b75a5a2966034e8ba911.tar.bz2
fork-ledger-589eabd8e60636b7b250b75a5a2966034e8ba911.zip
Threw away the "multiple parser" infrastructure.
-rw-r--r--Makefile.am2
-rw-r--r--python/py_textual.cc68
-rw-r--r--python/pyinterp.cc2
-rw-r--r--src/derive.cc16
-rw-r--r--src/filters.cc1
-rw-r--r--src/global.cc9
-rw-r--r--src/iterators.cc43
-rw-r--r--src/iterators.h42
-rw-r--r--src/journal.h43
-rw-r--r--src/ledger.h1
-rw-r--r--src/session.cc118
-rw-r--r--src/session.h24
-rw-r--r--src/textual.cc309
-rw-r--r--src/textual.h171
14 files changed, 230 insertions, 619 deletions
diff --git a/Makefile.am b/Makefile.am
index 9f64ca1e..013bd2a0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -106,7 +106,6 @@ pkginclude_HEADERS = \
src/entry.h \
src/account.h \
src/journal.h \
- src/textual.h \
src/timelog.h \
src/iterators.h \
src/compare.h \
@@ -222,7 +221,6 @@ libledger_python_la_SOURCES = \
python/py_scope.cc \
python/py_session.cc \
python/py_stream.cc \
- python/py_textual.cc \
python/py_timelog.cc \
python/py_times.cc \
python/py_token.cc \
diff --git a/python/py_textual.cc b/python/py_textual.cc
deleted file mode 100644
index dce242d8..00000000
--- a/python/py_textual.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2003-2009, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "pyinterp.h"
-#include "pyutils.h"
-#include "textual.h"
-
-#include <boost/python/exception_translator.hpp>
-#include <boost/python/implicit.hpp>
-#include <boost/python/args.hpp>
-
-namespace ledger {
-
-using namespace boost::python;
-
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_ArithmeticError, err.what()); \
- }
-
-//EXC_TRANSLATOR(textual_error)
-
-void export_textual()
-{
-#if 0
- class_< textual_parser_t > ("TextualParser")
- ;
-#endif
-
- //register_optional_to_python<amount_t>();
-
- //implicitly_convertible<string, amount_t>();
-
-#define EXC_TRANSLATE(type) \
- register_exception_translator<type>(&exc_translate_ ## type);
-
- //EXC_TRANSLATE(textual_error);
-}
-
-} // namespace ledger
diff --git a/python/pyinterp.cc b/python/pyinterp.cc
index aaa188da..d6248709 100644
--- a/python/pyinterp.cc
+++ b/python/pyinterp.cc
@@ -65,7 +65,6 @@ void export_report();
void export_scope();
void export_session();
void export_stream();
-void export_textual();
void export_timelog();
void export_times();
void export_token();
@@ -103,7 +102,6 @@ void initialize_for_python()
export_scope();
export_session();
export_stream();
- export_textual();
export_timelog();
export_times();
export_token();
diff --git a/src/derive.cc b/src/derive.cc
index 712fd807..dd261ed6 100644
--- a/src/derive.cc
+++ b/src/derive.cc
@@ -51,19 +51,15 @@ entry_t * derive_new_entry(report_t& report,
mask_t regexp(*i++);
- journals_iterator iter(session);
entries_list::reverse_iterator j;
- for (journal_t * journal = iter(); journal; journal = iter()) {
- for (j = journal->entries.rbegin();
- j != journal->entries.rend();
- j++) {
- if (regexp.match((*j)->payee)) {
- matching = *j;
- break;
- }
+ for (j = report.session.journal->entries.rbegin();
+ j != report.session.journal->entries.rend();
+ j++) {
+ if (regexp.match((*j)->payee)) {
+ matching = *j;
+ break;
}
- if (matching) break;
}
added->payee = matching ? matching->payee : regexp.expr.str();
diff --git a/src/filters.cc b/src/filters.cc
index 623a5dee..45c3fdaa 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -34,7 +34,6 @@
#include "compare.h"
#include "session.h"
#include "format.h"
-#include "textual.h"
namespace ledger {
diff --git a/src/global.cc b/src/global.cc
index 8915d763..f5b9b0b4 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -85,9 +85,9 @@ void global_scope_t::read_init()
ifstream init(init_file);
- journal_t temp;
- if (session().read_journal(temp, init_file) > 0 ||
- temp.auto_entries.size() > 0 || temp.period_entries.size() > 0) {
+ if (session().read_journal(init_file) > 0 ||
+ session().journal->auto_entries.size() > 0 ||
+ session().journal->period_entries.size() > 0) {
throw_(parse_error,
"Entries found in initialization file '" << init_file << "'");
}
@@ -105,8 +105,7 @@ void global_scope_t::read_journal_files()
if (session().HANDLED(account_))
master_account = session().HANDLER(account_).str();
- std::size_t count = session().read_data(*session().create_journal(),
- master_account);
+ std::size_t count = session().read_data(master_account);
if (count == 0)
throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");
diff --git a/src/iterators.cc b/src/iterators.cc
index 3e1375f6..2d924956 100644
--- a/src/iterators.cc
+++ b/src/iterators.cc
@@ -37,37 +37,23 @@ namespace ledger {
void entries_iterator::reset(session_t& session)
{
- journals_i = session.journals.begin();
- journals_end = session.journals.end();
-
- journals_uninitialized = false;
-
- if (journals_i != journals_end) {
- entries_i = (*journals_i).entries.begin();
- entries_end = (*journals_i).entries.end();
-
- entries_uninitialized = false;
- } else {
- entries_uninitialized = true;
- }
+ entries_i = session.journal->entries.begin();
+ entries_end = session.journal->entries.end();
+ entries_uninitialized = false;
}
entry_t * entries_iterator::operator()()
{
- if (entries_i == entries_end) {
- journals_i++;
- if (journals_i == journals_end)
- return NULL;
-
- entries_i = (*journals_i).entries.begin();
- entries_end = (*journals_i).entries.end();
- }
- return *entries_i++;
+ if (entries_i != entries_end)
+ return *entries_i++;
+ else
+ return NULL;
}
void session_xacts_iterator::reset(session_t& session)
{
entries.reset(session);
+
entry_t * entry = entries();
if (entry != NULL)
xacts.reset(*entry);
@@ -139,19 +125,6 @@ account_t * sorted_accounts_iterator::operator()()
return account;
}
-void journals_iterator::reset(session_t& session)
-{
- journals_i = session.journals.begin();
- journals_end = session.journals.end();
-}
-
-journal_t * journals_iterator::operator()()
-{
- if (journals_i == journals_end)
- return NULL;
- return &(*journals_i++);
-}
-
#if 0
// jww (2008-08-03): This needs to be changed into a commodities->xacts
// iterator.
diff --git a/src/iterators.h b/src/iterators.h
index ded403d9..699dd891 100644
--- a/src/iterators.h
+++ b/src/iterators.h
@@ -110,23 +110,16 @@ public:
*/
class entries_iterator : public noncopyable
{
- ptr_list<journal_t>::iterator journals_i;
- ptr_list<journal_t>::iterator journals_end;
-
- bool journals_uninitialized;
-
- entries_list::iterator entries_i;
- entries_list::iterator entries_end;
+ entries_list::iterator entries_i;
+ entries_list::iterator entries_end;
bool entries_uninitialized;
public:
- entries_iterator()
- : journals_uninitialized(true), entries_uninitialized(true) {
+ entries_iterator() : entries_uninitialized(true) {
TRACE_CTOR(entries_iterator, "");
}
- entries_iterator(session_t& session)
- : journals_uninitialized(true), entries_uninitialized(true) {
+ entries_iterator(session_t& session) : entries_uninitialized(true) {
TRACE_CTOR(entries_iterator, "session_t&");
reset(session);
}
@@ -250,33 +243,6 @@ public:
virtual account_t * operator()();
};
-/**
- * @brief Brief
- *
- * Long.
- */
-class journals_iterator : public noncopyable
-{
- ptr_list<journal_t>::iterator journals_i;
- ptr_list<journal_t>::iterator journals_end;
-
-public:
- journals_iterator() {
- TRACE_CTOR(journals_iterator, "");
- }
- journals_iterator(session_t& session) {
- TRACE_CTOR(journals_iterator, "session_t&");
- reset(session);
- }
- virtual ~journals_iterator() throw() {
- TRACE_DTOR(journals_iterator);
- }
-
- void reset(session_t& session);
-
- virtual journal_t * operator()();
-};
-
} // namespace ledger
#endif // _ITERATORS_H
diff --git a/src/journal.h b/src/journal.h
index 1b5607cc..b84f3448 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -65,14 +65,12 @@ class account_t;
class journal_t : public noncopyable
{
public:
- account_t * master;
- account_t * basket;
- entries_list entries;
- paths_list sources;
- optional<path> price_db;
+ account_t * master;
+ account_t * basket;
+ entries_list entries;
- auto_entries_list auto_entries;
- period_entries_list period_entries;
+ auto_entries_list auto_entries;
+ period_entries_list period_entries;
hooks_t<entry_finalizer_t, entry_t> entry_finalize_hooks;
@@ -98,33 +96,10 @@ public:
entry_finalize_hooks.remove_hook(finalizer);
}
- /**
- * @brief Provides an abstract interface for writing journal parsers.
- *
- * Any data format for Ledger data is possible, as long as it can be parsed
- * into a journal_t data tree. This class provides the basic interface which
- * must be implemented by every such journal parser.
- */
- class parser_t : public noncopyable
- {
- public:
- parser_t() {
- TRACE_CTOR(journal_t::parser_t, "");
- }
- virtual ~parser_t() {
- TRACE_DTOR(journal_t::parser_t);
- }
-
-#if defined(TEST_FOR_PARSER)
- virtual bool test(std::istream& in) const = 0;
-#endif
-
- virtual std::size_t parse(std::istream& in,
- session_t& session,
- journal_t& journal,
- account_t * master = NULL,
- const path * original_file = NULL) = 0;
- };
+ std::size_t parse(std::istream& in,
+ session_t& session,
+ account_t * master,
+ const path * original_file);
bool valid() const;
};
diff --git a/src/ledger.h b/src/ledger.h
index bb8ce488..89d34048 100644
--- a/src/ledger.h
+++ b/src/ledger.h
@@ -75,7 +75,6 @@
#include <expr.h>
#include <journal.h>
-#include <textual.h>
#include <iterators.h>
#include <compare.h>
diff --git a/src/session.cc b/src/session.cc
index f3d01eec..a1ff4892 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -33,7 +33,6 @@
#include "report.h"
#include "iterators.h"
#include "filters.h"
-#include "textual.h"
namespace ledger {
@@ -61,7 +60,8 @@ session_t::session_t()
current_year(CURRENT_DATE().year()),
commodity_pool(new commodity_pool_t),
- master(new account_t(NULL, ""))
+ master(new account_t(NULL, "")),
+ journal(new journal_t(master.get()))
{
TRACE_CTOR(session_t, "");
@@ -70,8 +70,6 @@ session_t::session_t()
else
HANDLER(price_db_).on(path("./.pricedb").string());
- register_parser(new textual_parser_t);
-
// Add time commodity conversions, so that timelog's may be parsed
// in terms of seconds, but reported as minutes or hours.
if (commodity_t * commodity = commodity_pool->create("s"))
@@ -80,58 +78,26 @@ session_t::session_t()
assert(false);
}
-journal_t * session_t::create_journal()
-{
- journal_t * journal = new journal_t(master.get());
- journals.push_back(journal);
- return journal;
-}
-
-void session_t::close_journal(journal_t * journal)
-{
- for (ptr_list<journal_t>::iterator i = journals.begin();
- i != journals.end();
- i++)
- if (&*i == journal) {
- journals.erase(i);
- return;
- }
- assert(false);
- checked_delete(journal);
-}
-
-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,
account_t * master)
{
if (! master)
- master = journal.master;
-
- foreach (journal_t::parser_t& parser, parsers)
-#if defined(TEST_FOR_PARSER)
- if (parser.test(in))
-#endif
- return parser.parse(in, *this, journal, master, &pathname);
-
- return 0;
+ master = journal->master;
+ return journal->parse(in, *this, master, &pathname);
}
-std::size_t session_t::read_journal(journal_t& journal,
- const path& pathname,
+std::size_t session_t::read_journal(const path& pathname,
account_t * master)
{
- journal.sources.push_back(pathname);
-
if (! exists(pathname))
throw_(std::logic_error, "Cannot read file" << pathname);
ifstream stream(pathname);
- return read_journal(journal, stream, pathname, master);
+ return read_journal(stream, pathname, master);
}
-std::size_t session_t::read_data(journal_t& journal,
- const string& master_account)
+std::size_t session_t::read_data(const string& master_account)
{
if (HANDLER(file_).data_files.empty())
throw_(parse_error, "No journal file was specified (please use -f)");
@@ -139,24 +105,18 @@ std::size_t session_t::read_data(journal_t& journal,
std::size_t entry_count = 0;
if (entry_count == 0) {
- account_t * acct = journal.master;
+ account_t * acct = journal->master;
if (! master_account.empty())
- acct = journal.find_account(master_account);
+ acct = journal->find_account(master_account);
- journal.price_db = HANDLER(price_db_).str();
- if (journal.price_db && exists(*journal.price_db)) {
- if (read_journal(journal, *journal.price_db)) {
+ if (HANDLED(price_db_) && exists(path(HANDLER(price_db_).str()))) {
+ if (read_journal(HANDLER(price_db_).str()))
throw_(parse_error, "Entries not allowed in price history file");
- } else {
- journal.sources.pop_back();
- }
}
foreach (const path& pathname, HANDLER(file_).data_files) {
if (pathname == "-") {
- journal.sources.push_back("/dev/stdin");
-
// To avoid problems with stdin and pipes, etc., we read the entire
// file in beforehand into a memory buffer, and then parcel it out
// from there.
@@ -172,12 +132,10 @@ std::size_t session_t::read_data(journal_t& journal,
std::istringstream buf_in(buffer.str());
- entry_count += read_journal(journal, buf_in, "/dev/stdin", acct);
+ entry_count += read_journal(buf_in, "/dev/stdin", acct);
}
else if (exists(pathname)) {
- entry_count += read_journal(journal, pathname, acct);
- if (journal.price_db)
- journal.sources.push_back(*journal.price_db);
+ entry_count += read_journal(pathname, acct);
}
else {
throw_(parse_error, "Could not open journal file '" << pathname << "'");
@@ -185,25 +143,11 @@ std::size_t session_t::read_data(journal_t& journal,
}
}
- VERIFY(journal.valid());
+ VERIFY(journal->valid());
return entry_count;
}
-void session_t::unregister_parser(journal_t::parser_t * parser)
-{
- for (ptr_list<journal_t::parser_t>::iterator i = parsers.begin();
- i != parsers.end();
- i++) {
- if (&*i == parser) {
- parsers.erase(i);
- return;
- }
- }
- assert(false);
- checked_delete(parser);
-}
-
void session_t::clean_xacts()
{
session_xacts_iterator walker(*this);
@@ -223,38 +167,6 @@ void session_t::clean_accounts()
master->clear_xdata();
}
-#if 0
-value_t session_t::resolve(const string& name, expr_t::scope_t& locals)
-{
- const char * p = name.c_str();
- switch (*p) {
- case 'd':
-#if 0
- if (name == "date_format") {
- // jww (2007-04-18): What to do here?
- return string_value(moment_t::output_format);
- }
-#endif
- break;
-
- case 'n':
- switch (*++p) {
- case 'o':
- if (name == "now")
- return value_t(now);
- break;
- }
- break;
-
- case 'r':
- if (name == "register_format")
- return string_value(register_format);
- break;
- }
- return expr_t::scope_t::resolve(name, locals);
-}
-#endif
-
option_t<session_t> * session_t::lookup_option(const char * p)
{
switch (*p) {
diff --git a/src/session.h b/src/session.h
index a628454a..ce1faa1c 100644
--- a/src/session.h
+++ b/src/session.h
@@ -66,10 +66,9 @@ public:
bool flush_on_next_data_file;
int current_year;
- shared_ptr<commodity_pool_t> commodity_pool;
- ptr_list<journal_t::parser_t> parsers;
- ptr_list<journal_t> journals;
- scoped_ptr<account_t> master;
+ shared_ptr<commodity_pool_t> commodity_pool;
+ scoped_ptr<account_t> master;
+ scoped_ptr<journal_t> journal;
explicit session_t();
virtual ~session_t() {
@@ -80,24 +79,13 @@ public:
flush_on_next_data_file = true;
}
- journal_t * create_journal();
- void close_journal(journal_t * journal);
-
- std::size_t read_journal(journal_t& journal,
- std::istream& in,
+ std::size_t read_journal(std::istream& in,
const path& pathname,
account_t * master = NULL);
- std::size_t read_journal(journal_t& journal,
- const path& pathname,
+ std::size_t read_journal(const path& pathname,
account_t * master = NULL);
- std::size_t read_data(journal_t& journal,
- const string& master_account = "");
-
- void register_parser(journal_t::parser_t * parser) {
- parsers.push_back(parser);
- }
- void unregister_parser(journal_t::parser_t * parser);
+ std::size_t read_data(const string& master_account = "");
void clean_xacts();
void clean_xacts(entry_t& entry);
diff --git a/src/textual.cc b/src/textual.cc
index d3a829d3..08a607fb 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -29,94 +29,107 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if defined(__GNUG__) && __GNUG__ < 3
-#define _XOPEN_SOURCE
-#endif
-
-#include "textual.h"
+#include "session.h"
+#include "journal.h"
#if defined(TIMELOG_SUPPORT)
#include "timelog.h"
#endif
-#include "parser.h"
-#include "session.h"
namespace ledger {
-#if defined(TEST_FOR_PARSER)
-
-bool textual_parser_t::test(std::istream& in) const
-{
- char buf[12];
- char * p;
-
- in.read(buf, 11);
- if (utf8::is_bom(buf))
- p = &buf[3];
- else
- p = buf;
-
- if (std::strncmp(p, "<?xml", 5) == 0)
- throw_(parse_error,
- "Ledger file contains XML data, but format was not recognized");
-
- in.clear();
- in.seekg(0, std::ios::beg);
- assert(in.good());
- return true;
-}
-
-#endif // TEST_FOR_PARSER
-
-std::size_t textual_parser_t::parse(std::istream& in,
- session_t& session,
- journal_t& journal,
- account_t * master,
- const path * original_file)
-{
- TRACE_START(parsing_total, 1, "Total time spent parsing text:");
+namespace {
+ class instance_t : public noncopyable, public scope_t
+ {
+ static const std::size_t MAX_LINE = 1024;
- std::list<account_t *> account_stack;
+ public:
+ std::list<account_t *>& account_stack;
#if defined(TIMELOG_SUPPORT)
- time_log_t timelog(journal);
+ time_log_t& timelog;
#endif
- instance_t parsing_instance(account_stack,
+ instance_t * parent;
+ std::istream& in;
+ session_t& session;
+ journal_t& journal;
+ account_t * master;
+ const path * original_file;
+ accounts_map account_aliases;
+
+ path pathname;
+ char linebuf[MAX_LINE + 1];
+ std::size_t linenum;
+ istream_pos_type line_beg_pos;
+ istream_pos_type curr_pos;
+ std::size_t count;
+ std::size_t errors;
+
+ scoped_ptr<auto_entry_finalizer_t> auto_entry_finalizer;
+
+ instance_t(std::list<account_t *>& _account_stack,
#if defined(TIMELOG_SUPPORT)
- timelog,
+ time_log_t& _timelog,
#endif
- in, session, journal, master,
- original_file);
- parsing_instance.parse();
-
- session.clean_accounts(); // remove calculated totals
-
- TRACE_STOP(parsing_total, 1);
-
- // These tracers were started in textual.cc
- TRACE_FINISH(entry_text, 1);
- TRACE_FINISH(entry_details, 1);
- TRACE_FINISH(entry_xacts, 1);
- TRACE_FINISH(entries, 1);
- TRACE_FINISH(instance_parse, 1); // report per-instance timers
- TRACE_FINISH(parsing_total, 1);
-
- if (parsing_instance.errors > 0)
- throw static_cast<int>(parsing_instance.errors);
-
- return parsing_instance.count;
-}
+ std::istream& _in,
+ session_t& _session,
+ journal_t& _journal,
+ account_t * _master = NULL,
+ const path * _original_file = NULL,
+ instance_t * _parent = NULL);
+
+ ~instance_t();
+
+ void parse();
+ std::streamsize read_line(char *& line);
+ bool peek_whitespace_line() {
+ return (in.good() && ! in.eof() &&
+ (in.peek() == ' ' || in.peek() == '\t'));
+ }
+ void read_next_directive();
-namespace {
-#if defined(STORE_XACT_EXPRS)
- optional<expr_t>
-#else
- void
+#if defined(TIMELOG_SUPPORT)
+ void clock_in_directive(char * line, bool capitalized);
+ void clock_out_directive(char * line, bool capitalized);
#endif
- parse_amount_expr(session_t& session,
- std::istream& in,
- amount_t& amount,
- xact_t * xact,
- uint_least8_t flags = 0)
+
+ void default_commodity_directive(char * line);
+ void default_account_directive(char * line);
+ void price_conversion_directive(char * line);
+ void price_entry_directive(char * line);
+ void nomarket_directive(char * line);
+ void year_directive(char * line);
+ void option_directive(char * line);
+ void automated_entry_directive(char * line);
+ void period_entry_directive(char * line);
+ void entry_directive(char * line, std::streamsize len);
+ void include_directive(char * line);
+ void account_directive(char * line);
+ void end_directive(char * line);
+ void alias_directive(char * line);
+ void define_directive(char * line);
+ void general_directive(char * line);
+
+ xact_t * parse_xact(char * line,
+ std::streamsize len,
+ account_t * account,
+ entry_t * entry);
+
+ bool parse_xacts(account_t * account,
+ entry_base_t& entry,
+ const string& kind);
+
+ entry_t * parse_entry(char * line,
+ std::streamsize len,
+ account_t * account);
+
+ virtual expr_t::ptr_op_t lookup(const string& name);
+ };
+
+ void parse_amount_expr(session_t& session,
+ std::istream& in,
+ amount_t& amount,
+ xact_t * xact,
+ uint_least8_t flags = 0)
{
expr_t expr(in, flags | static_cast<uint_least8_t>(expr_t::PARSE_PARTIAL));
@@ -140,47 +153,42 @@ namespace {
amount = result.as_amount();
DEBUG("textual.parse", "The transaction amount is " << amount);
-#if defined(STORE_XACT_EXPRS)
- return expr;
-#endif
}
-#if defined(STORE_XACT_EXPRS)
- return none;
-#endif
}
}
-textual_parser_t::instance_t::instance_t
- (std::list<account_t *>& _account_stack,
+instance_t::instance_t(std::list<account_t *>& _account_stack,
#if defined(TIMELOG_SUPPORT)
- time_log_t& _timelog,
+ time_log_t& _timelog,
#endif
- std::istream& _in,
- session_t& _session,
- journal_t& _journal,
- account_t * _master,
- const path * _original_file,
- instance_t * _parent)
+ std::istream& _in,
+ session_t& _session,
+ journal_t& _journal,
+ account_t * _master,
+ const path * _original_file,
+ instance_t * _parent)
: account_stack(_account_stack),
#if defined(TIMELOG_SUPPORT)
timelog(_timelog),
#endif
- parent(_parent), in(_in), session(_session),
- journal(_journal), master(_master),
- original_file(_original_file)
+ parent(_parent), in(_in), session(_session), journal(_journal),
+ master(_master), original_file(_original_file)
{
- TRACE_CTOR(textual_parser_t::instance_t, "...");
+ TRACE_CTOR(instance_t, "...");
if (! master)
master = journal.master;
account_stack.push_front(master);
- pathname = journal.sources.back();
+ if (_original_file)
+ pathname = *_original_file;
+ else
+ pathname = "/dev/stdin";
}
-textual_parser_t::instance_t::~instance_t()
+instance_t::~instance_t()
{
- TRACE_DTOR(textual_parser_t::instance_t);
+ TRACE_DTOR(instance_t);
account_stack.pop_front();
@@ -188,7 +196,7 @@ textual_parser_t::instance_t::~instance_t()
journal.remove_entry_finalizer(auto_entry_finalizer.get());
}
-void textual_parser_t::instance_t::parse()
+void instance_t::parse()
{
INFO("Parsing file '" << pathname.string() << "'");
@@ -241,13 +249,15 @@ void textual_parser_t::instance_t::parse()
TRACE_STOP(instance_parse, 1);
}
-std::streamsize textual_parser_t::instance_t::read_line(char *& line)
+std::streamsize instance_t::read_line(char *& line)
{
assert(in.good());
assert(! in.eof()); // no one should call us in that case
line_beg_pos = curr_pos;
-
+
+ check_for_signal();
+
in.getline(linebuf, MAX_LINE);
std::streamsize len = in.gcount();
@@ -270,7 +280,7 @@ std::streamsize textual_parser_t::instance_t::read_line(char *& line)
return 0;
}
-void textual_parser_t::instance_t::read_next_directive()
+void instance_t::read_next_directive()
{
char * line;
std::streamsize len = read_line(line);
@@ -369,8 +379,8 @@ void textual_parser_t::instance_t::read_next_directive()
#if defined(TIMELOG_SUPPORT)
-void textual_parser_t::instance_t::clock_in_directive(char * line,
- bool capitalized)
+void instance_t::clock_in_directive(char * line,
+ bool capitalized)
{
string date(line, 2, 19);
@@ -381,8 +391,8 @@ void textual_parser_t::instance_t::clock_in_directive(char * line,
account_stack.front()->find_account(p), n ? n : "");
}
-void textual_parser_t::instance_t::clock_out_directive(char * line,
- bool capitalized)
+void instance_t::clock_out_directive(char * line,
+ bool capitalized)
{
string date(line, 2, 19);
@@ -395,19 +405,19 @@ void textual_parser_t::instance_t::clock_out_directive(char * line,
}
#endif // TIMELOG_SUPPORT
-void textual_parser_t::instance_t::default_commodity_directive(char * line)
+void instance_t::default_commodity_directive(char * line)
{
amount_t amt(skip_ws(line + 1));
assert(amt.valid());
amount_t::current_pool->default_commodity = &amt.commodity();
}
-void textual_parser_t::instance_t::default_account_directive(char * line)
+void instance_t::default_account_directive(char * line)
{
journal.basket = account_stack.front()->find_account(skip_ws(line + 1));
}
-void textual_parser_t::instance_t::price_conversion_directive(char * line)
+void instance_t::price_conversion_directive(char * line)
{
if (char * p = std::strchr(line + 1, '=')) {
*p++ = '\0';
@@ -440,7 +450,7 @@ namespace {
}
}
-void textual_parser_t::instance_t::price_entry_directive(char * line)
+void instance_t::price_entry_directive(char * line)
{
char * date_field_ptr = skip_ws(line + 1);
char * time_field_ptr = next_element(date_field_ptr);
@@ -470,7 +480,7 @@ void textual_parser_t::instance_t::price_entry_directive(char * line)
commodity->add_price(datetime, price);
}
-void textual_parser_t::instance_t::nomarket_directive(char * line)
+void instance_t::nomarket_directive(char * line)
{
char * p = skip_ws(line + 1);
string symbol;
@@ -481,12 +491,12 @@ void textual_parser_t::instance_t::nomarket_directive(char * line)
commodity->add_flags(COMMODITY_NOMARKET);
}
-void textual_parser_t::instance_t::year_directive(char * line)
+void instance_t::year_directive(char * line)
{
session.current_year = std::atoi(skip_ws(line + 1));
}
-void textual_parser_t::instance_t::option_directive(char * line)
+void instance_t::option_directive(char * line)
{
char * p = next_element(line);
if (! p) {
@@ -497,7 +507,7 @@ void textual_parser_t::instance_t::option_directive(char * line)
process_option(line + 2, session, p, line);
}
-void textual_parser_t::instance_t::automated_entry_directive(char * line)
+void instance_t::automated_entry_directive(char * line)
{
if (! auto_entry_finalizer.get()) {
auto_entry_finalizer.reset(new auto_entry_finalizer_t(&journal));
@@ -525,7 +535,7 @@ void textual_parser_t::instance_t::automated_entry_directive(char * line)
}
}
-void textual_parser_t::instance_t::period_entry_directive(char * line)
+void instance_t::period_entry_directive(char * line)
{
std::auto_ptr<period_entry_t> pe(new period_entry_t(skip_ws(line + 1)));
if (! pe->period)
@@ -553,7 +563,7 @@ void textual_parser_t::instance_t::period_entry_directive(char * line)
}
}
-void textual_parser_t::instance_t::entry_directive(char * line, std::streamsize len)
+void instance_t::entry_directive(char * line, std::streamsize len)
{
TRACE_START(entries, 1, "Time spent handling entries:");
@@ -574,7 +584,7 @@ void textual_parser_t::instance_t::entry_directive(char * line, std::streamsize
TRACE_STOP(entries, 1);
}
-void textual_parser_t::instance_t::include_directive(char * line)
+void instance_t::include_directive(char * line)
{
path filename(next_element(line));
@@ -606,7 +616,7 @@ void textual_parser_t::instance_t::include_directive(char * line)
count += instance.count;
}
-void textual_parser_t::instance_t::account_directive(char * line)
+void instance_t::account_directive(char * line)
{
if (account_t * acct =
account_stack.front()->find_account(next_element(line)))
@@ -615,12 +625,12 @@ void textual_parser_t::instance_t::account_directive(char * line)
assert(! "Failed to create account");
}
-void textual_parser_t::instance_t::end_directive(char * line)
+void instance_t::end_directive(char * line)
{
account_stack.pop_front();
}
-void textual_parser_t::instance_t::alias_directive(char * line)
+void instance_t::alias_directive(char * line)
{
char * b = skip_ws(line + 1);
if (char * e = std::strchr(b, '=')) {
@@ -641,13 +651,13 @@ void textual_parser_t::instance_t::alias_directive(char * line)
}
}
-void textual_parser_t::instance_t::define_directive(char * line)
+void instance_t::define_directive(char * line)
{
expr_t def(skip_ws(line + 1));
def.compile(session); // causes definitions to be established
}
-void textual_parser_t::instance_t::general_directive(char * line)
+void instance_t::general_directive(char * line)
{
char * p = next_element(line);
string word(line + 1);
@@ -698,10 +708,10 @@ void textual_parser_t::instance_t::general_directive(char * line)
}
}
-xact_t * textual_parser_t::instance_t::parse_xact(char * line,
- std::streamsize len,
- account_t * account,
- entry_t * entry)
+xact_t * instance_t::parse_xact(char * line,
+ std::streamsize len,
+ account_t * account,
+ entry_t * entry)
{
TRACE_START(xact_details, 1, "Time spent parsing transactions:");
@@ -992,9 +1002,9 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
}
}
-bool textual_parser_t::instance_t::parse_xacts(account_t * account,
- entry_base_t& entry,
- const string& kind)
+bool instance_t::parse_xacts(account_t * account,
+ entry_base_t& entry,
+ const string& kind)
{
TRACE_START(entry_xacts, 1, "Time spent parsing transactions:");
@@ -1016,9 +1026,9 @@ bool textual_parser_t::instance_t::parse_xacts(account_t * account,
return added;
}
-entry_t * textual_parser_t::instance_t::parse_entry(char * line,
- std::streamsize len,
- account_t * account)
+entry_t * instance_t::parse_entry(char * line,
+ std::streamsize len,
+ account_t * account)
{
TRACE_START(entry_text, 1, "Time spent parsing entry text:");
@@ -1120,9 +1130,46 @@ entry_t * textual_parser_t::instance_t::parse_entry(char * line,
return curr.release();
}
-expr_t::ptr_op_t textual_parser_t::instance_t::lookup(const string& name)
+expr_t::ptr_op_t instance_t::lookup(const string& name)
{
return session.lookup(name);
}
+std::size_t journal_t::parse(std::istream& in,
+ session_t& session,
+ account_t * master,
+ const path * original_file)
+{
+ TRACE_START(parsing_total, 1, "Total time spent parsing text:");
+
+ std::list<account_t *> account_stack;
+#if defined(TIMELOG_SUPPORT)
+ time_log_t timelog(*this);
+#endif
+
+ instance_t parsing_instance(account_stack,
+#if defined(TIMELOG_SUPPORT)
+ timelog,
+#endif
+ in, session, *this, master, original_file);
+ parsing_instance.parse();
+
+ session.clean_accounts(); // remove calculated totals
+
+ TRACE_STOP(parsing_total, 1);
+
+ // These tracers were started in textual.cc
+ TRACE_FINISH(entry_text, 1);
+ TRACE_FINISH(entry_details, 1);
+ TRACE_FINISH(entry_xacts, 1);
+ TRACE_FINISH(entries, 1);
+ TRACE_FINISH(instance_parse, 1); // report per-instance timers
+ TRACE_FINISH(parsing_total, 1);
+
+ if (parsing_instance.errors > 0)
+ throw static_cast<int>(parsing_instance.errors);
+
+ return parsing_instance.count;
+}
+
} // namespace ledger
diff --git a/src/textual.h b/src/textual.h
deleted file mode 100644
index 3565579a..00000000
--- a/src/textual.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2003-2009, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @defgroup parse Parsers
- */
-
-/**
- * @file textual.h
- * @author John Wiegley
- *
- * @ingroup parse
- *
- * @brief Brief
- *
- * Long.
- */
-#ifndef _TEXTUAL_H
-#define _TEXTUAL_H
-
-#include "journal.h"
-#include "account.h"
-
-namespace ledger {
-
-#define TIMELOG_SUPPORT 1
-
-#if defined(TIMELOG_SUPPORT)
-class time_log_t;
-#endif
-
-/**
- * @brief Brief
- *
- * Long.
- */
-class textual_parser_t : public journal_t::parser_t
-{
-public:
-#if defined(TEST_FOR_PARSER)
- virtual bool test(std::istream& in) const;
-#endif
-
- virtual std::size_t parse(std::istream& in,
- session_t& session,
- journal_t& journal,
- account_t * master = NULL,
- const path * original_file = NULL);
-
-protected:
- class instance_t : public noncopyable, public scope_t
- {
- static const std::size_t MAX_LINE = 1024;
-
- public:
- std::list<account_t *>& account_stack;
-#if defined(TIMELOG_SUPPORT)
- time_log_t& timelog;
-#endif
-
- instance_t * parent;
- std::istream& in;
- session_t& session;
- journal_t& journal;
- account_t * master;
- const path * original_file;
- accounts_map account_aliases;
-
- path pathname;
- char linebuf[MAX_LINE + 1];
- std::size_t linenum;
- istream_pos_type line_beg_pos;
- istream_pos_type curr_pos;
- std::size_t count;
- std::size_t errors;
-
- scoped_ptr<auto_entry_finalizer_t> auto_entry_finalizer;
-
- instance_t(std::list<account_t *>& _account_stack,
-#if defined(TIMELOG_SUPPORT)
- time_log_t& _timelog,
-#endif
- std::istream& _in,
- session_t& _session,
- journal_t& _journal,
- account_t * _master = NULL,
- const path * _original_file = NULL,
- instance_t * _parent = NULL);
-
- ~instance_t();
-
- void parse();
- std::streamsize read_line(char *& line);
- bool peek_whitespace_line() {
- return (in.good() && ! in.eof() &&
- (in.peek() == ' ' || in.peek() == '\t'));
- }
- void read_next_directive();
-
-#if defined(TIMELOG_SUPPORT)
- void clock_in_directive(char * line, bool capitalized);
- void clock_out_directive(char * line, bool capitalized);
-#endif
-
- void default_commodity_directive(char * line);
- void default_account_directive(char * line);
- void price_conversion_directive(char * line);
- void price_entry_directive(char * line);
- void nomarket_directive(char * line);
- void year_directive(char * line);
- void option_directive(char * line);
- void automated_entry_directive(char * line);
- void period_entry_directive(char * line);
- void entry_directive(char * line, std::streamsize len);
- void include_directive(char * line);
- void account_directive(char * line);
- void end_directive(char * line);
- void alias_directive(char * line);
- void define_directive(char * line);
- void general_directive(char * line);
-
- xact_t * parse_xact(char * line,
- std::streamsize len,
- account_t * account,
- entry_t * entry);
-
- bool parse_xacts(account_t * account,
- entry_base_t& entry,
- const string& kind);
-
- entry_t * parse_entry(char * line,
- std::streamsize len,
- account_t * account);
-
- virtual expr_t::ptr_op_t lookup(const string& name);
- };
-
- friend class instance_t;
-};
-
-} // namespace ledger
-
-#endif // _TEXTUAL_H