summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ledger.13
-rw-r--r--src/chain.cc4
-rw-r--r--src/filters.cc60
-rw-r--r--src/filters.h20
-rw-r--r--src/report.cc1
-rw-r--r--src/report.h2
-rw-r--r--test/baseline/opt-inject.test0
7 files changed, 89 insertions, 1 deletions
diff --git a/doc/ledger.1 b/doc/ledger.1
index 4e72c792..ba4317f9 100644
--- a/doc/ledger.1
+++ b/doc/ledger.1
@@ -1,4 +1,4 @@
-.Dd June 15, 2010
+.Dd June 18, 2010
.Dt ledger 1
.Sh NAME
.Nm ledger
@@ -336,6 +336,7 @@ See
.It Fl \-help-disp
.It Fl \-import Ar STR
.It Fl \-init-file Ar FILE
+.It Fl \-inject Ar STR
.It Fl \-input-date-format Ar DATEFMT
.It Fl \-invert
.It Fl \-last Ar INT
diff --git a/src/chain.cc b/src/chain.cc
index 64550663..8010ba74 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -258,6 +258,10 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
if (report.HANDLED(related))
handler.reset(new related_posts(handler, report.HANDLED(related_all)));
+ if (report.HANDLED(inject_))
+ handler.reset(new inject_posts(handler, report.HANDLED(inject_).str(),
+ report.session.journal->master));
+
return handler;
}
diff --git a/src/filters.cc b/src/filters.cc
index 6e832149..33905856 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -1338,6 +1338,66 @@ void forecast_posts::flush()
item_handler<post_t>::flush();
}
+inject_posts::inject_posts(post_handler_ptr handler,
+ const string& tag_list,
+ account_t * master)
+ : item_handler<post_t>(handler)
+{
+ TRACE_CTOR(inject_posts, "post_handler_ptr, string");
+
+ scoped_array<char> buf(new char[tag_list.length() + 1]);
+ std::strcpy(buf.get(), tag_list.c_str());
+
+ for (char * q = std::strtok(buf.get(), ",");
+ q;
+ q = std::strtok(NULL, ",")) {
+
+ std::list<string> account_names;
+ split_string(q, ':', account_names);
+ account_t * account =
+ create_temp_account_from_path(account_names, temps, master);
+ account->add_flags(ACCOUNT_GENERATED);
+
+ tags_list.push_back
+ (tags_list_pair(q, tag_mapping_pair(account, tag_injected_set())));
+ }
+}
+
+void inject_posts::operator()(post_t& post)
+{
+ foreach (tags_list_pair& pair, tags_list) {
+ optional<value_t> tag_value = post.get_tag(pair.first, false);
+ if (! tag_value &&
+ pair.second.second.find(post.xact) == pair.second.second.end()) {
+ // When checking if the transaction has the tag, only inject once
+ // per transaction.
+ pair.second.second.insert(post.xact);
+ tag_value = post.xact->get_tag(pair.first);
+ }
+
+ if (tag_value) {
+ if (tag_value->is_amount()) {
+ xact_t& xact = temps.copy_xact(*post.xact);
+ xact._date = post.date();
+ xact.add_flags(ITEM_GENERATED);
+ post_t& temp = temps.copy_post(post, xact);
+
+ temp.account = pair.second.first;
+ temp.amount = tag_value->as_amount();
+ temp.add_flags(ITEM_GENERATED);
+
+ item_handler<post_t>::operator()(temp);
+ } else {
+ throw_(std::logic_error,
+ _("Attempt to inject a posting with non-amount %1 for tag %2")
+ << *tag_value << pair.first);
+ }
+ }
+ }
+
+ item_handler<post_t>::operator()(post);
+}
+
pass_down_accounts::pass_down_accounts(acct_handler_ptr handler,
accounts_iterator& iter,
const optional<predicate_t>& _pred,
diff --git a/src/filters.h b/src/filters.h
index 9102d4f1..180253d2 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -929,6 +929,26 @@ class forecast_posts : public generate_posts
}
};
+class inject_posts : public item_handler<post_t>
+{
+ typedef std::set<xact_t *> tag_injected_set;
+ typedef std::pair<account_t *, tag_injected_set> tag_mapping_pair;
+ typedef std::pair<string, tag_mapping_pair> tags_list_pair;
+
+ std::list<tags_list_pair> tags_list;
+ temporaries_t temps;
+
+ public:
+ inject_posts(post_handler_ptr handler, const string& tag_list,
+ account_t * master);
+
+ virtual ~inject_posts() throw() {
+ TRACE_DTOR(inject_posts);
+ }
+
+ virtual void operator()(post_t& post);
+};
+
//////////////////////////////////////////////////////////////////////
//
// Account filters
diff --git a/src/report.cc b/src/report.cc
index 9626283a..da7c11f5 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -955,6 +955,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
break;
case 'i':
OPT(invert);
+ else OPT(inject_);
break;
case 'j':
OPT_CH(amount_data);
diff --git a/src/report.h b/src/report.h
index a453d351..7d725b8c 100644
--- a/src/report.h
+++ b/src/report.h
@@ -260,6 +260,7 @@ public:
HANDLER(group_by_).report(out);
HANDLER(group_title_format_).report(out);
HANDLER(head_).report(out);
+ HANDLER(inject_).report(out);
HANDLER(invert).report(out);
HANDLER(limit_).report(out);
HANDLER(lot_dates).report(out);
@@ -616,6 +617,7 @@ public:
});
OPTION(report_t, head_);
+ OPTION(report_t, inject_);
OPTION_(report_t, invert, DO() {
parent->HANDLER(amount_).set_expr(string("--invert"), "-amount");
diff --git a/test/baseline/opt-inject.test b/test/baseline/opt-inject.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-inject.test