Merge branch 'next'

This commit is contained in:
John Wiegley 2010-06-05 16:15:09 -04:00
commit 290cac7b84
31 changed files with 439 additions and 152 deletions

11
acprep
View file

@ -124,7 +124,9 @@ class BoostInfo(object):
return None return None
def locate_boost(self): def locate_boost(self):
for path in map(lambda x: join(x, 'lib'), search_prefixes): lib64_dirs = map(lambda x: join(x, 'lib64'), search_prefixes)
lib_dirs = map(lambda x: join(x, 'lib'), search_prefixes)
for path in lib64_dirs + lib_dirs:
self.log.info('Looking for Boost in %s...' % path) self.log.info('Looking for Boost in %s...' % path)
self.suffix = self.find_boost_in_directory(path) self.suffix = self.find_boost_in_directory(path)
if self.suffix is not None: if self.suffix is not None:
@ -685,12 +687,16 @@ class PrepareBuild(CommandLineApp):
self.current_version()) self.current_version())
version_m4.close() version_m4.close()
def copytimes(self, src, dest):
os.utime(dest, (os.stat(src)[ST_ATIME], os.stat(src)[ST_MTIME]))
def phase_autogen(self, *args): def phase_autogen(self, *args):
self.log.info('Executing phase: autogen') self.log.info('Executing phase: autogen')
if not exists('autogen.sh') or \ if not exists('autogen.sh') or \
self.isnewer('tools/autogen.sh', 'autogen.sh'): self.isnewer('tools/autogen.sh', 'autogen.sh'):
shutil.copyfile('tools/autogen.sh', 'autogen.sh') shutil.copyfile('tools/autogen.sh', 'autogen.sh')
self.copytimes('tools/autogen.sh', 'autogen.sh')
self.execute('sh', 'tools/autogen.sh') self.execute('sh', 'tools/autogen.sh')
@ -704,10 +710,12 @@ class PrepareBuild(CommandLineApp):
if not exists('configure.ac') or \ if not exists('configure.ac') or \
self.isnewer('tools/configure.ac', 'configure.ac'): self.isnewer('tools/configure.ac', 'configure.ac'):
shutil.copyfile('tools/configure.ac', 'configure.ac') shutil.copyfile('tools/configure.ac', 'configure.ac')
self.copytimes('tools/configure.ac', 'configure.ac')
if not exists('Makefile.am') or \ if not exists('Makefile.am') or \
self.isnewer('tools/Makefile.am', 'Makefile.am'): self.isnewer('tools/Makefile.am', 'Makefile.am'):
shutil.copyfile('tools/Makefile.am', 'Makefile.am') shutil.copyfile('tools/Makefile.am', 'Makefile.am')
self.copytimes('tools/Makefile.am', 'Makefile.am')
reason = self.need_to_prepare_autotools() reason = self.need_to_prepare_autotools()
if reason: if reason:
@ -1159,6 +1167,7 @@ class PrepareBuild(CommandLineApp):
self.LDFLAGS.append('-g') self.LDFLAGS.append('-g')
def setup_flavor_opt(self): def setup_flavor_opt(self):
self.CPPFLAGS.append('-DNDEBUG=1')
if self.darwin_gcc: if self.darwin_gcc:
self.option_no_pch() self.option_no_pch()
if '--disable-shared' in self.configure_args: if '--disable-shared' in self.configure_args:

View file

