summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2006-03-16 19:14:30 +0000
committerJohn Wiegley <johnw@newartisans.com>2008-04-13 02:41:31 -0400
commit9800e3febc456edcafbb172c6bef67526a8481da (patch)
tree358f5ca7500ce774398e2511d16403129dc03051
parent31b68bbebcf448406020a8177efe6ae2f381d5cb (diff)
downloadfork-ledger-9800e3febc456edcafbb172c6bef67526a8481da.tar.gz
fork-ledger-9800e3febc456edcafbb172c6bef67526a8481da.tar.bz2
fork-ledger-9800e3febc456edcafbb172c6bef67526a8481da.zip
*** empty log message ***
-rw-r--r--amount.cc29
-rw-r--r--amount.h21
-rw-r--r--binary.cc40
-rw-r--r--config.cc50
-rw-r--r--config.h2
-rw-r--r--journal.cc2
-rw-r--r--main.cc3
-rw-r--r--textual.cc38
-rw-r--r--walk.cc4
9 files changed, 127 insertions, 62 deletions
diff --git a/amount.cc b/amount.cc
index cb046296..078e03a0 100644
--- a/amount.cc
+++ b/amount.cc
@@ -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);
diff --git a/amount.h b/amount.h
index 5df11817..c9ea7948 100644
--- a/amount.h
+++ b/amount.h
@@ -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 {
diff --git a/binary.cc b/binary.cc
index 005ed715..8f1d6c7b 100644
--- a/binary.cc
+++ b/binary.cc
@@ -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
diff --git a/config.cc b/config.cc
index 9e9a7f16..35c42137 100644
--- a/config.cc
+++ b/config.cc
@@ -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 },
diff --git a/config.h b/config.h
index 4c6b2ced..f642147d 100644
--- a/config.h
+++ b/config.h
@@ -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);
diff --git a/journal.cc b/journal.cc
index c326a223..68e3825c 100644
--- a/journal.cc
+++ b/journal.cc
@@ -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
diff --git a/main.cc b/main.cc
index 387524ba..705ee3af 100644
--- a/main.cc
+++ b/main.cc
@@ -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());
diff --git a/textual.cc b/textual.cc
index 4e2a12f4..3577145c 100644
--- a/textual.cc
+++ b/textual.cc
@@ -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;
diff --git a/walk.cc b/walk.cc
index cfb9af28..8a60cfaa 100644
--- a/walk.cc
+++ b/walk.cc
@@ -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;
}