Initial implementation of document_builder_t.

This commit is contained in:
John Wiegley 2007-05-14 11:09:28 +00:00
parent 77db7eb92f
commit 59fc3d1bdb
45 changed files with 832 additions and 3946 deletions

View file

@ -41,11 +41,13 @@ libledger_la_SOURCES = \
src/amount.cc \
src/balance.cc \
src/value.cc \
src/xml.cc \
src/document.cc \
src/node.cc \
src/xpath.cc \
src/builder.cc \
src/journal.cc \
src/textual.cc \
src/binary.cc \
src/transform.cc \
src/register.cc \
src/report.cc \
@ -99,26 +101,18 @@ pkginclude_HEADERS = \
src/builder.h \
src/commodity.h \
src/context.h \
src/csv.h \
src/derive.h \
src/emacs.h \
src/fdstream.hpp \
src/flags.h \
src/format.h \
src/gnucash.h \
src/journal.h \
src/ledger.h \
src/mask.h \
src/ofx.h \
src/option.h \
src/parser.h \
src/pyfstream.h \
src/pyinterp.h \
src/pyledger.h \
src/pyutils.h \
src/qif.h \
src/quotes.h \
src/reconcile.h \
src/register.h \
src/report.h \
src/scoped_execute.h \

View file

@ -1,7 +1,7 @@
#ifndef _BUILDER_H
#define _BUILDER_H
#include "xml.h"
#include "document.h"
namespace ledger {
namespace xml {
@ -44,8 +44,8 @@ public:
virtual void push_attr(const node_t::nameid_t name_id,
const string& value) = 0;
virtual void begin_node(const string& name) = 0;
virtual void begin_node(const node_t::nameid_t name_id) = 0;
virtual void begin_node(const string& name, bool terminal = false) = 0;
virtual void begin_node(const node_t::nameid_t name_id, bool terminal = false) = 0;
virtual void push_node(const string& name,
const optional<position_t>& end_pos = none) = 0;
@ -70,8 +70,71 @@ public:
* This builder can be used to parse ordinary XML into a document
* object structure which can then be traversed in memory.
*/
class xml_builder_t : public builder_t
class document_builder_t : public builder_t
{
public:
typedef std::list<std::pair<node_t::nameid_t, string> > attrs_list;
document_t& document;
attrs_list current_attrs;
node_t * current;
string current_text;
document_builder_t(document_t& _document)
: document(_document), current(&document) {}
virtual void push_attr(const string& name,
const string& value) {
push_attr(document.register_name(name), value);
}
virtual void push_attr(const node_t::nameid_t name_id,
const string& value) {
current_attrs.push_back(attrs_list::value_type(name_id, value.c_str()));
}
virtual void begin_node(const string& name, bool terminal = false) {
begin_node(document.register_name(name), terminal);
}
virtual void begin_node(const node_t::nameid_t name_id,
bool terminal = false) {
if (terminal)
current = current->as_parent_node().create_child<terminal_node_t>(name_id);
else
current = current->as_parent_node().create_child<parent_node_t>(name_id);
foreach (const attrs_list::value_type& pair, current_attrs)
current->set_attr(pair.first, pair.second.c_str());
current_attrs.clear();
}
virtual void push_node(const string& name,
const optional<position_t>& end_pos = none) {
begin_node(name, true);
end_node(name, end_pos);
}
virtual void push_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos = none) {
begin_node(name_id, true);
end_node(name_id, end_pos);
}
virtual node_t * current_node() {
return current;
}
virtual void append_text(const string& text) {
assert(! current->is_parent_node());
polymorphic_downcast<terminal_node_t *>(current)->set_text(text);
}
virtual node_t * end_node(const string& name,
const optional<position_t>& end_pos = none) {
current = &*current->parent();
}
virtual node_t * end_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos = none) {
current = &*current->parent();
}
};
/**
@ -91,7 +154,7 @@ class xml_builder_t : public builder_t
* constructed on the fly, as if they'd been created in the first
* place by a regular xml_builder_t.
*/
class journal_builder_t : public xml_builder_t
class journal_builder_t : public document_builder_t
{
public:
virtual void set_start_position(std::istream& in) {
@ -138,20 +201,20 @@ public:
push_attr("hello", value);
}
virtual void begin_node(const string& name) {
virtual void begin_node(const string& name, bool terminal = false) {
outs << '<' << name;
foreach (const attrs_list::value_type& attr, current_attrs)
outs << ' ' << attr.first << "=\"" << attr.second << "\"";
current_attrs.clear();
outs << '>';
}
virtual void begin_node(const node_t::nameid_t name_id) {
virtual void begin_node(const node_t::nameid_t name_id, bool terminal = false) {
begin_node("hello");
}
virtual void push_node(const string& name,
const optional<position_t>& end_pos = none) {
begin_node(name);
begin_node(name, true);
end_node(name, end_pos);
}
virtual void push_node(const node_t::nameid_t name_id,

View file

@ -455,14 +455,8 @@ commodity_t * commodity_pool_t::create(const string& symbol)
commodity->ident = commodities.size();
std::pair<commodities_t::iterator, bool> result =
commodities.insert(commodity.get());
if (! result.second) {
assert(false);
return NULL;
} else {
return commodity.release();
}
commodities.push_back(commodity.get());
return commodity.release();
}
commodity_t * commodity_pool_t::find_or_create(const string& symbol)
@ -498,11 +492,7 @@ commodity_t * commodity_pool_t::find(const commodity_t::ident_t ident)
commodities_by_ident;
commodities_by_ident& ident_index = commodities.get<0>();
commodities_by_ident::iterator i = ident_index.find(ident);
if (i != ident_index.end())
return *i;
else
return NULL;
return ident_index[ident];
}
commodity_t *
@ -598,14 +588,8 @@ commodity_pool_t::create(commodity_t& comm,
commodity->ident = commodities.size();
commodity->mapping_key_ = mapping_key;
std::pair<commodities_t::iterator, bool> result
= commodities.insert(commodity.get());
if (! result.second) {
assert(false);
return NULL;
} else {
return commodity.release();
}
commodities.push_back(commodity.get());
return commodity.release();
}
commodity_t * commodity_pool_t::find_or_create(commodity_t& comm,

View file

@ -318,9 +318,7 @@ class commodity_pool_t : public noncopyable
typedef multi_index_container<
commodity_t *,
multi_index::indexed_by<
multi_index::ordered_unique<
multi_index::member<commodity_t,
commodity_t::ident_t, &commodity_t::ident> >,
multi_index::random_access<>,
multi_index::hashed_unique<
multi_index::const_mem_fun<commodity_t,
string, &commodity_t::mapping_key> >

View file

@ -29,8 +29,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _XML_H
#define _XML_H
#ifndef _NODE_H
#define _NODE_H
#include "journal.h"
#include "value.h"
@ -507,4 +507,4 @@ wrap_node(document_t * doc, journal_t * journal, void * parent_node) {
} // namespace xml
} // namespace ledger
#endif // _XML_H
#endif // _NODE_H

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/

View file

@ -1,209 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "derive.h"
#include "mask.h"
namespace ledger {
void derive_command::operator()
(value_t& result, xml::xpath_t::scope_t * locals)
{
#if 0
std::ostream& out = *get_ptr<std::ostream>(locals, 0);
repitem_t * items = get_ptr<repitem_t>(locals, 1);
strings_list& args = *get_ptr<strings_list *>(locals, 2);
std::auto_ptr<entry_t> added(new entry_t);
entry_t * matching = NULL;
strings_list::iterator i = args.begin();
added->_date = *i++;
if (i == args.end())
throw new error("Too few arguments to 'entry'");
mask_t regexp(*i++);
entries_list::reverse_iterator j;
for (j = journal.entries.rbegin();
j != journal.entries.rend();
j++)
if (regexp.match((*j)->payee)) {
matching = *j;
break;
}
added->payee = matching ? matching->payee : regexp.pattern;
if (! matching) {
account_t * acct;
if (i == args.end() || ((*i)[0] == '-' || std::isdigit((*i)[0]))) {
acct = journal.find_account("Expenses");
}
else if (i != args.end()) {
acct = journal.find_account_re(*i);
if (! acct)
acct = journal.find_account(*i);
assert(acct);
i++;
}
if (i == args.end()) {
added->add_transaction(new transaction_t(acct));
} else {
transaction_t * xact = new transaction_t(acct, amount_t(*i++));
added->add_transaction(xact);
if (! xact->amount.commodity()) {
// If the amount has no commodity, we can determine it given
// the account by creating a final for the account and then
// checking if it contains only a single commodity. An
// account to which only dollars are applied would imply that
// dollars are wanted now too.
std::auto_ptr<item_handler<transaction_t> > formatter;
formatter.reset(new set_account_value);
walk_entries(journal.entries, *formatter.get());
formatter->flush();
sum_accounts(*journal.master);
value_t total = account_xdata(*acct).total;
if (total.type == value_t::AMOUNT)
xact->amount.set_commodity(((amount_t *) total.data)->commodity());
}
}
if (journal.basket)
acct = journal.basket;
else
acct = journal.find_account("Equity");
added->add_transaction(new transaction_t(acct));
}
else if (i == args.end()) {
// If no argument were given but the payee, assume the user wants
// to see the same transaction as last time.
added->code = matching->code;
for (transactions_list::iterator k = matching->transactions.begin();
k != matching->transactions.end();
k++)
added->add_transaction(new transaction_t(**k));
}
else if ((*i)[0] == '-' || std::isdigit((*i)[0])) {
transaction_t * m_xact, * xact, * first;
m_xact = matching->transactions.front();
first = xact = new transaction_t(m_xact->account, amount_t(*i++));
added->add_transaction(xact);
if (! xact->amount.commodity())
xact->amount.set_commodity(m_xact->amount.commodity());
m_xact = matching->transactions.back();
xact = new transaction_t(m_xact->account, - first->amount);
added->add_transaction(xact);
if (i != args.end()) {
account_t * acct = journal.find_account_re(*i);
if (! acct)
acct = journal.find_account(*i);
assert(acct);
added->transactions.back()->account = acct;
}
}
else {
while (i != args.end()) {
string& re_pat(*i++);
account_t * acct = NULL;
amount_t * amt = NULL;
mask_t acct_regex(re_pat);
for (; j != journal.entries.rend(); j++)
if (regexp.match((*j)->payee)) {
entry_t * entry = *j;
for (transactions_list::const_iterator x =
entry->transactions.begin();
x != entry->transactions.end();
x++)
if (acct_regex.match((*x)->account->fullname())) {
acct = (*x)->account;
amt = &(*x)->amount;
matching = entry;
goto found;
}
}
found:
if (! acct)
acct = journal.find_account_re(re_pat);
if (! acct)
acct = journal.find_account(re_pat);
transaction_t * xact;
if (i == args.end()) {
if (amt)
xact = new transaction_t(acct, *amt);
else
xact = new transaction_t(acct);
} else {
xact = new transaction_t(acct, amount_t(*i++));
if (! xact->amount.commodity()) {
if (amt)
xact->amount.set_commodity(amt->commodity());
else if (commodity_t::default_commodity)
xact->amount.set_commodity(*commodity_t::default_commodity);
}
}
added->add_transaction(xact);
}
assert(matching->transactions.back()->account);
if (account_t * draw_acct = matching->transactions.back()->account)
added->add_transaction(new transaction_t(draw_acct));
}
done:
if (! run_hooks(journal.entry_finalize_hooks, *added, false) ||
! added->finalize() ||
! run_hooks(journal.entry_finalize_hooks, *added, true))
throw new error("Failed to finalize derived entry (check commodities)");
return added.release();
#endif
}
} // namespace ledger

View file

@ -1,49 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
#ifndef _DERIVE_H
#define _DERIVE_H
#include "xpath.h"
namespace ledger {
class derive_command : public xml::xpath_t::functor_t
{
public:
derive_command() : xml::xpath_t::functor_t("entry", true) {}
virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals);
};
} // namespace ledger
#endif // _DERIVE_H

177
src/document.cc Normal file
View file

@ -0,0 +1,177 @@
/*
* Copyright (c) 2003-2007, 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 "document.h"
namespace ledger {
namespace xml {
namespace {
const std::size_t ledger_builtins_size = 39;
const char * ledger_builtins[] = {
"account",
"account-path",
"amount",
"amount-expr",
"arg",
"auto-entry",
"balance",
"checkin",
"cleared",
"code",
"commodity",
"commodity-conversion",
"commodity-nomarket",
"commodity-template",
"current-year",
"date",
"default-account",
"directive",
"effective",
"entries",
"entry",
"from",
"journal",
"ledger",
"name",
"note",
"payee",
"pending",
"period",
"period-entry",
"price",
"price-history",
"rule",
"symbol",
"template",
"time",
"to",
"transaction",
"virtual",
"year"
};
}
node_t::nameid_t document_t::register_name(const string& name)
{
optional<nameid_t> index = lookup_name_id(name);
if (index)
return *index;
if (! names)
names = names_t();
nameid_t real_index = names->size() + 1000;
names->push_back(name_pair(name, real_index));
DEBUG("xml.lookup", this << " Inserted name: " << name);
return real_index;
}
optional<node_t::nameid_t> document_t::lookup_name_id(const string& name) const
{
if (optional<node_t::nameid_t> id = lookup_builtin_id(name))
return id;
if (! names)
return none;
DEBUG("xml.lookup", this << " Finding name: " << name);
typedef names_t::nth_index<1>::type names_by_name;
const names_by_name& name_index = names->get<1>();
names_by_name::const_iterator i = name_index.find(name);
if (i != name_index.end())
return (*i).second;
return none;
}
optional<node_t::nameid_t> document_t::lookup_builtin_id(const string& name)
{
int first = 0;
int last = (int)ledger_builtins_size;
while (first <= last) {
int mid = (first + last) / 2; // compute mid point.
int result;
if ((result = (int)name[0] - (int)ledger_builtins[mid][0]) == 0)
result = std::strcmp(name.c_str(), ledger_builtins[mid]);
if (result > 0)
first = mid + 1; // repeat search in top half.
else if (result < 0)
last = mid - 1; // repeat search in bottom half.
else
return nameid_t(mid + 10);
}
return none;
}
optional<const char *> document_t::lookup_name(nameid_t id) const
{
if (id < 1000) {
switch (id) {
case CURRENT:
return "CURRENT";
case PARENT:
return "PARENT";
case ROOT:
return "ROOT";
case ALL:
return "ALL";
default:
assert(id >= 10);
return ledger_builtins[id - 10];
}
}
else if (names) {
int index = id - 1000;
typedef names_t::nth_index<0>::type names_by_random_access;
const names_by_random_access& random_access = names->get<0>();
if (index < random_access.size())
return random_access[index].first.c_str();
}
return none;
}
void document_t::print(std::ostream& out) const
{
out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
parent_node_t::print(out);
}
} // namespace xml
} // namespace ledger

150
src/document.h Normal file
View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2003-2007, 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.
*/
#ifndef _DOCUMENT_H
#define _DOCUMENT_H
#include "node.h"
#include "value.h"
namespace ledger {
namespace xml {
enum ledger_builtins_t {
ACCOUNT_ATTR = 10,
ACCOUNT_PATH_NODE,
AMOUNT_NODE,
AMOUNT_EXPR_NODE,
ARG_ATTR,
AUTO_ENTRY_NODE,
BALANCE_ATTR,
CHECKIN_NODE,
CLEARED_ATTR,
CODE_ATTR,
COMMODITY_NODE,
COMMODITY_CONVERSION_NODE,
COMMODITY_NOMARKET_NODE,
COMMODITY_TEMPLATE_NODE,
CURRENT_YEAR_NODE,
DATE_ATTR,
DEFAULT_ACCOUNT_NODE,
DIRECTIVE_NODE,
EFF_DATE_ATTR,
ENTRIES_NODE,
ENTRY_NODE,
FROM_ATTR,
JOURNAL_NODE,
LEDGER_NODE,
NAME_ATTR,
NOTE_NODE,
PAYEE_NODE,
PENDING_ATTR,
PERIOD_NODE,
PERIOD_ENTRY_NODE,
PRICE_ATTR,
PRICE_HISTORY_NODE,
RULE_NODE,
SYMBOL_ATTR,
TEMPLATE_ATTR,
TIME_ATTR,
TO_ATTR,
TRANSACTION_NODE,
VIRTUAL_ATTR,
YEAR_ATTR
};
class document_t : public parent_node_t
{
typedef std::pair<string, nameid_t> name_pair;
typedef multi_index_container<
name_pair,
multi_index::indexed_by<
multi_index::random_access<>,
multi_index::hashed_unique<
multi_index::member<name_pair, string, &name_pair::first> >
>
> names_t;
optional<names_t> names;
public:
// Ids 0-9 are reserved. 10-999 are for "builtin" names. 1000+ are
// for dynamically registered names.
enum special_names_t {
CURRENT, PARENT, ROOT, ALL
};
document_t(node_t::nameid_t _name_id)
: parent_node_t(_name_id, *this) {
TRACE_CTOR(xml::document_t, "node_t::nameid_t");
}
~document_t() {
TRACE_DTOR(xml::document_t);
}
nameid_t register_name(const string& name);
optional<nameid_t> lookup_name_id(const string& name) const;
static optional<nameid_t> lookup_builtin_id(const string& name);
optional<const char *> lookup_name(nameid_t id) const;
void print(std::ostream& out) const;
#if 0
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
class parser_t
{
public:
document_t * document;
XML_Parser parser;
string have_error;
const char * pending;
node_t::attrs_map * pending_attrs;
bool handled_data;
std::list<parent_node_t *> node_stack;
parser_t() : document(NULL), pending(NULL), pending_attrs(NULL),
handled_data(false) {}
virtual ~parser_t() {}
virtual bool test(std::istream& in) const;
virtual document_t * parse(std::istream& in);
};
#endif
#endif
};
} // namespace xml
} // namespace ledger
#endif // _DOCUMENT_H

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/

View file

@ -1,397 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "gnucash.h"
namespace ledger {
void startElement(void *userData, const char *name, const char ** /* attrs */)
{
gnucash_parser_t * parser = static_cast<gnucash_parser_t *>(userData);
if (std::strcmp(name, "gnc:account") == 0) {
parser->curr_account = new account_t(parser->master_account);
}
else if (std::strcmp(name, "act:name") == 0)
parser->action = gnucash_parser_t::ACCOUNT_NAME;
else if (std::strcmp(name, "act:id") == 0)
parser->action = gnucash_parser_t::ACCOUNT_ID;
else if (std::strcmp(name, "act:parent") == 0)
parser->action = gnucash_parser_t::ACCOUNT_PARENT;
else if (std::strcmp(name, "gnc:commodity") == 0)
parser->curr_comm = NULL;
else if (std::strcmp(name, "cmdty:id") == 0)
parser->action = gnucash_parser_t::COMM_SYM;
else if (std::strcmp(name, "cmdty:name") == 0)
parser->action = gnucash_parser_t::COMM_NAME;
else if (std::strcmp(name, "cmdty:fraction") == 0)
parser->action = gnucash_parser_t::COMM_PREC;
else if (std::strcmp(name, "gnc:transaction") == 0) {
assert(! parser->curr_entry);
parser->curr_entry = new entry_t;
}
else if (std::strcmp(name, "trn:num") == 0)
parser->action = gnucash_parser_t::ENTRY_NUM;
else if (std::strcmp(name, "trn:date-posted") == 0)
parser->action = gnucash_parser_t::ALMOST_ENTRY_DATE;
else if (parser->action == gnucash_parser_t::ALMOST_ENTRY_DATE &&
std::strcmp(name, "ts:date") == 0)
parser->action = gnucash_parser_t::ENTRY_DATE;
else if (std::strcmp(name, "trn:description") == 0)
parser->action = gnucash_parser_t::ENTRY_DESC;
else if (std::strcmp(name, "trn:split") == 0) {
assert(parser->curr_entry);
parser->curr_entry->add_transaction(new transaction_t(parser->curr_account));
}
else if (std::strcmp(name, "split:reconciled-state") == 0)
parser->action = gnucash_parser_t::XACT_STATE;
else if (std::strcmp(name, "split:amount") == 0)
parser->action = gnucash_parser_t::XACT_AMOUNT;
else if (std::strcmp(name, "split:value") == 0)
parser->action = gnucash_parser_t::XACT_VALUE;
else if (std::strcmp(name, "split:quantity") == 0)
parser->action = gnucash_parser_t::XACT_QUANTITY;
else if (std::strcmp(name, "split:account") == 0)
parser->action = gnucash_parser_t::XACT_ACCOUNT;
else if (std::strcmp(name, "split:memo") == 0)
parser->action = gnucash_parser_t::XACT_NOTE;
}
void endElement(void *userData, const char *name)
{
gnucash_parser_t * parser = static_cast<gnucash_parser_t *>(userData);
if (std::strcmp(name, "gnc:account") == 0) {
assert(parser->curr_account);
if (parser->curr_account->parent == parser->master_account)
parser->curr_journal->add_account(parser->curr_account);
parser->accounts_by_id.insert
(accounts_map::value_type(parser->curr_account_id, parser->curr_account));
parser->curr_account = NULL;
}
else if (std::strcmp(name, "gnc:commodity") == 0) {
parser->curr_comm = NULL;
}
else if (std::strcmp(name, "gnc:transaction") == 0) {
assert(parser->curr_entry);
// Add the new entry (what gnucash calls a 'transaction') to the
// journal
if (! parser->curr_journal->add_entry(parser->curr_entry)) {
print_entry(std::cerr, *parser->curr_entry);
parser->have_error = "The above entry does not balance";
checked_delete(parser->curr_entry);
} else {
parser->curr_entry->src_idx = parser->src_idx;
parser->curr_entry->beg_pos = parser->beg_pos;
parser->curr_entry->beg_line = parser->beg_line;
parser->curr_entry->end_pos = parser->instreamp->tellg();
parser->curr_entry->end_line =
XML_GetCurrentLineNumber(parser->expat_parser) - parser->offset;
parser->count++;
}
// Clear the relevant variables for the next run
parser->curr_entry = NULL;
parser->entry_comm = NULL;
}
else if (std::strcmp(name, "trn:split") == 0) {
transaction_t * xact = parser->curr_entry->transactions.back();
// Identify the commodity to use for the value of this
// transaction. The quantity indicates how many times that value
// the transaction is worth.
amount_t value;
commodity_t * default_commodity = NULL;
if (parser->entry_comm) {
default_commodity = parser->entry_comm;
} else {
gnucash_parser_t::account_comm_map::iterator ac =
parser->account_comms.find(xact->account);
if (ac != parser->account_comms.end())
default_commodity = (*ac).second;
}
if (default_commodity) {
parser->curr_quant.set_commodity(*default_commodity);
value = parser->curr_quant.round();
if (parser->curr_value.commodity() == *default_commodity)
parser->curr_value = value;
} else {
value = parser->curr_quant;
}
xact->state = parser->curr_state;
xact->amount = value;
if (value != parser->curr_value)
xact->cost = amount_t(parser->curr_value);
xact->beg_pos = parser->beg_pos;
xact->beg_line = parser->beg_line;
xact->end_pos = parser->instreamp->tellg();
xact->end_line =
XML_GetCurrentLineNumber(parser->expat_parser) - parser->offset;
// Clear the relevant variables for the next run
parser->curr_state = transaction_t::UNCLEARED;
parser->curr_value = amount_t();
parser->curr_quant = amount_t();
}
parser->action = gnucash_parser_t::NO_ACTION;
}
amount_t gnucash_parser_t::convert_number(const string& number,
int * precision)
{
const char * num = number.c_str();
if (char * p = std::strchr(num, '/')) {
string numer_str(num, p - num);
string denom_str(p + 1);
amount_t amt(numer_str);
amount_t den(denom_str);
if (precision)
*precision = denom_str.length() - 1;
if (! den) {
have_error = "Denominator in entry is zero!";
return amt;
} else {
return amt / den;
}
} else {
return amount_t(number);
}
}
void dataHandler(void *userData, const char *s, int len)
{
gnucash_parser_t * parser = static_cast<gnucash_parser_t *>(userData);
switch (parser->action) {
case gnucash_parser_t::ACCOUNT_NAME:
parser->curr_account->name = string(s, len);
break;
case gnucash_parser_t::ACCOUNT_ID:
parser->curr_account_id = string(s, len);
break;
case gnucash_parser_t::ACCOUNT_PARENT: {
accounts_map::iterator i = parser->accounts_by_id.find(string(s, len));
assert(i != parser->accounts_by_id.end());
parser->curr_account->parent = (*i).second;
parser->curr_account->depth = parser->curr_account->parent->depth + 1;
(*i).second->add_account(parser->curr_account);
break;
}
case gnucash_parser_t::COMM_SYM: {
string symbol(s, len);
if (symbol == "USD") symbol = "$";
parser->curr_comm = amount_t::current_pool->find_or_create(symbol);
assert(parser->curr_comm);
if (symbol != "$")
parser->curr_comm->add_flags(COMMODITY_STYLE_SEPARATED);
if (parser->curr_account)
parser->account_comms.insert
(gnucash_parser_t::account_comm_map::value_type
(parser->curr_account, parser->curr_comm));
else if (parser->curr_entry)
parser->entry_comm = parser->curr_comm;
break;
}
case gnucash_parser_t::COMM_NAME:
parser->curr_comm->set_name(string(s, len));
break;
case gnucash_parser_t::COMM_PREC:
parser->curr_comm->set_precision(len - 1);
break;
case gnucash_parser_t::ENTRY_NUM:
parser->curr_entry->code = string(s, len);
break;
case gnucash_parser_t::ENTRY_DATE:
parser->curr_entry->_date = parse_datetime(string(s, len));
break;
case gnucash_parser_t::ENTRY_DESC:
parser->curr_entry->payee = string(s, len);
break;
case gnucash_parser_t::XACT_STATE:
if (*s == 'y')
parser->curr_state = transaction_t::CLEARED;
else if (*s == 'n')
parser->curr_state = transaction_t::UNCLEARED;
else
parser->curr_state = transaction_t::PENDING;
break;
case gnucash_parser_t::XACT_VALUE: {
int precision;
assert(parser->entry_comm);
parser->curr_value = parser->convert_number(string(s, len), &precision);
parser->curr_value.set_commodity(*parser->entry_comm);
if (precision > parser->entry_comm->precision())
parser->entry_comm->set_precision(precision);
break;
}
case gnucash_parser_t::XACT_QUANTITY:
parser->curr_quant = parser->convert_number(string(s, len));
break;
case gnucash_parser_t::XACT_ACCOUNT: {
transaction_t * xact = parser->curr_entry->transactions.back();
accounts_map::iterator i =
parser->accounts_by_id.find(string(s, len));
if (i != parser->accounts_by_id.end()) {
xact->account = (*i).second;
} else {
xact->account = parser->curr_journal->find_account("<Unknown>");
parser->have_error = (string("Could not find account ") +
string(s, len));
}
break;
}
case gnucash_parser_t::XACT_NOTE:
parser->curr_entry->transactions.back()->note = string(s, len);
break;
case gnucash_parser_t::NO_ACTION:
case gnucash_parser_t::ALMOST_ENTRY_DATE:
case gnucash_parser_t::XACT_AMOUNT:
break;
default:
assert(false);
break;
}
}
bool gnucash_parser_t::test(std::istream& in) const
{
char buf[5];
in.read(buf, 5);
in.clear();
in.seekg(0, std::ios::beg);
return std::strncmp(buf, "<?xml", 5) == 0;
}
unsigned int gnucash_parser_t::parse(std::istream& in,
journal_t * journal,
account_t * master,
const optional<path>& original_file)
{
char buf[BUFSIZ];
// This is the date format used by Gnucash, so override whatever the
// user specified.
//
// jww (2006-09-13): Make this parser local somehow.
//date_t::input_format = "%Y-%m-%d %H:%M:%S %z";
count = 0;
action = NO_ACTION;
curr_journal = journal;
master_account = master ? master : journal->master;
curr_account = NULL;
curr_entry = NULL;
curr_comm = NULL;
entry_comm = NULL;
curr_state = transaction_t::UNCLEARED;
instreamp = &in;
pathname = original_file ? *original_file : "<gnucash>";
src_idx = journal->sources.size() - 1;
// GnuCash uses the USD commodity without defining it, which really
// means $.
commodity_t * usd = amount_t::current_pool->find_or_create("$");
usd->set_precision(2);
usd->add_flags(COMMODITY_STYLE_THOUSANDS);
offset = 2;
expat_parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, startElement, endElement);
XML_SetCharacterDataHandler(parser, dataHandler);
XML_SetUserData(parser, this);
while (in.good() && ! in.eof()) {
beg_pos = in.tellg();
beg_line = (XML_GetCurrentLineNumber(parser) - offset) + 1;
in.getline(buf, BUFSIZ - 1);
std::strcat(buf, "\n");
if (! XML_Parse(parser, buf, std::strlen(buf), in.eof())) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * msg = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser);
throw_(parse_error, msg);
}
if (! have_error.empty()) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
#if 0
// jww (2007-04-26): What is this doing?
parse_error err(have_error);
std::cerr << "Error: " << err.what() << std::endl;
#endif
have_error = "";
}
}
XML_ParserFree(parser);
accounts_by_id.clear();
curr_account_id.clear();
return count;
}
} // namespace ledger