@ -218,6 +218,10 @@ namespace {
return true; return true;
} }
value_t get_addr(account_t& account) {
return long(&account);
}
value_t get_depth_spacer(account_t& account) value_t get_depth_spacer(account_t& account)
{ {
std::size_t depth = 0; std::size_t depth = 0;
@ -296,6 +300,8 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind,
return WRAP_FUNCTOR(get_wrapper<&get_account>); return WRAP_FUNCTOR(get_wrapper<&get_account>);
else if (name == "account_base") else if (name == "account_base")
return WRAP_FUNCTOR(get_wrapper<&get_account_base>); return WRAP_FUNCTOR(get_wrapper<&get_account_base>);
else if (name == "addr")
return WRAP_FUNCTOR(get_wrapper<&get_addr>);
else if (name == "any") else if (name == "any")
return WRAP_FUNCTOR(&fn_any); return WRAP_FUNCTOR(&fn_any);
else if (name == "all") else if (name == "all")

View file

@ -149,10 +149,6 @@ namespace {
mpfr_set_prec(tempfb, num_prec + den_prec); mpfr_set_prec(tempfb, num_prec + den_prec);
mpfr_div(tempfb, tempfnum, tempfden, GMP_RNDN); mpfr_div(tempfb, tempfnum, tempfden, GMP_RNDN);
char bigbuf[4096];
mpfr_sprintf(bigbuf, "%.RNf", tempfb);
DEBUG("amount.convert", "num/den = " << bigbuf);
if (mpfr_asprintf(&buf, "%.*RNf", precision, tempfb) < 0) if (mpfr_asprintf(&buf, "%.*RNf", precision, tempfb) < 0)
throw_(amount_error, throw_(amount_error,
_("Cannot output amount to a floating-point representation")); _("Cannot output amount to a floating-point representation"));
@ -244,14 +240,18 @@ void amount_t::initialize()
// in terms of seconds, but reported as minutes or hours. // in terms of seconds, but reported as minutes or hours.
if (commodity_t * commodity = commodity_pool_t::current_pool->create("s")) if (commodity_t * commodity = commodity_pool_t::current_pool->create("s"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
#if !defined(NO_ASSERTS)
else else
assert(false); assert(false);
#endif
// Add a "percentile" commodity // Add a "percentile" commodity
if (commodity_t * commodity = commodity_pool_t::current_pool->create("%")) if (commodity_t * commodity = commodity_pool_t::current_pool->create("%"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
#if !defined(NO_ASSERTS)
else else
assert(false); assert(false);
#endif
is_initialized = true; is_initialized = true;
} }
@ -472,7 +472,7 @@ amount_t& amount_t::operator-=(const amount_t& amt)
return *this; return *this;
} }
amount_t& amount_t::operator*=(const amount_t& amt) amount_t& amount_t::multiply(const amount_t& amt, bool ignore_commodity)
{ {
VERIFY(amt.valid()); VERIFY(amt.valid());
@ -491,7 +491,7 @@ amount_t& amount_t::operator*=(const amount_t& amt)
quantity->prec = quantity->prec =
static_cast<precision_t>(quantity->prec + amt.quantity->prec); static_cast<precision_t>(quantity->prec + amt.quantity->prec);
if (! has_commodity()) if (! has_commodity() && ! ignore_commodity)
commodity_ = amt.commodity_; commodity_ = amt.commodity_;
if (has_commodity() && ! keep_precision()) { if (has_commodity() && ! keep_precision()) {
@ -741,24 +741,33 @@ amount_t::value(const bool primary_only,
#endif #endif
if (has_commodity() && if (has_commodity() &&
(! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) { (! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) {
if (in_terms_of && commodity() == *in_terms_of) { if (in_terms_of &&
commodity().referent() == in_terms_of->referent()) {
return *this; return *this;
} }
else if (has_annotation() && annotation().price && else if (has_annotation() && annotation().price &&
annotation().has_flags(ANNOTATION_PRICE_FIXATED)) { annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
return (*annotation().price * number()).rounded(); amount_t price(*annotation().price);
price.multiply(*this, true);
price.in_place_round();
return price;
} }
else { else {
optional<price_point_t> point = optional<price_point_t> point =
commodity().find_price(in_terms_of, moment); commodity().find_price(in_terms_of, moment);
// Whether a price was found or not, check whether we should attempt // Whether a price was found or not, check whether we should
// to download a price from the Internet. This is done if (a) no // attempt to download a price from the Internet. This is done
// price was found, or (b) the price is "stale" according to the // if (a) no price was found, or (b) the price is "stale"
// setting of --price-exp. // according to the setting of --price-exp.
point = commodity().check_for_updated_price(point, moment, in_terms_of); point = commodity().check_for_updated_price(point, moment,
if (point) in_terms_of);
return (point->price * number()).rounded(); if (point) {
amount_t price(point->price);
price.multiply(*this, true);
price.in_place_round();
return price;
}
} }
} }
} else { } else {

View file

@ -62,7 +62,6 @@ namespace ledger {
class commodity_t; class commodity_t;
class annotation_t; class annotation_t;
class keep_details_t; class keep_details_t;
class commodity_pool_t;
DECLARE_EXCEPTION(amount_error, std::runtime_error); DECLARE_EXCEPTION(amount_error, std::runtime_error);
@ -275,7 +274,10 @@ public:
amount_t& operator+=(const amount_t& amt); amount_t& operator+=(const amount_t& amt);
amount_t& operator-=(const amount_t& amt); amount_t& operator-=(const amount_t& amt);
amount_t& operator*=(const amount_t& amt); amount_t& operator*=(const amount_t& amt) {
return multiply(amt);
}
amount_t& multiply(const amount_t& amt, bool ignore_commodity = false);
/** Divide two amounts while extending the precision to preserve the /** Divide two amounts while extending the precision to preserve the
accuracy of the result. For example, if \c 10 is divided by \c 3, accuracy of the result. For example, if \c 10 is divided by \c 3,
@ -511,7 +513,7 @@ public:
amount's commodity: amount's commodity:
commodity() returns an amount's commodity. If the amount has no commodity() returns an amount's commodity. If the amount has no
commodity, the value returned is `current_pool->null_commodity'. commodity, the value returned is the `null_commodity'.
has_commodity() returns true if the amount has a commodity. has_commodity() returns true if the amount has a commodity.

View file

@ -190,7 +190,7 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
keep_date ? details.date : none, keep_date ? details.date : none,
keep_tag ? details.tag : none)); keep_tag ? details.tag : none));
} else { } else {
new_comm = pool().find_or_create(base_symbol()); new_comm = &referent();
} }
assert(new_comm); assert(new_comm);

View file

@ -120,12 +120,16 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
price_point_t point; price_point_t point;
bool found = false; bool found = false;
#if defined(DEBUG_ON)
#define DEBUG_INDENT(cat, indent) \ #define DEBUG_INDENT(cat, indent) \
do { \ do { \
if (SHOW_DEBUG(cat)) \ if (SHOW_DEBUG(cat)) \
for (int i = 0; i < indent; i++) \ for (int i = 0; i < indent; i++) \
ledger::_log_buffer << " "; \ ledger::_log_buffer << " "; \
} while (false) } while (false)
#else
#define DEBUG_INDENT(cat, indent)
#endif
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
@ -136,38 +140,34 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
if (oldest) { if (oldest) {
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " but no older than: " << *oldest); DEBUG("commodity.prices.find", "but no older than: " << *oldest);
} }
#endif #endif
if (prices.size() == 0) { if (prices.size() == 0) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " there are no prices in this history"); DEBUG("commodity.prices.find", "there are no prices in this history");
#endif
return none; return none;
} }
if (! moment) { if (! moment) {
history_map::const_reverse_iterator r = prices.rbegin(); history_map::const_reverse_iterator r = prices.rbegin();
point.when = (*r).first; point.when = (*r).first;
point.price = (*r).second; point.price = (*r).second;
found = true; found = true;
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " using most recent price"); DEBUG("commodity.prices.find", "using most recent price");
#endif
} else { } else {
history_map::const_iterator i = prices.lower_bound(*moment); history_map::const_iterator i = prices.upper_bound(*moment);
if (i == prices.end()) { if (i == prices.end()) {
history_map::const_reverse_iterator r = prices.rbegin(); history_map::const_reverse_iterator r = prices.rbegin();
point.when = (*r).first; point.when = (*r).first;
point.price = (*r).second; point.price = (*r).second;
found = true; found = true;
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " using last price"); DEBUG("commodity.prices.find", "using last price");
#endif
} else { } else {
point.when = (*i).first; point.when = (*i).first;
if (*moment < point.when) { if (*moment < point.when) {
@ -181,40 +181,31 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
point.price = (*i).second; point.price = (*i).second;
found = true; found = true;
} }
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " using found price"); DEBUG("commodity.prices.find", "using found price");
#endif
} }
} }
if (! found) { if (! found) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " could not find a price"); DEBUG("commodity.prices.find", "could not find a price");
#endif
return none; return none;
} }
else if (moment && point.when > *moment) { else if (moment && point.when > *moment) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " price is too young "); DEBUG("commodity.prices.find", "price is too young ");
#endif
return none; return none;
} }
else if (oldest && point.when < *oldest) { else if (oldest && point.when < *oldest) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " price is too old "); DEBUG("commodity.prices.find", "price is too old ");
#endif
return none; return none;
} }
else { else {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", DEBUG("commodity.prices.find",
" returning price: " << point.when << ", " << point.price); "returning price: " << point.when << ", " << point.price);
#endif
return point; return point;
} }
} }
@ -232,7 +223,13 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
optional<price_point_t> point; optional<price_point_t> point;
optional<datetime_t> limit = oldest; optional<datetime_t> limit = oldest;
assert(! commodity || source != *commodity); #if defined(VERIFY_ON)
if (commodity) {
VERIFY(source != *commodity);
VERIFY(! commodity->has_annotation());
VERIFY(source.referent() != commodity->referent());
}
#endif
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
@ -240,18 +237,18 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
if (commodity) if (commodity)
DEBUG("commodity.prices.find", " looking for: commodity '" << *commodity << "'"); DEBUG("commodity.prices.find", "looking for: commodity '" << *commodity << "'");
else else
DEBUG("commodity.prices.find", " looking for: any commodity"); DEBUG("commodity.prices.find", "looking for: any commodity");
if (moment) { if (moment) {
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " time index: " << *moment); DEBUG("commodity.prices.find", "time index: " << *moment);
} }
if (oldest) { if (oldest) {
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " only consider prices younger than: " << *oldest); DEBUG("commodity.prices.find", "only consider prices younger than: " << *oldest);
} }
#endif #endif
@ -262,16 +259,18 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
price_point_t best; price_point_t best;
bool found = false; bool found = false;
foreach (history_by_commodity_map::value_type hist, histories) { foreach (const history_by_commodity_map::value_type& hist, histories) {
commodity_t& comm(*hist.first); commodity_t& comm(*hist.first);
if (comm == source) if (comm == source)
continue; continue;
#if defined(DEBUG_ON) // Only value secondary commodities in terms of primary ones
if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY))
continue;
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", DEBUG("commodity.prices.find",
" searching for price via commodity '" << comm << "'"); "searching for price via commodity '" << comm << "'");
#endif
point = hist.second.find_price(moment, limit point = hist.second.find_price(moment, limit
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
@ -284,68 +283,59 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
optional<price_point_t> xlat; optional<price_point_t> xlat;
if (commodity && comm != *commodity) { if (commodity && comm != *commodity) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " looking for translation price"); DEBUG("commodity.prices.find", "looking for translation price");
#endif
xlat = comm.find_price(commodity, moment, limit xlat = comm.find_price(commodity, moment, limit, true
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
, indent + 2 , indent + 2
#endif #endif
); );
if (xlat) { if (xlat) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " found translated price " DEBUG("commodity.prices.find", "found translated price "
<< xlat->price << " from " << xlat->when); << xlat->price << " from " << xlat->when);
#endif
point->price = xlat->price * point->price; point->price = xlat->price * point->price;
if (xlat->when < point->when) { if (xlat->when < point->when) {
point->when = xlat->when; point->when = xlat->when;
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", DEBUG("commodity.prices.find",
" adjusting date of result back to " << point->when); "adjusting date of result back to " << point->when);
#endif
} }
} else { } else {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " saw no translated price there"); DEBUG("commodity.prices.find", "saw no translated price there");
#endif
continue; continue;
} }
} }
assert(! commodity || point->price.commodity() == *commodity); assert(! commodity || point->price.commodity() == *commodity);
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", DEBUG("commodity.prices.find",
" saw a price there: " << point->price << " from " << point->when); "saw a price there: " << point->price << " from " << point->when);
#endif
if (! limit || point->when > *limit) { if (! limit || point->when > *limit) {
limit = point->when; limit = point->when;
best = *point; best = *point;
found = true; found = true;
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
"search limit adjusted to " << *limit);
} }
} else { } else {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " saw no price there"); DEBUG("commodity.prices.find", "saw no price there");
#endif
} }
} }
if (found) { if (found) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent); DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
" found price " << best.price << " from " << best.when);
DEBUG("commodity.download", DEBUG("commodity.download",
"found price " << best.price << " from " << best.when); "found price " << best.price << " from " << best.when);
#endif
return best; return best;
} }
return none; return none;
@ -370,6 +360,97 @@ commodity_t::varied_history_t::history(const optional<commodity_t&>& commodity)
return none; return none;
} }
optional<price_point_t>
commodity_t::find_price(const optional<commodity_t&>& commodity,
const optional<datetime_t>& moment,
const optional<datetime_t>& oldest,
const bool nested
#if defined(DEBUG_ON)
, const int indent
#endif
) const
{
if (! has_flags(COMMODITY_WALKED) && base->varied_history &&
(commodity || ! has_flags(COMMODITY_PRIMARY))) {
optional<base_t::time_and_commodity_t> pair;
#if defined(VERIFY_ON)
optional<price_point_t> checkpoint;
bool found = false;
#endif
if (! nested) {
pair = base_t::time_and_commodity_t
(base_t::optional_time_pair_t(moment, oldest),
commodity ? &(*commodity) : NULL);
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", "looking for memoized args: "
<< (moment ? format_datetime(*moment) : "NONE") << ", "
<< (oldest ? format_datetime(*oldest) : "NONE") << ", "
<< (commodity ? commodity->symbol() : "NONE"));
base_t::memoized_price_map::iterator i = base->price_map.find(*pair);
if (i != base->price_map.end()) {
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", "found! returning: "
<< ((*i).second ? (*i).second->price : amount_t(0L)));
#if defined(VERIFY_ON)
IF_VERIFY() {
found = true;
checkpoint = (*i).second;
} else
#endif // defined(VERIFY_ON)
return (*i).second;
}
}
optional<price_point_t> point;
const_cast<commodity_t&>(*this).add_flags(COMMODITY_WALKED);
try {
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", "manually finding price...");
point = base->varied_history->find_price(*this, commodity,
moment, oldest
#if defined(DEBUG_ON)
, indent
#endif
);
}
catch (...) {
const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
throw;
}
const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
#if defined(VERIFY_ON)
if (DO_VERIFY() && found) {
VERIFY(checkpoint == point);
return checkpoint;
}
#endif // defined(VERIFY_ON)
if (! nested && pair) {
if (base->price_map.size() > base_t::max_price_map_size) {
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
"price map has grown too large, clearing it by half");
for (std::size_t i = 0; i < base_t::max_price_map_size >> 1; i++)
base->price_map.erase(base->price_map.begin());
}
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
"remembered: " << (point ? point->price : amount_t(0L)));
base->price_map.insert
(base_t::memoized_price_map::value_type(*pair, point));
}
return point;
}
return none;
}
optional<price_point_t> optional<price_point_t>
commodity_t::check_for_updated_price(const optional<price_point_t>& point, commodity_t::check_for_updated_price(const optional<price_point_t>& point,
const optional<datetime_t>& moment, const optional<datetime_t>& moment,
@ -428,9 +509,7 @@ namespace {
{ {
switch (buf[0]) { switch (buf[0]) {
case 'a': case 'a':
return (std::strcmp(buf, "and") == 0 || return std::strcmp(buf, "and") == 0;
std::strcmp(buf, "any") == 0 ||
std::strcmp(buf, "all") == 0);
case 'd': case 'd':
return std::strcmp(buf, "div") == 0; return std::strcmp(buf, "div") == 0;
case 'e': case 'e':

View file

@ -50,6 +50,7 @@
namespace ledger { namespace ledger {
class keep_details_t; class keep_details_t;
class commodity_pool_t;
DECLARE_EXCEPTION(commodity_error, std::runtime_error); DECLARE_EXCEPTION(commodity_error, std::runtime_error);
@ -58,6 +59,10 @@ struct price_point_t
datetime_t when; datetime_t when;
amount_t price; amount_t price;
bool operator==(const price_point_t& other) const {
return when == other.when && price == other.price;
}
#if defined(HAVE_BOOST_SERIALIZATION) #if defined(HAVE_BOOST_SERIALIZATION)
private: private:
/** Serialization. */ /** Serialization. */
@ -174,6 +179,16 @@ protected:
optional<amount_t> smaller; optional<amount_t> smaller;
optional<amount_t> larger; optional<amount_t> larger;
typedef std::pair<optional<datetime_t>,
optional<datetime_t> > optional_time_pair_t;
typedef std::pair<optional_time_pair_t,
commodity_t *> time_and_commodity_t;
typedef std::map<time_and_commodity_t,
optional<price_point_t> > memoized_price_map;
static const std::size_t max_price_map_size = 16;
mutable memoized_price_map price_map;
mutable bool searched; mutable bool searched;
public: public:
@ -333,36 +348,28 @@ public:
const bool reflexive = true) { const bool reflexive = true) {
if (! base->varied_history) if (! base->varied_history)
base->varied_history = varied_history_t(); base->varied_history = varied_history_t();
base->varied_history->add_price(*this, date, price, reflexive); base->varied_history->add_price(*this, date, price, reflexive);
DEBUG("commodity.prices.find", "Price added, clearing price_map");
base->price_map.clear(); // a price was added, invalid the map
} }
bool remove_price(const datetime_t& date, commodity_t& commodity) { bool remove_price(const datetime_t& date, commodity_t& commodity) {
if (base->varied_history) if (base->varied_history) {
base->varied_history->remove_price(date, commodity); base->varied_history->remove_price(date, commodity);
DEBUG("commodity.prices.find", "Price removed, clearing price_map");
base->price_map.clear(); // a price was added, invalid the map
}
return false; return false;
} }
optional<price_point_t> optional<price_point_t>
find_price(const optional<commodity_t&>& commodity = none, find_price(const optional<commodity_t&>& commodity = none,
const optional<datetime_t>& moment = none, const optional<datetime_t>& moment = none,
const optional<datetime_t>& oldest = none const optional<datetime_t>& oldest = none,
const bool nested = false
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
, const int indent = 0 , const int indent = 0
#endif #endif
) const { ) const;
if (base->varied_history && ! has_flags(COMMODITY_WALKED)) {
const_cast<commodity_t&>(*this).add_flags(COMMODITY_WALKED);
optional<price_point_t> point =
base->varied_history->find_price(*this, commodity, moment, oldest
#if defined(DEBUG_ON)
, indent
#endif
);
const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
return point;
}
return none;
}
optional<price_point_t> optional<price_point_t>
check_for_updated_price(const optional<price_point_t>& point, check_for_updated_price(const optional<price_point_t>& point,

View file

@ -155,17 +155,21 @@ public:
result_type calc(scope_t& scope) result_type calc(scope_t& scope)
{ {
if (! compiled) { if (! compiled) {
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) { if (SHOW_DEBUG("expr.compile")) {
DEBUG("expr.compile", "Before compilation:"); DEBUG("expr.compile", "Before compilation:");
dump(*_log_stream); dump(*_log_stream);
} }
#endif // defined(DEBUG_ON)
compile(scope); compile(scope);
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) { if (SHOW_DEBUG("expr.compile")) {
DEBUG("expr.compile", "After compilation:"); DEBUG("expr.compile", "After compilation:");
dump(*_log_stream); dump(*_log_stream);
} }
#endif // defined(DEBUG_ON)
} }
return real_calc(scope); return real_calc(scope);

View file

@ -50,7 +50,7 @@ void post_splitter::print_title(const value_t& val)
void post_splitter::flush() void post_splitter::flush()
{ {
foreach (value_to_posts_map::value_type pair, posts_map) { foreach (value_to_posts_map::value_type& pair, posts_map) {
preflush_func(pair.first); preflush_func(pair.first);
foreach (post_t * post, pair.second) foreach (post_t * post, pair.second)
@ -256,6 +256,7 @@ void anonymize_posts::operator()(post_t& post)
create_temp_account_from_path(account_names, temps, xact.journal->master); create_temp_account_from_path(account_names, temps, xact.journal->master);
post_t& temp = temps.copy_post(post, xact, new_account); post_t& temp = temps.copy_post(post, xact, new_account);
temp.note = none; temp.note = none;
temp.add_flags(POST_ANONYMIZED);
(*handler)(temp); (*handler)(temp);
} }
@ -894,7 +895,7 @@ void posts_as_equity::report_subtotal()
value_t total = 0L; value_t total = 0L;
foreach (values_map::value_type& pair, values) { foreach (values_map::value_type& pair, values) {
if (pair.second.value.is_balance()) { if (pair.second.value.is_balance()) {
foreach (balance_t::amounts_map::value_type amount_pair, foreach (const balance_t::amounts_map::value_type& amount_pair,
pair.second.value.as_balance().amounts) pair.second.value.as_balance().amounts)
handle_value(amount_pair.second, pair.second.account, &xact, temps, handle_value(amount_pair.second, pair.second.account, &xact, temps,
handler); handler);
@ -907,7 +908,7 @@ void posts_as_equity::report_subtotal()
values.clear(); values.clear();
if (total.is_balance()) { if (total.is_balance()) {
foreach (balance_t::amounts_map::value_type pair, foreach (const balance_t::amounts_map::value_type& pair,
total.as_balance().amounts) { total.as_balance().amounts) {
post_t& balance_post = temps.create_post(xact, balance_account); post_t& balance_post = temps.create_post(xact, balance_account);
balance_post.amount = - pair.second; balance_post.amount = - pair.second;
@ -1166,8 +1167,10 @@ void forecast_posts::flush()
} }
date_t& begin = *(*least).first.start; date_t& begin = *(*least).first.start;
#if !defined(NO_ASSERTS)
if ((*least).first.finish) if ((*least).first.finish)
assert(begin < *(*least).first.finish); assert(begin < *(*least).first.finish);
#endif
// If the next date in the series for this periodic posting is more than 5 // If the next date in the series for this periodic posting is more than 5
// years beyond the last valid post we generated, drop it from further // years beyond the last valid post we generated, drop it from further

View file

@ -226,16 +226,12 @@ class sort_posts : public item_handler<post_t>
public: public:
sort_posts(post_handler_ptr handler, const expr_t& _sort_order) sort_posts(post_handler_ptr handler, const expr_t& _sort_order)
: item_handler<post_t>(handler), : item_handler<post_t>(handler), sort_order(_sort_order) {
sort_order(_sort_order) { TRACE_CTOR(sort_posts, "post_handler_ptr, const value_expr&");
TRACE_CTOR(sort_posts,
"post_handler_ptr, const value_expr&");
} }
sort_posts(post_handler_ptr handler, const string& _sort_order) sort_posts(post_handler_ptr handler, const string& _sort_order)
: item_handler<post_t>(handler), : item_handler<post_t>(handler), sort_order(_sort_order) {
sort_order(_sort_order) { TRACE_CTOR(sort_posts, "post_handler_ptr, const string&");
TRACE_CTOR(sort_posts,
"post_handler_ptr, const string&");
} }
virtual ~sort_posts() { virtual ~sort_posts() {
TRACE_DTOR(sort_posts); TRACE_DTOR(sort_posts);

View file

@ -391,11 +391,13 @@ global_scope_t::read_command_arguments(scope_t& scope, strings_list args)
void global_scope_t::normalize_session_options() void global_scope_t::normalize_session_options()
{ {
#if defined(LOGGING_ON)
INFO("Initialization file is " << HANDLER(init_file_).str()); INFO("Initialization file is " << HANDLER(init_file_).str());
INFO("Price database is " << session().HANDLER(price_db_).str()); INFO("Price database is " << session().HANDLER(price_db_).str());
foreach (const path& pathname, session().HANDLER(file_).data_files) foreach (const path& pathname, session().HANDLER(file_).data_files)
INFO("Journal file is " << pathname.string()); INFO("Journal file is " << pathname.string());
#endif // defined(LOGGING_ON)
} }
expr_t::func_t global_scope_t::look_for_precommand(scope_t& scope, expr_t::func_t global_scope_t::look_for_precommand(scope_t& scope,

View file

@ -323,6 +323,10 @@ namespace {
return item.pos ? long(item.pos->sequence) : 0L; return item.pos ? long(item.pos->sequence) : 0L;
} }
value_t get_addr(item_t& item) {
return long(&item);
}
value_t get_depth(item_t&) { value_t get_depth(item_t&) {
return 0L; return 0L;
} }
@ -376,6 +380,8 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind,
return WRAP_FUNCTOR(get_wrapper<&get_actual>); return WRAP_FUNCTOR(get_wrapper<&get_actual>);
else if (name == "actual_date") else if (name == "actual_date")
return WRAP_FUNCTOR(get_wrapper<&get_actual_date>); return WRAP_FUNCTOR(get_wrapper<&get_actual_date>);
else if (name == "addr")
return WRAP_FUNCTOR(get_wrapper<&get_addr>);
break; break;
case 'b': case 'b':

View file

@ -94,9 +94,9 @@ void posts_commodities_iterator::reset(journal_t& journal)
comm->varied_history()) { comm->varied_history()) {
account_t * account = journal.master->find_account(comm->symbol()); account_t * account = journal.master->find_account(comm->symbol());
foreach (commodity_t::history_by_commodity_map::value_type pair, foreach (commodity_t::history_by_commodity_map::value_type& pair,
history->histories) { history->histories) {
foreach (commodity_t::history_map::value_type hpair, foreach (commodity_t::history_map::value_type& hpair,
pair.second.prices) { pair.second.prices) {
xact_t * xact; xact_t * xact;
string symbol = hpair.second.commodity().symbol(); string symbol = hpair.second.commodity().symbol();

View file

@ -78,10 +78,12 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
// Identifier references are first looked up at the point of // Identifier references are first looked up at the point of
// definition, and then at the point of every use if they could // definition, and then at the point of every use if they could
// not be found there. // not be found there.
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) { if (SHOW_DEBUG("expr.compile")) {
DEBUG("expr.compile", "Found definition:"); DEBUG("expr.compile", "Found definition:");
def->dump(*_log_stream, 0); def->dump(*_log_stream, 0);
} }
#endif // defined(DEBUG_ON)
return copy(def); return copy(def);
} }
else if (left()) { else if (left()) {

View file

@ -61,10 +61,16 @@ class expr_t::parser_t : public noncopyable
return lookahead; return lookahead;
} }
#if !defined(NO_ASSERTS)
void push_token(const token_t& tok) const { void push_token(const token_t& tok) const {
assert(&tok == &lookahead); assert(&tok == &lookahead);
use_lookahead = true; use_lookahead = true;
} }
#else
void push_token(const token_t&) const {
use_lookahead = true;
}
#endif // !defined(NO_ASSERTS)
void push_token() const { void push_token() const {
use_lookahead = true; use_lookahead = true;
} }

View file

@ -122,8 +122,11 @@ string commodity_pool_t::make_qualified_name(const commodity_t& comm,
comm.print(name); comm.print(name);
details.print(name, comm.pool().keep_base); details.print(name, comm.pool().keep_base);
DEBUG("amounts.commodities", "make_qualified_name for " #if defined(DEBUG_ON)
<< *comm.qualified_symbol << std::endl << details); if (comm.qualified_symbol)
DEBUG("amounts.commodities", "make_qualified_name for "
<< *comm.qualified_symbol << std::endl << details);
#endif
DEBUG("amounts.commodities", "qualified_name is " << name.str()); DEBUG("amounts.commodities", "qualified_name is " << name.str());
return name.str(); return name.str();
@ -361,4 +364,76 @@ commodity_pool_t::parse_price_expression(const std::string& str,
return NULL; return NULL;
} }
void commodity_pool_t::print_pricemap(std::ostream& out,
const keep_details_t& keep,
const optional<datetime_t>& moment)
{
typedef std::map<commodity_t *, commodity_t *> comm_map_t;
comm_map_t comm_map;
foreach (const commodities_map::value_type& comm_pair, commodities) {
commodity_t * comm(&comm_pair.second->strip_annotations(keep));
comm_map.insert(comm_map_t::value_type(comm, NULL));
}
out << "digraph commodities {\n";
foreach (const comm_map_t::value_type& comm_pair, comm_map) {
commodity_t * comm(comm_pair.first);
if (comm->has_flags(COMMODITY_BUILTIN))
continue;
out << " ";
if (commodity_t::symbol_needs_quotes(comm->symbol()))
out << comm->symbol() << ";\n";
else
out << "\"" << comm->symbol() << "\";\n";
if (! comm->has_flags(COMMODITY_NOMARKET) &&
(! commodity_pool_t::current_pool->default_commodity ||
comm != commodity_pool_t::current_pool->default_commodity)) {
if (optional<commodity_t::varied_history_t&> vhist =
comm->varied_history()) {
foreach (const commodity_t::history_by_commodity_map::value_type& pair,
vhist->histories) {
datetime_t most_recent;
amount_t most_recent_amt;
foreach (const commodity_t::history_map::value_type& inner_pair,
pair.second.prices) {
if ((most_recent.is_not_a_date_time() ||
inner_pair.first > most_recent) &&
(! moment || inner_pair.first <= moment)) {
most_recent = inner_pair.first;
most_recent_amt = inner_pair.second;
}
}
if (! most_recent.is_not_a_date_time()) {
out << " ";
if (commodity_t::symbol_needs_quotes(comm->symbol()))
out << comm->symbol();
else
out << "\"" << comm->symbol() << "\"";
out << " -> ";
if (commodity_t::symbol_needs_quotes(pair.first->symbol()))
out << pair.first->symbol();
else
out << "\"" << pair.first->symbol() << "\"";
out << " [label=\""
<< most_recent_amt.number() << "\\n"
<< format_date(most_recent.date(), FMT_WRITTEN)
<< "\" fontcolor=\"#008e28\"];\n";
}
}
}
}
}
out << "}\n";
}
} // namespace ledger } // namespace ledger

View file

@ -86,7 +86,7 @@ public:
virtual ~commodity_pool_t() { virtual ~commodity_pool_t() {
TRACE_DTOR(commodity_pool_t); TRACE_DTOR(commodity_pool_t);
foreach (commodities_map::value_type pair, commodities) foreach (commodities_map::value_type& pair, commodities)
checked_delete(pair.second); checked_delete(pair.second);
} }
@ -131,6 +131,12 @@ public:
const bool add_prices = true, const bool add_prices = true,
const optional<datetime_t>& moment = none); const optional<datetime_t>& moment = none);
// Output the commodity price map for a given date as a DOT file
void print_pricemap(std::ostream& out,
const keep_details_t& keep,
const optional<datetime_t>& moment = none);
#if defined(HAVE_BOOST_SERIALIZATION) #if defined(HAVE_BOOST_SERIALIZATION)
private: private:
/** Serialization. */ /** Serialization. */

View file

@ -52,11 +52,12 @@ class account_t;
class post_t : public item_t class post_t : public item_t
{ {
public: public:
#define POST_VIRTUAL 0x08 // the account was specified with (parens) #define POST_VIRTUAL 0x04 // the account was specified with (parens)
#define POST_MUST_BALANCE 0x10 // posting must balance in the transaction #define POST_MUST_BALANCE 0x08 // posting must balance in the transaction
#define POST_CALCULATED 0x20 // posting's amount was calculated #define POST_CALCULATED 0x10 // posting's amount was calculated
#define POST_COST_CALCULATED 0x40 // posting's cost was calculated #define POST_COST_CALCULATED 0x20 // posting's cost was calculated
#define POST_COST_IN_FULL 0x80 // cost specified using @@ #define POST_COST_IN_FULL 0x40 // cost specified using @@
#define POST_ANONYMIZED 0x80 // a temporary, anonymous posting
xact_t * xact; // only set for posts of regular xacts xact_t * xact; // only set for posts of regular xacts
account_t * account; account_t * account;

View file

@ -120,6 +120,7 @@ namespace {
foreach (post_t * post, xact.posts) { foreach (post_t * post, xact.posts) {
if (post->has_flags(ITEM_TEMP | ITEM_GENERATED) && if (post->has_flags(ITEM_TEMP | ITEM_GENERATED) &&
! post->has_flags(POST_ANONYMIZED) &&
! report.HANDLED(print_virtual)) ! report.HANDLED(print_virtual))
continue; continue;

View file

@ -115,8 +115,10 @@ struct string_from_python
utf8::unchecked::utf16to8(value, value + size, std::back_inserter(str)); utf8::unchecked::utf16to8(value, value + size, std::back_inserter(str));
else if (sizeof(Py_UNICODE) == 4) // UTF-32 else if (sizeof(Py_UNICODE) == 4) // UTF-32
utf8::unchecked::utf32to8(value, value + size, std::back_inserter(str)); utf8::unchecked::utf32to8(value, value + size, std::back_inserter(str));
#if !defined(NO_ASSERTS)
else else
assert(! "Py_UNICODE has an unexpected size"); assert(! "Py_UNICODE has an unexpected size");
#endif
if (value == 0) throw_error_already_set(); if (value == 0) throw_error_already_set();
void* storage = void* storage =

View file

@ -842,6 +842,18 @@ value_t report_t::echo_command(call_scope_t& scope)
return true; return true;
} }
value_t report_t::pricemap_command(call_scope_t& scope)
{
interactive_t args(scope, "&s");
std::ostream& out(output_stream);
commodity_pool_t::current_pool->print_pricemap
(out, what_to_keep(), args.has(0) ?
optional<datetime_t>(datetime_t(parse_date(args.get<string>(0)))) : none);
return true;
}
option_t<report_t> * report_t::lookup_option(const char * p) option_t<report_t> * report_t::lookup_option(const char * p)
{ {
switch (*p) { switch (*p) {
@ -1318,9 +1330,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
case symbol_t::COMMAND: case symbol_t::COMMAND:
switch (*p) { switch (*p) {
case 'a': case 'a':
if (is_eq(p, "accounts")) if (is_eq(p, "accounts")) {
return WRAP_FUNCTOR(reporter<>(new report_accounts(*this), *this, return WRAP_FUNCTOR(reporter<>(new report_accounts(*this), *this,
"#accounts")); "#accounts"));
}
break; break;
case 'b': case 'b':
@ -1381,48 +1394,60 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
HANDLER(print_virtual).on_only(string("#equity")); HANDLER(print_virtual).on_only(string("#equity"));
return WRAP_FUNCTOR(reporter<>(new print_xacts(*this), *this, "#equity")); return WRAP_FUNCTOR(reporter<>(new print_xacts(*this), *this, "#equity"));
} }
else if (is_eq(p, "entry")) else if (is_eq(p, "entry")) {
return WRAP_FUNCTOR(xact_command); return WRAP_FUNCTOR(xact_command);
else if (is_eq(p, "emacs")) }
else if (is_eq(p, "emacs")) {
return WRAP_FUNCTOR return WRAP_FUNCTOR
(reporter<>(new format_emacs_posts(output_stream), *this, "#emacs")); (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs"));
else if (is_eq(p, "echo")) }
else if (is_eq(p, "echo")) {
return MAKE_FUNCTOR(report_t::echo_command); return MAKE_FUNCTOR(report_t::echo_command);
}
break; break;
case 'p': case 'p':
if (*(p + 1) == '\0' || is_eq(p, "print")) if (*(p + 1) == '\0' || is_eq(p, "print")) {
return WRAP_FUNCTOR return WRAP_FUNCTOR
(reporter<>(new print_xacts(*this, HANDLED(raw)), *this, "#print")); (reporter<>(new print_xacts(*this, HANDLED(raw)), *this, "#print"));
else if (is_eq(p, "prices")) }
else if (is_eq(p, "prices")) {
return expr_t::op_t::wrap_functor return expr_t::op_t::wrap_functor
(reporter<post_t, post_handler_ptr, &report_t::commodities_report> (reporter<post_t, post_handler_ptr, &report_t::commodities_report>
(new format_posts(*this, report_format(HANDLER(prices_format_)), (new format_posts(*this, report_format(HANDLER(prices_format_)),
maybe_format(HANDLER(prepend_format_)), maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_long()), HANDLER(prepend_width_).value.to_long()),
*this, "#prices")); *this, "#prices"));
else if (is_eq(p, "pricedb")) }
else if (is_eq(p, "pricedb")) {
return expr_t::op_t::wrap_functor return expr_t::op_t::wrap_functor
(reporter<post_t, post_handler_ptr, &report_t::commodities_report> (reporter<post_t, post_handler_ptr, &report_t::commodities_report>
(new format_posts(*this, report_format(HANDLER(pricedb_format_)), (new format_posts(*this, report_format(HANDLER(pricedb_format_)),
maybe_format(HANDLER(prepend_format_)), maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_long()), HANDLER(prepend_width_).value.to_long()),
*this, "#pricedb")); *this, "#pricedb"));
else if (is_eq(p, "payees")) }
else if (is_eq(p, "pricemap")) {
return MAKE_FUNCTOR(report_t::pricemap_command);
}
else if (is_eq(p, "payees")) {
return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this, return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this,
"#payees")); "#payees"));
}
break; break;
case 'r': case 'r':
if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) {
return WRAP_FUNCTOR return WRAP_FUNCTOR
(reporter<> (reporter<>
(new format_posts(*this, report_format(HANDLER(register_format_)), (new format_posts(*this, report_format(HANDLER(register_format_)),
maybe_format(HANDLER(prepend_format_)), maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_long()), HANDLER(prepend_width_).value.to_long()),
*this, "#register")); *this, "#register"));
else if (is_eq(p, "reload")) }
else if (is_eq(p, "reload")) {
return MAKE_FUNCTOR(report_t::reload_command); return MAKE_FUNCTOR(report_t::reload_command);
}
break; break;
case 's': case 's':
@ -1448,6 +1473,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
case 'e': case 'e':
if (is_eq(p, "eval")) if (is_eq(p, "eval"))
return WRAP_FUNCTOR(eval_command); return WRAP_FUNCTOR(eval_command);
else if (is_eq(p, "expr"))
return WRAP_FUNCTOR(parse_command);
break; break;
case 'f': case 'f':
if (is_eq(p, "format")) if (is_eq(p, "format"))

View file

@ -198,6 +198,7 @@ public:
value_t reload_command(call_scope_t&); value_t reload_command(call_scope_t&);
value_t echo_command(call_scope_t& scope); value_t echo_command(call_scope_t& scope);
value_t pricemap_command(call_scope_t& scope);
keep_details_t what_to_keep() { keep_details_t what_to_keep() {
bool lots = HANDLED(lots) || HANDLED(lots_actual); bool lots = HANDLED(lots) || HANDLED(lots_actual);

View file

@ -50,7 +50,6 @@
namespace ledger { namespace ledger {
class commodity_pool_t;
class xact_t; class xact_t;
class session_t : public symbol_scope_t class session_t : public symbol_scope_t

View file

@ -695,8 +695,10 @@ void instance_t::master_account_directive(char * line)
{ {
if (account_t * acct = context.top_account()->find_account(line)) if (account_t * acct = context.top_account()->find_account(line))
context.state_stack.push_front(acct); context.state_stack.push_front(acct);
#if !defined(NO_ASSERTS)
else else
assert(! "Failed to create account"); assert(! "Failed to create account");
#endif
} }
void instance_t::end_directive(char * kind) void instance_t::end_directive(char * kind)
@ -763,8 +765,12 @@ void instance_t::payee_mapping_directive(char * line)
(payee_mapping_t(mask_t(regex), payee)); (payee_mapping_t(mask_t(regex), payee));
while (peek_whitespace_line()) { while (peek_whitespace_line()) {
#if defined(NO_ASSERTS)
read_line(line);
#else
std::streamsize len = read_line(line); std::streamsize len = read_line(line);
assert(len > 0); assert(len > 0);
#endif
regex = skip_ws(line); regex = skip_ws(line);
if (! *regex) if (! *regex)
@ -786,8 +792,12 @@ void instance_t::account_mapping_directive(char * line)
context.top_account()->find_account(account_name))); context.top_account()->find_account(account_name)));
while (peek_whitespace_line()) { while (peek_whitespace_line()) {
#if defined(NO_ASSERTS)
read_line(line);
#else
std::streamsize len = read_line(line); std::streamsize len = read_line(line);
assert(len > 0); assert(len > 0);
#endif
payee_regex = skip_ws(line); payee_regex = skip_ws(line);
if (! *payee_regex) if (! *payee_regex)

View file

@ -333,10 +333,12 @@ date_t date_specifier_t::begin(const optional_year& current_year) const
month_type the_month = month ? *month : date_t::month_type(1); month_type the_month = month ? *month : date_t::month_type(1);
day_type the_day = day ? *day : date_t::day_type(1); day_type the_day = day ? *day : date_t::day_type(1);
#if !defined(NO_ASSERTS)
if (day) if (day)
assert(! wday); assert(! wday);
else if (wday) else if (wday)
assert(! day); assert(! day);
#endif
// jww (2009-11-16): Handle wday. If a month is set, find the most recent // jww (2009-11-16): Handle wday. If a month is set, find the most recent
// wday in that month; if the year is set, then in that year. // wday in that month; if the year is set, then in that year.

View file

@ -49,17 +49,17 @@
*/ */
/*@{*/ /*@{*/
#define TIMERS_ON 1
#if defined(DEBUG_MODE) #if defined(DEBUG_MODE)
#define VERIFY_ON 1 #define VERIFY_ON 1
#define TRACING_ON 1 #define TRACING_ON 1
#define DEBUG_ON 1 #define DEBUG_ON 1
#define TIMERS_ON 1
#elif defined(NDEBUG) #elif defined(NDEBUG)
#define NO_ASSERTS 1 #define NO_ASSERTS 1
#define NO_LOGGING 1 //#define NO_LOGGING 1
#else #else
#define TRACING_ON 1 // use --trace X to enable #define TRACING_ON 1 // use --trace X to enable
#define TIMERS_ON 1
#endif #endif
/*@}*/ /*@}*/
@ -434,8 +434,8 @@ void finish_timer(const char * name);
(SHOW_TRACE(lvl) ? ledger::finish_timer(#name) : ((void)0)) (SHOW_TRACE(lvl) ? ledger::finish_timer(#name) : ((void)0))
#else #else
#define TRACE_START(name, lvl, msg) #define TRACE_START(name, lvl, msg)
#define TRACE_STOP(name) #define TRACE_STOP(name, lvl)
#define TRACE_FINISH(name) #define TRACE_FINISH(name, lvl)
#endif #endif
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
@ -474,8 +474,8 @@ void finish_timer(const char * name);
#else // ! (LOGGING_ON && TIMERS_ON) #else // ! (LOGGING_ON && TIMERS_ON)
#define TRACE_START(lvl, msg, name) #define TRACE_START(lvl, msg, name)
#define TRACE_STOP(name) #define TRACE_STOP(name, lvl)
#define TRACE_FINISH(name) #define TRACE_FINISH(name, lvl)
#define DEBUG_START(name, msg) #define DEBUG_START(name, msg)
#define DEBUG_START_(name, cat, msg) #define DEBUG_START_(name, cat, msg)

View file

@ -935,6 +935,20 @@ bool value_t::is_less_than(const value_t& val) const
} }
return ! no_amounts; return ! no_amounts;
} }
case SEQUENCE: {
sequence_t::const_iterator i = as_sequence().begin();
sequence_t::const_iterator j = val.as_sequence().begin();
for (; (i != as_sequence().end() &&
j != val.as_sequence().end()); i++, j++) {
if (! ((*i) < (*j)))
return false;
}
if (i == as_sequence().end())
return true;
else
return false;
break;
}
default: default:
break; break;
} }
@ -1041,6 +1055,20 @@ bool value_t::is_greater_than(const value_t& val) const
} }
return ! no_amounts; return ! no_amounts;
} }
case SEQUENCE: {
sequence_t::const_iterator i = as_sequence().begin();
sequence_t::const_iterator j = val.as_sequence().begin();
for (; (i != as_sequence().end() &&
j != val.as_sequence().end()); i++, j++) {
if (! ((*i) > (*j)))
return false;
}
if (i == as_sequence().end())
return false;
else
return true;
break;
}
default: default:
break; break;
} }

View file

@ -878,7 +878,6 @@ public:
sequence_t::iterator begin() { sequence_t::iterator begin() {
return as_sequence_lval().begin(); return as_sequence_lval().begin();
} }
sequence_t::iterator end() { sequence_t::iterator end() {
return as_sequence_lval().end(); return as_sequence_lval().end();
} }
@ -886,7 +885,6 @@ public:
sequence_t::const_iterator begin() const { sequence_t::const_iterator begin() const {
return as_sequence().begin(); return as_sequence().begin();
} }
sequence_t::const_iterator end() const { sequence_t::const_iterator end() const {
return as_sequence().end(); return as_sequence().end();
} }

View file

@ -62,10 +62,12 @@ xact_base_t::~xact_base_t()
void xact_base_t::add_post(post_t * post) void xact_base_t::add_post(post_t * post)
{ {
#if !defined(NO_ASSERTS)
// You can add temporary postings to transactions, but not real postings to // You can add temporary postings to transactions, but not real postings to
// temporary transactions. // temporary transactions.
if (! post->has_flags(ITEM_TEMP)) if (! post->has_flags(ITEM_TEMP))
assert(! has_flags(ITEM_TEMP)); assert(! has_flags(ITEM_TEMP));
#endif
posts.push_back(post); posts.push_back(post);
} }

View file

@ -2,18 +2,18 @@
<<< <<<
>>>1 >>>1
>>>2 >>>2
While parsing file "$sourcepath/src/amount.h", line 67: While parsing file "$sourcepath/src/amount.h", line 66:
Error: No quantity specified for amount Error: No quantity specified for amount
While parsing file "$sourcepath/src/amount.h", line 718: While parsing file "$sourcepath/src/amount.h", line 720:
Error: Invalid date/time: line amount_t amoun Error: Invalid date/time: line amount_t amoun
While parsing file "$sourcepath/src/amount.h", line 724: While parsing file "$sourcepath/src/amount.h", line 726:
Error: Invalid date/time: line string amount_ Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 730: While parsing file "$sourcepath/src/amount.h", line 732:
Error: Invalid date/time: line string amount_ Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 736: While parsing file "$sourcepath/src/amount.h", line 738:
Error: Invalid date/time: line string amount_ Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 742: While parsing file "$sourcepath/src/amount.h", line 744:
Error: Invalid date/time: line std::ostream& Error: Invalid date/time: line std::ostream&
While parsing file "$sourcepath/src/amount.h", line 749: While parsing file "$sourcepath/src/amount.h", line 751:
Error: Invalid date/time: line std::istream& Error: Invalid date/time: line std::istream&
=== 7 === 7

View file

@ -5,7 +5,7 @@ set -e
# Exit if it's not a branch we're interested in being thorough about # Exit if it's not a branch we're interested in being thorough about
if echo $(git rev-parse --symbolic-full-name HEAD) | \ if echo $(git rev-parse --symbolic-full-name HEAD) | \
egrep -q '^refs/heads/(next|t/)'; then egrep -q '^refs/heads/(t/)'; then
exit 0 exit 0
fi fi
@ -41,12 +41,12 @@ cd $TMPDIR
if [ ! -f Makefile -o \ if [ ! -f Makefile -o \
Makefile.in -nt Makefile -o \ Makefile.in -nt Makefile -o \
configure -nt Makefile -o \ configure -nt Makefile -o \
Makefile.am -nt Makefile.in -o \ tools/Makefile.am -nt Makefile.in -o \
configure.ac -nt configure -o \ tools/configure.ac -nt configure -o \
\( -f acprep -a acprep -nt Makefile \) ] \( -f acprep -a acprep -nt Makefile \) ]
then then
if [ -f acprep ]; then if [ -f acprep ]; then
./acprep default --local echo Will run acprep in a moment
elif [ -f autogen.sh ]; then elif [ -f autogen.sh ]; then
sh autogen.sh && ./configure sh autogen.sh && ./configure
else else
@ -56,6 +56,10 @@ fi
# Finally, (re)build this proposed source tree and see if it passes # Finally, (re)build this proposed source tree and see if it passes
# muster. # muster.
nice -n 20 make check if [ -f acprep ]; then
nice -n 20 ./acprep default --warn make check
else
nice -n 20 make check
fi
exit 0 exit 0