--exchange option now accepts multiple commodities

They must be separated by a comma, and all whitespace is ignored.
This commit is contained in:
John Wiegley 2009-02-22 17:51:11 -04:00
parent f2e4f4c6d1
commit ea75613760
8 changed files with 42 additions and 90 deletions

View file

@ -352,29 +352,6 @@ optional<price_point_t>
return none;
}
optional<price_point_t>
commodity_t::base_t::varied_history_t::
find_price(const commodity_t& source,
const std::vector<commodity_t *>& commodities,
const optional<datetime_t>& moment,
const optional<datetime_t>& oldest
#if defined(DEBUG_ON)
, const int indent
#endif
) const
{
foreach (commodity_t * commodity, commodities) {
if (optional<price_point_t> point = find_price(source, *commodity,
moment, oldest
#if defined(DEBUG_ON)
, indent
#endif
))
return point;
}
return none;
}
optional<commodity_t::base_t::history_t&>
commodity_t::base_t::varied_history_t::
history(const optional<commodity_t&>& commodity)
@ -400,22 +377,6 @@ optional<commodity_t::base_t::history_t&>
return none;
}
optional<commodity_t::history_t&>
commodity_t::base_t::varied_history_t::history
(const std::vector<commodity_t *>& commodities)
{
// This function differs from the single commodity case avoid in that
// 'commodities' represents a list of preferred valuation commodities.
// If no price can be located in terms of the first commodity, then
// the second is chosen, etc.
foreach (commodity_t * commodity, commodities) {
if (optional<history_t&> hist = history(*commodity))
return hist;
}
return none;
}
void commodity_t::exchange(commodity_t& commodity,
const amount_t& per_unit_cost,
const datetime_t& moment)

View file

@ -124,22 +124,11 @@ public:
const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
, const int indent = 0
#endif
) const;
optional<price_point_t>
find_price(const commodity_t& source,
const std::vector<commodity_t *>& commodities,
const optional<datetime_t>& moment = none,
const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
, const int indent = 0
#endif
) const;
optional<history_t&>
history(const optional<commodity_t&>& commodity = none);
optional<history_t&>
history(const std::vector<commodity_t *>& commodities);
};
#define COMMODITY_STYLE_DEFAULTS 0x000
@ -283,7 +272,6 @@ public:
}
optional<history_t&> history(const optional<commodity_t&>& commodity);
optional<history_t&> history(const std::vector<commodity_t *>& commodities);
public:
// These methods provide a transparent pass-through to the underlying
@ -324,23 +312,6 @@ public:
return none;
}
optional<price_point_t>
find_price(const std::vector<commodity_t *>& commodities,
const optional<datetime_t>& moment = none,
const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
, const int indent = 0
#endif
) const {
if (base->varied_history)
return base->varied_history->find_price(*this, commodities, moment, oldest
#if defined(DEBUG_ON)
, indent
#endif
);
return none;
}
// Methods to exchange one commodity for another, while recording the
// factored price.

View file

@ -73,7 +73,7 @@ public:
void verify_arguments() const;
bool has(std::size_t index) const {
if (index < args.size())
if (index < args.size() && ! args[index].is_null())
return true;
return false;
}

View file

@ -162,7 +162,7 @@ public:
if (handled)
return value;
else
return false;
return NULL_VALUE;
}
else {
return handled;

View file

@ -124,22 +124,34 @@ value_t report_t::fn_market_value(call_scope_t& scope)
{
interactive_t args(scope, "a&ts");
commodity_t * commodity = NULL;
if (args.has(2))
commodity = amount_t::current_pool->find_or_create(args.get<string>(2));
if (args.has(2)) {
scoped_array<char> buf(new char[args.get<string>(2).length() + 1]);
std::strcpy(buf.get(), args.get<string>(2).c_str());
DEBUG("report.market", "getting market value of: " << args.value_at(0));
value_t result =
args.value_at(0).value(! args.has(2),
args.has(1) ?
args.get<datetime_t>(1) : optional<datetime_t>(),
commodity ?
optional<commodity_t&>(*commodity) :
optional<commodity_t&>());
DEBUG("report.market", "result is: " << result);
return result;
bool primary_only = false;
for (char * p = std::strtok(buf.get(), ",");
p;
p = std::strtok(NULL, ",")) {
if (commodity_t * commodity = amount_t::current_pool->find(trim_ws(p))) {
value_t result =
args.value_at(0).value(primary_only, args.has(1) ?
args.get<datetime_t>(1) :
optional<datetime_t>(), *commodity);
if (! result.is_null())
return result;
}
// For subsequent, secondary commodities, don't convert primaries
primary_only = true;
}
} else {
value_t result =
args.value_at(0).value(! args.has(2), args.has(1) ?
args.get<datetime_t>(1) :
optional<datetime_t>());
if (! result.is_null())
return result;
}
return args.value_at(0);
}
value_t report_t::fn_strip(call_scope_t& args)

View file

@ -411,9 +411,9 @@ public:
OPTION_(report_t, market, DO() { // -V
parent->HANDLER(revalued).on_only();
parent->HANDLER(display_amount_)
.set_expr("exchange ? market(amount_expr, now, exchange) : market(amount_expr)");
.set_expr("market(amount_expr, now, exchange)");
parent->HANDLER(display_total_)
.set_expr("exchange ? market(total_expr, now, exchange) : market(total_expr)");
.set_expr("market(total_expr, now, exchange)");
});
OPTION_(report_t, monthly, DO() { // -M

View file

@ -522,6 +522,14 @@ inline char * skip_ws(char * ptr) {
return ptr;
}
inline char * trim_ws(char * ptr) {
std::size_t len = std::strlen(ptr);
int i = int(len) - 1;
while (i >= 0 && ptr[i] == ' ' || ptr[i] == '\t' || ptr[i] == '\n')
ptr[i--] = '\0';
return skip_ws(ptr);
}
inline char * next_element(char * buf, bool variable = false) {
for (char * p = buf; *p; p++) {
if (! (*p == ' ' || *p == '\t'))

View file

@ -1143,19 +1143,19 @@ value_t value_t::value(const bool primary_only,
{
switch (type()) {
case INTEGER:
return *this;
return NULL_VALUE;
case AMOUNT:
if (optional<amount_t> val =
as_amount().value(primary_only, moment, in_terms_of))
return *val;
return *this;
return NULL_VALUE;
case BALANCE:
if (optional<balance_t> bal =
as_balance().value(primary_only, moment, in_terms_of))
return *bal;
return *this;
return NULL_VALUE;
default:
break;