*** empty log message ***

This commit is contained in:
John Wiegley 2006-03-16 19:14:30 +00:00
parent 31b68bbebc
commit 9800e3febc
9 changed files with 127 additions and 62 deletions

View file

@ -596,10 +596,9 @@ bool amount_t::realzero() const
amount_t amount_t::value(const std::time_t moment) const
{
if (quantity) {
commodity_t& comm = commodity();
if (! (comm.flags() & COMMODITY_STYLE_NOMARKET))
if (amount_t amt = comm.value(moment))
return (amt * *this).round();
amount_t amt(commodity().value(moment));
if (! amt.realzero())
return (amt * *this).round();
}
return *this;
}
@ -973,6 +972,13 @@ void parse_annotations(std::istream& in, amount_t& price,
price.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
price.reduce();
// Since this price will maintain its own precision, make sure
// it is at least as large as the base commodity, since the user
// may have only specified {$1} or something similar.
if (price.quantity->prec < price.commodity().precision())
price = price.round(); // no need to retain individual precision
}
else if (c == '[') {
if (date)
@ -1084,7 +1090,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
}
assert(commodity_);
if (price || date || ! tag.empty())
if (! price.realzero() || date || ! tag.empty())
commodity_ =
annotated_commodity_t::find_or_create(*commodity_, price, date, tag);
}
@ -1435,6 +1441,19 @@ void commodity_base_t::add_price(const std::time_t date, const amount_t& price)
}
}
bool commodity_base_t::remove_price(const std::time_t date)
{
if (history) {
history_map::size_type n = history->prices.erase(date);
if (n > 0) {
if (history->prices.empty())
history = NULL;
return true;
}
}
return false;
}
commodity_base_t * commodity_base_t::create(const std::string& symbol)
{
commodity_base_t * commodity = new commodity_base_t(symbol);

View file

@ -283,6 +283,9 @@ class amount_t
friend void clean_commodity_history(char * item_pool,
char * item_pool_end);
friend void parse_annotations(std::istream& in, amount_t& price,
std::time_t& date, std::string& tag);
};
unsigned int sizeof_bigint_t();
@ -365,8 +368,9 @@ class commodity_base_t
amount_t * smaller;
amount_t * larger;
commodity_base_t() : precision(0), flags(COMMODITY_STYLE_DEFAULTS),
history(NULL), smaller(NULL), larger(NULL) {}
commodity_base_t()
: precision(0), flags(COMMODITY_STYLE_DEFAULTS),
history(NULL), smaller(NULL), larger(NULL) {}
commodity_base_t(const std::string& _symbol,
unsigned int _precision = 0,
@ -388,18 +392,13 @@ class commodity_base_t
struct history_t {
history_map prices;
std::time_t last_lookup;
std::time_t bogus_time;
history_t() : last_lookup(0), bogus_time(0) {}
};
history_t * history;
void add_price(const std::time_t date, const amount_t& price);
bool remove_price(const std::time_t date) {
if (history) {
history_map::size_type n = history->prices.erase(date);
return n > 0;
}
return false;
}
void add_price(const std::time_t date, const amount_t& price);
bool remove_price(const std::time_t date);
amount_t value(const std::time_t moment = std::time(NULL));
class updater_t {

View file

@ -12,9 +12,9 @@ namespace ledger {
static unsigned long binary_magic_number = 0xFFEED765;
#ifdef DEBUG_ENABLED
static unsigned long format_version = 0x00020607;
static unsigned long format_version = 0x00020609;
#else
static unsigned long format_version = 0x00020606;
static unsigned long format_version = 0x00020608;
#endif
static account_t ** accounts;
@ -415,6 +415,7 @@ inline void read_binary_commodity_base_extra(char *& data,
{
commodity_base_t * commodity = base_commodities[ident];
bool read_history = false;
for (unsigned long i = 0, count = read_binary_long<unsigned long>(data);
i < count;
i++) {
@ -429,8 +430,9 @@ inline void read_binary_commodity_base_extra(char *& data,
if (! commodity->history)
commodity->history = new commodity_base_t::history_t;
commodity->history->prices.insert(history_pair(when, amt));
read_history = true;
}
if (commodity->history)
if (read_history)
read_binary_long(data, commodity->history->last_lookup);
unsigned char flag;
@ -629,8 +631,7 @@ unsigned int read_binary_journal(std::istream& in,
// expression passed to an option, we'll just override the
// flags, but keep the commodity pointer intact.
if (c == commodity_base_t::commodities.end() ||
(*c).second->history || (*c).second->smaller ||
(*c).second->larger)
(*c).second->smaller || (*c).second->larger)
throw new error(std::string("Failed to read base commodity from cache: ") +
commodity->symbol);
@ -638,7 +639,6 @@ unsigned int read_binary_journal(std::istream& in,
(*c).second->note = commodity->note;
(*c).second->precision = commodity->precision;
(*c).second->flags = commodity->flags;
(*c).second->history = commodity->history;
(*c).second->smaller = commodity->smaller;
(*c).second->larger = commodity->larger;
@ -646,9 +646,6 @@ unsigned int read_binary_journal(std::istream& in,
}
}
for (commodity_base_t::ident_t i = 0; i < bc_count; i++)
read_binary_commodity_base_extra(data, i);
commodity_t::ident_t c_count = read_binary_long<commodity_t::ident_t>(data);
commodities = commodities_next = new commodity_t *[c_count];
@ -680,6 +677,9 @@ unsigned int read_binary_journal(std::istream& in,
commodity->base->symbol);
}
for (commodity_base_t::ident_t i = 0; i < bc_count; i++)
read_binary_commodity_base_extra(data, i);
commodity_t::ident_t ident;
read_binary_long(data, ident);
if (ident == 0xffffffff || ident == 0)
@ -971,8 +971,12 @@ void write_binary_commodity_base(std::ostream& out, commodity_base_t * commodity
write_binary_number(out, commodity->flags);
}
void write_binary_commodity_base_extra(std::ostream& out, commodity_base_t * commodity)
void write_binary_commodity_base_extra(std::ostream& out,
commodity_base_t * commodity)
{
if (commodity->history && commodity->history->bogus_time)
commodity->remove_price(commodity->history->bogus_time);
if (! commodity->history) {
write_binary_long<unsigned long>(out, 0);
} else {
@ -1127,12 +1131,6 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
i++)
write_binary_commodity_base(out, (*i).second);
for (base_commodities_map::const_iterator i =
commodity_base_t::commodities.begin();
i != commodity_base_t::commodities.end();
i++)
write_binary_commodity_base_extra(out, (*i).second);
write_binary_long<commodity_t::ident_t>
(out, commodity_t::commodities.size());
@ -1155,6 +1153,16 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
}
}
// Write out the history and smaller/larger convertible links after
// both the base and the main commodities have been written, since
// the amounts in both will refer to the mains.
for (base_commodities_map::const_iterator i =
commodity_base_t::commodities.begin();
i != commodity_base_t::commodities.end();
i++)
write_binary_commodity_base_extra(out, (*i).second);
if (commodity_t::default_commodity)
write_binary_long(out, commodity_t::default_commodity->ident);
else

View file

@ -106,21 +106,10 @@ std::string expand_path(const std::string& path)
return result;
}
std::string resolve_path(const std::string& path)
{
std::string resolved;;
inline std::string resolve_path(const std::string& path) {
if (path[0] == '~')
resolved = expand_path(path);
else
resolved = path;
#ifdef HAVE_REALPATH
char buf[PATH_MAX];
::realpath(resolved.c_str(), buf);
return std::string(buf);
#else
return resolved;
#endif
return expand_path(path);
return path;
}
void config_t::reset()
@ -1256,6 +1245,38 @@ OPT_BEGIN(market, "V") {
ledger::total_expr.reset(new value_expr("V"));
} OPT_END(market);
namespace {
void parse_price_setting(const char * optarg)
{
char * equals = std::strchr(optarg, '=');
if (! equals)
return;
while (std::isspace(*optarg))
optarg++;
while (equals > optarg && std::isspace(*(equals - 1)))
equals--;
std::string symbol(optarg, 0, equals - optarg);
amount_t price(equals + 1);
if (commodity_t * commodity = commodity_t::find_or_create(symbol)) {
commodity->add_price(now, price);
commodity->history()->bogus_time = now;
}
}
}
OPT_BEGIN(set_price, ":") {
std::string arg(optarg);
std::string::size_type beg = 0;
for (std::string::size_type pos = arg.find(';');
pos != std::string::npos;
beg = pos + 1, pos = arg.find(';', beg))
parse_price_setting(std::string(arg, beg, pos).c_str());
parse_price_setting(std::string(arg, beg).c_str());
} OPT_END(set_price);
OPT_BEGIN(performance, "g") {
ledger::amount_expr.reset(new value_expr("P(a,m)-b"));
ledger::total_expr.reset(new value_expr("P(O,m)-B"));
@ -1362,6 +1383,7 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
{ "reconcile-date", '\0', true, opt_reconcile_date, false },
{ "register-format", '\0', true, opt_register_format, false },
{ "related", 'r', false, opt_related, false },
{ "set-price", '\0', true, opt_set_price, false },
{ "sort", 'S', true, opt_sort, false },
{ "subtotal", 's', false, opt_subtotal, false },
{ "tail", '\0', true, opt_tail, false },

View file

@ -107,7 +107,7 @@ class config_t
std::list<item_handler<transaction_t> *>& ptrs);
};
#define CONFIG_OPTIONS_SIZE 89
#define CONFIG_OPTIONS_SIZE 90
extern option_t config_options[CONFIG_OPTIONS_SIZE];
void option_help(std::ostream& out);

View file

@ -197,7 +197,7 @@ bool entry_base_t::finalize()
continue;
if (! empty_allowed)
break;
throw new error("Only one transaction with null amount allowed per entry");
empty_allowed = false;
// If one transaction gives no value at all, its value will become

View file

@ -389,7 +389,8 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
// Write out the binary cache, if need be
if (config.use_cache && config.cache_dirty && ! config.cache_file.empty()) {
if (config.use_cache && config.cache_dirty &&
! config.cache_file.empty()) {
TRACE_PUSH(binary_cache, "Writing journal file");
std::ofstream stream(config.cache_file.c_str());

View file

@ -630,20 +630,36 @@ unsigned int textual_parser_t::parse(std::istream& in,
char * date_field = skip_ws(line + 1);
char * time_field = next_element(date_field);
if (! time_field) break;
char * symbol_and_price = next_element(time_field);
if (! symbol_and_price) break;
char date_buffer[64];
std::strcpy(date_buffer, date_field);
date_buffer[std::strlen(date_field)] = ' ';
std::strcpy(&date_buffer[std::strlen(date_field) + 1], time_field);
std::time_t date;
char * symbol_and_price;
std::time_t date;
struct std::tm when;
if (strptime(date_buffer, "%Y/%m/%d %H:%M:%S", &when)) {
date = std::mktime(&when);
if (std::isdigit(time_field[0])) {
symbol_and_price = next_element(time_field);
if (! symbol_and_price) break;
char date_buffer[64];
std::strcpy(date_buffer, date_field);
date_buffer[std::strlen(date_field)] = ' ';
std::strcpy(&date_buffer[std::strlen(date_field) + 1], time_field);
if (strptime(date_buffer, "%Y/%m/%d %H:%M:%S", &when)) {
date = std::mktime(&when);
} else {
throw new parse_error("Failed to parse date/time");
}
} else {
throw new parse_error("Failed to parse date");
symbol_and_price = time_field;
if (strptime(date_field, "%Y/%m/%d", &when)) {
when.tm_hour = 0;
when.tm_min = 0;
when.tm_sec = 0;
date = std::mktime(&when);
} else {
throw new parse_error("Failed to parse date");
}
}
std::string symbol;

View file

@ -42,7 +42,7 @@ void add_transaction_to(const transaction_t& xact, value_t& value)
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) {
value += transaction_xdata_(xact).composite_amount;
}
else if (xact.cost || value) {
else if (xact.cost || ! value.realzero()) {
value.add(xact.amount, xact.cost);
}
else {
@ -784,7 +784,7 @@ void sum_accounts(account_t& account)
value_t result;
compute_amount(result, details_t(account));
if (result)
if (! result.realzero())
xdata.total += result;
xdata.total_count += xdata.count;
}