summaryrefslogtreecommitdiff
path: root/filters.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2008-08-05 13:17:04 -0400
committerJohn Wiegley <johnw@newartisans.com>2008-08-05 18:05:49 -0400
commitf6f4a46cf5b14f9a2170cd6475958efbf320caec (patch)
tree05bc1defcdebc201de3dd10477483d906a842821 /filters.cc
parentb7970b29855563e4c67f85af8b31233eda80c22a (diff)
downloadfork-ledger-f6f4a46cf5b14f9a2170cd6475958efbf320caec.tar.gz
fork-ledger-f6f4a46cf5b14f9a2170cd6475958efbf320caec.tar.bz2
fork-ledger-f6f4a46cf5b14f9a2170cd6475958efbf320caec.zip
Moved around most of the files so that source code is in src/, documentation
is in doc/, etc.
Diffstat (limited to 'filters.cc')
-rw-r--r--filters.cc755
1 files changed, 0 insertions, 755 deletions
diff --git a/filters.cc b/filters.cc
deleted file mode 100644
index e5455423..00000000
--- a/filters.cc
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * Copyright (c) 2003-2008, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "filters.h"
-#include "iterators.h"
-#include "compare.h"
-#include "session.h"
-#include "format.h"
-#include "textual.h"
-
-namespace ledger {
-
-pass_down_xacts::pass_down_xacts(xact_handler_ptr handler,
- xacts_iterator& iter)
- : item_handler<xact_t>(handler)
-{
- TRACE_CTOR(pass_down_xacts, "xact_handler_ptr, xacts_iterator");
-
- for (xact_t * xact = iter(); xact; xact = iter())
- item_handler<xact_t>::operator()(*xact);
-}
-
-void truncate_entries::flush()
-{
- if (! xacts.size())
- return;
-
- entry_t * last_entry = (*xacts.begin())->entry;
-
- int l = 0;
- foreach (xact_t * xact, xacts)
- if (last_entry != xact->entry) {
- l++;
- last_entry = xact->entry;
- }
- l++;
-
- last_entry = (*xacts.begin())->entry;
-
- int i = 0;
- foreach (xact_t * xact, xacts) {
- if (last_entry != xact->entry) {
- last_entry = xact->entry;
- i++;
- }
-
- bool print = false;
- if (head_count) {
- if (head_count > 0 && i < head_count)
- print = true;
- else if (head_count < 0 && i >= - head_count)
- print = true;
- }
-
- if (! print && tail_count) {
- if (tail_count > 0 && l - i <= tail_count)
- print = true;
- else if (tail_count < 0 && l - i > - tail_count)
- print = true;
- }
-
- if (print)
- item_handler<xact_t>::operator()(*xact);
- }
- xacts.clear();
-
- item_handler<xact_t>::flush();
-}
-
-void set_account_value::operator()(xact_t& xact)
-{
- account_t * acct = xact.reported_account();
-
- account_t::xdata_t& xdata(acct->xdata());
- xact.add_to_value(xdata.value);
-
- xdata.count++;
- if (xact.has_flags(XACT_VIRTUAL))
- xdata.virtuals++;
-
- item_handler<xact_t>::operator()(xact);
-}
-
-void sort_xacts::post_accumulated_xacts()
-{
- std::stable_sort(xacts.begin(), xacts.end(),
- compare_items<xact_t>(sort_order));
-
- foreach (xact_t * xact, xacts) {
- xact->xdata().drop_flags(XACT_EXT_SORT_CALC);
- item_handler<xact_t>::operator()(*xact);
- }
-
- xacts.clear();
-}
-
-void calc_xacts::operator()(xact_t& xact)
-{
- try {
- xact_t::xdata_t& xdata(xact.xdata());
-
- if (last_xact && last_xact->has_xdata()) {
- if (xdata.total.is_null())
- xdata.total = last_xact->xdata().total;
- else
- xdata.total += last_xact->xdata().total;
- xdata.index = last_xact->xdata().index + 1;
- } else {
- xdata.index = 0;
- }
-
- if (! xdata.has_flags(XACT_EXT_NO_TOTAL))
- xact.add_to_value(xdata.total);
-
- item_handler<xact_t>::operator()(xact);
-
- last_xact = &xact;
- }
- catch (const std::exception& err) {
- add_error_context("Calculating transaction at");
-#if 0
- add_error_context(xact_context(xact));
-#endif
- throw err;
- }
-}
-
-void invert_xacts::operator()(xact_t& xact)
-{
- if (xact.has_xdata() &&
- xact.xdata().has_flags(XACT_EXT_COMPOUND)) {
- xact.xdata().value.negate();
- } else {
- xact.amount.negate();
- if (xact.cost)
- xact.cost->negate();
- }
-
- item_handler<xact_t>::operator()(xact);
-}
-
-
-static inline
-void handle_value(const value_t& value,
- account_t * account,
- entry_t * entry,
- unsigned int flags,
- std::list<xact_t>& temps,
- item_handler<xact_t>& handler,
- const date_t& date = date_t(),
- xacts_list * component_xacts = NULL)
-{
- temps.push_back(xact_t(account));
- xact_t& xact(temps.back());
- xact.entry = entry;
- xact.add_flags(XACT_TEMP);
- entry->add_xact(&xact);
-
- // If there are component xacts to associate with this
- // temporary, do so now.
-
- if (component_xacts)
- xact.xdata().copy_component_xacts(*component_xacts);
-
- // If the account for this xact is all virtual, then report
- // the xact as such. This allows subtotal reports to show
- // "(Account)" for accounts that contain only virtual xacts.
-
- if (account && account->has_xdata())
- if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS)) {
- xact.add_flags(XACT_VIRTUAL);
- if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS))
- xact.add_flags(XACT_BALANCE);
- }
-
- xact_t::xdata_t& xdata(xact.xdata());
-
- if (is_valid(date))
- xdata.date = date;
-
- value_t temp(value);
-
- switch (value.type()) {
- case value_t::BOOLEAN:
- case value_t::DATETIME:
- case value_t::DATE:
- case value_t::INTEGER:
- temp.cast(value_t::AMOUNT);
- // fall through...
-
- case value_t::AMOUNT:
- xact.amount = temp.as_amount();
- break;
-
- case value_t::BALANCE:
- case value_t::BALANCE_PAIR:
- xdata.value = temp;
- flags |= XACT_EXT_COMPOUND;
- break;
-
- default:
- assert(false); // jww (2008-04-24): What to do here?
- break;
- }
-
- if (flags)
- xdata.add_flags(flags);
-
- handler(xact);
-}
-
-void collapse_xacts::report_subtotal()
-{
- assert(count >= 1);
-
- if (count == 1) {
- item_handler<xact_t>::operator()(*last_xact);
- } else {
- entry_temps.push_back(entry_t());
- entry_t& entry = entry_temps.back();
- entry.payee = last_entry->payee;
- entry._date = last_entry->_date;
-
- handle_value(subtotal, &totals_account, last_entry, 0, xact_temps,
- *handler);
- }
-
- last_entry = NULL;
- last_xact = NULL;
- subtotal = 0L;
- count = 0;
-}
-
-void collapse_xacts::operator()(xact_t& xact)
-{
- // If we've reached a new entry, report on the subtotal
- // accumulated thus far.
-
- if (last_entry && last_entry != xact.entry && count > 0)
- report_subtotal();
-
- xact.add_to_value(subtotal);
- count++;
-
- last_entry = xact.entry;
- last_xact = &xact;
-}
-
-void related_xacts::flush()
-{
- if (xacts.size() > 0) {
- foreach (xact_t * xact, xacts) {
- if (xact->entry) {
- foreach (xact_t * r_xact, xact->entry->xacts) {
- xact_t::xdata_t& xdata(r_xact->xdata());
- if (! xdata.has_flags(XACT_EXT_HANDLED) &&
- (! xdata.has_flags(XACT_EXT_RECEIVED) ?
- ! r_xact->has_flags(XACT_AUTO | XACT_VIRTUAL) :
- also_matching)) {
- xdata.add_flags(XACT_EXT_HANDLED);
- item_handler<xact_t>::operator()(*r_xact);
- }
- }
- } else {
- // This code should only be reachable from the "output"
- // command, since that is the only command which attempts to
- // output auto or period entries.
- xact_t::xdata_t& xdata(xact->xdata());
- if (! xdata.has_flags(XACT_EXT_HANDLED) &&
- ! xact->has_flags(XACT_AUTO)) {
- xdata.add_flags(XACT_EXT_HANDLED);
- item_handler<xact_t>::operator()(*xact);
- }
- }
- }
- }
-
- item_handler<xact_t>::flush();
-}
-
-void changed_value_xacts::output_diff(const date_t& date)
-{
- value_t cur_bal;
-
- last_xact->xdata().date = date;
-#if 0
- compute_total(cur_bal, details_t(*last_xact));
-#endif
- cur_bal.round();
-
-#if 0
- // jww (2008-04-24): What does this do?
- last_xact->xdata().date = 0;
-#endif
-
- if (value_t diff = cur_bal - last_balance) {
- entry_temps.push_back(entry_t());
- entry_t& entry = entry_temps.back();
- entry.payee = "Commodities revalued";
- entry._date = date;
-
- handle_value(diff, NULL, &entry, XACT_EXT_NO_TOTAL, xact_temps,
- *handler);
- }
-}
-
-void changed_value_xacts::operator()(xact_t& xact)
-{
- if (last_xact)
- output_diff(last_xact->reported_date());
-
- if (changed_values_only)
- xact.xdata().add_flags(XACT_EXT_DISPLAYED);
-
- item_handler<xact_t>::operator()(xact);
-
-#if 0
- compute_total(last_balance, details_t(xact));
-#endif
- last_balance.round();
-
- last_xact = &xact;
-}
-
-void component_xacts::operator()(xact_t& xact)
-{
- if (handler && pred(xact)) {
- if (xact.has_xdata() &&
- xact.xdata().has_component_xacts())
-#if 0
- xact.xdata().walk_component_xacts(*handler);
-#else
- ;
-#endif
- else
- (*handler)(xact);
- }
-}
-
-void subtotal_xacts::report_subtotal(const char * spec_fmt)
-{
- std::ostringstream out_date;
- if (! spec_fmt) {
- string fmt = "- ";
- fmt += output_date_format;
- out_date << format_date(finish, string(fmt));
- } else {
- out_date << format_date(finish, string(spec_fmt));
- }
-
- entry_temps.push_back(entry_t());
- entry_t& entry = entry_temps.back();
- entry.payee = out_date.str();
- entry._date = start;
-
- foreach (values_map::value_type& pair, values)
- handle_value(pair.second.value, pair.second.account, &entry, 0,
- xact_temps, *handler, finish, &pair.second.components);
-
- values.clear();
-}
-
-void subtotal_xacts::operator()(xact_t& xact)
-{
- if (! is_valid(start) || xact.date() < start)
- start = xact.date();
- if (! is_valid(finish) || xact.date() > finish)
- finish = xact.date();
-
- account_t * acct = xact.reported_account();
- assert(acct);
-
- values_map::iterator i = values.find(acct->fullname());
- if (i == values.end()) {
- value_t temp;
- xact.add_to_value(temp);
- std::pair<values_map::iterator, bool> result
- = values.insert(values_pair(acct->fullname(), acct_value_t(acct, temp)));
- assert(result.second);
-
- if (remember_components)
- (*result.first).second.components.push_back(&xact);
- } else {
- xact.add_to_value((*i).second.value);
-
- if (remember_components)
- (*i).second.components.push_back(&xact);
- }
-
- // If the account for this xact is all virtual, mark it as
- // such, so that `handle_value' can show "(Account)" for accounts
- // that contain only virtual xacts.
-
- if (! xact.has_flags(XACT_VIRTUAL))
- xact.reported_account()->xdata().add_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS);
- else if (! xact.has_flags(XACT_BALANCE))
- xact.reported_account()->xdata().add_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS);
-}
-
-void interval_xacts::report_subtotal(const date_t& date)
-{
- assert(last_xact);
-
- start = interval.begin;
- if (is_valid(date))
- finish = date - gregorian::days(1);
- else
- finish = last_xact->date();
-
- subtotal_xacts::report_subtotal();
-
- last_xact = NULL;
-}
-
-void interval_xacts::operator()(xact_t& xact)
-{
- const date_t& date(xact.date());
-
- if ((is_valid(interval.begin) && date < interval.begin) ||
- (is_valid(interval.end) && date >= interval.end))
- return;
-
- if (interval) {
- if (! started) {
- if (! is_valid(interval.begin))
- interval.start(date);
- start = interval.begin;
- started = true;
- }
-
- date_t quant = interval.increment(interval.begin);
- if (date >= quant) {
- if (last_xact)
- report_subtotal(quant);
-
- date_t temp;
- while (date >= (temp = interval.increment(quant))) {
- if (quant == temp)
- break;
- quant = temp;
- }
- start = interval.begin = quant;
- }
-
- subtotal_xacts::operator()(xact);
- } else {
- item_handler<xact_t>::operator()(xact);
- }
-
- last_xact = &xact;
-}
-
-by_payee_xacts::~by_payee_xacts()
-{
- TRACE_DTOR(by_payee_xacts);
-
- foreach (payee_subtotals_map::value_type& pair, payee_subtotals)
- checked_delete(pair.second);
-}
-
-void by_payee_xacts::flush()
-{
- foreach (payee_subtotals_map::value_type& pair, payee_subtotals)
- pair.second->report_subtotal(pair.first.c_str());
-
- item_handler<xact_t>::flush();
-
- payee_subtotals.clear();
-}
-
-void by_payee_xacts::operator()(xact_t& xact)
-{
- payee_subtotals_map::iterator i = payee_subtotals.find(xact.entry->payee);
- if (i == payee_subtotals.end()) {
- payee_subtotals_pair
- temp(xact.entry->payee,
- new subtotal_xacts(handler, remember_components));
- std::pair<payee_subtotals_map::iterator, bool> result
- = payee_subtotals.insert(temp);
-
- assert(result.second);
- if (! result.second)
- return;
- i = result.first;
- }
-
- if (xact.date() > (*i).second->start)
- (*i).second->start = xact.date();
-
- (*(*i).second)(xact);
-}
-
-void set_comm_as_payee::operator()(xact_t& xact)
-{
- entry_temps.push_back(*xact.entry);
- entry_t& entry = entry_temps.back();
- entry._date = xact.date();
- entry.code = xact.entry->code;
-
- if (xact.amount.commodity())
- entry.payee = xact.amount.commodity().symbol();
- else
- entry.payee = "<none>";
-
- xact_temps.push_back(xact);
- xact_t& temp = xact_temps.back();
- temp.entry = &entry;
- temp.state = xact.state;
- temp.add_flags(XACT_TEMP);
-
- entry.add_xact(&temp);
-
- item_handler<xact_t>::operator()(temp);
-}
-
-void set_code_as_payee::operator()(xact_t& xact)
-{
- entry_temps.push_back(*xact.entry);
- entry_t& entry = entry_temps.back();
- entry._date = xact.date();
-
- if (xact.entry->code)
- entry.payee = *xact.entry->code;
- else
- entry.payee = "<none>";
-
- xact_temps.push_back(xact);
- xact_t& temp = xact_temps.back();
- temp.entry = &entry;
- temp.state = xact.state;
- temp.add_flags(XACT_TEMP);
-
- entry.add_xact(&temp);
-
- item_handler<xact_t>::operator()(temp);
-}
-
-void dow_xacts::flush()
-{
- for (int i = 0; i < 7; i++) {
- start = finish = date_t();
- foreach (xact_t * xact, days_of_the_week[i])
- subtotal_xacts::operator()(*xact);
- subtotal_xacts::report_subtotal("%As");
- days_of_the_week[i].clear();
- }
-
- subtotal_xacts::flush();
-}
-
-void generate_xacts::add_period_entries
- (period_entries_list& period_entries)
-{
- foreach (period_entry_t * entry, period_entries)
- foreach (xact_t * xact, entry->xacts)
- add_xact(entry->period, *xact);
-}
-
-void generate_xacts::add_xact(const interval_t& period,
- xact_t& xact)
-{
- pending_xacts.push_back(pending_xacts_pair(period, &xact));
-}
-
-void budget_xacts::report_budget_items(const date_t& date)
-{
- if (pending_xacts.size() == 0)
- return;
-
- bool reported;
- do {
- reported = false;
- foreach (pending_xacts_list::value_type& pair, pending_xacts) {
- date_t& begin = pair.first.begin;
- if (! is_valid(begin)) {
- pair.first.start(date);
- begin = pair.first.begin;
- }
-
- if (begin < date &&
- (! is_valid(pair.first.end) || begin < pair.first.end)) {
- xact_t& xact = *pair.second;
-
- DEBUG("ledger.walk.budget", "Reporting budget for "
- << xact.reported_account()->fullname());
-
- entry_temps.push_back(entry_t());
- entry_t& entry = entry_temps.back();
- entry.payee = "Budget entry";
- entry._date = begin;
-
- xact_temps.push_back(xact);
- xact_t& temp = xact_temps.back();
- temp.entry = &entry;
- temp.add_flags(XACT_AUTO | XACT_TEMP);
- temp.amount.negate();
- entry.add_xact(&temp);
-
- begin = pair.first.increment(begin);
-
- item_handler<xact_t>::operator()(temp);
-
- reported = true;
- }
- }
- } while (reported);
-}
-
-void budget_xacts::operator()(xact_t& xact)
-{
- bool xact_in_budget = false;
-
- foreach (pending_xacts_list::value_type& pair, pending_xacts)
- for (account_t * acct = xact.reported_account();
- acct;
- acct = acct->parent) {
- if (acct == (*pair.second).reported_account()) {
- xact_in_budget = true;
- // Report the xact as if it had occurred in the parent
- // account.
- if (xact.reported_account() != acct)
- xact.xdata().account = acct;
- goto handle;
- }
- }
-
- handle:
- if (xact_in_budget && flags & BUDGET_BUDGETED) {
- report_budget_items(xact.date());
- item_handler<xact_t>::operator()(xact);
- }
- else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
- item_handler<xact_t>::operator()(xact);
- }
-}
-
-void forecast_xacts::add_xact(const interval_t& period, xact_t& xact)
-{
- generate_xacts::add_xact(period, xact);
-
- interval_t& i = pending_xacts.back().first;
- if (! is_valid(i.begin)) {
- i.start(current_date);
- i.begin = i.increment(i.begin);
- } else {
- while (i.begin < current_date)
- i.begin = i.increment(i.begin);
- }
-}
-
-void forecast_xacts::flush()
-{
- xacts_list passed;
- date_t last;
-
- while (pending_xacts.size() > 0) {
- pending_xacts_list::iterator least = pending_xacts.begin();
- for (pending_xacts_list::iterator i = ++pending_xacts.begin();
- i != pending_xacts.end();
- i++)
- if ((*i).first.begin < (*least).first.begin)
- least = i;
-
- date_t& begin = (*least).first.begin;
-
- if (is_valid((*least).first.end) && begin >= (*least).first.end) {
- pending_xacts.erase(least);
- passed.remove((*least).second);
- continue;
- }
-
- xact_t& xact = *(*least).second;
-
- entry_temps.push_back(entry_t());
- entry_t& entry = entry_temps.back();
- entry.payee = "Forecast entry";
- entry._date = begin;
-
- xact_temps.push_back(xact);
- xact_t& temp = xact_temps.back();
- temp.entry = &entry;
- temp.add_flags(XACT_AUTO | XACT_TEMP);
- entry.add_xact(&temp);
-
- date_t next = (*least).first.increment(begin);
- if (next < begin || (is_valid(last) && (next - last).days() > 365 * 5))
- break;
- begin = next;
-
- item_handler<xact_t>::operator()(temp);
-
- if (temp.has_xdata() &&
- temp.xdata().has_flags(XACT_EXT_MATCHES)) {
- if (! pred(temp))
- break;
- last = temp.date();
- passed.clear();
- } else {
- bool found = false;
- foreach (xact_t * x, passed)
- if (x == &xact) {
- found = true;
- break;
- }
-
- if (! found) {
- passed.push_back(&xact);
- if (passed.size() >= pending_xacts.size())
- break;
- }
- }
- }
-
- item_handler<xact_t>::flush();
-}
-
-pass_down_accounts::pass_down_accounts(acct_handler_ptr handler,
- accounts_iterator& iter)
- : item_handler<account_t>(handler)
-{
- TRACE_CTOR(pass_down_accounts,
- "acct_handler_ptr, accounts_iterator");
- for (account_t * account = iter(); account; account = iter())
- item_handler<account_t>::operator()(*account);
-}
-
-} // namespace ledger