Restructured the code to use the new utility code in utils.h.

This commit is contained in:
John Wiegley 2007-04-27 10:08:42 +00:00
parent d016291483
commit 0eb597a681
45 changed files with 1277 additions and 1163 deletions

30
COPYRIGHT Normal file
View file

@ -0,0 +1,30 @@
/*
* 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.
*/

166
amount.cc
View file

@ -1,33 +1,44 @@
// amount.cc
/**
* @file amount.cc
* @author John Wiegley
* @date Thu Apr 26 15:19:46 2007
*
* @brief Types for handling commoditized math.
*
* This file defines member functions for amount_t and the various
* flavors of commodity_t.
*/
// 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.
/*
* 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 "amount.h"
#include "binary.h"
@ -325,7 +336,7 @@ amount_t::amount_t(const double val)
void amount_t::_release()
{
DEBUG_PRINT("amounts.refs",
DEBUG_("amounts.refs",
quantity << " ref--, now " << (quantity->ref - 1));
if (--quantity->ref == 0) {
if (! (quantity->flags & BIGINT_BULK_ALLOC))
@ -367,7 +378,7 @@ void amount_t::_copy(const amount_t& amt)
quantity = new bigint_t(*amt.quantity);
} else {
quantity = amt.quantity;
DEBUG_PRINT("amounts.refs",
DEBUG_("amounts.refs",
quantity << " ref++, now " << (quantity->ref + 1));
quantity->ref++;
}
@ -473,10 +484,11 @@ void amount_t::_clear()
amount_t& amount_t::operator+=(const amount_t& amt)
{
if (commodity() != amt.commodity()) {
throw new amount_error
throw amount_exception
(string("Adding amounts with different commodities: ") +
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
context());
}
if (! amt.quantity)
@ -508,10 +520,11 @@ amount_t& amount_t::operator+=(const amount_t& amt)
amount_t& amount_t::operator-=(const amount_t& amt)
{
if (commodity() != amt.commodity())
throw new amount_error
throw amount_exception
(string("Subtracting amounts with different commodities: ") +
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
context());
if (! amt.quantity)
return *this;
@ -545,10 +558,11 @@ amount_t& amount_t::operator*=(const amount_t& amt)
{
if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity()) {
throw new amount_error
throw amount_exception
(string("Multiplying amounts with different commodities: ") +
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
context());
}
if (! amt.quantity) {
@ -585,14 +599,15 @@ amount_t& amount_t::operator/=(const amount_t& amt)
{
if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity()) {
throw new amount_error
throw amount_exception
(string("Dividing amounts with different commodities: ") +
(has_commodity() ? commodity_->qualified_symbol : "NONE") + " != " +
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"));
(amt.has_commodity() ? amt.commodity_->qualified_symbol : "NONE"),
context());
}
if (! amt.quantity || ! amt) {
throw new amount_error("Divide by zero");
throw amount_exception("Divide by zero", context());
}
else if (! quantity) {
*this = amt;
@ -658,9 +673,10 @@ int amount_t::compare(const amount_t& amt) const
return sign();
if (has_commodity() && amt.commodity() && commodity() != amt.commodity())
throw new amount_error
throw amount_exception
(string("Cannot compare amounts with different commodities: ") +
commodity().symbol() + " and " + amt.commodity().symbol());
commodity().symbol() + " and " + amt.commodity().symbol(),
context());
if (quantity->prec == amt.quantity->prec) {
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity));
@ -1119,7 +1135,8 @@ static void parse_commodity(std::istream& in, string& symbol)
if (c == '"')
in.get(c);
else
throw new amount_error("Quoted commodity symbol lacks closing quote");
throw amount_exception("Quoted commodity symbol lacks closing quote",
context());
} else {
READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]);
}
@ -1136,14 +1153,15 @@ bool parse_annotations(std::istream& in, amount_t& price,
char c = peek_next_nonws(in);
if (c == '{') {
if (price)
throw new amount_error("Commodity specifies more than one price");
throw amount_exception("Commodity specifies more than one price",
context());
in.get(c);
READ_INTO(in, buf, 255, c, c != '}');
if (c == '}')
in.get(c);
else
throw new amount_error("Commodity price lacks closing brace");
throw amount_exception("Commodity price lacks closing brace", context());
price.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
price.in_place_reduce();
@ -1158,28 +1176,32 @@ bool parse_annotations(std::istream& in, amount_t& price,
}
else if (c == '[') {
if (is_valid_moment(date))
throw new amount_error("Commodity specifies more than one date");
throw amount_exception("Commodity specifies more than one date",
context());
in.get(c);
READ_INTO(in, buf, 255, c, c != ']');
if (c == ']')
in.get(c);
else
throw new amount_error("Commodity date lacks closing bracket");
throw amount_exception("Commodity date lacks closing bracket",
context());
date = parse_datetime(buf);
has_date = true;
}
else if (c == '(') {
if (! tag.empty())
throw new amount_error("Commodity specifies more than one tag");
throw amount_exception("Commodity specifies more than one tag",
context());
in.get(c);
READ_INTO(in, buf, 255, c, c != ')');
if (c == ')')
in.get(c);
else
throw new amount_error("Commodity tag lacks closing parenthesis");
throw amount_exception("Commodity tag lacks closing parenthesis",
context());
tag = buf;
}
@ -1188,7 +1210,7 @@ bool parse_annotations(std::istream& in, amount_t& price,
}
} while (true);
DEBUG_PRINT("amounts.commodities",
DEBUG_("amounts.commodities",
"Parsed commodity annotations: "
<< " price " << price << " "
<< " date " << date << " "
@ -1251,7 +1273,8 @@ void amount_t::parse(std::istream& in, unsigned char flags)
}
if (quant.empty())
throw new amount_error("No quantity specified for amount");
throw amount_exception("No quantity specified for amount",
context());
_init();
@ -1446,7 +1469,7 @@ void amount_t::read_quantity(char *& data)
data += sizeof(unsigned int);
quantity = (bigint_t *) (bigints + (index - 1) * sizeof(bigint_t));
DEBUG_PRINT("amounts.refs",
DEBUG_("amounts.refs",
quantity << " ref++, now " << (quantity->ref + 1));
quantity->ref++;
}
@ -1535,12 +1558,12 @@ bool amount_t::valid() const
{
if (quantity) {
if (quantity->ref == 0) {
DEBUG_PRINT("ledger.validate", "amount_t: quantity->ref == 0");
DEBUG_("ledger.validate", "amount_t: quantity->ref == 0");
return false;
}
}
else if (commodity_) {
DEBUG_PRINT("ledger.validate", "amount_t: commodity_ != NULL");
DEBUG_("ledger.validate", "amount_t: commodity_ != NULL");
return false;
}
return true;
@ -1561,7 +1584,7 @@ void amount_t::annotate_commodity(const amount_t& tprice,
}
assert(this_base);
DEBUG_PRINT("amounts.commodities", "Annotating commodity for amount "
DEBUG_("amounts.commodities", "Annotating commodity for amount "
<< *this << std::endl
<< " price " << tprice << " "
<< " date " << tdate << " "
@ -1575,7 +1598,7 @@ void amount_t::annotate_commodity(const amount_t& tprice,
if (ann_comm)
set_commodity(*ann_comm);
DEBUG_PRINT("amounts.commodities", " Annotated amount is " << *this);
DEBUG_("amounts.commodities", " Annotated amount is " << *this);
}
amount_t amount_t::strip_annotations(const bool _keep_price,
@ -1586,7 +1609,7 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
(_keep_price && _keep_date && _keep_tag))
return *this;
DEBUG_PRINT("amounts.commodities", "Reducing commodity for amount "
DEBUG_("amounts.commodities", "Reducing commodity for amount "
<< *this << std::endl
<< " keep price " << _keep_price << " "
<< " keep date " << _keep_date << " "
@ -1613,7 +1636,7 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
amount_t t(*this);
t.set_commodity(*new_comm);
DEBUG_PRINT("amounts.commodities", " Reduced amount is " << t);
DEBUG_("amounts.commodities", " Reduced amount is " << t);
return t;
}
@ -1623,7 +1646,7 @@ amount_t amount_t::price() const
if (commodity_ && commodity_->annotated) {
amount_t t(((annotated_commodity_t *)commodity_)->price);
t *= number();
DEBUG_PRINT("amounts.commodities",
DEBUG_("amounts.commodities",
"Returning price of " << *this << " = " << t);
return t;
}
@ -1633,7 +1656,7 @@ amount_t amount_t::price() const
moment_t amount_t::date() const
{
if (commodity_ && commodity_->annotated) {
DEBUG_PRINT("amounts.commodities",
DEBUG_("amounts.commodities",
"Returning date of " << *this << " = "
<< ((annotated_commodity_t *)commodity_)->date);
return ((annotated_commodity_t *)commodity_)->date;
@ -1675,7 +1698,7 @@ commodity_base_t * commodity_base_t::create(const string& symbol)
{
commodity_base_t * commodity = new commodity_base_t(symbol);
DEBUG_PRINT("amounts.commodities", "Creating base commodity " << symbol);
DEBUG_("amounts.commodities", "Creating base commodity " << symbol);
std::pair<base_commodities_map::iterator, bool> result
= commodities.insert(base_commodities_pair(symbol, commodity));
@ -1696,18 +1719,18 @@ bool commodity_t::needs_quotes(const string& symbol)
bool commodity_t::valid() const
{
if (symbol().empty() && this != null_commodity) {
DEBUG_PRINT("ledger.validate",
DEBUG_("ledger.validate",
"commodity_t: symbol().empty() && this != null_commodity");
return false;
}
if (annotated && ! base) {
DEBUG_PRINT("ledger.validate", "commodity_t: annotated && ! base");
DEBUG_("ledger.validate", "commodity_t: annotated && ! base");
return false;
}
if (precision() > 16) {
DEBUG_PRINT("ledger.validate", "commodity_t: precision() > 16");
DEBUG_("ledger.validate", "commodity_t: precision() > 16");
return false;
}
@ -1728,7 +1751,7 @@ commodity_t * commodity_t::create(const string& symbol)
commodity->qualified_symbol = symbol;
}
DEBUG_PRINT("amounts.commodities",
DEBUG_("amounts.commodities",
"Creating commodity " << commodity->qualified_symbol);
std::pair<commodities_map::iterator, bool> result
@ -1750,7 +1773,7 @@ commodity_t * commodity_t::create(const string& symbol)
commodity_t * commodity_t::find_or_create(const string& symbol)
{
DEBUG_PRINT("amounts.commodities", "Find-or-create commodity " << symbol);
DEBUG_("amounts.commodities", "Find-or-create commodity " << symbol);
commodity_t * commodity = find(symbol);
if (commodity)
@ -1760,7 +1783,7 @@ commodity_t * commodity_t::find_or_create(const string& symbol)
commodity_t * commodity_t::find(const string& symbol)
{
DEBUG_PRINT("amounts.commodities", "Find commodity " << symbol);
DEBUG_("amounts.commodities", "Find commodity " << symbol);
commodities_map::const_iterator i = commodities.find(symbol);
if (i != commodities.end())
@ -1872,7 +1895,7 @@ annotated_commodity_t::create(const commodity_t& comm,
commodity->qualified_symbol = comm.symbol();
DEBUG_PRINT("amounts.commodities", "Creating annotated commodity "
DEBUG_("amounts.commodities", "Creating annotated commodity "
<< "symbol " << commodity->symbol()
<< " key " << mapping_key << std::endl
<< " price " << price << " "
@ -1899,20 +1922,21 @@ namespace {
const string& tag)
{
if (price < 0)
throw new amount_error("A commodity's price may not be negative");
throw amount_exception("A commodity's price may not be negative",
context());
std::ostringstream name;
comm.write(name);
annotated_commodity_t::write_annotations(name, price, date, tag);
DEBUG_PRINT("amounts.commodities", "make_qualified_name for "
DEBUG_("amounts.commodities", "make_qualified_name for "
<< comm.qualified_symbol << std::endl
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
DEBUG_PRINT("amounts.commodities", "qualified_name is " << name.str());
DEBUG_("amounts.commodities", "qualified_name is " << name.str());
return name.str();
}

View file

@ -746,16 +746,10 @@ inline commodity_t& amount_t::commodity() const {
return *commodity_;
}
void parse_conversion(const string& larger_str,
const string& smaller_str);
class amount_error : public error {
public:
amount_error(const string& _reason) throw() : error(_reason) {}
virtual ~amount_error() throw() {}
};
DECLARE_EXCEPTION(amount_exception);
struct compare_amount_commodities {
bool operator()(const amount_t * left, const amount_t * right) const;

View file

@ -15,10 +15,8 @@ amount_t balance_t::amount(const commodity_t& commodity) const
if (temp.amounts.size() == 1)
return temp.amount(commodity);
std::ostringstream errmsg;
errmsg << "Requested amount of a balance with multiple commodities: "
<< temp;
throw new amount_error(errmsg.str());
throw_(amount_exception,
"Requested amount of a balance with multiple commodities: " << temp);
}
}
else if (amounts.size() > 0) {
@ -176,7 +174,7 @@ balance_t& balance_t::operator*=(const balance_t& bal)
std::ostringstream errmsg;
errmsg << "Cannot multiply two balances: " << temp << " * " << bal;
throw new amount_error(errmsg.str());
throw amount_exception(errmsg.str(), context());
}
}
@ -215,7 +213,7 @@ balance_t& balance_t::operator*=(const amount_t& amt)
errmsg << "Attempt to multiply balance by a commodity"
<< " not found in that balance: "
<< temp << " * " << amt;
throw new amount_error(errmsg.str());
throw amount_exception(errmsg.str(), context());
}
}
return *this;
@ -226,7 +224,7 @@ balance_t& balance_t::operator/=(const balance_t& bal)
if (bal.realzero()) {
std::ostringstream errmsg;
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
throw new amount_error(errmsg.str());
throw amount_exception(errmsg.str(), context());
}
else if (realzero()) {
return *this = 0L;
@ -245,7 +243,7 @@ balance_t& balance_t::operator/=(const balance_t& bal)
std::ostringstream errmsg;
errmsg << "Cannot divide between two balances: " << temp << " / " << bal;
throw new amount_error(errmsg.str());
throw amount_exception(errmsg.str(), context());
}
}
@ -254,7 +252,7 @@ balance_t& balance_t::operator/=(const amount_t& amt)
if (amt.realzero()) {
std::ostringstream errmsg;
errmsg << "Attempt to divide by zero: " << *this << " / " << amt;
throw new amount_error(errmsg.str());
throw amount_exception(errmsg.str(), context());
}
else if (realzero()) {
return *this = 0L;
@ -286,7 +284,7 @@ balance_t& balance_t::operator/=(const amount_t& amt)
errmsg << "Attempt to divide balance by a commodity"
<< " not found in that balance: "
<< temp << " * " << amt;
throw new amount_error(errmsg.str());
throw amount_exception(errmsg.str(), context());
}
}
return *this;
@ -306,10 +304,9 @@ balance_t::operator amount_t() const
if (temp.amounts.size() == 1)
return (*temp.amounts.begin()).second;
std::ostringstream errmsg;
errmsg << "Cannot convert a balance with "
<< "multiple commodities to an amount: " << temp;
throw new amount_error(errmsg.str());
throw_(amount_exception,
"Cannot convert a balance with " <<
"multiple commodities to an amount: " << temp);
}
}

15
error.h
View file

@ -16,19 +16,24 @@ public:
exception(const string& _reason,
const context& immediate_ctxt) throw()
: reason(_reason) {
EXCEPTION(reason);
push(immediate_ctxt);
}
virtual ~exception() throw() {}
void push(const context& intermediate_ctxt) throw() {
context_stack.push_front(intermediate_ctxt);
}
void write(std::ostream& out) const throw() {
#if 0
for (std::list<context>::const_iterator
i = context.begin();
i != context.end();
i = context_stack.begin();
i != context_stack.end();
i++)
(*i).write(out);
#endif
}
const char * what() const throw() {
@ -36,13 +41,13 @@ public:
}
};
#define DEFINE_EXCEPTION(name) \
#define DECLARE_EXCEPTION(name) \
class name : public exception { \
public: \
name(const string& _reason, \
const context& immediate_ctxt) throw() \
: exception(_reason, immediate_ctxt) {} \
};
}
#if 0
@ -125,6 +130,7 @@ class fatal_assert : public fatal {
inline void unexpected(char c, char wanted)
{
#if 0
if ((unsigned char) c == 0xff) {
if (wanted)
throw new error(string("Missing '") + wanted + "'");
@ -137,6 +143,7 @@ inline void unexpected(char c, char wanted)
else
throw new error(string("Invalid char '") + c + "'");
}
#endif
}
} // namespace ledger

View file

@ -89,7 +89,7 @@ void format_t::parse(const string& fmt)
if (current->max_width != -1 && current->min_width != -1 &&
current->max_width < current->min_width)
throw new format_error("Maximum width is less than the minimum width");
throw_(format_exception, "Maximum width is less than the minimum width");
switch (*p) {
case '|':
@ -111,7 +111,7 @@ void format_t::parse(const string& fmt)
p++;
}
if (*p != close)
throw new format_error(string("Missing '") + close + "'");
throw_(format_exception, "Missing '" << close << "'");
if (open == '{') {
assert(! current->xpath);

View file

@ -101,12 +101,7 @@ class format_t
}
};
class format_error : public error {
public:
format_error(const string& reason, error_context * ctxt = NULL) throw()
: error(reason, ctxt) {}
virtual ~format_error() throw() {}
};
DECLARE_EXCEPTION(format_exception);
} // namespace ledger

View file

@ -341,13 +341,16 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * msg = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser);
throw new parse_error(msg);
throw_(parse_exception, 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 = "";
}
}

View file

@ -32,9 +32,9 @@ struct gnucash_parser_t : public parser_t
std::istream * instreamp;
unsigned int offset;
XML_Parser parser;
string path;
string path;
unsigned int src_idx;
istream_pos_type beg_pos;
unsigned long beg_pos;
unsigned long beg_line;
transaction_t::state_t curr_state;

View file

@ -35,12 +35,12 @@ moment_t transaction_t::effective_date() const
bool transaction_t::valid() const
{
if (! entry) {
DEBUG_PRINT("ledger.validate", "transaction_t: ! entry");
DEBUG_("ledger.validate", "transaction_t: ! entry");
return false;
}
if (state != UNCLEARED && state != CLEARED && state != PENDING) {
DEBUG_PRINT("ledger.validate", "transaction_t: state is bad");
DEBUG_("ledger.validate", "transaction_t: state is bad");
return false;
}
@ -53,27 +53,27 @@ bool transaction_t::valid() const
break;
}
if (! found) {
DEBUG_PRINT("ledger.validate", "transaction_t: ! found");
DEBUG_("ledger.validate", "transaction_t: ! found");
return false;
}
if (! account) {
DEBUG_PRINT("ledger.validate", "transaction_t: ! account");
DEBUG_("ledger.validate", "transaction_t: ! account");
return false;
}
if (! amount.valid()) {
DEBUG_PRINT("ledger.validate", "transaction_t: ! amount.valid()");
DEBUG_("ledger.validate", "transaction_t: ! amount.valid()");
return false;
}
if (cost && ! cost->valid()) {
DEBUG_PRINT("ledger.validate", "transaction_t: cost && ! cost->valid()");
DEBUG_("ledger.validate", "transaction_t: cost && ! cost->valid()");
return false;
}
if (flags & ~0x003f) {
DEBUG_PRINT("ledger.validate", "transaction_t: flags are bad");
DEBUG_("ledger.validate", "transaction_t: flags are bad");
return false;
}
@ -199,7 +199,7 @@ bool entry_base_t::finalize()
continue;
if (! empty_allowed)
throw new error("Only one transaction with null amount allowed per entry");
throw_(exception, "Only one transaction with null amount allowed per entry");
empty_allowed = false;
// If one transaction gives no value at all, its value will become
@ -255,12 +255,16 @@ bool entry_base_t::finalize()
}
if (balance) {
#if 1
throw_(balance_exception, "Entry does not balance");
#else
error * err =
new balance_error("Entry does not balance",
new entry_context(*this, "While balancing entry:"));
err->context.push_front
(new value_context(balance, "Unbalanced remainder is:"));
throw err;
#endif
}
return true;
@ -307,7 +311,7 @@ void entry_t::add_transaction(transaction_t * xact)
bool entry_t::valid() const
{
if (! is_valid_moment(_date) || ! journal) {
DEBUG_PRINT("ledger.validate", "entry_t: ! _date || ! journal");
DEBUG_("ledger.validate", "entry_t: ! _date || ! journal");
return false;
}
@ -315,7 +319,7 @@ bool entry_t::valid() const
i != transactions.end();
i++)
if ((*i)->entry != this || ! (*i)->valid()) {
DEBUG_PRINT("ledger.validate", "entry_t: transaction not valid");
DEBUG_("ledger.validate", "entry_t: transaction not valid");
return false;
}
@ -466,7 +470,7 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
bool account_t::valid() const
{
if (depth > 256 || ! journal) {
DEBUG_PRINT("ledger.validate", "account_t: depth > 256 || ! journal");
DEBUG_("ledger.validate", "account_t: depth > 256 || ! journal");
return false;
}
@ -474,12 +478,12 @@ bool account_t::valid() const
i != accounts.end();
i++) {
if (this == (*i).second) {
DEBUG_PRINT("ledger.validate", "account_t: parent refers to itself!");
DEBUG_("ledger.validate", "account_t: parent refers to itself!");
return false;
}
if (! (*i).second->valid()) {
DEBUG_PRINT("ledger.validate", "account_t: child not valid");
DEBUG_("ledger.validate", "account_t: child not valid");
return false;
}
}
@ -575,7 +579,7 @@ bool journal_t::remove_entry(entry_t * entry)
bool journal_t::valid() const
{
if (! master->valid()) {
DEBUG_PRINT("ledger.validate", "journal_t: master not valid");
DEBUG_("ledger.validate", "journal_t: master not valid");
return false;
}
@ -583,7 +587,7 @@ bool journal_t::valid() const
i != entries.end();
i++)
if (! (*i)->valid()) {
DEBUG_PRINT("ledger.validate", "journal_t: entry not valid");
DEBUG_("ledger.validate", "journal_t: entry not valid");
return false;
}
@ -591,7 +595,7 @@ bool journal_t::valid() const
i != commodity_t::commodities.end();
i++)
if (! (*i).second->valid()) {
DEBUG_PRINT("ledger.validate", "journal_t: commodity not valid");
DEBUG_("ledger.validate", "journal_t: commodity not valid");
return false;
}
@ -634,6 +638,7 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base,
#endif
}
#if 0
void entry_context::describe(std::ostream& out) const throw()
{
if (! desc.empty())
@ -657,6 +662,7 @@ xact_context::xact_context(const ledger::transaction_t& _xact,
}
line = xact.beg_line;
}
#endif
} // namespace ledger

View file

@ -85,6 +85,7 @@ class transaction_t
bool valid() const;
};
#if 0
class xact_context : public file_context {
public:
const transaction_t& xact;
@ -93,6 +94,7 @@ class xact_context : public file_context {
const string& desc = "") throw();
virtual ~xact_context() throw() {}
};
#endif
class journal_t;
@ -196,6 +198,7 @@ struct entry_finalizer_t {
void print_entry(std::ostream& out, const entry_base_t& entry,
const string& prefix = "");
#if 0
class entry_context : public error_context {
public:
const entry_base_t& entry;
@ -207,14 +210,9 @@ class entry_context : public error_context {
virtual void describe(std::ostream& out) const throw();
};
#endif
class balance_error : public error {
public:
balance_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~balance_error() throw() {}
};
DECLARE_EXCEPTION(balance_exception);
class auto_entry_t : public entry_base_t

73
main.cc
View file

@ -38,11 +38,11 @@ static int read_and_report(report_t * report, int argc, char * argv[],
else
session.use_cache = session.data_file.empty() && session.price_db.empty();
DEBUG_PRINT("ledger.session.cache", "1. use_cache = " << session.use_cache);
DEBUG_("ledger.session.cache", "1. use_cache = " << session.use_cache);
// Process the environment settings
TRACE(main, "Processing options and environment settings");
TRACE(1, "Processing options and environment settings");
process_environment(const_cast<const char **>(envp), "LEDGER_", report);
@ -60,15 +60,15 @@ static int read_and_report(report_t * report, int argc, char * argv[],
if (session.data_file == session.cache_file)
session.use_cache = false;
DEBUG_PRINT("ledger.session.cache", "2. use_cache = " << session.use_cache);
DEBUG_("ledger.session.cache", "2. use_cache = " << session.use_cache);
TRACE(main, string("Initialization file is ") + session.init_file);
TRACE(main, string("Price database is ") + session.price_db);
TRACE(main, string("Binary cache is ") + session.cache_file);
TRACE(main, string("Main journal is ") + session.data_file);
TRACE(1, "Initialization file is " << session.init_file);
TRACE(1, "Price database is " << session.price_db);
TRACE(1, "Binary cache is " << session.cache_file);
TRACE(1, "Main journal is " << session.data_file);
TRACE(main, string("Based on option settings, binary cache ") +
(session.use_cache ? "WILL " : "will NOT ") + "be used");
TRACE(1, "Based on option settings, binary cache " <<
(session.use_cache ? "WILL " : "will NOT ") << "be used");
// Read the command word and create a command object based on it
@ -160,7 +160,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
command.reset(def->functor_obj());
if (! command.get())
throw new error(string("Unrecognized command '") + verb + "'");
throw_(exception, string("Unrecognized command '") + verb + "'");
}
// Parse the initialization file, which can only be textual; then
@ -186,11 +186,11 @@ static int read_and_report(report_t * report, int argc, char * argv[],
else if (! report->pager.empty()) {
status = pipe(pfd);
if (status == -1)
throw new error("Failed to create pipe");
throw_(exception, "Failed to create pipe");
status = fork();
if (status < 0) {
throw new error("Failed to fork child process");
throw_(exception, "Failed to fork child process");
}
else if (status == 0) { // child
const char *arg0;
@ -332,29 +332,29 @@ static int read_and_report(report_t * report, int argc, char * argv[],
if (session.use_cache && session.cache_dirty &&
! session.cache_file.empty()) {
TRACE_PUSH(binary_cache, "Writing journal file");
TRACE_START(binary_cache, 1, "Writing journal file");
std::ofstream stream(session.cache_file.c_str());
#if 0
write_binary_journal(stream, journal);
#endif
TRACE_POP(binary_cache, "Finished writing");
TRACE_FINISH(binary_cache, 1);
}
#if defined(FREE_MEMORY)
// Cleanup memory -- if this is a beta or development build.
#if DEBUG_LEVEL >= BETA
{ TRACE_PUSH(cleanup, "Cleaning up allocated memory");
TRACE_START(cleanup, 1, "Cleaning up allocated memory");
#ifdef USE_BOOST_PYTHON
shutdown_ledger_for_python();
shutdown_ledger_for_python();
#endif
if (! report->output_file.empty())
delete out;
if (! report->output_file.empty())
delete out;
TRACE_POP(cleanup, "Finished cleaning"); }
TRACE_STOP(cleanup, 1);
#endif
// If the user specified a pager, wait for it to exit now
@ -367,7 +367,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
// Wait for child to finish
wait(&status);
if (status & 0xffff != 0)
throw new error("Something went wrong in the pager");
throw_(exception, "Something went wrong in the pager");
}
#endif
@ -388,10 +388,8 @@ int main(int argc, char * argv[], char * envp[])
#if DEBUG_LEVEL < BETA
ledger::do_cleanup = false;
#else
ledger::tracing_active = true;
#endif
TRACE_PUSH(main, "Ledger starting");
TRACE(1, "Ledger starting");
ledger::amount_t::initialize();
@ -410,12 +408,6 @@ int main(int argc, char * argv[], char * envp[])
session->register_parser(new qif_parser_t);
session->register_parser(new textual_parser_t);
#if DEBUG_LEVEL >= BETA
DEBUG_IF("ledger.trace.memory") {
ledger::trace_class_mode = true;
}
#endif
std::auto_ptr<ledger::report_t> report(new ledger::report_t(session.get()));
status = read_and_report(report.get(), argc, argv, envp);
@ -427,9 +419,8 @@ int main(int argc, char * argv[], char * envp[])
} else {
ledger::amount_t::shutdown();
}
TRACE_POP(main, "Ledger done");
}
#if 0
catch (error * err) {
std::cout.flush();
// Push a null here since there's no file context
@ -439,9 +430,6 @@ int main(int argc, char * argv[], char * envp[])
err->reveal_context(std::cerr, "Error");
std::cerr << err->what() << std::endl;
delete err;
#if DEBUG_LEVEL >= BETA
ledger::tracing_active = false;
#endif
}
catch (fatal * err) {
std::cout.flush();
@ -452,32 +440,21 @@ int main(int argc, char * argv[], char * envp[])
err->reveal_context(std::cerr, "Fatal");
std::cerr << err->what() << std::endl;
delete err;
#if DEBUG_LEVEL >= BETA
ledger::tracing_active = false;
#endif
}
#endif
catch (const std::exception& err) {
std::cout.flush();
std::cerr << "Error: " << err.what() << std::endl;
#if DEBUG_LEVEL >= BETA
ledger::tracing_active = false;
#endif
}
catch (int _status) {
#if DEBUG_LEVEL >= BETA
ledger::tracing_active = false;
#endif
status = _status;
}
#if DEBUG_LEVEL >= BETA
DEBUG_IF("ledger.trace.memory") {
IF_DEBUG_("ledger.trace.memory") {
report_memory(std::cerr);
std::cerr << "Total calls to new: " << new_calls << std::endl
<< "Total memory new'd: " << new_size << std::endl;
}
ledger::tracing_active = false;
#endif
return status;
}

6
mask.h
View file

@ -21,12 +21,6 @@ class mask_t
}
};
class mask_error : public error {
public:
mask_error(const string& _reason) throw() : error(_reason) {}
virtual ~mask_error() throw() {}
};
} // namespace ledger
#endif // _MASK_H

8
ofx.cc
View file

@ -23,7 +23,7 @@ int ofx_proc_account_cb(struct OfxAccountData data, void * account_data)
if (! data.account_id_valid)
return -1;
DEBUG_PRINT("ledger.ofx.parse", "account " << data.account_name);
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));
@ -80,7 +80,7 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data,
xact->cost = new amount_t(stream.str() + " " + default_commodity->base_symbol());
}
DEBUG_PRINT("ledger.ofx.parse", "xact " << xact->amount
DEBUG_("ledger.ofx.parse", "xact " << xact->amount
<< " from " << *xact->account);
if (data.date_initiated_valid)
@ -142,13 +142,13 @@ int ofx_proc_security_cb(struct OfxSecurityData data, void * security_data)
commodities_map::iterator i = ofx_securities.find(data.unique_id);
if (i == ofx_securities.end()) {
DEBUG_PRINT("ledger.ofx.parse", "security " << symbol);
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_PRINT("ledger.ofx.parse", " price " << data.unitprice);
DEBUG_("ledger.ofx.parse", " price " << data.unitprice);
commodity->add_price(data.date_unitprice, amount_t(data.unitprice));
}

View file

@ -45,7 +45,9 @@ namespace {
void process_option(xml::xpath_t::functor_t * opt, xml::xpath_t::scope_t * scope,
const char * arg)
{
#if 0
try {
#endif
std::auto_ptr<xml::xpath_t::scope_t> args;
if (arg) {
args.reset(new xml::xpath_t::scope_t(scope, xml::xpath_t::scope_t::ARGUMENT));
@ -54,17 +56,17 @@ namespace {
value_t temp;
(*opt)(temp, args.get());
#if 0
}
catch (error * err) {
#if 0
err->context.push_back
(new error_context
(string("While parsing option '--") + opt->long_opt +
"'" + (opt->short_opt != '\0' ?
(string(" (-") + opt->short_opt + "):") : ":")));
#endif
throw err;
}
#endif
}
}
@ -103,9 +105,15 @@ void process_environment(const char ** envp, const string& tag,
*r = '\0';
if (*q == '=') {
#if 0
try {
#endif
if (! process_option(buf, scope, q + 1))
/*throw new option_error("unknown option")*/;
#if 0
throw new option_error("unknown option")
#endif
;
#if 0
}
catch (error * err) {
err->context.push_back
@ -114,6 +122,7 @@ void process_environment(const char ** envp, const string& tag,
*p + "':"));
throw err;
}
#endif
}
}
}
@ -149,22 +158,21 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
std::auto_ptr<xml::xpath_t::op_t> opt(find_option(scope, name));
if (! opt.get())
throw new option_error(string("illegal option --") + name);
throw_(option_exception, "illegal option --" << name);
xml::xpath_t::functor_t * def = opt->functor_obj();
if (! def)
throw new option_error(string("illegal option --") + name);
throw_(option_exception, "illegal option --" << name);
if (def->wants_args && value == NULL) {
value = *++i;
if (value == NULL)
throw new option_error(string("missing option argument for --") +
name);
throw_(option_exception, "missing option argument for --" << name);
}
process_option(def, scope, value);
}
else if ((*i)[1] == '\0') {
throw new option_error(string("illegal option -"));
throw_(option_exception, "illegal option -");
}
else {
std::list<xml::xpath_t::op_t *> option_queue;
@ -173,11 +181,11 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) {
xml::xpath_t::op_t * opt = find_option(scope, c);
if (! opt)
throw new option_error(string("illegal option -") + c);
throw_(option_exception, "illegal option -" << c);
xml::xpath_t::functor_t * def = opt->functor_obj();
if (! def)
throw new option_error(string("illegal option -") + c);
throw_(option_exception, "illegal option -" << c);
option_queue.push_back(opt);
}
@ -194,12 +202,13 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
if (def->wants_args) {
value = *++i;
if (value == NULL)
throw new option_error(string("missing option argument for -") +
throw_(option_exception, "missing option argument for -" <<
#if 0
def->short_opt);
def->short_opt
#else
'?');
'?'
#endif
);
}
process_option(def, scope, value);

