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
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.suffix = self.find_boost_in_directory(path)
if self.suffix is not None:
@ -685,12 +687,16 @@ class PrepareBuild(CommandLineApp):
self.current_version())
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):
self.log.info('Executing phase: autogen')
if not exists('autogen.sh') or \
self.isnewer('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')
@ -704,10 +710,12 @@ class PrepareBuild(CommandLineApp):
if not exists('configure.ac') or \
self.isnewer('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 \
self.isnewer('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()
if reason:
@ -1159,6 +1167,7 @@ class PrepareBuild(CommandLineApp):
self.LDFLAGS.append('-g')
def setup_flavor_opt(self):
self.CPPFLAGS.append('-DNDEBUG=1')
if self.darwin_gcc:
self.option_no_pch()
if '--disable-shared' in self.configure_args:

View file

@ -218,6 +218,10 @@ namespace {
return true;
}
value_t get_addr(account_t& account) {
return long(&account);
}
value_t get_depth_spacer(account_t& account)
{
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>);
else if (name == "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")
return WRAP_FUNCTOR(&fn_any);
else if (name == "all")

View file

@ -149,10 +149,6 @@ namespace {
mpfr_set_prec(tempfb, num_prec + den_prec);
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)
throw_(amount_error,
_("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.
if (commodity_t * commodity = commodity_pool_t::current_pool->create("s"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
#if !defined(NO_ASSERTS)
else
assert(false);
#endif
// Add a "percentile" commodity
if (commodity_t * commodity = commodity_pool_t::current_pool->create("%"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
#if !defined(NO_ASSERTS)
else
assert(false);
#endif
is_initialized = true;
}
@ -472,7 +472,7 @@ amount_t& amount_t::operator-=(const amount_t& amt)
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());
@ -491,7 +491,7 @@ amount_t& amount_t::operator*=(const amount_t& amt)
quantity->prec =
static_cast<precision_t>(quantity->prec + amt.quantity->prec);
if (! has_commodity())
if (! has_commodity() && ! ignore_commodity)
commodity_ = amt.commodity_;
if (has_commodity() && ! keep_precision()) {
@ -741,24 +741,33 @@ amount_t::value(const bool primary_only,
#endif
if (has_commodity() &&
(! 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;
}
else if (has_annotation() && annotation().price &&
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 {
optional<price_point_t> point =
commodity().find_price(in_terms_of, moment);
// Whether a price was found or not, check whether we should attempt
// to download a price from the Internet. This is done if (a) no
// price was found, or (b) the price is "stale" according to the
// setting of --price-exp.
point = commodity().check_for_updated_price(point, moment, in_terms_of);
if (point)
return (point->price * number()).rounded();
// Whether a price was found or not, check whether we should
// attempt to download a price from the Internet. This is done
// if (a) no price was found, or (b) the price is "stale"
// according to the setting of --price-exp.
point = commodity().check_for_updated_price(point, moment,
in_terms_of);
if (point) {
amount_t price(point->price);
price.multiply(*this, true);
price.in_place_round();
return price;
}
}
}
} else {

View file

@ -62,7 +62,6 @@ namespace ledger {
class commodity_t;
class annotation_t;
class keep_details_t;
class commodity_pool_t;
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) {
return multiply(amt);
}
amount_t& multiply(const amount_t& amt, bool ignore_commodity = false);
/** Divide two amounts while extending the precision to preserve the
accuracy of the result. For example, if \c 10 is divided by \c 3,
@ -511,7 +513,7 @@ public:
amount's commodity:
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.

View file

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

View file

@ -120,12 +120,16 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
price_point_t point;
bool found = false;
#if defined(DEBUG_ON)
#define DEBUG_INDENT(cat, indent) \
do { \
if (SHOW_DEBUG(cat)) \
for (int i = 0; i < indent; i++) \
ledger::_log_buffer << " "; \
} while (false)
#else
#define DEBUG_INDENT(cat, indent)
#endif
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
@ -136,38 +140,34 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
if (oldest) {
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
if (prices.size() == 0) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " there are no prices in this history");
#endif
DEBUG("commodity.prices.find", "there are no prices in this history");
return none;
}
if (! moment) {
history_map::const_reverse_iterator r = prices.rbegin();
point.when = (*r).first;
point.when = (*r).first;
point.price = (*r).second;
found = true;
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " using most recent price");
#endif
DEBUG("commodity.prices.find", "using most recent price");
} else {
history_map::const_iterator i = prices.lower_bound(*moment);
history_map::const_iterator i = prices.upper_bound(*moment);
if (i == prices.end()) {
history_map::const_reverse_iterator r = prices.rbegin();
point.when = (*r).first;
point.price = (*r).second;
found = true;
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " using last price");
#endif
DEBUG("commodity.prices.find", "using last price");
} else {
point.when = (*i).first;
if (*moment < point.when) {
@ -181,40 +181,31 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
point.price = (*i).second;
found = true;
}
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " using found price");
#endif
DEBUG("commodity.prices.find", "using found price");
}
}
if (! found) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " could not find a price");
#endif
DEBUG("commodity.prices.find", "could not find a price");
return none;
}
else if (moment && point.when > *moment) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " price is too young ");
#endif
DEBUG("commodity.prices.find", "price is too young ");
return none;
}
else if (oldest && point.when < *oldest) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " price is too old ");
#endif
DEBUG("commodity.prices.find", "price is too old ");
return none;
}
else {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
" returning price: " << point.when << ", " << point.price);
#endif
"returning price: " << point.when << ", " << point.price);
return point;
}
}
@ -232,7 +223,13 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
optional<price_point_t> point;
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)
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);
if (commodity)
DEBUG("commodity.prices.find", " looking for: commodity '" << *commodity << "'");
DEBUG("commodity.prices.find", "looking for: commodity '" << *commodity << "'");
else
DEBUG("commodity.prices.find", " looking for: any commodity");
DEBUG("commodity.prices.find", "looking for: any commodity");
if (moment) {
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", " time index: " << *moment);
DEBUG("commodity.prices.find", "time index: " << *moment);
}
if (oldest) {
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
@ -262,16 +259,18 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
price_point_t best;
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);
if (comm == source)
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("commodity.prices.find",
" searching for price via commodity '" << comm << "'");
#endif
"searching for price via commodity '" << comm << "'");
point = hist.second.find_price(moment, limit
#if defined(DEBUG_ON)
@ -284,68 +283,59 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
optional<price_point_t> xlat;
if (commodity && comm != *commodity) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " looking for translation price");
#endif
DEBUG("commodity.prices.find", "looking for translation price");
xlat = comm.find_price(commodity, moment, limit
xlat = comm.find_price(commodity, moment, limit, true
#if defined(DEBUG_ON)
, indent + 2
#endif
);
if (xlat) {
#if defined(DEBUG_ON)
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);
#endif
point->price = xlat->price * point->price;
if (xlat->when < point->when) {
point->when = xlat->when;
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
" adjusting date of result back to " << point->when);
#endif
"adjusting date of result back to " << point->when);
}
} else {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " saw no translated price there");
#endif
DEBUG("commodity.prices.find", "saw no translated price there");
continue;
}
}
assert(! commodity || point->price.commodity() == *commodity);
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
" saw a price there: " << point->price << " from " << point->when);
#endif
"saw a price there: " << point->price << " from " << point->when);
if (! limit || point->when > *limit) {
limit = point->when;
best = *point;
found = true;
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
"search limit adjusted to " << *limit);
}
} else {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", " saw no price there");
#endif
DEBUG("commodity.prices.find", "saw no price there");
}
}
if (found) {
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
" found price " << best.price << " from " << best.when);
DEBUG("commodity.download",
"found price " << best.price << " from " << best.when);
#endif
return best;
}
return none;
@ -370,6 +360,97 @@ commodity_t::varied_history_t::history(const optional<commodity_t&>& commodity)
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>
commodity_t::check_for_updated_price(const optional<price_point_t>& point,
const optional<datetime_t>& moment,
@ -428,9 +509,7 @@ namespace {
{
switch (buf[0]) {
case 'a':
return (std::strcmp(buf, "and") == 0 ||
std::strcmp(buf, "any") == 0 ||
std::strcmp(buf, "all") == 0);
return std::strcmp(buf, "and") == 0;
case 'd':
return std::strcmp(buf, "div") == 0;
case 'e':

View file

@ -50,6 +50,7 @@
namespace ledger {
class keep_details_t;
class commodity_pool_t;
DECLARE_EXCEPTION(commodity_error, std::runtime_error);
@ -58,6 +59,10 @@ struct price_point_t
datetime_t when;
amount_t price;
bool operator==(const price_point_t& other) const {
return when == other.when && price == other.price;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
@ -174,6 +179,16 @@ protected:
optional<amount_t> smaller;
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;
public:
@ -333,36 +348,28 @@ public:
const bool reflexive = true) {
if (! base->varied_history)
base->varied_history = varied_history_t();
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) {
if (base->varied_history)
if (base->varied_history) {
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;
}
optional<price_point_t>
find_price(const optional<commodity_t&>& commodity = 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)
, const int indent = 0
#endif
) 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;
}
) const;
optional<price_point_t>
check_for_updated_price(const optional<price_point_t>& point,

View file

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

View file

@ -50,7 +50,7 @@ void post_splitter::print_title(const value_t& val)
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);
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);
post_t& temp = temps.copy_post(post, xact, new_account);
temp.note = none;
temp.add_flags(POST_ANONYMIZED);
(*handler)(temp);
}
@ -894,7 +895,7 @@ void posts_as_equity::report_subtotal()
value_t total = 0L;
foreach (values_map::value_type& pair, values) {
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)
handle_value(amount_pair.second, pair.second.account, &xact, temps,
handler);
@ -907,7 +908,7 @@ void posts_as_equity::report_subtotal()
values.clear();
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) {
post_t& balance_post = temps.create_post(xact, balance_account);
balance_post.amount = - pair.second;
@ -1166,8 +1167,10 @@ void forecast_posts::flush()
}
date_t& begin = *(*least).first.start;
#if !defined(NO_ASSERTS)
if ((*least).first.finish)
assert(begin < *(*least).first.finish);
#endif
// 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

View file

@ -226,16 +226,12 @@ class sort_posts : public item_handler<post_t>
public:
sort_posts(post_handler_ptr handler, const expr_t& _sort_order)
: item_handler<post_t>(handler),
sort_order(_sort_order) {
TRACE_CTOR(sort_posts,
"post_handler_ptr, const value_expr&");
: item_handler<post_t>(handler), sort_order(_sort_order) {
TRACE_CTOR(sort_posts, "post_handler_ptr, const value_expr&");
}
sort_posts(post_handler_ptr handler, const string& _sort_order)
: item_handler<post_t>(handler),
sort_order(_sort_order) {
TRACE_CTOR(sort_posts,
"post_handler_ptr, const string&");
: item_handler<post_t>(handler), sort_order(_sort_order) {
TRACE_CTOR(sort_posts, "post_handler_ptr, const string&");
}
virtual ~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()
{
#if defined(LOGGING_ON)
INFO("Initialization file is " << HANDLER(init_file_).str());
INFO("Price database is " << session().HANDLER(price_db_).str());
foreach (const path& pathname, session().HANDLER(file_).data_files)
INFO("Journal file is " << pathname.string());
#endif // defined(LOGGING_ON)
}
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;
}
value_t get_addr(item_t& item) {
return long(&item);
}
value_t get_depth(item_t&) {
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>);
else if (name == "actual_date")
return WRAP_FUNCTOR(get_wrapper<&get_actual_date>);
else if (name == "addr")
return WRAP_FUNCTOR(get_wrapper<&get_addr>);
break;
case 'b':

View file

@ -94,9 +94,9 @@ void posts_commodities_iterator::reset(journal_t& journal)
comm->varied_history()) {
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) {
foreach (commodity_t::history_map::value_type hpair,
foreach (commodity_t::history_map::value_type& hpair,
pair.second.prices) {
xact_t * xact;
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
// definition, and then at the point of every use if they could
// not be found there.
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) {
DEBUG("expr.compile", "Found definition:");
def->dump(*_log_stream, 0);
}
#endif // defined(DEBUG_ON)
return copy(def);
}
else if (left()) {

View file

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

View file

@ -122,8 +122,11 @@ string commodity_pool_t::make_qualified_name(const commodity_t& comm,
comm.print(name);
details.print(name, comm.pool().keep_base);
DEBUG("amounts.commodities", "make_qualified_name for "
<< *comm.qualified_symbol << std::endl << details);
#if defined(DEBUG_ON)
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());
return name.str();
@ -361,4 +364,76 @@ commodity_pool_t::parse_price_expression(const std::string& str,
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

View file

@ -86,7 +86,7 @@ public:
virtual ~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);
}
@ -131,6 +131,12 @@ public:
const bool add_prices = true,
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)
private:
/** Serialization. */

View file

@ -52,11 +52,12 @@ class account_t;
class post_t : public item_t
{
public:
#define POST_VIRTUAL 0x08 // the account was specified with (parens)
#define POST_MUST_BALANCE 0x10 // posting must balance in the transaction
#define POST_CALCULATED 0x20 // posting's amount was calculated
#define POST_COST_CALCULATED 0x40 // posting's cost was calculated
#define POST_COST_IN_FULL 0x80 // cost specified using @@
#define POST_VIRTUAL 0x04 // the account was specified with (parens)
#define POST_MUST_BALANCE 0x08 // posting must balance in the transaction
#define POST_CALCULATED 0x10 // posting's amount was calculated
#define POST_COST_CALCULATED 0x20 // posting's cost was calculated
#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
account_t * account;

View file

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

View file

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

View file

@ -842,6 +842,18 @@ value_t report_t::echo_command(call_scope_t& scope)
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)
{
switch (*p) {
@ -1318,9 +1330,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
case symbol_t::COMMAND:
switch (*p) {
case 'a':
if (is_eq(p, "accounts"))
if (is_eq(p, "accounts")) {
return WRAP_FUNCTOR(reporter<>(new report_accounts(*this), *this,
"#accounts"));
}
break;
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"));
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);
else if (is_eq(p, "emacs"))
}
else if (is_eq(p, "emacs")) {
return WRAP_FUNCTOR
(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);
}
break;
case 'p':
if (*(p + 1) == '\0' || is_eq(p, "print"))
if (*(p + 1) == '\0' || is_eq(p, "print")) {
return WRAP_FUNCTOR
(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
(reporter<post_t, post_handler_ptr, &report_t::commodities_report>
(new format_posts(*this, report_format(HANDLER(prices_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_long()),
*this, "#prices"));
else if (is_eq(p, "pricedb"))
}
else if (is_eq(p, "pricedb")) {
return expr_t::op_t::wrap_functor
(reporter<post_t, post_handler_ptr, &report_t::commodities_report>
(new format_posts(*this, report_format(HANDLER(pricedb_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_long()),
*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,
"#payees"));
}
break;
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
(reporter<>
(new format_posts(*this, report_format(HANDLER(register_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_long()),
*this, "#register"));
else if (is_eq(p, "reload"))
}
else if (is_eq(p, "reload")) {
return MAKE_FUNCTOR(report_t::reload_command);
}
break;
case 's':
@ -1448,6 +1473,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
case 'e':
if (is_eq(p, "eval"))
return WRAP_FUNCTOR(eval_command);
else if (is_eq(p, "expr"))
return WRAP_FUNCTOR(parse_command);
break;
case 'f':
if (is_eq(p, "format"))

View file

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

View file

@ -50,7 +50,6 @@
namespace ledger {
class commodity_pool_t;
class xact_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))
context.state_stack.push_front(acct);
#if !defined(NO_ASSERTS)
else
assert(! "Failed to create account");
#endif
}
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));
while (peek_whitespace_line()) {
#if defined(NO_ASSERTS)
read_line(line);
#else
std::streamsize len = read_line(line);
assert(len > 0);
#endif
regex = skip_ws(line);
if (! *regex)
@ -786,8 +792,12 @@ void instance_t::account_mapping_directive(char * line)
context.top_account()->find_account(account_name)));
while (peek_whitespace_line()) {
#if defined(NO_ASSERTS)
read_line(line);
#else
std::streamsize len = read_line(line);
assert(len > 0);
#endif
payee_regex = skip_ws(line);
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);
day_type the_day = day ? *day : date_t::day_type(1);
#if !defined(NO_ASSERTS)
if (day)
assert(! wday);
else if (wday)
assert(! day);
#endif
// 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.

View file

@ -49,17 +49,17 @@
*/
/*@{*/
#define TIMERS_ON 1
#if defined(DEBUG_MODE)
#define VERIFY_ON 1
#define TRACING_ON 1
#define DEBUG_ON 1
#define TIMERS_ON 1
#elif defined(NDEBUG)
#define NO_ASSERTS 1
#define NO_LOGGING 1
//#define NO_LOGGING 1
#else
#define TRACING_ON 1 // use --trace X to enable
#define TIMERS_ON 1
#endif
/*@}*/
@ -434,8 +434,8 @@ void finish_timer(const char * name);
(SHOW_TRACE(lvl) ? ledger::finish_timer(#name) : ((void)0))
#else
#define TRACE_START(name, lvl, msg)
#define TRACE_STOP(name)
#define TRACE_FINISH(name)
#define TRACE_STOP(name, lvl)
#define TRACE_FINISH(name, lvl)
#endif
#if defined(DEBUG_ON)
@ -474,8 +474,8 @@ void finish_timer(const char * name);
#else // ! (LOGGING_ON && TIMERS_ON)
#define TRACE_START(lvl, msg, name)
#define TRACE_STOP(name)
#define TRACE_FINISH(name)
#define TRACE_STOP(name, lvl)
#define TRACE_FINISH(name, lvl)
#define DEBUG_START(name, 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;
}
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:
break;
}
@ -1041,6 +1055,20 @@ bool value_t::is_greater_than(const value_t& val) const
}
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:
break;
}

View file

@ -878,7 +878,6 @@ public:
sequence_t::iterator begin() {
return as_sequence_lval().begin();
}
sequence_t::iterator end() {
return as_sequence_lval().end();
}
@ -886,7 +885,6 @@ public:
sequence_t::const_iterator begin() const {
return as_sequence().begin();
}
sequence_t::const_iterator end() const {
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)
{
#if !defined(NO_ASSERTS)
// You can add temporary postings to transactions, but not real postings to
// temporary transactions.
if (! post->has_flags(ITEM_TEMP))
assert(! has_flags(ITEM_TEMP));
#endif
posts.push_back(post);
}

View file

@ -2,18 +2,18 @@
<<<
>>>1
>>>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
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
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_
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_
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_
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&
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&
=== 7

View file

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