View file

@ -1,103 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
#ifndef _GNUCASH_H
#define _GNUCASH_H
#include "parser.h"
#include "journal.h"
namespace ledger {
struct gnucash_parser_t : public parser_t
{
typedef std::map<const string, account_t *> accounts_map;
typedef std::map<account_t *, commodity_t *> account_comm_map;
journal_t * curr_journal;
account_t * master_account;
account_t * curr_account;
string curr_account_id;
entry_t * curr_entry;
commodity_t * entry_comm;
commodity_t * curr_comm;
amount_t curr_value;
amount_t curr_quant;
XML_Parser expat_parser;
accounts_map accounts_by_id;
account_comm_map account_comms;
unsigned int count;
string have_error;
std::istream * instreamp;
unsigned int offset;
XML_Parser parser;
path pathname;
unsigned int src_idx;
unsigned long beg_pos;
unsigned long beg_line;
transaction_t::state_t curr_state;
enum action_t {
NO_ACTION,
ACCOUNT_NAME,
ACCOUNT_ID,
ACCOUNT_PARENT,
COMM_SYM,
COMM_NAME,
COMM_PREC,
ENTRY_NUM,
ALMOST_ENTRY_DATE,
ENTRY_DATE,
ENTRY_DESC,
XACT_STATE,
XACT_AMOUNT,
XACT_VALUE,
XACT_QUANTITY,
XACT_ACCOUNT,
XACT_NOTE
} action;
public:
virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none);
amount_t convert_number(const string& number, int * precision = NULL);
};
} // namespace ledger
#endif // _GNUCASH_H