View file

@ -15,11 +15,7 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
xml::xpath_t::scope_t * scope,
std::list<string>& args);
class option_error : public error {
public:
option_error(const string& reason) throw() : error(reason) {}
virtual ~option_error() throw() {}
};
DECLARE_EXCEPTION(option_exception);
} // namespace ledger

View file

@ -21,7 +21,65 @@ class parser_t
const string * original_file = NULL) = 0;
};
DEFINE_EXCEPTION(parse_exception)
DECLARE_EXCEPTION(parse_exception);
/************************************************************************
*
* General utility parsing functions
*/
inline char * skip_ws(char * ptr) {
while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
ptr++;
return ptr;
}
inline char peek_next_nonws(std::istream& in) {
char c = in.peek();
while (! in.eof() && std::isspace(c)) {
in.get(c);
c = in.peek();
}
return c;
}
#define READ_INTO(str, targ, size, var, cond) { \
char * _p = targ; \
var = str.peek(); \
while (! str.eof() && var != '\n' && (cond) && _p - targ < size) { \
str.get(var); \
if (str.eof()) \
break; \
if (var == '\\') { \
str.get(var); \
if (in.eof()) \
break; \
} \
*_p++ = var; \
var = str.peek(); \
} \
*_p = '\0'; \
}
#define READ_INTO_(str, targ, size, var, idx, cond) { \
char * _p = targ; \
var = str.peek(); \
while (! str.eof() && var != '\n' && (cond) && _p - targ < size) { \
str.get(var); \
if (str.eof()) \
break; \
idx++; \
if (var == '\\') { \
str.get(var); \
if (in.eof()) \
break; \
idx++; \
} \
*_p++ = var; \
var = str.peek(); \
} \
*_p = '\0'; \
}
} // namespace ledger

