summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/amount.cc2
-rw-r--r--src/context.h2
-rw-r--r--src/csv.cc8
-rw-r--r--src/error.cc2
-rw-r--r--src/filters.cc3
-rw-r--r--src/global.cc57
-rw-r--r--src/global.h8
-rw-r--r--src/item.cc5
-rw-r--r--src/journal.cc13
-rw-r--r--src/post.h2
-rw-r--r--src/py_xact.cc6
-rw-r--r--src/report.cc15
-rw-r--r--src/session.cc8
-rw-r--r--src/textual.cc2
-rw-r--r--src/xact.cc44
15 files changed, 122 insertions, 55 deletions
diff --git a/src/amount.cc b/src/amount.cc
index 671215c2..ee03827e 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -690,7 +690,7 @@ void amount_t::in_place_ceiling()
throw_(amount_error, _("Cannot ceiling an uninitialized amount"));
_dup();
-
+
mpz_t quot;
mpz_init(quot);
mpz_cdiv_q(quot, mpq_numref(MP(quantity)), mpq_denref(MP(quantity)));
diff --git a/src/context.h b/src/context.h
index 7373be39..9fe0613b 100644
--- a/src/context.h
+++ b/src/context.h
@@ -121,7 +121,7 @@ inline parse_context_t open_for_reading(const path& pathname,
throw_(std::runtime_error,
_f("Cannot read journal file %1%") % filename);
- path parent(pathname.parent_path());
+ path parent(filename.parent_path());
shared_ptr<std::istream> stream(new ifstream(filename));
parse_context_t context(stream, parent);
context.pathname = filename;
diff --git a/src/csv.cc b/src/csv.cc
index dbd2dbfe..c7b75712 100644
--- a/src/csv.cc
+++ b/src/csv.cc
@@ -166,7 +166,7 @@ xact_t * csv_reader::read_xact(bool rich_data)
string total;
string field;
- while (instr.good() && ! instr.eof()) {
+ while (instr.good() && ! instr.eof() && n < index.size()) {
field = read_field(instr);
switch (index[n]) {
@@ -175,7 +175,8 @@ xact_t * csv_reader::read_xact(bool rich_data)
break;
case FIELD_DATE_AUX:
- xact->_date_aux = parse_date(field);
+ if (! field.empty())
+ xact->_date_aux = parse_date(field);
break;
case FIELD_CODE:
@@ -224,7 +225,8 @@ xact_t * csv_reader::read_xact(bool rich_data)
break;
case FIELD_NOTE:
- xact->note = field;
+ if (! field.empty())
+ xact->note = field;
break;
case FIELD_UNKNOWN:
diff --git a/src/error.cc b/src/error.cc
index 58339db7..8aa1d3d6 100644
--- a/src/error.cc
+++ b/src/error.cc
@@ -84,7 +84,7 @@ string source_context(const path& file,
const string& prefix)
{
const std::streamoff len = end_pos - pos;
- if (! len || file == path("/dev/stdin"))
+ if (! len || file.empty())
return _("<no source context>");
assert(len > 0);
diff --git a/src/filters.cc b/src/filters.cc
index 5e2bf983..7570809a 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -983,7 +983,8 @@ void interval_posts::flush()
sort_posts_by_date());
// Determine the beginning interval by using the earliest post
- if (! interval.find_period(all_posts.front()->date()))
+ if (all_posts.front() &&
+ ! interval.find_period(all_posts.front()->date()))
throw_(std::logic_error, _("Failed to find period for interval report"));
// Walk the interval forward reporting all posts within each one
diff --git a/src/global.cc b/src/global.cc
index 3e83ba04..5fc10f02 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -107,32 +107,53 @@ global_scope_t::~global_scope_t()
#endif
}
+void global_scope_t::parse_init(path init_file)
+{
+ TRACE_START(init, 1, "Read initialization file");
+
+ parse_context_stack_t parsing_context;
+ parsing_context.push(init_file);
+ parsing_context.get_current().journal = session().journal.get();
+ parsing_context.get_current().scope = &report();
+
+ if (session().journal->read(parsing_context) > 0 ||
+ session().journal->auto_xacts.size() > 0 ||
+ session().journal->period_xacts.size() > 0) {
+ throw_(parse_error, _f("Transactions found in initialization file '%1%'")
+ % init_file);
+ }
+
+ TRACE_FINISH(init, 1);
+}
+
void global_scope_t::read_init()
{
+ // if specified on the command line init_file_ is filled in
+ // global_scope_t::handle_debug_options. If it was specified on the command line
+ // fail is the file doesn't exist. If no init file was specified
+ // on the command-line then try the default values, but don't fail if there
+ // isn't one.
+ path init_file;
if (HANDLED(init_file_)) {
- path init_file(HANDLER(init_file_).str());
+ init_file=HANDLER(init_file_).str();
if (exists(init_file)) {
- TRACE_START(init, 1, "Read initialization file");
-
- parse_context_stack_t parsing_context;
- parsing_context.push(init_file);
- parsing_context.get_current().journal = session().journal.get();
- parsing_context.get_current().scope = &report();
-
- if (session().journal->read(parsing_context) > 0 ||
- session().journal->auto_xacts.size() > 0 ||
- session().journal->period_xacts.size() > 0) {
- throw_(parse_error, _f("Transactions found in initialization file '%1%'")
- % init_file);
- }
-
- TRACE_FINISH(init, 1);
+ parse_init(init_file);
} else {
throw_(parse_error, _f("Could not find specified init file %1%") % init_file);
}
+ } else {
+ if (const char * home_var = std::getenv("HOME")){
+ init_file = (path(home_var) / ".ledgerrc");
+ } else {
+ init_file = ("./.ledgerrc");
+ }
+ }
+ if(exists(init_file)){
+ parse_init(init_file);
}
}
+
char * global_scope_t::prompt_string()
{
static char prompt[32];
@@ -477,8 +498,8 @@ void handle_debug_options(int argc, char * argv[])
#endif
}
else if (i + 1 < argc && std::strcmp(argv[i], "--init-file") == 0) {
- _init_file = argv[i + 1];
- i++;
+ _init_file = argv[i + 1];
+ i++;
}
else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
#if DEBUG_ON
diff --git a/src/global.h b/src/global.h
index d37043fc..11459529 100644
--- a/src/global.h
+++ b/src/global.h
@@ -67,6 +67,7 @@ public:
return _("global scope");
}
+ void parse_init(path init_file);
void read_init();
void read_environment_settings(char * envp[]);
strings_list read_command_arguments(scope_t& scope, strings_list args);
@@ -153,14 +154,9 @@ See LICENSE file included with the distribution for details and disclaimer.");
OPTION__
(global_scope_t, init_file_, // -i
CTOR(global_scope_t, init_file_) {
- if(!_init_file.empty())
+ if (!_init_file.empty())
// _init_file is filled during handle_debug_options
on(none, _init_file);
- else
- if (const char * home_var = std::getenv("HOME"))
- on(none, (path(home_var) / ".ledgerrc").string());
- else
- on(none, path("./.ledgerrc").string());
});
OPTION(global_scope_t, options);
diff --git a/src/item.cc b/src/item.cc
index 24d03ba1..4e2a487c 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -476,7 +476,6 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind,
else if (name == "filepath")
return WRAP_FUNCTOR(get_wrapper<&get_filepath>);
break;
- break;
case 'h':
if (name == "has_tag")
@@ -583,8 +582,8 @@ string item_context(const item_t& item, const string& desc)
std::ostringstream out;
- if (item.pos->pathname == path("/dev/stdin")) {
- out << desc << _(" from standard input:");
+ if (item.pos->pathname.empty()) {
+ out << desc << _(" from streamed input:");
return out.str();
}
diff --git a/src/journal.cc b/src/journal.cc
index e6c09125..68939be6 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -127,8 +127,19 @@ account_t * journal_t::register_account(const string& name, post_t * post,
// object.
if (account_aliases.size() > 0) {
accounts_map::const_iterator i = account_aliases.find(name);
- if (i != account_aliases.end())
+ if (i != account_aliases.end()) {
result = (*i).second;
+ } else {
+ // only check the very first account for alias expansion, in case
+ // that can be expanded successfully
+ size_t colon = name.find(':');
+ if(colon != string::npos) {
+ accounts_map::const_iterator i = account_aliases.find(name.substr(0, colon));
+ if (i != account_aliases.end()) {
+ result = find_account((*i).second->fullname() + name.substr(colon));
+ }
+ }
+ }
}
// Create the account object and associate it with the journal; this
diff --git a/src/post.h b/src/post.h
index a9a44a79..c9aec6b2 100644
--- a/src/post.h
+++ b/src/post.h
@@ -83,7 +83,7 @@ public:
const optional<string>& _note = none)
: item_t(_flags, _note), xact(NULL), account(_account), amount(_amount)
{
- TRACE_CTOR(post_t, "account_t *, const amount_t&, flags_t, const optional<string>&");
+ TRACE_CTOR(post_t, "account_t *, amount_t, flags_t, optional<string>");
}
post_t(const post_t& post)
: item_t(post),
diff --git a/src/py_xact.cc b/src/py_xact.cc
index 3d792c7b..96674207 100644
--- a/src/py_xact.cc
+++ b/src/py_xact.cc
@@ -119,8 +119,8 @@ void export_xact()
.def("__str__", py_xact_to_string)
.add_property("code",
- make_getter(&xact_t::code),
- make_setter(&xact_t::code))
+ make_getter(&xact_t::code, return_value_policy<return_by_value>()),
+ make_setter(&xact_t::code, return_value_policy<return_by_value>()))
.add_property("payee",
make_getter(&xact_t::payee),
make_setter(&xact_t::payee))
@@ -157,6 +157,8 @@ void export_xact()
make_getter(&period_xact_t::period_string),
make_setter(&period_xact_t::period_string))
;
+
+ register_optional_to_python<std::string>();
}
} // namespace ledger
diff --git a/src/report.cc b/src/report.cc
index 08365a6b..d4beaf2a 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -1089,6 +1089,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(anon);
else OPT_ALT(color, ansi);
else OPT(auto_match);
+ else OPT(aux_date);
else OPT(average);
else OPT(account_width_);
else OPT(amount_width_);
@@ -1096,7 +1097,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
case 'b':
OPT(balance_format_);
else OPT(base);
- else OPT_ALT(basis, cost);
+ else OPT(basis);
else OPT_(begin_);
else OPT(bold_if_);
else OPT(budget);
@@ -1105,6 +1106,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
break;
case 'c':
OPT(csv_format_);
+ else OPT_ALT(gain, change);
else OPT(cleared);
else OPT(collapse);
else OPT(collapse_if_zero);
@@ -1122,6 +1124,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(dc);
else OPT(depth_);
else OPT(deviation);
+ else OPT_ALT(rich_data, detail);
else OPT_(display_);
else OPT(display_amount_);
else OPT(display_total_);
@@ -1146,7 +1149,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT_ALT(head_, first_);
break;
case 'g':
- OPT_ALT(gain, change);
+ OPT(gain);
else OPT(group_by_);
else OPT(group_title_format_);
else OPT(generated);
@@ -1173,7 +1176,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT_ALT(tail_, last_);
break;
case 'm':
- OPT_ALT(market, value);
+ OPT(market);
else OPT(monthly);
else OPT(meta_);
else OPT(meta_width_);
@@ -1203,6 +1206,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(price);
else OPT(prices_format_);
else OPT(pricedb_format_);
+ else OPT(primary_date);
else OPT(payee_width_);
else OPT(prepend_format_);
else OPT(prepend_width_);
@@ -1220,7 +1224,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(revalued);
else OPT(revalued_only);
else OPT(revalued_total_);
- else OPT_ALT(rich_data, detail);
+ else OPT(rich_data);
break;
case 's':
OPT(sort_);
@@ -1247,6 +1251,9 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(unrealized_losses_);
else OPT(unround);
break;
+ case 'v':
+ OPT_ALT(market, value);
+ break;
case 'w':
OPT(weekly);
else OPT_(wide);
diff --git a/src/session.cc b/src/session.cc
index 7072fb09..632002d4 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -98,8 +98,12 @@ std::size_t session_t::read_data(const string& master_account)
acct = journal->find_account(master_account);
optional<path> price_db_path;
- if (HANDLED(price_db_))
+ if (HANDLED(price_db_)){
price_db_path = resolve_path(HANDLER(price_db_).str());
+ if (!exists(price_db_path.get())){
+ throw_(parse_error, _f("Could not find specified price file %1%") % price_db_path);
+ }
+ }
if (HANDLED(explicit))
journal->force_checking = true;
@@ -143,7 +147,7 @@ std::size_t session_t::read_data(const string& master_account)
}
foreach (const path& pathname, HANDLER(file_).data_files) {
- if (pathname == "-") {
+ if (pathname == "-" || pathname == "/dev/stdin") {
// To avoid problems with stdin and pipes, etc., we read the entire
// file in beforehand into a memory buffer, and then parcel it out
// from there.
diff --git a/src/textual.cc b/src/textual.cc
index 8a055251..6106914f 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -575,7 +575,7 @@ void instance_t::automated_xact_directive(char * line)
item = ae.get();
// This is a trailing note, and possibly a metadata info tag
- item->append_note(p + 1, *context.scope, true);
+ ae->append_note(p + 1, *context.scope, true);
item->add_flags(ITEM_NOTE_ON_NEXT_LINE);
item->pos->end_pos = context.curr_pos;
item->pos->end_line++;
diff --git a/src/xact.cc b/src/xact.cc
index ec1d372c..7ac7a9e9 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -36,6 +36,7 @@
#include "account.h"
#include "journal.h"
#include "context.h"
+#include "format.h"
#include "pool.h"
namespace ledger {
@@ -644,6 +645,18 @@ namespace {
}
}
+static string apply_format(const string& str, scope_t& scope)
+{
+ if (contains(str, "%(")) {
+ format_t str_format(str);
+ std::ostringstream buf;
+ buf << str_format(scope);
+ return buf.str();
+ } else {
+ return str;
+ }
+}
+
void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context)
{
posts_list initial_posts(xact.posts.begin(), xact.posts.end());
@@ -695,8 +708,9 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context)
if (deferred_notes) {
foreach (deferred_tag_data_t& data, *deferred_notes) {
if (data.apply_to_post == NULL)
- initial_post->parse_tags(data.tag_data.c_str(), bound_scope,
- data.overwrite_existing);
+ initial_post->append_note(
+ apply_format(data.tag_data, bound_scope).c_str(),
+ bound_scope, data.overwrite_existing);
}
}
@@ -775,18 +789,26 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context)
account = account->parent;
account = account->find_account(fullname);
}
+ else if (contains(fullname, "%(")) {
+ format_t account_name(fullname);
+ std::ostringstream buf;
+ buf << account_name(bound_scope);
+ while (account->parent)
+ account = account->parent;
+ account = account->find_account(buf.str());
+ }
// Copy over details so that the resulting post is a mirror of
// the automated xact's one.
post_t * new_post = new post_t(account, amt);
new_post->copy_details(*post);
- // A Cleared transaction implies all of its automatic posting are cleared
+ // A Cleared transaction implies all of its automatic posting are cleared
// CPR 2012/10/23
- if(xact.state() == item_t::CLEARED){
- DEBUG("xact.extend.cleared", "CLEARED");
- new_post->set_state(item_t::CLEARED);
- }
+ if (xact.state() == item_t::CLEARED) {
+ DEBUG("xact.extend.cleared", "CLEARED");
+ new_post->set_state(item_t::CLEARED);
+ }
new_post->add_flags(ITEM_GENERATED);
new_post->account =
@@ -795,9 +817,11 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context)
if (deferred_notes) {
foreach (deferred_tag_data_t& data, *deferred_notes) {
- if (! data.apply_to_post || data.apply_to_post == post)
- new_post->parse_tags(data.tag_data.c_str(), bound_scope,
- data.overwrite_existing);
+ if (! data.apply_to_post || data.apply_to_post == post) {
+ new_post->append_note(
+ apply_format(data.tag_data, bound_scope).c_str(),
+ bound_scope, data.overwrite_existing);
+ }
}
}