View file

@ -364,6 +364,7 @@ auto_entry_t::~auto_entry_t() {
void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
{
#if 0
transactions_list initial_xacts(entry.transactions.begin(),
entry.transactions.end());
@ -400,6 +401,7 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
}
}
}
#endif
}
account_t::~account_t()

View file

@ -44,10 +44,9 @@
#include <amount.h>
#include <balance.h>
#include <value.h>
#include <xml.h>
#include <xpath.h>
#include <format.h>
#include <quotes.h>
//#include <quotes.h>
#include <session.h>
#include <journal.h>

View file

@ -186,8 +186,8 @@ static int read_and_report(report_t * report, int argc, char * argv[],
std::cout << "Result of calculation: ";
}
std::cout << expr.calc((xml::document_t *)NULL, report).
strip_annotations() << std::endl;
xml::document_t temp(xml::LEDGER_NODE);
std::cout << expr.calc(temp, report).strip_annotations() << std::endl;
return 0;
}
@ -215,8 +215,16 @@ static int read_and_report(report_t * report, int argc, char * argv[],
{
textual_parser_t text_parser;
ifstream input(session.data_file);
#if 1
xml::document_t temp(xml::LEDGER_NODE);
xml::document_builder_t builder(temp);
text_parser.parse(input, session.data_file, builder);
temp.print(std::cout);
#else
xml::xml_writer_t writer(std::cout);
text_parser.parse(input, session.data_file, writer);
#endif
}
INFO_FINISH(journal);
return 0;
@ -292,8 +300,8 @@ static int read_and_report(report_t * report, int argc, char * argv[],
*out << "Result of calculation: ";
}
*out << expr.calc((xml::document_t *)NULL, report).
strip_annotations() << std::endl;
xml::document_t temp(xml::LEDGER_NODE);
*out << expr.calc(temp, report).strip_annotations() << std::endl;
return 0;
}

View file

@ -29,35 +29,72 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QUOTES_H
#define _QUOTES_H
#include "amount.h"
#include "node.h"
#include "document.h"
namespace ledger {
namespace xml {
class quotes_by_script
const char * node_t::name() const
{
path price_db;
time_duration pricing_leeway;
bool& cache_dirty;
return *document().lookup_name(name_id());
}
public:
quotes_by_script(path _price_db,
time_duration _pricing_leeway,
bool& _cache_dirty)
: price_db(_price_db), pricing_leeway(_pricing_leeway),
cache_dirty(_cache_dirty) {}
void output_xml_string(std::ostream& out, const string& str)
{
for (const char * s = str.c_str(); *s; s++) {
switch (*s) {
case '<':
out << "&lt;";
break;
case '>':
out << "&gt;";
break;
case '&':
out << "&amp;";
break;
default:
out << *s;
break;
}
}
}
virtual optional<amount_t>
operator()(commodity_t& commodity,
const optional<moment_t>& date,
const optional<moment_t>& moment,
const optional<moment_t>& last);
};
void parent_node_t::print(std::ostream& out) const
{
out << '<' << name();
if (attributes) {
typedef attributes_t::nth_index<0>::type attributes_by_order;
foreach (const attr_pair& attr, attributes->get<0>())
out << ' ' << document().lookup_name(attr.first)
<< "=\"" << attr.second << "\"";
}
IF_VERIFY()
out << " type=\"parent_node_t\"";
out << '>';
DECLARE_EXCEPTION(download_error);
foreach (node_t * child, *this)
child->print(out);
out << "</" << name() << '>';
}
void terminal_node_t::print(std::ostream& out) const
{
if (data.empty()) {
out << '<' << name();
IF_VERIFY()
out << " type=\"terminal_node_t\"";
out << " />";
} else {
out << '<' << name();
IF_VERIFY()
out << " type=\"terminal_node_t\"";
out << '>';
output_xml_string(out, text());
out << "</" << name() << '>';
}
}
} // namespace xml
} // namespace ledger
#endif // _QUOTES_H

276
src/node.h Normal file
View file

@ -0,0 +1,276 @@
/*
* Copyright (c) 2003-2007, 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.
*/
#ifndef _NODE_H
#define _NODE_H
#include "journal.h"
#include "value.h"
//#include "parser.h"
namespace ledger {
class transaction_t;
class entry_t;
class account_t;
class journal_t;
namespace xml {
#define XML_NODE_IS_PARENT 0x1
DECLARE_EXCEPTION(conversion_error);
class parent_node_t;
class document_t;
class node_t : public supports_flags<>, public noncopyable
{
public:
typedef uint_fast16_t nameid_t;
nameid_t name_id_;
protected:
document_t& document_;
optional<parent_node_t&> parent_;
typedef std::pair<nameid_t, string> attr_pair;
typedef multi_index_container<
attr_pair,
multi_index::indexed_by<
multi_index::sequenced<>,
multi_index::hashed_unique<
multi_index::member<attr_pair, nameid_t, &attr_pair::first> >
>
> attributes_t;
optional<attributes_t> attributes;
public:
node_t(nameid_t _name_id, document_t& _document,
const optional<parent_node_t&>& _parent = none, flags_t _flags = 0)
: supports_flags<>(_flags), name_id_(_name_id),
document_(_document), parent_(_parent) {
TRACE_CTOR(node_t, "document_t&, parent_node_t&, nameid_t, flags_t");
}
virtual ~node_t() {
TRACE_DTOR(node_t);
}
bool is_parent_node() const {
return has_flags(XML_NODE_IS_PARENT);
}
parent_node_t& as_parent_node() {
if (! is_parent_node())
throw_(std::logic_error, "Request to cast leaf node to a parent node");
return *polymorphic_downcast<parent_node_t *>(this);
}
const parent_node_t& as_parent_node() const {
if (! is_parent_node())
throw_(std::logic_error, "Request to cast leaf node to a parent node");
return *polymorphic_downcast<const parent_node_t *>(this);
}
virtual value_t to_value() const = 0;
virtual void print(std::ostream& out) const = 0;
const char * name() const;
nameid_t name_id() const {
return name_id_;
}
document_t& document() const {
return document_;
}
optional<parent_node_t&> parent() const {
return parent_;
}
void set_attr(const nameid_t _name_id, const char * value) {
if (! attributes)
attributes = attributes_t();
attributes->push_back(attr_pair(_name_id, value));
}
optional<const string&> get_attr(const nameid_t _name_id) {
if (attributes) {
typedef attributes_t::nth_index<1>::type attributes_by_name;
attributes_by_name& name_index = attributes->get<1>();
attributes_by_name::iterator i = name_index.find(_name_id);
if (i != name_index.end())
return (*i).second;
}
return none;
}
};
class parent_node_t : public node_t
{
typedef multi_index_container<
node_t *,
multi_index::indexed_by<
multi_index::sequenced<>,
multi_index::hashed_non_unique<
multi_index::member<node_t, nameid_t, &node_t::name_id_> >,
multi_index::hashed_unique<multi_index::identity<node_t *> >
>
> children_t;
children_t children;
public:
typedef children_t::nth_index<0>::type children_by_order;
typedef children_t::nth_index<1>::type children_by_nameid;
typedef children_t::nth_index<2>::type children_by_ptr;
parent_node_t(nameid_t _name_id, document_t& _document,
const optional<parent_node_t&>& _parent = none)
: node_t(_name_id, _document, _parent, XML_NODE_IS_PARENT) {
TRACE_CTOR(parent_node_t, "document_t *, parent_node_t *");
}
virtual ~parent_node_t() {
TRACE_DTOR(parent_node_t);
clear_children();
}
template <typename T>
T * create_child(nameid_t _name_id) {
T * child = new T(_name_id, document(), *this);
children.push_back(child);
}
void delete_child(node_t * child) {
children_by_ptr& ptr_index = children.get<2>();
children_by_ptr::iterator i = ptr_index.find(child);
if (i == ptr_index.end())
throw_(std::logic_error, "Request to delete node which is not a child");
node_t * ptr = *i;
ptr_index.erase(i);
checked_delete(ptr);
}
struct match_nameid {
nameid_t nameid;
match_nameid(nameid_t _nameid) : nameid(_nameid) {}
bool operator()(const node_t * node) const {
return node->name_id() == nameid;
}
};
typedef children_by_order::iterator iterator;
typedef children_by_order::iterator const_iterator;
children_by_order::iterator begin() {
return children.get<0>().begin();
}
children_by_order::const_iterator begin() const {
return children.get<0>().begin();
}
children_by_order::iterator end() {
return children.get<0>().end();
}
children_by_order::const_iterator end() const {
return children.get<0>().end();
}
children_by_nameid::iterator begin(nameid_t _name_id) {
return std::find_if(children.get<1>().begin(),
children.get<1>().end(), match_nameid(_name_id));
}
children_by_nameid::const_iterator begin(nameid_t _name_id) const {
return std::find_if(children.get<1>().begin(),
children.get<1>().end(), match_nameid(_name_id));
}
children_by_nameid::iterator end(nameid_t) {
return children.get<1>().end();
}
children_by_nameid::const_iterator end(nameid_t) const {
return children.get<1>().end();
}
void clear_children() {
typedef children_t::nth_index<0>::type children_by_index;
children_by_index& child_index = children.get<0>();
for (children_by_index::iterator i = child_index.begin();
i != child_index.end();
i++)
checked_delete(*i);
children.clear();
}
virtual value_t to_value() const {
throw_(std::logic_error, "Cannot convert parent node to a value");
}
void print(std::ostream& out) const;
};
class terminal_node_t : public node_t
{
string data;
public:
terminal_node_t(nameid_t _name_id, document_t& _document,
const optional<parent_node_t&>& _parent = none)
: node_t(_name_id, _document, _parent)
{
TRACE_CTOR(terminal_node_t, "document_t *, parent_node_t *");
}
virtual ~terminal_node_t() {
TRACE_DTOR(terminal_node_t);
}
const char * text() const {
return data.c_str();
}
void set_text(const string& _data) {
data = _data;
}
void set_text(const char * _data) {
data = _data;
}
virtual value_t to_value() const {
return text();
}
void print(std::ostream& out) const;
};
} // namespace xml
} // namespace ledger
#endif // _NODE_H

View file