View file

@ -46,11 +46,11 @@ commodity_t * py_find_commodity(const string& symbol)
}
#define EXC_TRANSLATOR(type) \
void exc_translate_ ## type(const type * const err) { \
PyErr_SetString(PyExc_ArithmeticError, err->what()); \
void exc_translate_ ## type(const type& err) { \
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
EXC_TRANSLATOR(amount_error)
EXC_TRANSLATOR(amount_exception)
void export_amount()
{
@ -236,7 +236,7 @@ void export_amount()
;
#define EXC_TRANSLATE(type) \
register_exception_translator<type *>(&exc_translate_ ## type);
register_exception_translator<type>(&exc_translate_ ## type);
EXC_TRANSLATE(amount_error);
EXC_TRANSLATE(amount_exception);
}

View file

@ -71,7 +71,7 @@ object python_interpreter_t::import(const string& str)
try {
PyObject * mod = PyImport_Import(PyString_FromString(str.c_str()));
if (! mod)
throw error(string("Failed to import Python module ") + str);
throw_(exception, "Failed to import Python module " << str);
object newmod(handle<>(borrowed(mod)));
@ -86,7 +86,7 @@ object python_interpreter_t::import(const string& str)
}
catch (const error_already_set&) {
PyErr_Print();
throw error(string("Importing Python module ") + str);
throw_(exception, "Importing Python module " << str);
}
}
@ -120,7 +120,7 @@ object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
}
catch (const error_already_set&) {
PyErr_Print();
throw error("Evaluating Python code");
throw_(exception, "Evaluating Python code");
}
}
@ -138,7 +138,7 @@ object python_interpreter_t::eval(const string& str, py_eval_mode_t mode)
}
catch (const error_already_set&) {
PyErr_Print();
throw error("Evaluating Python code");
throw_(exception, "Evaluating Python code");
}
}
@ -165,8 +165,8 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
}
else if (PyObject * err = PyErr_Occurred()) {
PyErr_Print();
throw new xml::xpath_t::calc_error
(string("While calling Python function '") + name() + "'");
throw_(xml::xpath_t::calc_exception,
"While calling Python function '" << name() << "'");
} else {
assert(0);
}
@ -177,8 +177,8 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
}
catch (const error_already_set&) {
PyErr_Print();
throw new xml::xpath_t::calc_error
(string("While calling Python function '") + name() + "'");
throw_(xml::xpath_t::calc_exception,
"While calling Python function '" << name() << "'");
}
}
@ -194,7 +194,8 @@ void python_interpreter_t::lambda_t::operator()(value_t& result,
}
catch (const error_already_set&) {
PyErr_Print();
throw new xml::xpath_t::calc_error("While evaluating Python lambda expression");
throw_(xml::xpath_t::calc_exception,
"While evaluating Python lambda expression");
}
}

10
qif.cc
View file

@ -56,8 +56,8 @@ unsigned int qif_parser_t::parse(std::istream& in,
src_idx = journal->sources.size() - 1;
linenum = 1;
istream_pos_type beg_pos = 0;
unsigned long beg_line = 0;
unsigned long beg_pos = 0;
unsigned long beg_line = 0;
#define SET_BEG_POS_AND_LINE() \
if (! beg_line) { \
@ -73,7 +73,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
case '\t':
if (peek_next_nonws(in) != '\n') {
get_line(in);
throw new parse_error("Line begins with whitespace");
throw_(parse_exception, "Line begins with whitespace");
}
// fall through...
@ -90,8 +90,8 @@ unsigned int qif_parser_t::parse(std::istream& in,
std::strcmp(line, "Type:Cat") == 0 ||
std::strcmp(line, "Type:Class") == 0 ||
std::strcmp(line, "Type:Memorized") == 0)
throw new parse_error(string("QIF files of type ") + line +
" are not supported.");
throw_(parse_exception,
"QIF files of type " << line << " are not supported.");
break;
case 'D':

View file

@ -8,17 +8,17 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
const ptime& last,
amount_t& price)
{
DEBUG_CLASS("ledger.quotes.download");
logger("quotes.download");
DEBUG_PRINT_("commodity: " << commodity.symbol);
DEBUG_PRINT_TIME_(now);
DEBUG_PRINT_TIME_(moment);
DEBUG_PRINT_TIME_(date);
DEBUG_PRINT_TIME_(last);
DEBUG("commodity: " << commodity.symbol);
DEBUG(" now: " << now);
DEBUG(" moment: " << moment);
DEBUG(" date: " << date);
DEBUG(" last: " << last);
if (commodity.history)
DEBUG_PRINT_TIME_(commodity.history->last_lookup);
DEBUG_PRINT_("pricing_leeway is " << pricing_leeway);
if (SHOW_DEBUG() && commodity.history)
DEBUG("last_lookup: " << commodity.history->last_lookup);
DEBUG("pricing_leeway is " << pricing_leeway);
if ((commodity.history &&
(time_now - commodity.history->last_lookup) < pricing_leeway) ||
@ -26,7 +26,7 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
(price && moment > date && (moment - date) <= pricing_leeway))
return;
DEBUG_PRINT_("downloading quote for symbol " << commodity.symbol);
DEBUG("downloading quote for symbol " << commodity.symbol);
char buf[256];
buf[0] = '\0';
@ -47,7 +47,7 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
char * p = strchr(buf, '\n');
if (p) *p = '\0';
DEBUG_PRINT_("downloaded quote: " << buf);
DEBUG("downloaded quote: " << buf);
price.parse(buf);
commodity.add_price(now, price);
@ -70,9 +70,10 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
#endif
}
} else {
throw new error(string("Failed to download price for '") +
throw exception(string("Failed to download price for '") +
commodity.symbol + "' (command: \"getquote " +
commodity.symbol + "\")");
commodity.symbol + "\")",
context());
}
}

View file

