diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | python/py_textual.cc | 68 | ||||
-rw-r--r-- | python/pyinterp.cc | 2 | ||||
-rw-r--r-- | src/derive.cc | 16 | ||||
-rw-r--r-- | src/filters.cc | 1 | ||||
-rw-r--r-- | src/global.cc | 9 | ||||
-rw-r--r-- | src/iterators.cc | 43 | ||||
-rw-r--r-- | src/iterators.h | 42 | ||||
-rw-r--r-- | src/journal.h | 43 | ||||
-rw-r--r-- | src/ledger.h | 1 | ||||
-rw-r--r-- | src/session.cc | 118 | ||||
-rw-r--r-- | src/session.h | 24 | ||||
-rw-r--r-- | src/textual.cc | 309 | ||||
-rw-r--r-- | src/textual.h | 171 |
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 |