@ -1,246 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "ofx.h"
namespace ledger {
typedef std::map<const string, account_t *> accounts_map;
typedef std::map<const string, commodity_t *> commodities_map;
journal_t * curr_journal;
accounts_map ofx_accounts;
commodities_map ofx_account_currencies;
commodities_map ofx_securities;
account_t * master_account;
int ofx_proc_statement_cb(struct OfxStatementData data, void * statement_data)
{
}
int ofx_proc_account_cb(struct OfxAccountData data, void * account_data)
{
if (! data.account_id_valid)
return -1;
DEBUG("ledger.ofx.parse", "account " << data.account_name);
account_t * account = new account_t(master_account, data.account_name);
curr_journal->add_account(account);
ofx_accounts.insert(accounts_pair(data.account_id, account));
if (data.currency_valid) {
commodity_t * commodity = commodity_t::find_or_create(data.currency);
commodity->add_flags(COMMODITY_STYLE_SUFFIXED | COMMODITY_STYLE_SEPARATED);
commodities_map::iterator i = ofx_account_currencies.find(data.account_id);
if (i == ofx_account_currencies.end())
ofx_account_currencies.insert(commodities_pair(data.account_id,
commodity));
}
return 0;
}
int ofx_proc_transaction_cb(struct OfxTransactionData data,
void * transaction_data)
{
if (! data.account_id_valid || ! data.units_valid)
return -1;
accounts_map::iterator i = ofx_accounts.find(data.account_id);
assert(i != ofx_accounts.end());
account_t * account = (*i).second;
entry_t * entry = new entry_t;
entry->add_transaction(new transaction_t(account));
transaction_t * xact = entry->transactions.back();
// get the account's default currency
commodities_map::iterator ac = ofx_account_currencies.find(data.account_id);
assert(ac != ofx_account_currencies.end());
commodity_t * default_commodity = (*ac).second;
std::ostringstream stream;
stream << - data.units;
// jww (2005-02-09): what if the amount contains fees?
if (data.unique_id_valid) {
commodities_map::iterator s = ofx_securities.find(data.unique_id);
assert(s != ofx_securities.end());
xact->amount = stream.str() + " " + (*s).second->base_symbol();
} else {
xact->amount = stream.str() + " " + default_commodity->base_symbol();
}
if (data.unitprice_valid && data.unitprice != 1.0) {
std::ostringstream cstream;
stream << - data.unitprice << " " << default_commodity->base_symbol();
xact->cost = new amount_t(stream.str());
}
DEBUG("ofx.parse", "xact " << xact->amount << " from " << *xact->account);
if (data.date_initiated_valid)
entry->_date = data.date_initiated;
else if (data.date_posted_valid)
entry->_date = data.date_posted;
if (data.check_number_valid)
entry->code = data.check_number;
else if (data.reference_number_valid)
entry->code = data.reference_number;
if (data.name_valid)
entry->payee = data.name;
if (data.memo_valid)
xact->note = data.memo;
// jww (2005-02-09): check for fi_id_corrected? or is this handled
// by the library?
// Balance all entries into <Unknown>, since it is not specified.
account = curr_journal->find_account("<Unknown>");
entry->add_transaction(new transaction_t(account));
if (! curr_journal->add_entry(entry)) {
print_entry(std::cerr, *entry);
#if 0
// jww (2005-02-09): uncomment
have_error = "The above entry does not balance";
#endif
checked_delete(entry);
return -1;
}
return 0;
}
int ofx_proc_security_cb(struct OfxSecurityData data, void * security_data)
{
if (! data.unique_id_valid)
return -1;
string symbol;
if (data.ticker_valid)
symbol = data.ticker;
else if (data.currency_valid)
symbol = data.currency;
else
return -1;
commodity_t * commodity = commodity_t::find_or_create(symbol);
commodity->add_flags(COMMODITY_STYLE_SUFFIXED | COMMODITY_STYLE_SEPARATED);
if (data.secname_valid)
commodity->set_name(data.secname);
if (data.memo_valid)
commodity->set_note(data.memo);
commodities_map::iterator i = ofx_securities.find(data.unique_id);
if (i == ofx_securities.end()) {
DEBUG("ledger.ofx.parse", "security " << symbol);
ofx_securities.insert(commodities_pair(data.unique_id, commodity));
}
// jww (2005-02-09): What is the commodity for data.unitprice?
if (data.date_unitprice_valid && data.unitprice_valid) {
DEBUG("ledger.ofx.parse", " price " << data.unitprice);
commodity->add_price(data.date_unitprice, amount_t(data.unitprice));
}
return 0;
}
int ofx_proc_status_cb(struct OfxStatusData data, void * status_data)
{
}
bool ofx_parser_t::test(std::istream& in) const
{
char buf[80];
in.getline(buf, 79);
if (std::strncmp(buf, "OFXHEADER", 9) == 0) {
in.clear();
in.seekg(0, std::ios::beg);
return true;
}
else if (std::strncmp(buf, "<?xml", 5) != 0) {
in.clear();
in.seekg(0, std::ios::beg);
return false;
}
in.getline(buf, 79);
if (std::strncmp(buf, "<?OFX", 5) != 0 &&
std::strncmp(buf, "<?ofx", 5) != 0) {
in.clear();
in.seekg(0, std::ios::beg);
return false;
}
in.clear();
in.seekg(0, std::ios::beg);
return true;
}
unsigned int ofx_parser_t::parse(std::istream& in,
journal_t * journal,
account_t * master,
const string * original_file)
{
if (! original_file)
return 0;
curr_journal = journal;
master_account = master ? master : journal->master;
LibofxContextPtr libofx_context = libofx_get_new_context();
ofx_set_statement_cb (libofx_context, ofx_proc_statement_cb, 0);
ofx_set_account_cb (libofx_context, ofx_proc_account_cb, 0);
ofx_set_transaction_cb(libofx_context, ofx_proc_transaction_cb, 0);
ofx_set_security_cb (libofx_context, ofx_proc_security_cb, 0);
ofx_set_status_cb (libofx_context, ofx_proc_status_cb, 0);
// The processing is done by way of callbacks, which are all defined
// above.
libofx_proc_file(libofx_context, original_file->c_str(), AUTODETECT);
libofx_free_context(libofx_context);
return 1; // jww (2005-02-09): count;
}
} // namespace ledger

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
#ifndef _OFX_H
#define _OFX_H
#include "parser.h"
namespace ledger {
class ofx_parser_t : public parser_t
{
public:
virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none);
};
} // namespace ledger
#endif // _OFX_H

View file