@ -3,6 +3,95 @@
namespace ledger {
string abbreviate(const string& str,
unsigned int width,
elision_style_t elision_style,
const bool is_account,
int abbrev_length)
{
const unsigned int len = str.length();
if (len <= width)
return str;
assert(width < 4095);
static char buf[4096];
switch (elision_style) {
case TRUNCATE_LEADING:
// This method truncates at the beginning.
std::strncpy(buf, str.c_str() + (len - width), width);
buf[0] = '.';
buf[1] = '.';
break;
case TRUNCATE_MIDDLE:
// This method truncates in the middle.
std::strncpy(buf, str.c_str(), width / 2);
std::strncpy(buf + width / 2,
str.c_str() + (len - (width / 2 + width % 2)),
width / 2 + width % 2);
buf[width / 2 - 1] = '.';
buf[width / 2] = '.';
break;
case ABBREVIATE:
if (is_account) {
std::list<string> parts;
string::size_type beg = 0;
for (string::size_type pos = str.find(':');
pos != string::npos;
beg = pos + 1, pos = str.find(':', beg))
parts.push_back(string(str, beg, pos - beg));
parts.push_back(string(str, beg));
string result;
unsigned int newlen = len;
for (std::list<string>::iterator i = parts.begin();
i != parts.end();
i++) {
// Don't contract the last element
std::list<string>::iterator x = i;
if (++x == parts.end()) {
result += *i;
break;
}
if (newlen > width) {
result += string(*i, 0, abbrev_length);
result += ":";
newlen -= (*i).length() - abbrev_length;
} else {
result += *i;
result += ":";
}
}
if (newlen > width) {
// Even abbreviated its too big to show the last account, so
// abbreviate all but the last and truncate at the beginning.
std::strncpy(buf, result.c_str() + (result.length() - width), width);
buf[0] = '.';
buf[1] = '.';
} else {
std::strcpy(buf, result.c_str());
}
break;
}
// fall through...
case TRUNCATE_TRAILING:
// This method truncates at the end (the default).
std::strncpy(buf, str.c_str(), width - 2);
buf[width - 2] = '.';
buf[width - 1] = '.';
break;
}
buf[width] = '\0';
return buf;
}
static void scan_for_transactions(std::ostream& out, const xml::node_t * node)
{
if (! (node->flags & XML_NODE_IS_PARENT))

View file

@ -20,6 +20,19 @@ class register_command : public xml::xpath_t::functor_t
virtual void print_document(std::ostream& out, xml::document_t * doc);
};
enum elision_style_t {
TRUNCATE_TRAILING,
TRUNCATE_MIDDLE,
TRUNCATE_LEADING,
ABBREVIATE
};
string abbreviate(const string& str,
unsigned int width,
elision_style_t elision_style = TRUNCATE_TRAILING,
const bool is_account = false,
int abbrev_length = 2);
} // namespace ledger
#endif // _REGISTER_H

View file

@ -22,7 +22,7 @@ void report_t::apply_transforms(xml::document_t * document)
void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals)
{
if (locals->args.size() < 2)
throw new error("usage: abbrev(STRING, WIDTH [, STYLE, ABBREV_LEN])");
throw_(exception, "usage: abbrev(STRING, WIDTH [, STYLE, ABBREV_LEN])");
string str = locals->args[0].to_string();
long wid = locals->args[1];
@ -41,7 +41,7 @@ void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals)
void report_t::ftime(value_t&, xml::xpath_t::scope_t * locals)
{
if (locals->args.size() < 1)
throw new error("usage: ftime(DATE [, DATE_FORMAT])");
throw_(exception, "usage: ftime(DATE [, DATE_FORMAT])");
moment_t date = locals->args[0].to_datetime();

View file

@ -27,7 +27,7 @@ unsigned int session_t::read_journal(const string& path,
journal->sources.push_back(path);
if (access(path.c_str(), R_OK) == -1)
throw new error(string("Cannot read file '") + path + "'");
throw_(exception, "Cannot read file '" << path << "'");
if (! original_file)
original_file = &path;
@ -42,7 +42,7 @@ void session_t::read_init()
return;
if (access(init_file.c_str(), R_OK) == -1)
throw new error(string("Cannot read init file '") + init_file + "'");
throw_(exception, "Cannot read init file '" << init_file << "'");
std::ifstream init(init_file.c_str());
@ -51,7 +51,7 @@ void session_t::read_init()
journal_t * session_t::read_data(const string& master_account)
{
TRACE_PUSH(parser, "Parsing journal file");
TRACE_START(parser, 1, "Parsing journal file");
journal_t * journal = new_journal();
journal->document = new xml::document_t;
@ -59,12 +59,12 @@ journal_t * session_t::read_data(const string& master_account)
unsigned int entry_count = 0;
DEBUG_PRINT("ledger.cache",
DEBUG_("ledger.cache",
"3. use_cache = " << use_cache);
if (use_cache && ! cache_file.empty() &&
! data_file.empty()) {
DEBUG_PRINT("ledger.cache",
DEBUG_("ledger.cache",
"using_cache " << cache_file);
cache_dirty = true;
if (access(cache_file.c_str(), R_OK) != -1) {
@ -90,15 +90,15 @@ journal_t * session_t::read_data(const string& master_account)
if (! journal->price_db.empty() &&
access(journal->price_db.c_str(), R_OK) != -1) {
if (read_journal(journal->price_db, journal)) {
throw new error("Entries not allowed in price history file");
throw_(exception, "Entries not allowed in price history file");
} else {
DEBUG_PRINT("ledger.cache",
DEBUG_("ledger.cache",
"read price database " << journal->price_db);
journal->sources.pop_back();
}
}
DEBUG_PRINT("ledger.cache",
DEBUG_("ledger.cache",
"rejected cache, parsing " << data_file);
if (data_file == "-") {
use_cache = false;
@ -112,13 +112,13 @@ journal_t * session_t::read_data(const string& master_account)
}
}
VALIDATE(journal->valid());
VERIFY(journal->valid());
if (entry_count == 0)
throw new error("Failed to locate any journal entries; "
"did you specify a valid file with -f?");
throw_(exception, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");
TRACE_POP(parser, "Finished parsing");
TRACE_STOP(parser, 1);
return journal;
}
@ -185,6 +185,8 @@ xml::xpath_t::op_t * session_t::lookup(const string& name)
return xml::xpath_t::scope_t::lookup(name);
}
// jww (2007-04-26): All of Ledger should be accessed through a
// session_t object
void initialize()
{
amount_t::initialize();
@ -193,7 +195,6 @@ void initialize()
void shutdown()
{
amount_t::shutdown();
assert(live_count.size() == 0);
}
} // namespace ledger

View file

@ -3,6 +3,7 @@
#include "journal.h"
#include "parser.h"
#include "register.h"
namespace ledger {

View file

@ -21,16 +21,17 @@
#include <algorithm>
#include <exception>
#include <fstream>
#include <iostream>
#include <streambuf>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <sstream>
#include <stack>
#include <streambuf>
#include <string>
#include <vector>

View file

@ -339,7 +339,7 @@ void BasicAmountTestCase::testIntegerDivision()
amount_t x1(123L);
amount_t y1(456L);
assertThrow(x1 / 0L, amount_error *);
assertThrow(x1 / 0L, amount_exception);
assertEqual(amount_t(0L), amount_t(0L) / x1);
assertEqual(amount_t(0L), 0L / x1);
assertEqual(x1, x1 / 1L);
@ -376,7 +376,7 @@ void BasicAmountTestCase::testFractionalDivision()
amount_t x1(123.123);
amount_t y1(456.456);
assertThrow(x1 / 0L, amount_error *);
assertThrow(x1 / 0L, amount_exception);
assertEqual(amount_t("0.008121959"), amount_t(1.0) / x1);
assertEqual(amount_t("0.008121959"), 1.0 / x1);
assertEqual(x1, x1 / 1.0);

View file

@ -3,10 +3,10 @@
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CommodityTestCase, "numerics");
void CommodityTestCase::setUp() {
amount_t::initialize();
ledger::initialize();
}
void CommodityTestCase::tearDown() {
amount_t::shutdown();
ledger::shutdown();
}
void CommodityTestCase::testPriceHistory()

View file

@ -6,7 +6,7 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CommodityAmountTestCase, "numerics");
void CommodityAmountTestCase::setUp()
{
amount_t::initialize();
ledger::initialize();
// Cause the display precision for dollars to be initialized to 2.
amount_t x1("$1.00");
@ -17,7 +17,7 @@ void CommodityAmountTestCase::setUp()
void CommodityAmountTestCase::tearDown()
{
amount_t::full_strings = false;
amount_t::shutdown();
ledger::shutdown();
}
void CommodityAmountTestCase::testConstructors()
@ -232,13 +232,13 @@ void CommodityAmountTestCase::testAddition()
assertEqual(string("$246.90"), (x1 + x1).to_string());
assertEqual(string("$246.91"), (x1 + x2).to_string());
assertThrow(x1 + x0, amount_error *);
assertThrow(x1 + x3, amount_error *);
assertThrow(x1 + x4, amount_error *);
assertThrow(x1 + x5, amount_error *);
assertThrow(x1 + x6, amount_error *);
assertThrow(x1 + 123.45, amount_error *);
assertThrow(x1 + 123L, amount_error *);
assertThrow(x1 + x0, amount_exception);
assertThrow(x1 + x3, amount_exception);
assertThrow(x1 + x4, amount_exception);
assertThrow(x1 + x5, amount_exception);
assertThrow(x1 + x6, amount_exception);
assertThrow(x1 + 123.45, amount_exception);
assertThrow(x1 + 123L, amount_exception);
assertEqual(amount_t("DM 246.90"), x3 + x3);
assertEqual(amount_t("246.90 euro"), x4 + x4);
@ -290,13 +290,13 @@ void CommodityAmountTestCase::testSubtraction()
assertEqual(string("$0.00"), (x1 - x1).to_string());
assertEqual(string("$-0.01"), (x1 - x2).to_string());
assertThrow(x1 - x0, amount_error *);
assertThrow(x1 - x3, amount_error *);
assertThrow(x1 - x4, amount_error *);
assertThrow(x1 - x5, amount_error *);
assertThrow(x1 - x6, amount_error *);
assertThrow(x1 - 123.45, amount_error *);
assertThrow(x1 - 123L, amount_error *);
assertThrow(x1 - x0, amount_exception);
assertThrow(x1 - x3, amount_exception);
assertThrow(x1 - x4, amount_exception);
assertThrow(x1 - x5, amount_exception);
assertThrow(x1 - x6, amount_exception);
assertThrow(x1 - 123.45, amount_exception);
assertThrow(x1 - 123L, amount_exception);
assertEqual(amount_t("DM 0.00"), x3 - x3);
assertEqual(amount_t("DM 23.45"), x3 - amount_t("DM 100.00"));
@ -374,9 +374,9 @@ void CommodityAmountTestCase::testMultiplication()
assertEqual(string("$15200.00"), (x1 * x2).to_string());
assertEqual(string("$15199.99986168"), (x2 * x1).to_string());
assertThrow(x1 * x3, amount_error *);
assertThrow(x1 * x4, amount_error *);
assertThrow(x1 * x5, amount_error *);
assertThrow(x1 * x3, amount_exception);
assertThrow(x1 * x4, amount_exception);
assertThrow(x1 * x5, amount_exception);
x1 *= amount_t("123.12");
assertEqual(internalAmount("$15158.5344"), x1);
@ -410,7 +410,7 @@ void CommodityAmountTestCase::testDivision()
amount_t x4("123.45 euro");
amount_t x5("123.45€");
assertThrow(x1 / 0L, amount_error *);
assertThrow(x1 / 0L, amount_exception);
assertEqual(amount_t("$0.00"), 0L / x1);
assertEqual(x1, x1 / 1L);
assertEqual(internalAmount("$0.00812216"), 1L / x1);
@ -428,9 +428,9 @@ void CommodityAmountTestCase::testDivision()
assertEqual(string("$1.00"), (x1 / x2).to_string());
assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_string());
assertThrow(x1 / x3, amount_error *);
assertThrow(x1 / x4, amount_error *);
assertThrow(x1 / x5, amount_error *);
assertThrow(x1 / x3, amount_exception);
assertThrow(x1 / x4, amount_exception);
assertThrow(x1 / x5, amount_exception);
x1 /= amount_t("123.12");
assertEqual(internalAmount("$1.00"), x1);

View file

@ -52,7 +52,7 @@ parse_amount_expr(std::istream& in, journal_t *,
{
xml::xpath_t xpath(in, flags | XPATH_PARSE_RELAXED | XPATH_PARSE_PARTIAL);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed an amount expression");
#ifdef DEBUG_ENABLED
@ -66,7 +66,7 @@ parse_amount_expr(std::istream& in, journal_t *,
amount = xpath.calc(static_cast<xml::transaction_node_t *>(xact.data)).to_amount();
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"The transaction amount is " << amount);
}
@ -112,7 +112,9 @@ transaction_t * parse_transaction(char * line,
}
string err_desc;
#if 0
try {
#endif
xact->entry = entry; // this might be NULL
@ -122,12 +124,12 @@ transaction_t * parse_transaction(char * line,
switch (*state) {
case '*':
xact->state = transaction_t::CLEARED;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed the CLEARED flag");
break;
case '!':
xact->state = transaction_t::PENDING;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed the PENDING flag");
break;
}
@ -139,18 +141,18 @@ transaction_t * parse_transaction(char * line,
if ((*b == '[' && *e == ']') ||
(*b == '(' && *e == ')')) {
xact->flags |= TRANSACTION_VIRTUAL;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a virtual account name");
if (*b == '[') {
xact->flags |= TRANSACTION_BALANCE;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a balanced virtual account name");
}
*account_path++ = '\0';
*e = '\0';
}
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed account name " << account_path);
if (account_aliases.size() > 0) {
accounts_map::const_iterator i = account_aliases.find(account_path);
@ -202,9 +204,9 @@ transaction_t * parse_transaction(char * line,
xact->amount_expr = string(line, beg, end - beg);
}
}
catch (error * err) {
catch (exception& err) {
err_desc = "While parsing transaction amount:";
throw err;
throw;
}
// Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST)
@ -212,14 +214,14 @@ transaction_t * parse_transaction(char * line,
if (in.good() && ! in.eof()) {
char c = peek_next_nonws(in);
if (c == '@') {
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Found a price indicator");
bool per_unit = true;
in.get(c);
if (in.peek() == '@') {
in.get(c);
per_unit = false;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"And it's for a total price");
}
@ -240,13 +242,13 @@ transaction_t * parse_transaction(char * line,
xact->cost_expr = (string("@@") +
string(amount, beg, end - beg));
}
catch (error * err) {
catch (exception& err) {
err_desc = "While parsing transaction cost:";
throw err;
throw;
}
if (*xact->cost < 0)
throw new parse_error("A transaction's cost may not be negative");
throw_(parse_exception, "A transaction's cost may not be negative");
amount_t per_unit_cost(*xact->cost);
if (per_unit)
@ -260,13 +262,13 @@ transaction_t * parse_transaction(char * line,
xact->entry->actual_date(),
xact->entry->code);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Total cost is " << *xact->cost);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Per-unit cost is " << per_unit_cost);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Annotated amount is " << xact->amount);
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Bare amount is " << xact->amount.number());
}
}
@ -274,7 +276,7 @@ transaction_t * parse_transaction(char * line,
xact->amount.in_place_reduce();
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Reduced amount is " << xact->amount);
}
@ -282,7 +284,7 @@ transaction_t * parse_transaction(char * line,
if (note) {
xact->note = note;
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a note '" << xact->note << "'");
if (char * b = std::strchr(xact->note.c_str(), '['))
@ -291,7 +293,7 @@ transaction_t * parse_transaction(char * line,
std::strncpy(buf, b + 1, e - b - 1);
buf[e - b - 1] = '\0';
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a transaction date " << buf);
if (char * p = std::strchr(buf, '=')) {
@ -305,6 +307,7 @@ transaction_t * parse_transaction(char * line,
return xact.release();
#if 0
}
catch (error * err) {
err->context.push_back
@ -312,6 +315,7 @@ transaction_t * parse_transaction(char * line,
err_desc : "While parsing transaction:"));
throw err;
}
#endif
}
bool parse_transactions(std::istream& in,
@ -345,13 +349,6 @@ bool parse_transactions(std::istream& in,
return added;
}
namespace {
TIMER_DEF(parsing_total, "total parsing time")
TIMER_DEF(entry_xacts, "parsing transactions")
TIMER_DEF(entry_details, "parsing entry details")
TIMER_DEF(entry_date, "parsing entry date")
}
entry_t * parse_entry(std::istream& in, char * line, journal_t * journal,
account_t * master, textual_parser_t& /* parser */,
unsigned long beg_pos)
@ -415,18 +412,18 @@ entry_t * parse_entry(std::istream& in, char * line, journal_t * journal,
// Parse the date
TIMER_START(entry_date);
TRACE_START(entry_date, 2, "Parsing entry date");
curr->_date = parse_datetime(date);
if (date_eff)
curr->_date_eff = parse_datetime(date_eff);
TIMER_STOP(entry_date);
TRACE_STOP(entry_date, 2);
// Parse the optional cleared flag: *
TIMER_START(entry_details);
TRACE_START(entry_details, 2, "Parsing entry details");
transaction_t::state_t state = transaction_t::UNCLEARED;
if (statep) {
@ -450,11 +447,11 @@ entry_t * parse_entry(std::istream& in, char * line, journal_t * journal,
assert(payee);
curr->payee = *payee != '\0' ? payee : "<Unspecified payee>";
TIMER_STOP(entry_details);
TRACE_STOP(entry_details, 2);
// Parse all of the transactions associated with this entry
TIMER_START(entry_xacts);
TRACE_START(entry_xacts, 2, "Parsing entry transactions");
unsigned long end_pos;
unsigned long beg_line = linenum;
@ -495,7 +492,7 @@ entry_t * parse_entry(std::istream& in, char * line, journal_t * journal,
curr->data = NULL;
}
TIMER_STOP(entry_xacts);
TRACE_STOP(entry_xacts, 2);
return curr.release();
}
@ -513,7 +510,7 @@ static inline void parse_symbol(char *& p, string& symbol)
if (*p == '"') {
char * q = std::strchr(p + 1, '"');
if (! q)
throw new parse_error("Quoted commodity symbol lacks closing quote");
throw_(parse_exception, "Quoted commodity symbol lacks closing quote");
symbol = string(p + 1, 0, q - p - 1);
p = q + 2;
} else {
@ -525,7 +522,7 @@ static inline void parse_symbol(char *& p, string& symbol)
p += symbol.length();
}
if (symbol.empty())
throw new parse_error("Failed to parse commodity");
throw_(parse_exception, "Failed to parse commodity");
}
bool textual_parser_t::test(std::istream& in) const
@ -535,9 +532,9 @@ bool textual_parser_t::test(std::istream& in) const
in.read(buf, 5);
if (std::strncmp(buf, "<?xml", 5) == 0) {
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
throw new parse_error("Ledger file contains XML data, but format was not recognized");
throw_(parse_exception, "Ledger file contains XML data, but format was not recognized");
#else
throw new parse_error("Ledger file contains XML data, but no XML support present");
throw_(parse_exception, "Ledger file contains XML data, but no XML support present");
#endif
}
@ -559,11 +556,11 @@ static void clock_out_from_timelog(const moment_t& when,
time_entries.clear();
}
else if (time_entries.empty()) {
throw new parse_error("Timelog check-out event without a check-in");
throw_(parse_exception, "Timelog check-out event without a check-in");
}
else if (! account) {
throw new parse_error
("When multiple check-ins are active, checking out requires an account");
throw_(parse_exception,
"When multiple check-ins are active, checking out requires an account");
}
else {
bool found = false;
@ -579,8 +576,8 @@ static void clock_out_from_timelog(const moment_t& when,
}
if (! found)
throw new parse_error
("Timelog check-out event does not match any current check-ins");
throw_(parse_exception,
"Timelog check-out event does not match any current check-ins");
}
if (desc && event.desc.empty()) {
@ -594,8 +591,8 @@ static void clock_out_from_timelog(const moment_t& when,
curr->payee = event.desc;
if (curr->_date < event.checkin)
throw new parse_error
("Timelog check-out date less than corresponding check-in");
throw_(parse_exception,
"Timelog check-out date less than corresponding check-in");
char buf[32];
std::sprintf(buf, "%lds", (long)(curr->_date - event.checkin).total_seconds());
@ -608,7 +605,7 @@ static void clock_out_from_timelog(const moment_t& when,
curr->add_transaction(xact);
if (! journal->add_entry(curr.get()))
throw new parse_error("Failed to record 'out' timelog entry");
throw_(parse_exception, "Failed to record 'out' timelog entry");
else
curr.release();
}
@ -623,7 +620,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
unsigned int count = 0;
unsigned int errors = 0;
TIMER_START(parsing_total);
TRACE_START(parsing_total, 2, "Parsing textual file");
std::list<account_t *> account_stack;
@ -643,7 +640,9 @@ unsigned int textual_parser_t::parse(std::istream& in,
unsigned long beg_line = linenum;
while (in.good() && ! in.eof()) {
#if 0
try {
#endif
in.getline(line, MAX_LINE);
if (in.eof())
break;
@ -659,7 +658,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case '\t': {
char * p = skip_ws(line);
if (*p && *p != '\r')
throw new parse_error("Line begins with whitespace");
throw_(parse_exception, "Line begins with whitespace");
break;
}
@ -681,8 +680,8 @@ unsigned int textual_parser_t::parse(std::istream& in,
i != time_entries.end();
i++)
if (event.account == (*i).account)
throw new parse_error
("Cannot double check-in to the same account");
throw_(parse_exception,
"Cannot double check-in to the same account");
time_entries.push_back(event);
break;
@ -691,7 +690,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case 'o':
case 'O':
if (time_entries.empty()) {
throw new parse_error("Timelog check-out event without a check-in");
throw_(parse_exception, "Timelog check-out event without a check-in");
} else {
string date(line, 2, 19);
@ -776,7 +775,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
break;
case '-': // option setting
throw new parse_error("Option settings are not allowed in journal files");
throw_(parse_exception, "Option settings are not allowed in journal files");
case '=': { // automated entry
if (! added_auto_entry_hook) {
@ -800,7 +799,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case '~': { // period entry
period_entry_t * pe = new period_entry_t(skip_ws(line + 1));
if (! pe->period)
throw new parse_error(string("Parsing time period '") + skip_ws(line + 1) + "'");
throw_(parse_exception, string("Parsing time period '") + skip_ws(line + 1) + "'");
if (parse_transactions(in, journal, account_stack.front(), *pe,
"period", end_pos)) {
@ -813,7 +812,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
pe->end_pos = end_pos;
pe->end_line = linenum;
} else {
throw new parse_error("Period entry failed to balance");
throw_(parse_exception, "Period entry failed to balance");
}
}
break;
@ -840,7 +839,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
}
path = resolve_path(path);
DEBUG_PRINT("ledger.textual.include", "line " << linenum << ": " <<
DEBUG_("ledger.textual.include", "line " << linenum << ": " <<
"Including path '" << path << "'");
include_stack.push_back(std::pair<string, int>
@ -903,15 +902,16 @@ unsigned int textual_parser_t::parse(std::istream& in,
count++;
} else {
delete entry;
throw new parse_error("Entry does not balance");
throw_(parse_exception, "Entry does not balance");
}
} else {
throw new parse_error("Failed to parse entry");
throw_(parse_exception, "Failed to parse entry");
}
end_pos = pos;
break;
}
}
#if 0
}
catch (error * err) {
for (std::list<std::pair<string, int> >::reverse_iterator i =
@ -930,6 +930,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
delete err;
errors++;
}
#endif
beg_pos = end_pos;
}
@ -947,7 +948,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (errors > 0)
throw (int)errors;
TIMER_STOP(parsing_total);
TRACE_STOP(parsing_total, 2);
return count;
}

View file

@ -23,6 +23,7 @@ void write_textual_journal(journal_t& journal, string path,
std::ostream& out);
#endif
#if 0
class include_context : public file_context {
public:
include_context(const string& file, unsigned long line,
@ -36,6 +37,7 @@ class include_context : public file_context {
out << "\"" << file << "\", line " << line << ":" << std::endl;
}
};
#endif
} // namespace ledger

View file

@ -46,4 +46,4 @@ moment_t datetime_range_from_stream(std::istream& in)
{
}
}
} // namespace ledger

14
times.h
View file

@ -36,11 +36,7 @@ inline bool is_valid_moment(const moment_t& moment) {
extern moment_t& now;
class datetime_error : public error {
public:
datetime_error(const string& _reason) throw() : error(_reason) {}
virtual ~datetime_error() throw() {}
};
DECLARE_EXCEPTION(datetime_exception);
class interval_t
{
@ -86,6 +82,7 @@ extern ptime time_now;
extern date date_now;
extern bool day_before_month;
#if 0
struct intorchar
{
int ival;
@ -97,8 +94,9 @@ struct intorchar
intorchar(const intorchar& o) : ival(o.ival), sval(o.sval) {}
};
}
ledger::moment_t parse_abs_datetime(std::istream& input);
#endif
#endif /* _TIMES_H */
} // namespace ledger
#endif // _TIMES_H

146
util.cc
View file

@ -1,146 +0,0 @@
#include "utils.h"
namespace ledger {
string expand_path(const string& path)
{
if (path.length() == 0 || path[0] != '~')
return path;
const char * pfx = NULL;
string::size_type pos = path.find_first_of('/');
if (path.length() == 1 || pos == 1) {
pfx = std::getenv("HOME");
#ifdef HAVE_GETPWUID
if (! pfx) {
// Punt. We're trying to expand ~/, but HOME isn't set
struct passwd * pw = getpwuid(getuid());
if (pw)
pfx = pw->pw_dir;
}
#endif
}
#ifdef HAVE_GETPWNAM
else {
string user(path, 1, pos == string::npos ?
string::npos : pos - 1);
struct passwd * pw = getpwnam(user.c_str());
if (pw)
pfx = pw->pw_dir;
}
#endif
// if we failed to find an expansion, return the path unchanged.
if (! pfx)
return path;
string result(pfx);
if (pos == string::npos)
return result;
if (result.length() == 0 || result[result.length() - 1] != '/')
result += '/';
result += path.substr(pos + 1);
return result;
}
string resolve_path(const string& path)
{
if (path[0] == '~')
return expand_path(path);
return path;
}
string abbreviate(const string& str, unsigned int width,
elision_style_t elision_style, const bool is_account,
int abbrev_length)
{
const unsigned int len = str.length();
if (len <= width)
return str;
assert(width < 4095);
static char buf[4096];
switch (elision_style) {
case TRUNCATE_LEADING:
// This method truncates at the beginning.
std::strncpy(buf, str.c_str() + (len - width), width);
buf[0] = '.';
buf[1] = '.';
break;
case TRUNCATE_MIDDLE:
// This method truncates in the middle.
std::strncpy(buf, str.c_str(), width / 2);
std::strncpy(buf + width / 2,
str.c_str() + (len - (width / 2 + width % 2)),
width / 2 + width % 2);
buf[width / 2 - 1] = '.';
buf[width / 2] = '.';
break;
case ABBREVIATE:
if (is_account) {
std::list<string> parts;
string::size_type beg = 0;
for (string::size_type pos = str.find(':');
pos != string::npos;
beg = pos + 1, pos = str.find(':', beg))
parts.push_back(string(str, beg, pos - beg));
parts.push_back(string(str, beg));
string result;
unsigned int newlen = len;
for (std::list<string>::iterator i = parts.begin();
i != parts.end();
i++) {
// Don't contract the last element
std::list<string>::iterator x = i;
if (++x == parts.end()) {
result += *i;
break;
}
if (newlen > width) {
result += string(*i, 0, abbrev_length);
result += ":";
newlen -= (*i).length() - abbrev_length;
} else {
result += *i;
result += ":";
}
}
if (newlen > width) {
// Even abbreviated its too big to show the last account, so
// abbreviate all but the last and truncate at the beginning.
std::strncpy(buf, result.c_str() + (result.length() - width), width);
buf[0] = '.';
buf[1] = '.';
} else {
std::strcpy(buf, result.c_str());
}
break;
}
// fall through...
case TRUNCATE_TRAILING:
// This method truncates at the end (the default).
std::strncpy(buf, str.c_str(), width - 2);
buf[width - 2] = '.';
buf[width - 1] = '.';
break;
}
buf[width] = '\0';
return buf;
}
} // namespace ledger

88
util.h
View file

@ -1,88 +0,0 @@
#ifndef _UTIL_H
#define _UTIL_H
namespace ledger {
inline char * skip_ws(char * ptr) {
while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
ptr++;
return ptr;
}
inline char peek_next_nonws(std::istream& in) {
char c = in.peek();
while (! in.eof() && std::isspace(c)) {
in.get(c);
c = in.peek();
}
return c;
}
#define READ_INTO(str, targ, size, var, cond) { \
char * _p = targ; \
var = str.peek(); \
while (! str.eof() && var != '\n' && (cond) && _p - targ < size) { \
str.get(var); \
if (str.eof()) \
break; \
if (var == '\\') { \
str.get(var); \
if (in.eof()) \
break; \
} \
*_p++ = var; \
var = str.peek(); \
} \
*_p = '\0'; \
}
#define READ_INTO_(str, targ, size, var, idx, cond) { \
char * _p = targ; \
var = str.peek(); \
while (! str.eof() && var != '\n' && (cond) && _p - targ < size) { \
str.get(var); \
if (str.eof()) \
break; \
idx++; \
if (var == '\\') { \
str.get(var); \
if (in.eof()) \
break; \
idx++; \
} \
*_p++ = var; \
var = str.peek(); \
} \
*_p = '\0'; \
}
ledger::string resolve_path(const ledger::string& path);
#ifdef HAVE_REALPATH
extern "C" char *realpath(const char *, char resolved_path[]);
#endif
enum elision_style_t {
TRUNCATE_TRAILING,
TRUNCATE_MIDDLE,
TRUNCATE_LEADING,
ABBREVIATE
};
ledger::string abbreviate(const ledger::string& str, unsigned int width,
elision_style_t elision_style = TRUNCATE_TRAILING,
const bool is_account = false, int abbrev_length = 2);
static inline const
ledger::string& either_or(const ledger::string& first,
const ledger::string& second)
{
if (first.empty())
return second;
else
return first;
}
} // namespace ledger
#endif // _UTIL_H

240
utils.cc
View file

@ -1,10 +1,14 @@
#include "utils.h"
#include "times.h"
namespace ledger
/**********************************************************************
*
* Assertions
*/
#if defined(ASSERTS_ON)
namespace ledger {
void debug_assert(const string& reason,
const string& func,
const string& file,
@ -16,35 +20,50 @@ void debug_assert(const string& reason,
throw exception(buf.str(), context());
}
} // namespace ledger
#endif
/**********************************************************************
*
* Verification (basically, very slow asserts)
*/
#if defined(VERIFY_ON)
int new_calls = 0;
unsigned long new_size = 0;
namespace ledger {
#if defined(FULL_DEBUG)
bool verify_enabled = true;
#else
bool verify_enabled = false;
#endif
int new_calls = 0;
unsigned long new_size = 0;
}
void * operator new(std::size_t size) throw (std::bad_alloc) {
void * ptr = std::malloc(size);
new_calls++;
new_size += size;
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void * operator new[](std::size_t size) throw (std::bad_alloc) {
void * ptr = std::malloc(size);
new_calls++;
new_size += size;
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void * operator new(std::size_t size, const std::nothrow_t&) throw() {
void * ptr = std::malloc(size);
new_calls++;
new_size += size;
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void * operator new[](std::size_t size, const std::nothrow_t&) throw() {
void * ptr = std::malloc(size);
new_calls++;
new_size += size;
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void operator delete(void * ptr) throw() {
@ -60,6 +79,8 @@ void operator delete[](void * ptr, const std::nothrow_t&) throw() {
std::free(ptr);
}
namespace ledger {
live_objects_map live_objects;
object_count_map ctor_count;
object_count_map object_count;
@ -99,8 +120,7 @@ bool trace_ctor_func(void * ptr, const char * cls_name, const char * args,
std::strcat(name, args);
std::strcat(name, ")");
DEBUG_PRINT("ledger.trace.debug",
"trace_ctor " << ptr << " " << name);
DEBUG_("ledger.trace.debug", "TRACE_CTOR " << ptr << " " << name);
live_objects.insert(live_objects_pair(ptr, cls_name));
@ -114,7 +134,7 @@ bool trace_ctor_func(void * ptr, const char * cls_name, const char * args,
bool trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size)
{
DEBUG_PRINT("ledger.trace.debug", "trace_dtor " << ptr << " " << cls_name);
DEBUG_("ledger.trace.debug", "TRACE_DTOR " << ptr << " " << cls_name);
live_objects_map::iterator i = live_objects.find(ptr);
if (i == live_objects.end()) {
@ -179,103 +199,177 @@ void report_memory(std::ostream& out)
#if ! defined(USE_BOOST_PYTHON)
string::string() : std::string() {
trace_ctor(string, "");
TRACE_CTOR(string, "");
}
string::string(const string& str) : std::string(str) {
trace_ctor(string, "const string&");
TRACE_CTOR(string, "const string&");
}
string::string(const std::string& str) : std::string(str) {
trace_ctor(string, "const std::string&");
TRACE_CTOR(string, "const std::string&");
}
string::string(const int len, char x) : std::string(len, x) {
trace_ctor(string, "const int, char");
TRACE_CTOR(string, "const int, char");
}
string::string(const char * str) : std::string(str) {
trace_ctor(string, "const char *");
TRACE_CTOR(string, "const char *");
}
string::string(const char * str, const char * end) : std::string(str, end) {
trace_ctor(string, "const char *, const char *");
TRACE_CTOR(string, "const char *, const char *");
}
string::string(const string& str, int x) : std::string(str, x) {
trace_ctor(string, "const string&, int");
TRACE_CTOR(string, "const string&, int");
}
string::string(const string& str, int x, int y) : std::string(str, x, y) {
trace_ctor(string, "const string&, int, int");
TRACE_CTOR(string, "const string&, int, int");
}
string::string(const char * str, int x) : std::string(str, x) {
trace_ctor(string, "const char *, int");
TRACE_CTOR(string, "const char *, int");
}
string::string(const char * str, int x, int y) : std::string(str, x, y) {
trace_ctor(string, "const char *, int, int");
TRACE_CTOR(string, "const char *, int, int");
}
string::~string() {
trace_dtor(string);
TRACE_DTOR(string);
}
#endif
} // namespace ledger
#endif // VERIFY_ON
#if defined(TIMERS_ON)
/**********************************************************************
*
* Logging
*/
#if defined(LOGGING_ON) && defined(DEBUG_ON)
#include <boost/regex.hpp>
namespace ledger {
log_level_t _log_level;
unsigned int _trace_level;
std::string _log_category;
std::ostream * _log_stream = &std::cerr;
std::ostringstream _log_buffer;
bool logger_func(log_level_t level)
{
_log_buffer.str("");
}
} // namespace ledger
#endif // LOGGING_ON && DEBUG_ON
/**********************************************************************
*
* Timers (allows log entries to specify cumulative time spent)
*/
#if defined(LOGGING_ON) && defined(TIMERS_ON)
namespace ledger {
void start_timer(const char * name)
{
#if 0
begin = std::clock();
#endif
}
void stop_timer(const char * name)
{
#if 0
cumulative += std::clock() - begin;
#endif
}
void finish_timer(const char * name)
{
DEBUG_PRINT(cls.c_str(), file << ":" << line << ": "
<< category << " = "
<< (double(cumulative) / double(CLOCKS_PER_SEC)) << "s");
#if 0
DEBUG_(cls.c_str(), file << ":" << line << ": "
<< category << " = "
<< (double(cumulative) / double(CLOCKS_PER_SEC)) << "s");
#endif
}
} // namespace ledger
#endif // LOGGING_ON && TIMERS_ON
/**********************************************************************
*
* Exception handling
*/
namespace ledger {
std::ostringstream _exc_buffer;
} // namespace ledger
/**********************************************************************
*
* General utility functions
*/
namespace ledger {
string expand_path(const string& path)
{
if (path.length() == 0 || path[0] != '~')
return path;
const char * pfx = NULL;
string::size_type pos = path.find_first_of('/');
if (path.length() == 1 || pos == 1) {
pfx = std::getenv("HOME");
#ifdef HAVE_GETPWUID
if (! pfx) {
// Punt. We're trying to expand ~/, but HOME isn't set
struct passwd * pw = getpwuid(getuid());
if (pw)
pfx = pw->pw_dir;
}
#endif
}
#ifdef HAVE_GETPWNAM
else {
string user(path, 1, pos == string::npos ?
string::npos : pos - 1);
struct passwd * pw = getpwnam(user.c_str());
if (pw)
pfx = pw->pw_dir;
}
#endif
// if we failed to find an expansion, return the path unchanged.
if (! pfx)
return path;
string result(pfx);
if (pos == string::npos)
return result;
if (result.length() == 0 || result[result.length() - 1] != '/')
result += '/';
result += path.substr(pos + 1);
return result;
}
string resolve_path(const string& path)
{
if (path[0] == '~')
return expand_path(path);
return path;
}
#endif // TIMERS_ON
#if defined(LOGGING_ON) && defined(DEBUG_ON)
std::ostream * _debug_stream = &std::cerr;
bool _free_debug_stream = false;
boost::regex _debug_regex;
bool _set_debug_regex = false;
bool _debug_regex_on = false;
bool _debug_active(const char * const cls) {
if (! _set_debug_regex) {
const char * user_class = std::getenv("DEBUG_CLASS");
if (user_class) {
_debug_regex = user_class;
_debug_regex_on = true;
}
_set_debug_regex = true;
}
if (_debug_regex_on)
return boost::regex_match(cls, _debug_regex);
return false;
}
static struct init_streams {
init_streams() {
// If debugging is enabled and DEBUG_FILE is set, all debugging
// output goes to that file.
if (const char * p = std::getenv("DEBUG_FILE")) {
_debug_stream = new std::ofstream(p);
_free_debug_stream = true;
}
}
~init_streams() {
if (_free_debug_stream && _debug_stream) {
delete _debug_stream;
_debug_stream = NULL;
}
}
} _debug_init;
#endif // LOGGING_ON && DEBUG_ON
} // namespace ledger

315
utils.h
View file

@ -3,7 +3,18 @@
#include <system.hh>
/**********************************************************************
*
* Forward declarations
*/
namespace ledger {
#if ! defined(USE_BOOST_PYTHON)
class string;
#else
typedef std::string string;
#endif
}
/**********************************************************************
*
@ -11,15 +22,17 @@ namespace ledger {
*/
#if defined(FULL_DEBUG)
#define VERIFY_ON 1
#define TRACING_ON 1
#define DEBUG_ON 1
#define TIMERS_ON 1
#define VERIFY_ON 1
#define TRACING_ON 1
#define DEBUG_ON 1
#define TIMERS_ON 1
#define FREE_MEMORY 1
#elif defined(NO_DEBUG)
#define NO_ASSERTS 1
#define NO_LOGGING 1
#define NO_ASSERTS 1
#define NO_LOGGING 1
#else
#define TIMERS_ON 1 // jww (2007-04-25): is this correct?
#define VERIFY_ON 1 // compiled in, use --verify to enable
#define TIMERS_ON 1 // jww (2007-04-25): is this correct?
#endif
/**********************************************************************
@ -38,14 +51,14 @@ namespace ledger {
#include <boost/current_function.hpp>
void debug_assert(const ledger::string& reason,
const ledger::string& func,
const ledger::string& file,
unsigned long line);
namespace ledger {
void debug_assert(const string& reason, const string& func,
const string& file, unsigned long line);
}
#define assert(x) \
((x) ? ((void)0) : debug_assert(#x, BOOST_CURRENT_FUNCTION, \
__FILE__, __LINE__)
__FILE__, __LINE__))
#endif // ASSERTS_ON
@ -56,22 +69,15 @@ void debug_assert(const ledger::string& reason,
#if defined(VERIFY_ON)
namespace ledger {
extern bool verify_enabled;
#define verify(x) (verify_enabled ? assert(x) : ((void)0))
#define VERIFY(x) (verify_enabled ? assert(x) : ((void)0))
extern int new_calls;
extern unsigned long new_size;
void * operator new(std::size_t) throw(std::bad_alloc);
void * operator new[](std::size_t) throw(std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();
void * operator new(std::size_t, const std::nothrow_t&) throw();
void * operator new[](std::size_t, const std::nothrow_t&) throw();
void operator delete(void*, const std::nothrow_t&) throw();
void operator delete[](void*, const std::nothrow_t&) throw();
typedef std::multimap<void *, std::string> live_objects_map;
typedef std::pair<void *, std::string> live_objects_pair;
typedef std::pair<unsigned int, std::size_t> count_size_pair;
@ -87,10 +93,10 @@ bool trace_ctor_func(void * ptr, const char * cls_name, const char * args,
std::size_t cls_size);
bool trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size);
#define trace_ctor(cls, args) \
verify(trace_ctor_func(this, #cls, args, sizeof(cls)))
#define trace_dtor(cls) \
verify(trace_dtor_func(this, #cls, sizeof(cls)))
#define TRACE_CTOR(cls, args) \
VERIFY(trace_ctor_func(this, #cls, args, sizeof(cls)))
#define TRACE_DTOR(cls) \
VERIFY(trace_dtor_func(this, #cls, sizeof(cls)))
void report_memory(std::ostream& out);
@ -158,11 +164,13 @@ inline bool operator!=(const string& __lhs, const char* __rhs)
#endif
} // namespace ledger
#else // ! VERIFY_ON
#define verify(x)
#define trace_ctor(cls, args)
#define trace_dtor(cls)
#define VERIFY(x)
#define TRACE_CTOR(cls, args)
#define TRACE_DTOR(cls)
#endif // VERIFY_ON
@ -176,7 +184,7 @@ inline bool operator!=(const string& __lhs, const char* __rhs)
#endif
#if defined(LOGGING_ON)
// Logging
namespace ledger {
enum log_level_t {
LOG_OFF = 0,
@ -199,65 +207,99 @@ extern std::string _log_category;
extern std::ostream * _log_stream;
extern std::ostringstream _log_buffer;
#define category(cat) \
static const char * const _this_category = (cat)
bool logger_func(log_level_t level);
bool logger(log_level_t level);
#define logger(cat) \
static const char * const _this_category = cat
#define SHOW_TRACE(lvl) \
(_log_level >= LOG_TRACE && lvl >= _trace_level)
#define SHOW_DEBUG_(cat) \
(_log_level >= LOG_DEBUG && \
(_log_category == cat || \
_log_category.find(string(cat) + ".") == 0))
#define SHOW_DEBUG() SHOW_DEBUG_(_this_category)
#define SHOW_INFO_(cat) \
(_log_level >= LOG_INFO && \
(_log_category == cat || \
_log_category.find(string(cat) + ".") == 0))
#define SHOW_INFO() SHOW_INFO_(_this_category)
#define SHOW_WARN() (_log_level >= LOG_WARN)
#define SHOW_ERROR() (_log_level >= LOG_ERROR)
#define SHOW_FATAL() (_log_level >= LOG_FATAL)
#define SHOW_CRITICAL() (_log_level >= LOG_CRIT)
#if defined(TRACING_ON)
#define trace(lvl, msg) \
(_log_level >= LOG_TRACE && lvl >= _trace_level ? \
((_log_buffer << msg), logger(LOG_TRACE)) : false)
#define TRACE(lvl, msg) \
(SHOW_TRACE(lvl) ? ((_log_buffer << msg), logger_func(LOG_TRACE)) : false)
#else
#define trace(lvl, msg)
#define TRACE(lvl, msg)
#endif
#if defined(DEBUG_ON)
#define debug_(cat, msg) \
(_log_level >= LOG_DEBUG && \
(_log_category == cat || \
_log_category.find(cat ".") == 0) ? \
((_log_buffer << msg), logger(LOG_DEBUG)) : false)
#define debug(msg) debug_(_this_category, msg)
#define DEBUG_(cat, msg) \
(SHOW_DEBUG_(cat) ? ((_log_buffer << msg), logger_func(LOG_DEBUG)) : false)
#define DEBUG(msg) DEBUG_(_this_category, msg)
#else
#define debug_(cat, msg)
#define debug(msg)
#define DEBUG_(cat, msg)
#define DEBUG(msg)
#endif
#define exception_occurred(msg) \
log_macro(LOG_EXCEPT, msg)
#define INFO_(cat, msg) \
(SHOW_INFO(cat) ? ((_log_buffer << msg), logger_func(LOG_INFO)) : false)
#define INFO(msg) INFO_(_this_category, msg)
#define info_(cat, msg) \
(_log_level >= LOG_INFO && \
(_log_category == cat || \
_log_category.find(cat ".") == 0) ? \
((_log_buffer << msg), logger(LOG_INFO)) : false)
#define info(msg) info_(_this_category, msg)
#define log_macro(level, msg) \
#define LOG_MACRO(level, msg) \
(_log_level >= level ? \
((_log_buffer << msg), logger(level)) : false)
((_log_buffer << msg), logger_func(level)) : false)
#define warn(msg) log_macro(LOG_WARN, msg)
#define error(msg) log_macro(LOG_ERROR, msg)
#define fatal(msg) log_macro(LOG_FATAL, msg)
#define critical(msg) log_macro(LOG_CRIT, msg)
#define WARN(msg) LOG_MACRO(LOG_WARN, msg)
#define ERROR(msg) LOG_MACRO(LOG_ERROR, msg)
#define FATAL(msg) LOG_MACRO(LOG_FATAL, msg)
#define CRITICAL(msg) LOG_MACRO(LOG_CRIT, msg)
#define EXCEPTION(msg) LOG_MACRO(LOG_EXCEPT, msg)
} // namespace ledger
#else // ! LOGGING_ON
#define category(cat)
#define trace(lvl, msg)
#define debug(msg)
#define debug_(cat, msg)
#define info(msg)
#define info_(cat, msg)
#define warn(msg)
#define error(msg)
#define fatal(msg)
#define critical(msg)
#define logger(cat)
#define SHOW_TRACE(lvl) false
#define SHOW_DEBUG_(cat) false
#define SHOW_DEBUG() false
#define SHOW_INFO_(cat) false
#define SHOW_INFO() false
#define SHOW_WARN() false
#define SHOW_ERROR() false
#define SHOW_FATAL() false
#define SHOW_CRITICAL() false
#define TRACE(lvl, msg)
#define DEBUG(msg)
#define DEBUG_(cat, msg)
#define INFO(msg)
#define INFO_(cat, msg)
#define WARN(msg)
#define ERROR(msg)
#define FATAL(msg)
#define CRITICAL(msg)
#endif // LOGGING_ON
#define IF_TRACE(lvl) if (SHOW_TRACE(lvl))
#define IF_DEBUG_(cat) if (SHOW_DEBUG_(cat))
#define IF_DEBUG() if (SHOW_DEBUG())
#define IF_INFO_(cat) if (SHOW_INFO_(cat))
#define IF_INFO() if (SHOW_INFO())
#define IF_WARN() if (SHOW_WARN())
#define IF_ERROR() if (SHOW_ERROR())
#define IF_FATAL() if (SHOW_FATAL())
#define IF_CRITICAL() if (SHOW_CRITICAL())
/**********************************************************************
*
* Timers (allows log entries to specify cumulative time spent)
@ -265,6 +307,8 @@ bool logger(log_level_t level);
#if defined(LOGGING_ON) && defined(TIMERS_ON)
namespace ledger {
struct timer_t {
std::clock_t count;
std::string message;
@ -278,46 +322,63 @@ void stop_timer(const char * name);
void finish_timer(const char * name);
#if defined(TRACING_ON)
#define trace_start(name, lvl, msg) \
(trace(lvl, msg) && start_timer(name))
#define trace_stop(name) stop_timer(name)
#define trace_finish(name) finish_timer(name)
#define TRACE_START(name, lvl, msg) \
(TRACE(lvl, msg) ? start_timer(#name) : ((void)0))
#define TRACE_STOP(name, lvl) \
(SHOW_TRACE(lvl) ? stop_timer(#name) : ((void)0))
#define TRACE_FINISH(name, lvl) \
(SHOW_TRACE(lvl) ? finish_timer(#name) : ((void)0))
#else
#define trace_start(name, lvl, msg)
#define trace_stop(name)
#define trace_finish(name)
#define TRACE_START(name, lvl, msg)
#define TRACE_STOP(name)
#define TRACE_FINISH(name)
#endif
#if defined(DEBUG_ON)
#define debug_start(name, msg) \
(debug(msg) && start_timer(name))
#define debug_start_(name, cat, msg) \
(debug_(cat, msg) && start_timer(name))
#define debug_stop(name) stop_timer(name)
#define debug_finish(name) finish_timer(name)
#define DEBUG_START_(name, cat, msg) \
(DEBUG_(cat, msg) ? start_timer(#name) : ((void)0))
#define DEBUG_START(name, msg) \
DEBUG_START_(name, _this_category, msg)
#define DEBUG_STOP_(name, cat) \
(SHOW_DEBUG_(cat) ? stop_timer(#name) : ((void)0))
#define DEBUG_STOP(name) \
DEBUG_STOP_(name, _this_category)
#define DEBUG_FINISH_(name, cat) \
(SHOW_DEBUG_(cat) ? finish_timer(#name) : ((void)0))
#define DEBUG_FINISH(name) \
DEBUG_FINISH_(name, _this_category)
#else
#define debug_start(name, msg)
#define debug_start_(name, cat, msg)
#define debug_stop(name)
#define debug_finish(name)
#define DEBUG_START(name, msg)
#define DEBUG_START_(name, cat, msg)
#define DEBUG_STOP(name)
#define DEBUG_FINISH(name)
#endif
#define info_start(name, msg) \
(info(msg) && start_timer(name))
#define info_start_(name, cat, msg)
#define info_stop(name) stop_timer(name)
#define info_finish(name) finish_timer(name)
#define info_start_(name, cat, msg) \
(info_(cat, msg) && start_timer(#name))
#define info_start(name, msg) \
info_start_(name, _this_category, msg)
#define info_stop_(name, cat) \
(show_info_(cat) ? stop_timer(#name) : ((void)0))
#define info_stop(name) \
info_stop_(name, _this_category)
#define info_finish_(name, cat) \
(show_info_(cat) ? finish_timer(#name) : ((void)0))
#define info_finish(name) \
info_finish_(name, _this_category)
} // namespace ledger
#else // ! (LOGGING_ON && TIMERS_ON)
#define trace_start(lvl, msg, name)
#define trace_stop(name)
#define trace_finish(name)
#define TRACE_START(lvl, msg, name)
#define TRACE_STOP(name)
#define TRACE_FINISH(name)
#define debug_start(name, msg)
#define debug_start_(name, cat, msg)
#define debug_stop(name)
#define debug_finish(name)
#define DEBUG_START(name, msg)
#define DEBUG_START_(name, cat, msg)
#define DEBUG_STOP(name)
#define DEBUG_FINISH(name)
#define info_start(name, msg)
#define info_start_(name, cat, msg)
@ -326,32 +387,46 @@ void finish_timer(const char * name);
#endif // TIMERS_ON
/**********************************************************************
*
* Debug macros
*/
#if defined(DEBUG_ON)
#define if_debug_(cat) \
if (_log_level >= LOG_DEBUG && \
(_log_category == cat || \
_log_category.find(cat ".") == 0))
#define if_debug() if_debug_(_this_category)
#else // ! DEBUG_ON
#define if_debug(cat) if (false)
#endif // DEBUG_ON
/**********************************************************************
*
* Exception handling
*/
#import "error.h"
#include "error.h"
// } namespace ledger
namespace ledger {
extern std::ostringstream _exc_buffer;
template <typename T>
inline void throw_func(const std::string& message) {
_exc_buffer.str("");
throw T(message, context());
}
#define throw_(cls, msg) \
((_exc_buffer << msg), throw_func<cls>(_exc_buffer.str()))
} // namespace ledger
/**********************************************************************
*
* General utility functions
*/
namespace ledger {
string resolve_path(const string& path);
#ifdef HAVE_REALPATH
extern "C" char * realpath(const char *, char resolved_path[]);
#endif
inline const string& either_or(const string& first,
const string& second) {
return first.empty() ? second : first;
}
} // namespace ledger
#endif // _UTILS_H

498
value.cc

File diff suppressed because it is too large Load diff

10
value.h
View file

@ -560,6 +560,7 @@ template <> value_t::operator string() const;
std::ostream& operator<<(std::ostream& out, const value_t& val);
#if 0
class value_context : public error_context
{
value_t * bal;
@ -570,14 +571,9 @@ class value_context : public error_context
virtual void describe(std::ostream& out) const throw();
};
#endif
class value_error : public error {
public:
value_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~value_error() throw() {}
};
DECLARE_EXCEPTION(value_exception);
} // namespace ledger

23
xml.cc
View file

@ -48,7 +48,7 @@ int document_t::register_name(const string& name)
names.push_back(name);
index = names.size() - 1;
DEBUG_PRINT("xml.lookup", this << " Inserting name: " << names.back());
DEBUG_("xml.lookup", this << " Inserting name: " << names.back());
std::pair<names_map::iterator, bool> result =
names_index.insert(names_pair(names.back(), index));
@ -63,7 +63,7 @@ int document_t::lookup_name_id(const string& name) const
if ((id = lookup_builtin_id(name)) != -1)
return id;
DEBUG_PRINT("xml.lookup", this << " Finding name: " << name);
DEBUG_("xml.lookup", this << " Finding name: " << name);
names_map::const_iterator i = names_index.find(name);
if (i != names_index.end())
@ -131,7 +131,7 @@ document_t * node_t::document;
node_t::node_t(document_t * _document, parent_node_t * _parent,
unsigned int _flags)
: name_id(0), parent(_parent), next(NULL), prev(NULL),
flags(_flags), info(NULL), attrs(NULL)
flags(_flags), attrs(NULL)
{
TRACE_CTOR(node_t, "document_t *, node_t *");
document = _document;
@ -268,7 +268,7 @@ static void startElement(void *userData, const char *name, const char **attrs)
{
parser_t * parser = static_cast<parser_t *>(userData);
DEBUG_PRINT("xml.parse", "startElement(" << name << ")");
DEBUG_("xml.parse", "startElement(" << name << ")");
if (parser->pending) {
parent_node_t * node = create_node<parent_node_t>(parser);
@ -295,7 +295,7 @@ static void endElement(void *userData, const char *name)
{
parser_t * parser = static_cast<parser_t *>(userData);
DEBUG_PRINT("xml.parse", "endElement(" << name << ")");
DEBUG_("xml.parse", "endElement(" << name << ")");
if (parser->pending) {
terminal_node_t * node = create_node<terminal_node_t>(parser);
@ -317,7 +317,7 @@ static void dataHandler(void *userData, const char *s, int len)
{
parser_t * parser = static_cast<parser_t *>(userData);
DEBUG_PRINT("xml.parse", "dataHandler(" << string(s, len) << ")");
DEBUG_("xml.parse", "dataHandler(" << string(s, len) << ")");
bool all_whitespace = true;
for (int i = 0; i < len; i++) {
@ -382,21 +382,24 @@ document_t * parser_t::parse(std::istream& in)
catch (const std::exception& err) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
XML_ParserFree(parser);
throw new parse_error(err.what());
throw_(parse_exception, err.what());
}
if (! have_error.empty()) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
parse_error err(have_error);
#if 0
// jww (2007-04-26): What is this doing??
parse_exception 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));
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser);
throw new parse_error(err);
throw_(parse_exception, err);
}
}

19
xml.h
View file

@ -14,13 +14,7 @@ namespace xml {
#define XML_NODE_IS_PARENT 0x1
class conversion_error : public error {
public:
conversion_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~conversion_error() throw() {}
};
DECLARE_EXCEPTION(conversion_exception);
class parent_node_t;
class document_t;
@ -38,7 +32,6 @@ public:
node_t * next;
node_t * prev;
unsigned int flags;
void * info;
typedef std::map<string, string> attrs_map;
typedef std::pair<string, string> attrs_pair;
@ -91,7 +84,7 @@ public:
}
virtual value_t to_value() const {
throw new conversion_error("Cannot convert node to a value");
throw_(conversion_exception, "Cannot convert node to a value");
}
virtual void write(std::ostream& out, int depth = 0) const = 0;
@ -248,13 +241,7 @@ class parser_t
virtual document_t * parse(std::istream& in);
};
class parse_error : public error {
public:
parse_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~parse_error() throw() {}
};
DECLARE_EXCEPTION(parse_exception);
#endif

View file

@ -207,13 +207,16 @@ unsigned int xml_parser_t::parse(std::istream& in,
catch (const std::exception& err) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
XML_ParserFree(parser);
throw new parse_error(err.what());
throw_(parse_exception, err.what());
}
if (! have_error.empty()) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
#if 0
// jww (2007-04-26): What is this code doing?
parse_error err(have_error);
std::cerr << "Error: " << err.what() << std::endl;
#endif
have_error = "";
}
@ -221,7 +224,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser);
throw new parse_error(err);
throw_(parse_exception, err);
}
}

152
xpath.cc
View file

@ -1,4 +1,5 @@
#include "xpath.h"
#include "parser.h"
#if 0
#ifdef USE_BOOST_PYTHON
#include "py_eval.h"
@ -375,14 +376,12 @@ void xpath_t::token_t::next(std::istream& in, unsigned short flags)
kind = VALUE;
value = temp;
}
catch (amount_error * err) {
catch (amount_exception& err) {
// If the amount had no commodity, it must be an unambiguous
// variable reference
// jww (2007-04-19): There must be a more efficient way to do this!
if (std::strcmp(err->what(), "No quantity specified for amount") == 0) {
delete err;
if (std::strcmp(err.what(), "No quantity specified for amount") == 0) {
in.clear();
in.seekg(pos, std::ios::beg);
@ -390,7 +389,7 @@ void xpath_t::token_t::next(std::istream& in, unsigned short flags)
assert(! (std::isdigit(c) || c == '.'));
parse_ident(in);
} else {
throw err;
throw;
}
}
}
@ -409,15 +408,13 @@ void xpath_t::token_t::unexpected()
{
switch (kind) {
case TOK_EOF:
throw new parse_error("Unexpected end of expression");
throw_(parse_exception, "Unexpected end of expression");
case IDENT:
throw new parse_error(string("Unexpected symbol '") +
value.to_string() + "'");
throw_(parse_exception, "Unexpected symbol '" << value << "'");
case VALUE:
throw new parse_error(string("Unexpected value '") +
value.to_string() + "'");
throw_(parse_exception, "Unexpected value '" << value << "'");
default:
throw new parse_error(string("Unexpected operator '") + symbol + "'");
throw_(parse_exception, "Unexpected operator '" << symbol << "'");
}
}
@ -425,15 +422,15 @@ void xpath_t::token_t::unexpected(char c, char wanted)
{
if ((unsigned char) c == 0xff) {
if (wanted)
throw new parse_error(string("Missing '") + wanted + "'");
throw_(parse_exception, "Missing '" << wanted << "'");
else
throw new parse_error("Unexpected end");
throw_(parse_exception, "Unexpected end");
} else {
if (wanted)
throw new parse_error(string("Invalid char '") + c +
"' (wanted '" + wanted + "')");
throw_(parse_exception, "Invalid char '" << c <<
"' (wanted '" << wanted << "')");
else
throw new parse_error(string("Invalid char '") + c + "'");
throw_(parse_exception, "Invalid char '" << c << "'");
}
}
@ -472,7 +469,7 @@ xpath_t::op_t * xpath_t::wrap_mask(const string& pattern)
void xpath_t::scope_t::define(const string& name, op_t * def)
{
DEBUG_PRINT("ledger.xpath.syms", "Defining '" << name << "' = " << def);
DEBUG_("ledger.xpath.syms", "Defining '" << name << "' = " << def);
std::pair<symbol_map::iterator, bool> result
= symbols.insert(symbol_pair(name, def));
@ -485,8 +482,8 @@ void xpath_t::scope_t::define(const string& name, op_t * def)
std::pair<symbol_map::iterator, bool> result2
= symbols.insert(symbol_pair(name, def));
if (! result2.second)
throw new compile_error(string("Redefinition of '") +
name + "' in same scope");
throw_(compile_exception,
"Redefinition of '" << name << "' in same scope");
}
def->acquire();
}
@ -533,7 +530,7 @@ bool xpath_t::function_scope_t::resolve(const string& name,
if (value->type == value_t::XML_NODE)
result.set_string(value->to_xml_node()->text());
else
throw new calc_error("Attempt to call text() on a non-node value");
throw_(calc_exception, "Attempt to call text() on a non-node value");
return true;
}
break;
@ -545,7 +542,7 @@ xpath_t::op_t::~op_t()
{
TRACE_DTOR(xpath_t::op_t);
DEBUG_PRINT("ledger.xpath.memory", "Destroying " << this);
DEBUG_("ledger.xpath.memory", "Destroying " << this);
assert(refc == 0);
switch (kind) {
@ -600,13 +597,9 @@ void xpath_t::op_t::get_value(value_t& result) const
case ARG_INDEX:
result = (long)arg_index;
break;
default: {
std::ostringstream buf;
write(buf);
throw new calc_error
(string("Cannot determine value of expression symbol '") +
string(buf.str()) + "'");
}
default:
throw_(calc_exception,
"Cannot determine value of expression symbol '" << *this << "'");
}
}
@ -646,7 +639,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
goto done;
}
catch(const boost::python::error_already_set&) {
throw new parse_error("Error parsing lambda expression");
throw_(parse_exception, "Error parsing lambda expression");
}
#endif /* USE_BOOST_PYTHON */
#endif
@ -690,7 +683,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
case token_t::AT_SYM:
tok = next_token(in, tflags);
if (tok.kind != token_t::IDENT)
throw parse_error("@ symbol must be followed by attribute name");
throw_(parse_exception, "@ symbol must be followed by attribute name");
node.reset(new op_t(op_t::ATTR_NAME));
node->name = new string(tok.value.to_string());
@ -728,8 +721,8 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const
case token_t::LPAREN:
node.reset(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL));
if (! node.get())
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags);
if (tok.kind != token_t::RPAREN)
tok.unexpected(); // jww (2006-09-09): wanted )
@ -767,7 +760,7 @@ xpath_t::parse_predicate_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_value_expr(in, tflags | XPATH_PARSE_PARTIAL));
if (! node->right)
throw new parse_error("[ operator not followed by valid expression");
throw_(parse_exception, "[ operator not followed by valid expression");
tok = next_token(in, tflags);
if (tok.kind != token_t::RBRACKET)
@ -801,7 +794,7 @@ xpath_t::parse_path_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_predicate_expr(in, tflags));
if (! node->right)
throw new parse_error("/ operator not followed by a valid term");
throw_(parse_exception, "/ operator not followed by a valid term");
tok = next_token(in, tflags);
}
@ -823,8 +816,8 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
case token_t::EXCLAM: {
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
if (! texpr.get())
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
// A very quick optimization
if (texpr->kind == op_t::VALUE) {
*texpr->valuep = ! *texpr->valuep;
@ -839,8 +832,8 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
case token_t::MINUS: {
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
if (! texpr.get())
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
// A very quick optimization
if (texpr->kind == op_t::VALUE) {
texpr->valuep->in_place_negate();
@ -856,8 +849,8 @@ xpath_t::parse_unary_expr(std::istream& in, unsigned short tflags) const
case token_t::PERCENT: {
std::auto_ptr<op_t> texpr(parse_path_expr(in, tflags));
if (! texpr.get())
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
// A very quick optimization
if (texpr->kind == op_t::VALUE) {
static value_t perc("100.0%");
@ -893,8 +886,8 @@ xpath_t::parse_union_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_union_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
} else {
push_token(tok);
}
@ -916,8 +909,8 @@ xpath_t::parse_mul_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_mul_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags);
}
@ -942,8 +935,8 @@ xpath_t::parse_add_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_add_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags);
}
@ -1012,11 +1005,11 @@ xpath_t::parse_logic_expr(std::istream& in, unsigned short tflags) const
if (! node->right) {
if (tok.kind == token_t::PLUS)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
else
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
}
}
}
@ -1037,8 +1030,8 @@ xpath_t::parse_and_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_and_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
} else {
push_token(tok);
}
@ -1059,8 +1052,8 @@ xpath_t::parse_or_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_or_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
} else {
push_token(tok);
}
@ -1082,15 +1075,15 @@ xpath_t::parse_querycolon_expr(std::istream& in, unsigned short tflags) const
node->set_right(new op_t(op_t::O_COLON));
node->right->set_left(parse_querycolon_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags);
if (tok.kind != token_t::COLON)
tok.unexpected(); // jww (2006-09-09): wanted :
node->right->set_right(parse_querycolon_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
} else {
push_token(tok);
}
@ -1111,8 +1104,8 @@ xpath_t::parse_value_expr(std::istream& in, unsigned short tflags) const
node->set_left(prev.release());
node->set_right(parse_value_expr(in, tflags));
if (! node->right)
throw new parse_error(string(tok.symbol) +
" operator not followed by argument");
throw_(parse_exception,
tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags);
}
@ -1124,7 +1117,7 @@ xpath_t::parse_value_expr(std::istream& in, unsigned short tflags) const
}
}
else if (! (tflags & XPATH_PARSE_PARTIAL)) {
throw new parse_error(string("Failed to parse value expression"));
throw_(parse_exception, "Failed to parse value expression");
}
return node.release();
@ -1188,7 +1181,7 @@ void xpath_t::op_t::find_values(value_t * context, scope_t * scope,
}
}
} else {
throw new calc_error("Recursive path selection on a non-node value");
throw_(calc_exception, "Recursive path selection on a non-node value");
}
}
}
@ -1199,7 +1192,7 @@ bool xpath_t::op_t::test_value(value_t * context, scope_t * scope,
xpath_t expr(compile(context, scope, true));
if (expr->kind != VALUE)
throw new calc_error("Predicate expression does not yield a constant value");
throw_(calc_exception, "Predicate expression does not yield a constant value");
switch (expr->valuep->type) {
case value_t::INTEGER:
@ -1262,7 +1255,9 @@ void xpath_t::op_t::append_value(value_t& val,
xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
bool resolve)
{
#if 0
try {
#endif
switch (kind) {
case VALUE:
return acquire();
@ -1274,25 +1269,25 @@ 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 new compile_error("Referencing parent node from a non-node value");
throw_(compile_exception, "Referencing parent node from a non-node value");
else if (context->to_xml_node()->parent)
return wrap_value(context->to_xml_node()->parent)->acquire();
else
throw new compile_error("Referencing parent node from the root node");
throw_(compile_exception, "Referencing parent node from the root node");
case document_t::ROOT:
if (context->type != value_t::XML_NODE)
throw new compile_error("Referencing root node from a non-node value");
throw_(compile_exception, "Referencing root node from a non-node value");
else
return wrap_value(context->to_xml_node()->document->top)->acquire();
case document_t::ALL: {
if (context->type != value_t::XML_NODE)
throw new compile_error("Referencing child nodes from a non-node value");
throw_(compile_exception, "Referencing child nodes from a non-node value");
node_t * ptr = context->to_xml_node();
if (! (ptr->flags & XML_NODE_IS_PARENT))
throw new compile_error("Request for child nodes of a leaf node");
throw_(compile_exception, "Request for child nodes of a leaf node");
parent_node_t * parent = static_cast<parent_node_t *>(ptr);
@ -1366,7 +1361,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
if (arg_index < scope->args.to_sequence()->size())
return wrap_value((*scope->args.to_sequence())[arg_index])->acquire();
else
throw new compile_error("Reference to non-existing argument");
throw_(compile_exception, "Reference to non-existing argument");
} else {
return acquire();
}
@ -1650,7 +1645,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
}
if (lexpr->valuep->type != value_t::STRING)
throw new compile_error("Left operand of mask operator is not a string");
throw_(compile_exception, "Left operand of mask operator is not a string");
assert(rexpr->mask);
@ -1759,8 +1754,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
return func->compile(context, call_args.get(), resolve);
}
else {
throw new calc_error(string("Unknown function name '") +
*left->name + "'");
throw_(calc_exception, "Unknown function name '" << *left->name << "'");
}
}
else if (left->kind == FUNCTOR) {
@ -1815,7 +1809,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
i++, index++) {
assert((*i).type != value_t::SEQUENCE);
if ((*i).type != value_t::XML_NODE)
throw new compile_error("Attempting to apply path selection "
throw_(compile_exception, "Attempting to apply path selection "
"to non-node(s)");
function_scope_t xpath_fscope(seq, &(*i), index, scope);
@ -1831,8 +1825,8 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
}
default:
throw new compile_error("Attempting to apply path selection "
"to non-node(s)");
throw_(compile_exception, "Attempting to apply path selection "
"to non-node(s)");
}
if (result_seq->size() == 1)
@ -1863,6 +1857,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
assert(0);
break;
}
#if 0
}
catch (error * err) {
#if 0
@ -1873,6 +1868,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
#endif
throw err;
}
#endif
assert(0);
return NULL;
@ -1880,7 +1876,9 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope,
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));
@ -1893,6 +1891,7 @@ void xpath_t::calc(value_t& result, node_t * node, scope_t * scope) const
xpath_t final(ptr->compile(&context_node, scope, true));
final->get_value(result);
}
#if 0
}
catch (error * err) {
if (err->context.empty() ||
@ -1908,8 +1907,10 @@ void xpath_t::calc(value_t& result, node_t * node, scope_t * scope) const
#endif
throw err;
}
#endif
}
#if 0
xpath_t::context::context(const xpath_t& _xpath,
const op_t * _err_node,
const string& desc) throw()
@ -1952,6 +1953,7 @@ void xpath_t::context::describe(std::ostream& out) const throw()
out << std::endl;
}
}
#endif
bool xpath_t::op_t::write(std::ostream& out,
const bool relaxed,

44
xpath.h
View file

@ -11,30 +11,11 @@ class xpath_t
public:
struct op_t;
class parse_error : public error {
public:
parse_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~parse_error() throw() {}
};
class compile_error : public error {
public:
compile_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~compile_error() throw() {}
};
class calc_error : public error {
public:
calc_error(const string& _reason,
error_context * _ctxt = NULL) throw()
: error(_reason, _ctxt) {}
virtual ~calc_error() throw() {}
};
DECLARE_EXCEPTION(parse_exception);
DECLARE_EXCEPTION(compile_exception);
DECLARE_EXCEPTION(calc_exception);
#if 0
class context : public error_context {
public:
const xpath_t& xpath;
@ -47,6 +28,7 @@ public:
virtual void describe(std::ostream& out) const throw();
};
#endif
public:
class scope_t;
@ -439,21 +421,21 @@ public:
}
void release() const {
DEBUG_PRINT("ledger.xpath.memory",
DEBUG_("ledger.xpath.memory",
"Releasing " << this << ", refc now " << refc - 1);
assert(refc > 0);
if (--refc == 0)
delete this;
}
op_t * acquire() {
DEBUG_PRINT("ledger.xpath.memory",
DEBUG_("ledger.xpath.memory",
"Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0);
refc++;
return this;
}
const op_t * acquire() const {
DEBUG_PRINT("ledger.xpath.memory",
DEBUG_("ledger.xpath.memory",
"Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0);
refc++;
@ -580,8 +562,11 @@ public:
unsigned short tflags = XPATH_PARSE_RELAXED) const
{
std::istringstream stream(str);
#if 0
try {
#endif
return parse_expr(stream, tflags);
#if 0
}
catch (error * err) {
err->context.push_back
@ -589,6 +574,7 @@ public:
"While parsing value expression:"));
throw err;
}
#endif
}
op_t * parse_expr(const char * p,
@ -749,6 +735,11 @@ public:
friend class scope_t;
};
inline std::ostream& operator<<(std::ostream& out, const xpath_t::op_t& op) {
op.write(out);
return out;
};
} // namespace xml
template <typename T>
@ -770,7 +761,6 @@ class xml_command : public xml::xpath_t::functor_t
doc->write(*out);
}
};
} // namespace ledger