@ -1,233 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
unsigned int balance_len(balance_t& bal)
{
return bal.amounts.size();
}
amount_t balance_getitem(balance_t& bal, int i)
{
std::size_t len = bal.amounts.size();
if (abs(i) >= len) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
int x = i < 0 ? len + i : i;
balance_t::amounts_map::iterator elem = bal.amounts.begin();
while (--x >= 0)
elem++;
return (*elem).second;
}
unsigned int balance_pair_len(balance_pair_t& bal_pair)
{
return balance_len(bal_pair.quantity);
}
amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i)
{
return balance_getitem(bal_pair.quantity, i);
}
void export_balance()
{
class_< balance_t > ("Balance")
.def(init<balance_t>())
.def(init<amount_t>())
.def(init<long>())
.def(init<unsigned long>())
.def(init<double>())
.def(self += self)
.def(self += other<amount_t>())
.def(self += long())
.def(self + self)
.def(self + other<amount_t>())
.def(self + long())
.def(self -= self)
.def(self -= other<amount_t>())
.def(self -= long())
.def(self - self)
.def(self - other<amount_t>())
.def(self - long())
.def(self *= self)
.def(self *= other<amount_t>())
.def(self *= long())
.def(self * self)
.def(self * other<amount_t>())
.def(self * long())
.def(self /= self)
.def(self /= other<amount_t>())
.def(self /= long())
.def(self / self)
.def(self / other<amount_t>())
.def(self / long())
.def(- self)
.def(self < self)
.def(self < other<amount_t>())
.def(self < long())
.def(self <= self)
.def(self <= other<amount_t>())
.def(self <= long())
.def(self > self)
.def(self > other<amount_t>())
.def(self > long())
.def(self >= self)
.def(self >= other<amount_t>())
.def(self >= long())
.def(self == self)
.def(self == other<amount_t>())
.def(self == long())
.def(self != self)
.def(self != other<amount_t>())
.def(self != long())
.def(! self)
.def(self_ns::str(self))
.def("__abs__", &balance_t::abs)
.def("__len__", balance_len)
.def("__getitem__", balance_getitem)
.def("valid", &balance_t::valid)
.def("realzero", &balance_t::realzero)
.def("amount", &balance_t::amount)
.def("value", &balance_t::value)
.def("price", &balance_t::price)
.def("date", &balance_t::date)
.def("strip_annotations", &balance_t::strip_annotations)
.def("write", &balance_t::write)
.def("round", &balance_t::round)
.def("negate", &balance_t::negate)
.def("negated", &balance_t::negated)
;
class_< balance_pair_t > ("BalancePair")
.def(init<balance_pair_t>())
.def(init<balance_t>())
.def(init<amount_t>())
.def(init<long>())
.def(init<unsigned long>())
.def(init<double>())
.def(self += self)
.def(self += other<balance_t>())
.def(self += other<amount_t>())
.def(self += long())
.def(self + self)
.def(self + other<balance_t>())
.def(self + other<amount_t>())
.def(self + long())
.def(self -= self)
.def(self -= other<balance_t>())
.def(self -= other<amount_t>())
.def(self -= long())
.def(self - self)
.def(self - other<balance_t>())
.def(self - other<amount_t>())
.def(self - long())
.def(self *= self)
.def(self *= other<balance_t>())
.def(self *= other<amount_t>())
.def(self *= long())
.def(self * self)
.def(self * other<balance_t>())
.def(self * other<amount_t>())
.def(self * long())
.def(self /= self)
.def(self /= other<balance_t>())
.def(self /= other<amount_t>())
.def(self /= long())
.def(self / self)
.def(self / other<balance_t>())
.def(self / other<amount_t>())
.def(self / long())
.def(- self)
.def(self < self)
.def(self < other<balance_t>())
.def(self < other<amount_t>())
.def(self < long())
.def(self <= self)
.def(self <= other<balance_t>())
.def(self <= other<amount_t>())
.def(self <= long())
.def(self > self)
.def(self > other<balance_t>())
.def(self > other<amount_t>())
.def(self > long())
.def(self >= self)
.def(self >= other<balance_t>())
.def(self >= other<amount_t>())
.def(self >= long())
.def(self == self)
.def(self == other<balance_t>())
.def(self == other<amount_t>())
.def(self == long())
.def(self != self)
.def(self != other<balance_t>())
.def(self != other<amount_t>())
.def(self != long())
.def(! self)
.def(self_ns::str(self))
.def("__abs__", &balance_pair_t::abs)
.def("__len__", balance_pair_len)
.def("__getitem__", balance_pair_getitem)
.def("valid", &balance_pair_t::valid)
.def("realzero", &balance_pair_t::realzero)
.def("amount", &balance_pair_t::amount)
.def("value", &balance_pair_t::value)
.def("price", &balance_pair_t::price)
.def("date", &balance_pair_t::date)
.def("strip_annotations", &balance_pair_t::strip_annotations)
.def("write", &balance_pair_t::write)
.def("round", &balance_pair_t::round)
.def("negate", &balance_pair_t::negate)
.def("negated", &balance_pair_t::negated)
.add_property("cost",
make_getter(&balance_pair_t::cost,
return_value_policy<reference_existing_object>()))
;
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
void export_format()
{
class_< format_t > ("Format")
.def(init<string>())
.def("parse", &format_t::parse)
.def("format", &format_t::format)
;
}

View file

@ -1,404 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
entry_t& transaction_entry(const transaction_t& xact)
{
return *xact.entry;
}
unsigned int transactions_len(entry_base_t& entry)
{
return entry.transactions.size();
}
transaction_t& transactions_getitem(entry_base_t& entry, int i)
{
static int last_index = 0;
static entry_base_t * last_entry = NULL;
static transactions_list::iterator elem;
std::size_t len = entry.transactions.size();
if (abs(i) >= len) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
if (&entry == last_entry && i == last_index + 1) {
last_index = i;
return **++elem;
}
int x = i < 0 ? len + i : i;
elem = entry.transactions.begin();
while (--x >= 0)
elem++;
last_entry = &entry;
last_index = i;
return **elem;
}
unsigned int entries_len(journal_t& journal)
{
return journal.entries.size();
}
entry_t& entries_getitem(journal_t& journal, int i)
{
static int last_index = 0;
static journal_t * last_journal = NULL;
static entries_list::iterator elem;
std::size_t len = journal.entries.size();
if (abs(i) >= len) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
if (&journal == last_journal && i == last_index + 1) {
last_index = i;
return **++elem;
}
int x = i < 0 ? len + i : i;
elem = journal.entries.begin();
while (--x >= 0)
elem++;
last_journal = &journal;
last_index = i;
return **elem;
}
unsigned int accounts_len(account_t& account)
{
return account.accounts.size();
}
account_t& accounts_getitem(account_t& account, int i)
{
static int last_index = 0;
static account_t * last_account = NULL;
static accounts_map::iterator elem;
std::size_t len = account.accounts.size();
if (abs(i) >= len) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
if (&account == last_account && i == last_index + 1) {
last_index = i;
return *(*++elem).second;
}
int x = i < 0 ? len + i : i;
elem = account.accounts.begin();
while (--x >= 0)
elem++;
last_account = &account;
last_index = i;
return *(*elem).second;
}
PyObject * py_account_get_data(account_t& account)
{
return (PyObject *) account.data;
}
void py_account_set_data(account_t& account, PyObject * obj)
{
account.data = obj;
}
account_t * py_find_account_1(journal_t& journal, const string& name)
{
return journal.find_account(name);
}
account_t * py_find_account_2(journal_t& journal, const string& name,
const bool auto_create)
{
return journal.find_account(name, auto_create);
}
bool py_add_entry(journal_t& journal, entry_t * entry) {
return journal.add_entry(new entry_t(*entry));
}
void py_add_transaction(entry_base_t& entry, transaction_t * xact) {
return entry.add_transaction(new transaction_t(*xact));
}
struct entry_base_wrap : public entry_base_t
{
PyObject * self;
entry_base_wrap(PyObject * self_) : self(self_) {}
virtual bool valid() const {
return call_method<bool>(self, "valid");
}
};
struct py_entry_finalizer_t : public entry_finalizer_t {
object pyobj;
py_entry_finalizer_t() {}
py_entry_finalizer_t(object obj) : pyobj(obj) {}
py_entry_finalizer_t(const py_entry_finalizer_t& other)
: pyobj(other.pyobj) {}
virtual bool operator()(entry_t& entry, bool post) {
return call<bool>(pyobj.ptr(), entry, post);
}
};
std::list<py_entry_finalizer_t> py_finalizers;
void py_add_entry_finalizer(journal_t& journal, object x)
{
py_finalizers.push_back(py_entry_finalizer_t(x));
journal.add_entry_finalizer(&py_finalizers.back());
}
void py_remove_entry_finalizer(journal_t& journal, object x)
{
for (std::list<py_entry_finalizer_t>::iterator i = py_finalizers.begin();
i != py_finalizers.end();
i++)
if ((*i).pyobj == x) {
journal.remove_entry_finalizer(&(*i));
py_finalizers.erase(i);
return;
}
}
void py_run_entry_finalizers(journal_t& journal, entry_t& entry, bool post)
{
run_hooks(journal.entry_finalize_hooks, entry, post);
}
#define EXC_TRANSLATOR(type) \
void exc_translate_ ## type(const type& err) { \
PyErr_SetString(PyExc_RuntimeError, err.what()); \
}
EXC_TRANSLATOR(balance_error)
EXC_TRANSLATOR(interval_expr_error)
EXC_TRANSLATOR(format_error)
EXC_TRANSLATOR(parse_error)
value_t py_transaction_amount(transaction_t * xact) {
return value_t(xact->amount);
}
transaction_t::state_t py_entry_state(entry_t * entry) {
transaction_t::state_t state;
if (entry->get_state(&state))
return state;
else
return transaction_t::UNCLEARED;
}
void export_journal()
{
scope().attr("TRANSACTION_NORMAL") = TRANSACTION_NORMAL;
scope().attr("TRANSACTION_VIRTUAL") = TRANSACTION_VIRTUAL;
scope().attr("TRANSACTION_BALANCE") = TRANSACTION_BALANCE;
scope().attr("TRANSACTION_AUTO") = TRANSACTION_AUTO;
scope().attr("TRANSACTION_BULK_ALLOC") = TRANSACTION_BULK_ALLOC;
scope().attr("TRANSACTION_CALCULATED") = TRANSACTION_CALCULATED;
enum_< transaction_t::state_t > ("State")
.value("Uncleared", transaction_t::UNCLEARED)
.value("Cleared", transaction_t::CLEARED)
.value("Pending", transaction_t::PENDING)
;
class_< transaction_t > ("Transaction")
.def(init<optional<account_t *> >())
.def(init<account_t *, amount_t, optional<unsigned int, const string&> >())
.def(self == self)
.def(self != self)
.add_property("entry",
make_getter(&transaction_t::entry,
return_value_policy<reference_existing_object>()))
.add_property("account",
make_getter(&transaction_t::account,
return_value_policy<reference_existing_object>()))
.add_property("amount", &py_transaction_amount)
.def_readonly("amount_expr", &transaction_t::amount_expr)
.add_property("cost",
make_getter(&transaction_t::cost,
return_internal_reference<1>()))
.def_readonly("cost_expr", &transaction_t::cost_expr)
.def_readwrite("state", &transaction_t::state)
.def_readwrite("flags", &transaction_t::flags)
.def_readwrite("note", &transaction_t::note)
.def_readonly("beg_pos", &transaction_t::beg_pos)
.def_readonly("beg_line", &transaction_t::beg_line)
.def_readonly("end_pos", &transaction_t::end_pos)
.def_readonly("end_line", &transaction_t::end_line)
.def("actual_date", &transaction_t::actual_date)
.def("effective_date", &transaction_t::effective_date)
.def("date", &transaction_t::date)
.def("use_effective_date", &transaction_t::use_effective_date)
.def("valid", &transaction_t::valid)
;
class_< account_t >
("Account", init<optional<account_t *, string, string> >()
[with_custodian_and_ward<1, 2>()])
.def(self == self)
.def(self != self)
.def(self_ns::str(self))
.def("__len__", accounts_len)
.def("__getitem__", accounts_getitem, return_internal_reference<1>())
.add_property("journal",
make_getter(&account_t::journal,
return_value_policy<reference_existing_object>()))
.add_property("parent",
make_getter(&account_t::parent,
return_value_policy<reference_existing_object>()))
.def_readwrite("name", &account_t::name)
.def_readwrite("note", &account_t::note)
.def_readonly("depth", &account_t::depth)
.add_property("data", py_account_get_data, py_account_set_data)
.def_readonly("ident", &account_t::ident)
.def("fullname", &account_t::fullname)
.def("add_account", &account_t::add_account)
.def("remove_account", &account_t::remove_account)
.def("find_account", &account_t::find_account,
return_value_policy<reference_existing_object>())
.def("valid", &account_t::valid)
;
class_< journal_t > ("Journal")
.def(self == self)
.def(self != self)
.def("__len__", entries_len)
.def("__getitem__", entries_getitem, return_internal_reference<1>())
.add_property("master", make_getter(&journal_t::master,
return_internal_reference<1>()))
.add_property("basket", make_getter(&journal_t::basket,
return_internal_reference<1>()))
.def_readonly("sources", &journal_t::sources)
.def_readwrite("price_db", &journal_t::price_db)
.def("add_account", &journal_t::add_account)
.def("remove_account", &journal_t::remove_account)
.def("find_account", py_find_account_1, return_internal_reference<1>())
.def("find_account", py_find_account_2, return_internal_reference<1>())
.def("find_account_re", &journal_t::find_account_re,
return_internal_reference<1>())
.def("add_entry", py_add_entry)
.def("remove_entry", &journal_t::remove_entry)
.def("add_entry_finalizer", py_add_entry_finalizer)
.def("remove_entry_finalizer", py_remove_entry_finalizer)
.def("run_entry_finalizers", py_run_entry_finalizers)
.def("valid", &journal_t::valid)
;
class_< entry_base_t, entry_base_wrap, boost::noncopyable > ("EntryBase")
.def("__len__", transactions_len)
.def("__getitem__", transactions_getitem,
return_internal_reference<1>())
.def_readonly("journal", &entry_base_t::journal)
.def_readonly("src_idx", &entry_base_t::src_idx)
.def_readonly("beg_pos", &entry_base_t::beg_pos)
.def_readonly("beg_line", &entry_base_t::beg_line)
.def_readonly("end_pos", &entry_base_t::end_pos)
.def_readonly("end_line", &entry_base_t::end_line)
.def("add_transaction", py_add_transaction)
.def("remove_transaction", &entry_base_t::remove_transaction)
.def(self == self)
.def(self != self)
.def("finalize", &entry_base_t::finalize)
.def("valid", &entry_base_t::valid)
;
class_< entry_t, bases<entry_base_t> > ("Entry")
.add_property("date", &entry_t::date)
.add_property("effective_date", &entry_t::effective_date)
.add_property("actual_date", &entry_t::actual_date)
.def_readwrite("code", &entry_t::code)
.def_readwrite("payee", &entry_t::payee)
.add_property("state", &py_entry_state)
.def("valid", &entry_t::valid)
;
#define EXC_TRANSLATE(type) \
register_error_translator<type>(&exc_translate_ ## type);
EXC_TRANSLATE(balance_error);
EXC_TRANSLATE(interval_expr_error);
EXC_TRANSLATE(format_error);
EXC_TRANSLATE(parse_error);
}

View file

@ -1,103 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
struct py_option_t : public option_t
{
PyObject * self;
py_option_t(PyObject * self_,
const string& long_opt,
const bool wants_arg)
: self(self_), option_t(long_opt, wants_arg) {}
virtual ~py_option_t() {}
virtual bool check(option_source_t source) {
return call_method<bool>(self, "check", source);
}
virtual void select(report_t * report, const char * optarg = NULL) {
if (optarg)
return call_method<void>(self, "select", report, optarg);
else
return call_method<void>(self, "select", report);
}
};
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(option_select_overloads,
py_option_t::select, 1, 2)
typedef std::map<const string, object> options_map;
options_map options;
static option_t * find_option(const string& name)
{
options_map::const_iterator i = options.find(name);
if (i != options.end())
return extract<py_option_t *>((*i).second.ptr());
return NULL;
}
void shutdown_option()
{
options.clear();
}
void export_option()
{
class_< option_t, py_option_t, boost::noncopyable >
("Option", init<const string&, bool>())
.def_readonly("long_opt", &py_option_t::long_opt)
.def_readonly("short_opt", &py_option_t::short_opt)
.def_readonly("wants_arg", &py_option_t::wants_arg)
.def_readwrite("handled", &py_option_t::handled)
.def("check", &py_option_t::check)
.def("select", &py_option_t::select, option_select_overloads())
;
enum_< option_t::option_source_t > ("OptionSource")
.value("InitFile", option_t::INIT_FILE)
.value("Environment", option_t::ENVIRONMENT)
.value("DataFile", option_t::DATA_FILE)
.value("CommandLine", option_t::COMMAND_LINE)
;
class_< options_map > ("OptionsMap")
.def(map_indexing_suite<options_map>())
;
scope().attr("options") = ptr(&options);
}

View file

@ -1,79 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "parser.h"
#if 0
#ifdef USE_BOOST_PYTHON
using namespace boost::python;
using namespace ledger;
struct py_parser_t : public parser_t
{
PyObject * self;
py_parser_t(PyObject * self_) : self(self_) {}
virtual bool test(std::istream& in) const {
return call_method<bool>(self, "test", in);
}
virtual repitem_t * parse(std::istream& in,
journal_t * journal,
account_t * master = NULL,
const string * original_file = NULL) {
return call_method<unsigned int>(self, "parse", in, journal, master,
original_file);
}
};
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(parser_parse_overloads,
py_parser_t::parse, 2, 4)
BOOST_PYTHON_FUNCTION_OVERLOADS(parse_journal_overloads, parse_journal, 2, 4)
BOOST_PYTHON_FUNCTION_OVERLOADS(parse_journal_file_overloads,
parse_journal_file, 2, 4)
void export_parser() {
class_< parser_t, py_parser_t, boost::noncopyable > ("Parser")
.def("test", &py_parser_t::test)
.def("parse", &py_parser_t::parse, parser_parse_overloads())
;
def("register_parser", register_parser);
def("unregister_parser", unregister_parser);
def("parse_journal", parse_journal, parse_journal_overloads());
def("parse_journal_file", parse_journal_file, parse_journal_file_overloads());
}
#endif // USE_BOOST_PYTHON
#endif

View file

@ -1,44 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
void export_report()
{
class_< report_t > ("Report")
.add_property("session",
make_getter(&report_t::session,
return_value_policy<reference_existing_object>()))
.def("apply_transforms", &report_t::apply_transforms)
;
}

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
void export_session()
{
class_< session_t > ("Session")
.def_readwrite("init_file", &session_t::init_file)
.def_readwrite("data_file", &session_t::data_file)
.def_readwrite("cache_file", &session_t::cache_file)
.def_readwrite("price_db", &session_t::price_db)
.def_readwrite("balance_format", &session_t::balance_format)
.def_readwrite("register_format", &session_t::register_format)
.def_readwrite("wide_register_format", &session_t::wide_register_format)
.def_readwrite("plot_amount_format", &session_t::plot_amount_format)
.def_readwrite("plot_total_format", &session_t::plot_total_format)
.def_readwrite("print_format", &session_t::print_format)
.def_readwrite("write_hdr_format", &session_t::write_hdr_format)
.def_readwrite("write_xact_format", &session_t::write_xact_format)
.def_readwrite("equity_format", &session_t::equity_format)
.def_readwrite("prices_format", &session_t::prices_format)
.def_readwrite("pricesdb_format", &session_t::pricesdb_format)
.def_readwrite("pricing_leeway", &session_t::pricing_leeway)
.def_readwrite("download_quotes", &session_t::download_quotes)
.def_readwrite("use_cache", &session_t::use_cache)
.def_readwrite("cache_dirty", &session_t::cache_dirty)
.def_readwrite("debug_mode", &session_t::debug_mode)
.def_readwrite("verbose_mode", &session_t::verbose_mode)
.def_readwrite("trace_alloc_mode", &session_t::trace_alloc_mode)
.def_readwrite("trace_class_mode", &session_t::trace_class_mode)
.def_readwrite("journals", &session_t::journals)
;
}

View file

@ -1,39 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
void export_transform()
{
class_< repitem_t > ("Transform")
;
}

View file

@ -1,368 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
long balance_len(balance_t& bal);
amount_t balance_getitem(balance_t& bal, int i);
long balance_pair_len(balance_pair_t& bal_pair);
amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i);
long value_len(value_t& val)
{
switch (val.type) {
case value_t::BOOLEAN:
case value_t::INTEGER:
case value_t::DATETIME:
case value_t::AMOUNT:
return 1;
case value_t::BALANCE:
return balance_len(*((balance_t *) val.data));
case value_t::BALANCE_PAIR:
return balance_pair_len(*((balance_pair_t *) val.data));
case value_t::STRING:
case value_t::XML_NODE:
case value_t::POINTER:
return 1;
case value_t::SEQUENCE:
return (*(value_t::sequence_t **) val.data)->size();
default:
assert(false);
break;
}
assert(false);
return 0;
}
amount_t value_getitem(value_t& val, int i)
{
std::size_t len = value_len(val);
if (abs(i) >= len) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
switch (val.type) {
case value_t::BOOLEAN:
throw_(value_error, "Cannot cast a boolean to an amount");
case value_t::INTEGER:
return long(val);
case value_t::DATETIME:
throw_(value_error, "Cannot cast a date/time to an amount");
case value_t::AMOUNT:
return *((amount_t *) val.data);
case value_t::BALANCE:
return balance_getitem(*((balance_t *) val.data), i);
case value_t::BALANCE_PAIR:
return balance_pair_getitem(*((balance_pair_t *) val.data), i);
case value_t::STRING:
throw_(value_error, "Cannot cast a string to an amount");
case value_t::XML_NODE:
return (*(xml::node_t **) data)->to_value();
case value_t::POINTER:
throw_(value_error, "Cannot cast a pointer to an amount");
case value_t::SEQUENCE:
return (*(value_t::sequence_t **) val.data)[i];
default:
assert(false);
break;
}
assert(false);
return 0L;
}
double py_to_float(value_t& val)
{
return double(val);
}
void export_value()
{
class_< value_t > ("value")
.def(init<value_t>())
.def(init<balance_pair_t>())
.def(init<balance_t>())
.def(init<amount_t>())
.def(init<string>())
.def(init<double>())
.def(init<long>())
.def(initmoment_t())
.def(self + self)
.def(self + other<string>())
.def(self + other<balance_pair_t>())
.def(self + other<balance_t>())
.def(self + other<amount_t>())
.def(self + long())
.def(self + double())
.def(other<string>() + self)
.def(other<balance_pair_t>() + self)
.def(other<balance_t>() + self)
.def(other<amount_t>() + self)
.def(long() + self)
.def(double() + self)
.def(self - self)
.def(self - other<string>())
.def(self - other<balance_pair_t>())
.def(self - other<balance_t>())
.def(self - other<amount_t>())
.def(self - long())
.def(self - double())
.def(other<string>() - self)
.def(other<balance_pair_t>() - self)
.def(other<balance_t>() - self)
.def(other<amount_t>() - self)
.def(long() - self)
.def(double() - self)
.def(self * self)
.def(self * other<string>())
.def(self * other<balance_pair_t>())
.def(self * other<balance_t>())
.def(self * other<amount_t>())
.def(self * long())
.def(self * double())
.def(other<string>() * self)
.def(other<balance_pair_t>() * self)
.def(other<balance_t>() * self)
.def(other<amount_t>() * self)
.def(long() * self)
.def(double() * self)
.def(self / self)
.def(self / other<string>())
.def(self / other<balance_pair_t>())
.def(self / other<balance_t>())
.def(self / other<amount_t>())
.def(self / long())
.def(self / double())
.def(other<string>() / self)
.def(other<balance_pair_t>() / self)
.def(other<balance_t>() / self)
.def(other<amount_t>() / self)
.def(long() / self)
.def(double() / self)
.def(- self)
.def(self += self)
.def(self += other<string>())
.def(self += other<balance_pair_t>())
.def(self += other<balance_t>())
.def(self += other<amount_t>())
.def(self += long())
.def(self += double())
.def(self -= self)
.def(self -= other<string>())
.def(self -= other<balance_pair_t>())
.def(self -= other<balance_t>())
.def(self -= other<amount_t>())
.def(self -= long())
.def(self -= double())
.def(self *= self)
.def(self *= other<string>())
.def(self *= other<balance_pair_t>())
.def(self *= other<balance_t>())
.def(self *= other<amount_t>())
.def(self *= long())
.def(self *= double())
.def(self /= self)
.def(self /= other<string>())
.def(self /= other<balance_pair_t>())
.def(self /= other<balance_t>())
.def(self /= other<amount_t>())
.def(self /= long())
.def(self /= double())
.def(self < self)
.def(self < other<string>())
.def(self < other<balance_pair_t>())
.def(self < other<balance_t>())
.def(self < other<amount_t>())
.def(self < long())
.def(self < othermoment_t())
.def(self < double())
.def(other<string>() < self)
.def(other<balance_pair_t>() < self)
.def(other<balance_t>() < self)
.def(other<amount_t>() < self)
.def(long() < self)
.def(othermoment_t() < self)
.def(double() < self)
.def(self <= self)
.def(self <= other<string>())
.def(self <= other<balance_pair_t>())
.def(self <= other<balance_t>())
.def(self <= other<amount_t>())
.def(self <= long())
.def(self <= othermoment_t())
.def(self <= double())
.def(other<string>() <= self)
.def(other<balance_pair_t>() <= self)
.def(other<balance_t>() <= self)
.def(other<amount_t>() <= self)
.def(long() <= self)
.def(othermoment_t() <= self)
.def(double() <= self)
.def(self > self)
.def(self > other<string>())
.def(self > other<balance_pair_t>())
.def(self > other<balance_t>())
.def(self > other<amount_t>())
.def(self > long())
.def(self > othermoment_t())
.def(self > double())
.def(other<string>() > self)
.def(other<balance_pair_t>() > self)
.def(other<balance_t>() > self)
.def(other<amount_t>() > self)
.def(long() > self)
.def(othermoment_t() > self)
.def(double() > self)
.def(self >= self)
.def(self >= other<string>())
.def(self >= other<balance_pair_t>())
.def(self >= other<balance_t>())
.def(self >= other<amount_t>())
.def(self >= long())
.def(self >= othermoment_t())
.def(self >= double())
.def(other<string>() >= self)
.def(other<balance_pair_t>() >= self)
.def(other<balance_t>() >= self)
.def(other<amount_t>() >= self)
.def(long() >= self)
.def(othermoment_t() >= self)
.def(double() >= self)
.def(self == self)
.def(self == other<string>())
.def(self == other<balance_pair_t>())
.def(self == other<balance_t>())
.def(self == other<amount_t>())
.def(self == long())
.def(self == othermoment_t())
.def(self == double())
.def(other<string>() == self)
.def(other<balance_pair_t>() == self)
.def(other<balance_t>() == self)
.def(other<amount_t>() == self)
.def(long() == self)
.def(othermoment_t() == self)
.def(double() == self)
.def(self != self)
.def(self != other<string>())
.def(self != other<balance_pair_t>())
.def(self != other<balance_t>())
.def(self != other<amount_t>())
.def(self != long())
.def(self != othermoment_t())
.def(self != double())
.def(other<string>() != self)
.def(other<balance_pair_t>() != self)
.def(other<balance_t>() != self)
.def(other<amount_t>() != self)
.def(long() != self)
.def(othermoment_t() != self)
.def(double() != self)
.def(! self)
.def(self_ns::int_(self))
.def(self_ns::float_(self))
.def(self_ns::str(self))
.def_readonly("type", &value_t::type)
.def("__abs__", &value_t::abs)
.def("__len__", value_len)
.def("__getitem__", value_getitem)
.def("cast", &value_t::cast)
.def("cost", &value_t::cost)
.def("price", &value_t::price)
.def("date", &value_t::date)
.def("strip_annotations", &value_t::strip_annotations)
.def("add", &value_t::add, return_internal_reference<>())
.def("value", &value_t::value)
.def("round", &value_t::round)
.def("negate", &value_t::negate)
.def("write", &value_t::write)
;
enum_< value_t::type_t > ("ValueType")
.value("Boolean", value_t::BOOLEAN)
.value("Integer", value_t::INTEGER)
.value("DateTime", value_t::DATETIME)
.value("Amount", value_t::AMOUNT)
.value("Balance", value_t::BALANCE)
.value("BalancePair", value_t::BALANCE_PAIR)
.value("String", value_t::STRING)
.value("XmlNode", value_t::XML_NODE)
.value("Pointer", value_t::POINTER)
.value("Sequence", value_t::SEQUENCE)
;
}

View file

@ -1,110 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
using namespace boost::python;
using namespace ledger;
value_t py_calc_1(xpath_t::op_t& xpath_t, const details_t& item)
{
value_t result;
xpath_t.calc(result, item);
return result;
}
template <typename T>
value_t py_calc(xpath_t::op_t& xpath_t, const T& item)
{
value_t result;
xpath_t.calc(result, details_t(item));
return result;
}
xpath_t::op_t * py_parse_xpath_t_1(const string& str)
{
return parse_xpath_t(str);
}
#define EXC_TRANSLATOR(type) \
void exc_translate_ ## type(const type& err) { \
PyErr_SetString(PyExc_RuntimeError, err.what()); \
}
EXC_TRANSLATOR(xpath_t_error)
EXC_TRANSLATOR(calc_error)
#if 0
EXC_TRANSLATOR(mask_error)
#endif
void export_xpath()
{
class_< details_t > ("Details", init<const entry_t&>())
.def(init<const transaction_t&>())
.def(init<const account_t&>())
.add_property("entry",
make_getter(&details_t::entry,
return_value_policy<reference_existing_object>()))
.add_property("xact",
make_getter(&details_t::xact,
return_value_policy<reference_existing_object>()))
.add_property("account",
make_getter(&details_t::account,
return_value_policy<reference_existing_object>()))
;
class_< xpath_t::op_t > ("ValueExpr", init<xpath_t::op_t::kind_t>())
.def("calc", py_calc_1)
.def("calc", py_calc<account_t>)
.def("calc", py_calc<entry_t>)
.def("calc", py_calc<transaction_t>)
;
def("parse_xpath_t", py_parse_xpath_t_1,
return_value_policy<manage_new_object>());
class_< item_predicate<transaction_t> >
("TransactionPredicate", init<string>())
.def("__call__", &item_predicate<transaction_t>::operator())
;
class_< item_predicate<account_t> >
("AccountPredicate", init<string>())
.def("__call__", &item_predicate<account_t>::operator())
;
#define EXC_TRANSLATE(type) \
register_error_translator<type>(&exc_translate_ ## type);
EXC_TRANSLATE(xpath_t_error);
EXC_TRANSLATE(calc_error);
#if 0
EXC_TRANSLATE(mask_error);
#endif
}

View file

@ -1,274 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "qif.h"
#include "journal.h"
namespace ledger {
#define MAX_LINE 1024
static char line[MAX_LINE + 1];
static path pathname;
static unsigned int src_idx;
static unsigned int linenum;
static inline char * get_line(std::istream& in) {
in.getline(line, MAX_LINE);
int len = std::strlen(line);
if (line[len - 1] == '\r')
line[len - 1] = '\0';
linenum++;
return line;
}
bool qif_parser_t::test(std::istream& in) const
{
char magic[sizeof(unsigned int) + 1];
in.read(magic, sizeof(unsigned int));
magic[sizeof(unsigned int)] = '\0';
in.clear();
in.seekg(0, std::ios::beg);
return (std::strcmp(magic, "!Typ") == 0 ||
std::strcmp(magic, "\n!Ty") == 0 ||
std::strcmp(magic, "\r\n!T") == 0);
}
unsigned int qif_parser_t::parse(std::istream& in,
journal_t * journal,
account_t * master,
const optional<path>&)
{
std::auto_ptr<entry_t> entry;
std::auto_ptr<amount_t> amount;
transaction_t * xact;
unsigned int count = 0;
account_t * misc = NULL;
commodity_t * def_commodity = NULL;
bool saw_splits = false;
bool saw_category = false;
transaction_t * total = NULL;
entry.reset(new entry_t);
xact = new transaction_t(master);
entry->add_transaction(xact);
pathname = journal->sources.back();
src_idx = journal->sources.size() - 1;
linenum = 1;
unsigned long beg_pos = 0;
unsigned long beg_line = 0;
#define SET_BEG_POS_AND_LINE() \
if (! beg_line) { \
beg_pos = in.tellg(); \
beg_line = linenum; \
}
while (in.good() && ! in.eof()) {
char c;
in.get(c);
switch (c) {
case ' ':
case '\t':
if (peek_next_nonws(in) != '\n') {
get_line(in);
throw_(parse_error, "Line begins with whitespace");
}
// fall through...
case '\n':
linenum++;
case '\r': // skip blank lines
break;
case '!':
get_line(in);
if (std::strcmp(line, "Type:Invst") == 0 ||
std::strcmp(line, "Account") == 0 ||
std::strcmp(line, "Type:Cat") == 0 ||
std::strcmp(line, "Type:Class") == 0 ||
std::strcmp(line, "Type:Memorized") == 0)
throw_(parse_error,
"QIF files of type " << line << " are not supported.");
break;
case 'D':
SET_BEG_POS_AND_LINE();
get_line(in);
entry->_date = parse_datetime(line);
break;
case 'T':
case '$': {
SET_BEG_POS_AND_LINE();
get_line(in);
xact->amount = amount_t(line);
unsigned char flags = xact->amount->commodity().flags();
unsigned char prec = xact->amount->commodity().precision();
if (! def_commodity) {
def_commodity = amount_t::current_pool->find_or_create("$");
assert(def_commodity);
}
xact->amount->set_commodity(*def_commodity);
def_commodity->add_flags(flags);
if (prec > def_commodity->precision())
def_commodity->set_precision(prec);
if (c == '$') {
saw_splits = true;
xact->amount->in_place_negate();
} else {
total = xact;
}
break;
}
case 'C':
SET_BEG_POS_AND_LINE();
c = in.peek();
if (c == '*' || c == 'X') {
in.get(c);
xact->state = transaction_t::CLEARED;
}
break;
case 'N':
SET_BEG_POS_AND_LINE();
get_line(in);
entry->code = line;
break;
case 'P':
case 'M':
case 'L':
case 'S':
case 'E': {
SET_BEG_POS_AND_LINE();
get_line(in);
switch (c) {
case 'P':
entry->payee = line;
break;
case 'S':
xact = new transaction_t(NULL);
entry->add_transaction(xact);
// fall through...
case 'L': {
int len = std::strlen(line);
if (line[len - 1] == ']')
line[len - 1] = '\0';
xact->account = journal->find_account(line[0] == '[' ?
line + 1 : line);
if (c == 'L')
saw_category = true;
break;
}
case 'M':
case 'E':
xact->note = line;
break;
}
break;
}
case 'A':
SET_BEG_POS_AND_LINE();
// jww (2004-08-19): these are ignored right now
get_line(in);
break;
case '^': {
account_t * other;
if (xact->account == master) {
if (! misc)
misc = journal->find_account("Miscellaneous");
other = misc;
} else {
other = master;
}
if (total && saw_category) {
if (! saw_splits)
total->amount->in_place_negate(); // negate, to show correct flow
else
total->account = other;
}
if (! saw_splits) {
transaction_t * nxact = new transaction_t(other);
// The amount doesn't need to be set because the code below
// will balance this transaction against the other.
entry->add_transaction(nxact);
}
if (journal->add_entry(entry.get())) {
entry->src_idx = src_idx;
entry->beg_pos = beg_pos;
entry->beg_line = beg_line;
entry->end_pos = in.tellg();
entry->end_line = linenum;
entry.release();
count++;
}
// reset things for the next entry
entry.reset(new entry_t);
xact = new transaction_t(master);
entry->add_transaction(xact);
saw_splits = false;
saw_category = false;
total = NULL;
beg_line = 0;
break;
}
default:
get_line(in);
break;
}
}
return count;
}
} // namespace ledger

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/
#ifndef _QIF_H
#define _QIF_H
#include "parser.h"
namespace ledger {
class qif_parser_t : public parser_t
{
public:
virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none);
};
} // namespace ledger
#endif // _QIF_H

View file

@ -1,117 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "quotes.h"
namespace ledger {
optional<amount_t>
quotes_by_script::operator()(commodity_t& commodity,
const optional<moment_t>& date,
const optional<moment_t>& moment,
const optional<moment_t>& last)
{
LOGGER("quotes.download");
IF_DEBUG_() {
DEBUG_("commodity: " << commodity.symbol());
DEBUG_(" now: " << now);
if (date)
DEBUG_(" date: " << date);
if (moment)
DEBUG_(" moment: " << moment);
if (last)
DEBUG_(" last: " << last);
if (commodity.history())
DEBUG_("last_lookup: " << commodity.history()->last_lookup);
}
DEBUG_("pricing_leeway is " << pricing_leeway);
if ((commodity.history() &&
(now - commodity.history()->last_lookup) < pricing_leeway) ||
(last && (now - *last) < pricing_leeway) ||
(moment && date && *moment > *date &&
(*moment - *date) <= pricing_leeway))
return none;
DEBUG_("downloading quote for symbol " << commodity.symbol());
char buf[256];
buf[0] = '\0';
bool success = true;
if (FILE * fp = popen((string("getquote \"") +
commodity.base_symbol() + "\"").c_str(), "r")) {
if (feof(fp) || ! fgets(buf, 255, fp))
success = false;
if (pclose(fp) != 0)
success = false;
} else {
success = false;
}
if (success && buf[0]) {
char * p = strchr(buf, '\n');
if (p) *p = '\0';
DEBUG_("downloaded quote: " << buf);
amount_t price;
price.parse(buf);
commodity.add_price(now, price);
commodity.history()->last_lookup = now;
cache_dirty = true;
assert(! price_db.empty());
#if defined(__GNUG__) && __GNUG__ < 3
ofstream database(price_db, ios::out | ios::app);
#else
ofstream database(price_db, std::ios_base::out | std::ios_base::app);
#endif
#if 0
// jww (2007-04-18): Need to convert to local time and print
// here, print with UTC timezone specifier
database << "P " << now.to_string("%Y/%m/%d %H:%M:%S")
<< " " << commodity.symbol << " " << price << endl;
#endif
return price;
} else {
throw_(download_error,
"Failed to download price for '" << commodity.symbol() <<
"' (command: \"getquote " << commodity.base_symbol() << "\")");
}
return none;
}
} // namespace ledger

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2003-2007, 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.
*/

View file

@ -125,15 +125,12 @@ string abbreviate(const string& str,
static void scan_for_transactions(std::ostream& out, const xml::node_t * node)
{
#if 0
if (! node->has_flags(XML_NODE_IS_PARENT))
return;
const xml::parent_node_t * parent = node->as_parent_node();
for (const xml::node_t * child = parent->children();
child;
child = child->next)
if (child->name_id == xml::document_t::TRANSACTION) {
foreach (const xml::node_t * child, node->as_parent_node()) {
if (child->name_id == xml::TRANSACTION_NODE) {
const xml::transaction_node_t * xact_node =
dynamic_cast<const xml::transaction_node_t *>(child);
assert(xact_node);
@ -154,13 +151,14 @@ static void scan_for_transactions(std::ostream& out, const xml::node_t * node)
} else {
scan_for_transactions(out, child);
}
#endif
}
void register_command::print_document(std::ostream& out,
xml::document_t * doc)
{
#if 1
scan_for_transactions(out, doc->top);
scan_for_transactions(out, doc);
out.flush();
#else
value_t nodelist;

View file

@ -88,7 +88,9 @@ class report_t : public xml::xpath_t::scope_t
//
void eval(const string& expr) {
#if 0
xml::xpath_t(expr).compile((xml::document_t *)NULL, this);
#endif
}
void option_eval(value_t&, xml::xpath_t::scope_t * locals) {
eval(locals->args[0].as_string());

View file

@ -146,6 +146,8 @@ extern "C" {
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key_extractors.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/operators.hpp>
#include <boost/optional.hpp>

View file

@ -33,13 +33,15 @@
namespace ledger {
using namespace xml;
#define MAX_LINE 1024
typedef xml::builder_t::position_t position_t;
typedef builder_t::position_t position_t;
void parse_transaction(xml::builder_t& builder,
char * line,
position_t& end_of_line)
void parse_transaction(builder_t& builder,
char * line,
position_t& end_of_line)
{
// First cut up the input line into its various parts.
@ -125,7 +127,7 @@ void parse_transaction(xml::builder_t& builder,
builder.end_node(TRANSACTION_NODE, end_of_line);
}
bool parse_transactions(std::istream& in, xml::builder_t& builder)
bool parse_transactions(std::istream& in, builder_t& builder)
{
TRACE_START(entry_xacts, 1, "Time spent parsing transactions:");
@ -155,10 +157,10 @@ bool parse_transactions(std::istream& in, xml::builder_t& builder)
return added;
}
void parse_entry(std::istream& in,
xml::builder_t& builder,
char * line,
position_t& end_of_line)
void parse_entry(std::istream& in,
builder_t& builder,
char * line,
position_t& end_of_line)
{
TRACE_START(entry_text, 1, "Time spent preparing entry text:");
@ -226,7 +228,7 @@ void parse_entry(std::istream& in,
builder.push_attr(DATE_ATTR, date);
if (date_eff)
builder.push_attr(DATE_EFF_ATTR, date_eff);
builder.push_attr(EFF_DATE_ATTR, date_eff);
if (statep) {
switch (*statep) {
@ -273,9 +275,9 @@ bool textual_parser_t::test(std::istream& in) const
return true;
}
void textual_parser_t::parse(std::istream& in,
const path& pathname,
xml::builder_t& builder)
void textual_parser_t::parse(std::istream& in,
const path& pathname,
builder_t& builder)
{
TRACE_START(parsing_total, 1, "Total time spent parsing text:");

View file

@ -30,7 +30,7 @@
*/
#include "value.h"
#include "xml.h"
#include "node.h"
namespace ledger {
@ -1610,7 +1610,7 @@ std::ostream& operator<<(std::ostream& out, const value_t& val)
if (val.as_xml_node()->has_flags(XML_NODE_IS_PARENT))
out << '<' << val.as_xml_node()->name() << '>';
else
out << val.as_xml_node()->text();
out << val.as_xml_node()->to_value();
break;
case value_t::POINTER:

View file

@ -1,584 +0,0 @@
/*
* Copyright (c) 2003-2007, 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 "xml.h"
#include "journal.h"
namespace ledger {
namespace xml {
const std::size_t document_t::ledger_builtins_size = 12;
const char * document_t::ledger_builtins[] = {
"account",
"account-path",
"amount",
"code",
"commodity",
"entries",
"entry",
"journal",
"name",
"note",
"payee",
"transaction"
};
document_t::~document_t()
{
TRACE_DTOR(xml::document_t);
if (top && top != &stub)
checked_delete(top);
}
void document_t::set_top(node_t * _top)
{
if (top && top != &stub)
checked_delete(top);
top = _top;
}
int document_t::register_name(const string& name)
{
int index = lookup_name_id(name);
if (index != -1)
return index;
names.push_back(name);
index = names.size() - 1;
DEBUG("xml.lookup", this << " Inserting name: " << names.back());
std::pair<names_map::iterator, bool> result =
names_index.insert(names_map::value_type(names.back(), index));
assert(result.second);
return index + 1000;
}
int document_t::lookup_name_id(const string& name) const
{
int id;
if ((id = lookup_builtin_id(name)) != -1)
return id;
DEBUG("xml.lookup", this << " Finding name: " << name);
names_map::const_iterator i = names_index.find(name);
if (i != names_index.end())
return (*i).second + 1000;
return -1;
}
int document_t::lookup_builtin_id(const string& name)
{
int first = 0;
int last = (int)ledger_builtins_size;
while (first <= last) {
int mid = (first + last) / 2; // compute mid point.
int result;
if ((result = (int)name[0] - (int)ledger_builtins[mid][0]) == 0)
result = std::strcmp(name.c_str(), ledger_builtins[mid]);
if (result > 0)
first = mid + 1; // repeat search in top half.
else if (result < 0)
last = mid - 1; // repeat search in bottom half.
else
return mid + 10;
}
return -1;
}
const char * document_t::lookup_name(int id) const
{
if (id < 1000) {
switch (id) {
case CURRENT:
return "CURRENT";
case PARENT:
return "PARENT";
case ROOT:
return "ROOT";
case ALL:
return "ALL";
default:
assert(id >= 10);
return ledger_builtins[id - 10];
}
} else {
return names[id - 1000].c_str();
}
}
void document_t::print(std::ostream& out) const
{
if (top) {
out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
top->print(out);
}
}
#ifndef THREADSAFE
document_t * node_t::document = NULL;
#endif
node_t::node_t(document_t * _document, parent_node_t * _parent, flags_t _flags)
: supports_flags<>(_flags), name_id(0), parent(_parent),
next(NULL), prev(NULL), attrs(NULL)
{
TRACE_CTOR(node_t, "document_t *, node_t *");
document = _document;
if (document && ! document->top)
document->set_top(this);
if (parent)
parent->add_child(this);
}
void node_t::extract()
{
if (prev)
prev->next = next;
if (parent) {
if (parent->_children == this)
parent->_children = next;
if (parent->_last_child == this)
parent->_last_child = prev;
parent = NULL;
}
if (next)
next->prev = prev;
next = NULL;
prev = NULL;
}
const char * node_t::name() const
{
return document->lookup_name(name_id);
}
int node_t::set_name(const char * _name)
{
name_id = document->register_name(_name);
return name_id;
}
node_t * node_t::lookup_child(const char * _name) const
{
int id = document->lookup_name_id(_name);
return lookup_child(id);
}
node_t * node_t::lookup_child(const string& _name) const
{
int id = document->lookup_name_id(_name);
return lookup_child(id);
}
void parent_node_t::clear()
{
node_t * child = _children;
while (child) {
node_t * tnext = child->next;
checked_delete(child);
child = tnext;
}
}
void parent_node_t::add_child(node_t * node)
{
// It is important that this node is not called before children(),
// otherwise, this node will not get auto-populated.
if (_children == NULL) {
assert(_last_child == NULL);
_children = node;
node->prev = NULL;
} else {
assert(_last_child != NULL);
_last_child->next = node;
node->prev = _last_child;
}
node->parent = this;
while (node->next) {
node_t * next_node = node->next;
assert(next_node->prev == node);
next_node->parent = this;
node = next_node;
}
_last_child = node;
}
void parent_node_t::print(std::ostream& out, int depth) const
{
for (int i = 0; i < depth; i++) out << " ";
out << '<' << name() << ">\n";
for (node_t * child = children(); child; child = child->next)
child->print(out, depth + 1);
for (int i = 0; i < depth; i++) out << " ";
out << "</" << name() << ">\n";
}
void terminal_node_t::print(std::ostream& out, int depth) const
{
for (int i = 0; i < depth; i++) out << " ";
if (data.empty()) {
out << '<' << name() << " />\n";
} else {
out << '<' << name() << ">"
<< text()
<< "</" << name() << ">\n";
}
}
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
template <typename T>
inline T * create_node(document_t::parser_t * parser)
{
T * node = new T(parser->document, parser->node_stack.empty() ?
NULL : parser->node_stack.front());
node->set_name(parser->pending);
node->attrs = parser->pending_attrs;
parser->pending = NULL;
parser->pending_attrs = NULL;
return node;
}
static void startElement(void *userData, const char *name, const char **attrs)
{
document_t::parser_t * parser = static_cast<document_t::parser_t *>(userData);
DEBUG("xml.parse", "startElement(" << name << ")");
if (parser->pending) {
parent_node_t * node = create_node<parent_node_t>(parser);
if (parser->node_stack.empty())
parser->document->top = node;
parser->node_stack.push_front(node);
}
parser->pending = name;
if (attrs) {
for (const char ** p = attrs; *p; p += 2) {
if (! parser->pending_attrs)
parser->pending_attrs = new node_t::attrs_map;
std::pair<node_t::attrs_map::iterator, bool> result
= parser->pending_attrs->insert
(node_t::attrs_map::value_type(*p, *(p + 1)));
assert(result.second);
}
}
}
static void endElement(void *userData, const char *name)
{
document_t::parser_t * parser = static_cast<document_t::parser_t *>(userData);
DEBUG("xml.parse", "endElement(" << name << ")");
if (parser->pending) {
terminal_node_t * node = create_node<terminal_node_t>(parser);
if (parser->node_stack.empty()) {
parser->document->top = node;
return;
}
}
else if (! parser->handled_data) {
assert(! parser->node_stack.empty());
parser->node_stack.pop_front();
}
else {
parser->handled_data = false;
}
}
static void dataHandler(void *userData, const char *s, int len)
{
document_t::parser_t * parser = static_cast<document_t::parser_t *>(userData);
DEBUG("xml.parse", "dataHandler(" << string(s, len) << ")");
bool all_whitespace = true;
for (int i = 0; i < len; i++) {
if (! std::isspace(s[i])) {
all_whitespace = false;
break;
}
}
// jww (2006-09-28): I currently do not support text nodes within a
// node that has children.
if (! all_whitespace) {
terminal_node_t * node = create_node<terminal_node_t>(parser);
node->set_text(string(s, len));
parser->handled_data = true;
if (parser->node_stack.empty()) {
parser->document->top = node;
return;
}
}
}
bool document_t::parser_t::test(std::istream& in) const
{
char buf[80];
in.getline(buf, 79);
if (std::strncmp(buf, "<?xml", 5) != 0) {
in.clear();
in.seekg(0, std::ios::beg);
return false;
}
in.clear();
in.seekg(0, std::ios::beg);
return true;
}
document_t * document_t::parser_t::parse(std::istream& in)
{
std::auto_ptr<document_t> doc(new document_t);
document = doc.get();
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, startElement, endElement);
XML_SetCharacterDataHandler(parser, dataHandler);
XML_SetUserData(parser, this);
char buf[BUFSIZ];
while (! in.eof()) {
in.getline(buf, BUFSIZ - 1);
std::strcat(buf, "\n");
bool result;
try {
result = XML_Parse(parser, buf, std::strlen(buf), in.eof());
}
catch (const std::exception& err) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
XML_ParserFree(parser);
throw_(parse_error, err.what());
}
if (! have_error.empty()) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
#if 0
// jww (2007-04-26): What is this doing??
parse_error err(have_error);
std::cerr << "Error: " << err.what() << std::endl;
#endif
have_error = "";
}
if (! result) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser);
throw_(parse_error, err);
}
}
XML_ParserFree(parser);
document = NULL;
return doc.release();
}
#endif // HAVE_EXPAT || HAVE_XMLPARSE
node_t * commodity_node_t::children() const
{
// jww (2007-04-19): Need to report the commodity and its details
return NULL;
}
node_t * amount_node_t::children() const
{
// jww (2007-04-19): Need to report the quantity and commodity
return NULL;
}
node_t * transaction_node_t::children() const
{
return parent_node_t::children();
}
node_t * transaction_node_t::lookup_child(int _name_id) const
{
switch (_name_id) {
case document_t::PAYEE:
payee_virtual_node = new terminal_node_t(document);
payee_virtual_node->set_text(transaction->entry->payee);
return payee_virtual_node;
case document_t::ACCOUNT:
return new account_node_t(document, transaction->account,
const_cast<transaction_node_t *>(this));
}
return NULL;
}
value_t transaction_node_t::to_value() const
{
if (transaction->amount)
return *transaction->amount;
else
return value_t();
}
node_t * entry_node_t::children() const
{
if (! _children)
for (transactions_list::iterator i = entry->transactions.begin();
i != entry->transactions.end();
i++)
new transaction_node_t(document, *i, const_cast<entry_node_t *>(this));
return parent_node_t::children();
}
node_t * entry_node_t::lookup_child(int _name_id) const
{
switch (_name_id) {
case document_t::CODE: {
if (! entry->code)
break;
// jww (2007-04-20): I have to save this and then delete it later
terminal_node_t * code_node =
new terminal_node_t(document, const_cast<entry_node_t *>(this));
code_node->set_name(document_t::CODE);
code_node->set_text(*entry->code);
return code_node;
}
case document_t::PAYEE: {
// jww (2007-04-20): I have to save this and then delete it later
terminal_node_t * payee_node =
new terminal_node_t(document, const_cast<entry_node_t *>(this));
payee_node->set_name(document_t::PAYEE);
payee_node->set_text(entry->payee);
return payee_node;
}
}
return NULL;
}
node_t * account_node_t::children() const
{
if (! _children) {
if (! account->name.empty()) {
terminal_node_t * name_node =
new terminal_node_t(document, const_cast<account_node_t *>(this));
name_node->set_name(document_t::NAME);
name_node->set_text(account->name);
}
if (account->note) {
terminal_node_t * note_node =
new terminal_node_t(document, const_cast<account_node_t *>(this));
note_node->set_name(document_t::NOTE);
note_node->set_text(*account->note);
}
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
new account_node_t(document, (*i).second, const_cast<account_node_t *>(this));
}
return parent_node_t::children();
}
node_t * journal_node_t::children() const
{
if (! _children) {
#if 0
account_node_t * master_account =
new account_node_t(document, journal->master, const_cast<journal_node_t *>(this));
#endif
parent_node_t * entries =
new parent_node_t(document, const_cast<journal_node_t *>(this));
entries->set_name(document_t::ENTRIES);
for (entries_list::iterator i = journal->entries.begin();
i != journal->entries.end();
i++)
new entry_node_t(document, *i, const_cast<journal_node_t *>(this));
}
return parent_node_t::children();
}
void output_xml_string(std::ostream& out, const string& str)
{
for (const char * s = str.c_str(); *s; s++) {
switch (*s) {
case '<':
out << "&lt;";
break;
case '>':
out << "&gt;";
break;
case '&':
out << "&amp;";
break;
default:
out << *s;
break;
}
}
}
} // namespace xml
} // namespace ledger

View file

@ -562,7 +562,7 @@ bool xpath_t::function_scope_t::resolve(const string& name,
case 't':
if (name == "text") {
if (value->type == value_t::XML_NODE)
result.set_string(value->as_xml_node()->text());
result = value->as_xml_node()->to_value();
else
throw_(calc_error, "Attempt to call text() on a non-node value");
return true;
@ -679,14 +679,14 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
#endif
string ident = tok.value.as_string();
int id = -1;
if (std::isdigit(ident[0])) {
node.reset(new op_t(op_t::ARG_INDEX));
node->arg_index = lexical_cast<unsigned int>(ident.c_str());
}
else if ((id = document_t::lookup_builtin_id(ident)) != -1) {
else if (optional<node_t::nameid_t> id =
document_t::lookup_builtin_id(ident)) {
node.reset(new op_t(op_t::NODE_ID));
node->name_id = id;
node->name_id = *id;
}
else {
node.reset(new op_t(op_t::NODE_NAME));
@ -1213,11 +1213,8 @@ void xpath_t::op_t::find_values(value_t * context, scope_t * scope,
if (recursive) {
if (context->type == value_t::XML_NODE) {
node_t * ptr = context->as_xml_node();
if (ptr->has_flags(XML_NODE_IS_PARENT)) {
parent_node_t * parent = static_cast<parent_node_t *>(ptr);
for (node_t * node = parent->children();
node;
node = node->next) {
if (ptr->is_parent_node()) {
foreach (node_t * node, ptr->as_parent_node()) {
value_t temp(node);
find_values(&temp, scope, result_seq, recursive);
}
@ -1308,8 +1305,8 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
case document_t::PARENT:
if (context->type != value_t::XML_NODE)
throw_(compile_error, "Referencing parent node from a non-node value");
else if (context->as_xml_node()->parent)
return wrap_value(context->as_xml_node()->parent)->acquire();
else if (context->as_xml_node()->parent())
return wrap_value(&*context->as_xml_node()->parent())->acquire();
else
throw_(compile_error, "Referencing parent node from the root node");
@ -1317,15 +1314,14 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
if (context->type != value_t::XML_NODE)
throw_(compile_error, "Referencing root node from a non-node value");
else
return wrap_value(context->as_xml_node()->document->top)->acquire();
return wrap_value(&context->as_xml_node()->document())->acquire();
case document_t::ALL: {
if (context->type != value_t::XML_NODE)
throw_(compile_error, "Referencing child nodes from a non-node value");
parent_node_t * parent = context->as_xml_node()->as_parent_node();
value_t::sequence_t nodes;
for (node_t * node = parent->children(); node; node = node->next)
foreach (node_t * node, context->as_xml_node()->as_parent_node())
nodes.push_back(node);
return wrap_value(nodes)->acquire();
@ -1343,37 +1339,37 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
// First, look up the symbol as a node name within the current
// context. If any exist, then return the set of names.
value_t::sequence_t nodes;
if (ptr->is_parent_node()) {
value_t::sequence_t nodes;
if (ptr->has_flags(XML_NODE_IS_PARENT)) {
parent_node_t * parent = static_cast<parent_node_t *>(ptr);
for (node_t * node = parent->children();
node;
node = node->next) {
foreach (node_t * node, ptr->as_parent_node()) {
if ((kind == NODE_NAME &&
std::strcmp(name->c_str(), node->name()) == 0) ||
(kind == NODE_ID && name_id == node->name_id))
(kind == NODE_ID && name_id == node->name_id()))
nodes.push_back(node);
}
return wrap_value(nodes)->acquire();
}
return wrap_value(nodes)->acquire();
} else {
assert(ptr);
int id = ptr->document->lookup_name_id(*name);
if (id != -1) {
if (optional<node_t::nameid_t> id =
ptr->document().lookup_name_id(*name)) {
op_t * node = new_node(NODE_ID);
node->name_id = id;
node->name_id = *id;
return node->acquire();
}
}
}
return acquire();
case ATTR_NAME: {
// jww (2006-09-29): Attrs should map strings to values, not strings
const char * value = context->as_xml_node()->get_attr(name->c_str());
return wrap_value(value)->acquire();
}
case ATTR_NAME:
if (optional<node_t::nameid_t> id =
context->as_xml_node()->document().lookup_name_id(*name)) {
optional<const string&> value = context->as_xml_node()->get_attr(*id);
if (value)
return wrap_value(*value)->acquire();
}
return acquire();
case VAR_NAME:
case FUNC_NAME:
@ -1903,23 +1899,16 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
return NULL;
}
void xpath_t::calc(value_t& result, node_t * node, scope_t * scope) const
void xpath_t::calc(value_t& result, node_t& node, scope_t * scope) const
{
#if 0
try {
#endif
if (node) {
value_t context_node(node);
xpath_t final(ptr->compile(&context_node, scope, true));
// jww (2006-09-09): Give a better error here if this is not
// actually a value
final->get_value(result);
} else {
std::auto_ptr<terminal_node_t> fake_node(new terminal_node_t(NULL));
value_t context_node(fake_node.get());
xpath_t final(ptr->compile(&context_node, scope, true));
final->get_value(result);
}
value_t context_node(&node);
xpath_t final(ptr->compile(&context_node, scope, true));
// jww (2006-09-09): Give a better error here if this is not
// actually a value
final->get_value(result);
#if 0
}
catch (error * err) {
@ -2041,11 +2030,7 @@ bool xpath_t::op_t::print(std::ostream& out,
break;
case NODE_ID:
#ifdef THREADSAFE
out << '%' << name_id;
#else
out << node_t::document->lookup_name(name_id);
#endif
break;
case NODE_NAME:
@ -2331,11 +2316,7 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const
break;
case NODE_ID:
#ifdef THREADSAFE
out << "NODE_ID - " << name_id;
#else
out << "NODE_ID - " << node_t::document->lookup_name(name_id);
#endif
break;
case ATTR_NAME:

View file

@ -32,7 +32,7 @@
#ifndef _XPATH_H
#define _XPATH_H
#include "xml.h"
#include "document.h"
namespace ledger {
namespace xml {
@ -123,8 +123,7 @@ public:
void (T::*_mptr)(value_t& result))
: functor_t(_name, false), ptr(_ptr), mptr(_mptr) {}
virtual void operator()(value_t& result,
scope_t * locals = NULL) {
virtual void operator()(value_t& result, scope_t * locals = NULL) {
assert(ptr);
assert(mptr);
assert(locals || locals == NULL);
@ -430,7 +429,7 @@ public:
string * name; // used by constant SYMBOL
unsigned int arg_index; // used by ARG_INDEX and O_ARG
functor_t * functor; // used by terminal FUNCTOR
unsigned int name_id; // used by NODE_NAME and ATTR_NAME
node_t::nameid_t name_id; // used by NODE_NAME and ATTR_NAME
#if 0
mask_t * mask; // used by terminal MASK
#endif
@ -720,30 +719,9 @@ public:
reset(tmp ? tmp->acquire() : NULL);
}
void compile(const string& _expr, scope_t * scope = NULL,
unsigned short _flags = XPATH_PARSE_RELAXED) {
parse(_expr, _flags);
// jww (2006-09-24): fix
compile((node_t *)NULL, scope);
}
void compile(std::istream& in, scope_t * scope = NULL,
unsigned short _flags = XPATH_PARSE_RELAXED) {
parse(in, _flags);
// jww (2006-09-24): fix
compile((node_t *)NULL, scope);
}
void compile(document_t * document, scope_t * scope = NULL) {
if (! document) {
document_t tdoc;
compile(tdoc.top, scope);
} else {
compile(document->top, scope);
}
}
void compile(node_t * top_node, scope_t * scope = NULL) {
void compile(node_t& top_node, scope_t * scope = NULL) {
if (ptr) {
value_t noderef(top_node);
value_t noderef(&top_node);
op_t * compiled = ptr->compile(&noderef, scope);
if (compiled == ptr)
compiled->release();
@ -752,16 +730,9 @@ public:
}
}
virtual void calc(value_t& result, node_t * node, scope_t * scope = NULL) const;
virtual value_t calc(document_t * document, scope_t * scope = NULL) const {
if (! ptr)
return 0L;
value_t temp;
calc(temp, document ? document->top : NULL, scope);
return temp;
}
virtual value_t calc(node_t * tcontext, scope_t * scope = NULL) const {
virtual void calc(value_t& result, node_t& node,
scope_t * scope = NULL) const;
virtual value_t calc(node_t& tcontext, scope_t * scope = NULL) const {
if (! ptr)
return 0L;
value_t temp;
@ -769,15 +740,15 @@ public:
return temp;
}
static void eval(value_t& result, const string& _expr,
document_t * document, scope_t * scope = NULL) {
static void eval(value_t& result, const string& _expr, node_t& top,
scope_t * scope = NULL) {
xpath_t temp(_expr);
temp.calc(result, document->top, scope);
temp.calc(result, top, scope);
}
static value_t eval(const string& _expr, document_t * document,
static value_t eval(const string& _expr, node_t& top,
scope_t * scope = NULL) {
xpath_t temp(_expr);
return temp.calc(document, scope);
return temp.calc(top, scope);
}
void print(std::ostream& out) const {