diff options
Diffstat (limited to 'src/traversal/transform.cc')
-rw-r--r-- | src/traversal/transform.cc | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/src/traversal/transform.cc b/src/traversal/transform.cc new file mode 100644 index 00000000..3331c2f3 --- /dev/null +++ b/src/traversal/transform.cc @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2003-2007, 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 "transform.h" + +namespace ledger { + +#if 0 +void populate_account(account_t& acct, xml::document_t& document) +{ + if (! acct.parent) + return; + + account_repitem_t * acct_item; + if (acct.data == NULL) { + acct.data = acct_item = + static_cast<account_repitem_t *>(repitem_t::wrap(&acct)); + if (acct.parent) { + if (acct.parent->data == NULL) + populate_account(*acct.parent, acct_item); + else + static_cast<account_repitem_t *>(acct.parent->data)-> + add_child(acct_item); + } + } else { + acct_item = static_cast<account_repitem_t *>(acct.data); + } + + if (item->kind == repitem_t::ACCOUNT) + acct_item->add_child(item); + else + acct_item->add_content(item); +} + +class populate_accounts : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + if (item->kind == repitem_t::TRANSACTION) { + item->extract(); + populate_account(*static_cast<xact_repitem_t *>(item)->account(), item); + } + } +}; + +class clear_account_data : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + if (item->kind == repitem_t::ACCOUNT) + static_cast<account_repitem_t *>(item)->account->data = NULL; + } +}; + +void accounts_transform::execute(xml::document_t& document) +{ + populate_accounts cb1; + items->select_all(cb1); + + for (repitem_t * j = items->children; j; j = j->next) { + assert(j->kind == repitem_t::JOURNAL); + + j->clear(); + + for (accounts_map::iterator i = j->journal->master->accounts.begin(); + i != j->journal->master->accounts.end(); + i++) { + assert((*i).second->data); + j->add_child(static_cast<account_repitem_t *>((*i).second->data)); + (*i).second->data = NULL; + } + } + + clear_account_data cb2; + items->select_all(cb2); +} + +void compact_transform::execute(xml::document_t& document) +{ + for (repitem_t * i = items; i; i = i->next) { + if (i->kind == repitem_t::ACCOUNT) { + while (! i->contents && + i->children && ! i->children->next) { + account_repitem_t * p = static_cast<account_repitem_t *>(i); + i = p->children; + p->children = NULL; + p->last_child = NULL; + + i->set_parent(p->parent); + p->set_parent(NULL); + i->prev = p->prev; + if (p->prev) + p->prev->next = i; + p->prev = NULL; + i->next = p->next; + if (p->next) + p->next->prev = i; + p->next = NULL; + + if (i->parent->children == p) + i->parent->children = i; + if (i->parent->last_child == p) + i->parent->last_child = i; + + account_repitem_t * acct = static_cast<account_repitem_t *>(i); + acct->parents_elided = p->parents_elided + 1; + + checked_delete(p); + } + } + + if (i->children) + execute(i->children); + } +} + +void clean_transform::execute(xml::document_t& document) +{ + repitem_t * i = items; + while (i) { + if (i->kind == repitem_t::ACCOUNT) { + value_t temp; + i->add_total(temp); + if (! temp) { + repitem_t * next = i->next; + checked_delete(i); + i = next; + continue; + } + } +#if 0 + else if (i->kind == repitem_t::ENTRY && ! i->contents) { + assert(! i->children); + repitem_t * next = i->next; + checked_delete(i); + i = next; + continue; + } +#endif + + if (i->children) + execute(i->children); + + i = i->next; + } +} + +void entries_transform::execute(xml::document_t& document) +{ +} + +void optimize_transform::execute(xml::document_t& document) +{ + for (repitem_t * i = items; i; i = i->next) { + if (i->kind == repitem_t::ENTRY) { + if (i->contents && + i->contents->next && + ! i->contents->next->next) { // exactly two transactions + xact_repitem_t * first = + static_cast<xact_repitem_t *>(i->contents); + xact_repitem_t * second = + static_cast<xact_repitem_t *>(i->contents->next); + if (first->xact->amount == - second->xact->amount) + ; + } + } + + if (i->children) + execute(i->children); + } +} + +void split_transform::execute(xml::document_t& document) +{ + for (repitem_t * i = items; i; i = i->next) { + if (i->contents && i->contents->next) { + repitem_t * j; + + switch (i->kind) { + case repitem_t::TRANSACTION: + assert(false); + j = new xact_repitem_t(static_cast<xact_repitem_t *>(i)->xact); + break; + case repitem_t::ENTRY: + j = new entry_repitem_t(static_cast<entry_repitem_t *>(i)->entry); + break; + case repitem_t::ACCOUNT: + j = new account_repitem_t(static_cast<account_repitem_t *>(i)->account); + break; + default: + j = new repitem_t(i->kind); + break; + } + + j->set_parent(i->parent); + j->prev = i; + j->next = i->next; + i->next = j; + + j->contents = i->contents->next; + j->contents->prev = NULL; + j->contents->set_parent(j); + i->contents->next = NULL; + + j->last_content = i->last_content; + if (j->contents == i->last_content) + i->last_content = i->contents; + } + + if (i->children) + execute(i->children); + } +} + +void merge_transform::execute(xml::document_t& document) +{ + for (repitem_t * i = items; i; i = i->next) { + if (i->next) { + assert(i->kind == i->next->kind); + bool merge = false; + switch (i->kind) { + case repitem_t::TRANSACTION: + assert(false); + break; + case repitem_t::ENTRY: + if (static_cast<entry_repitem_t *>(i)->entry == + static_cast<entry_repitem_t *>(i->next)->entry) + merge = true; + break; + case repitem_t::ACCOUNT: +#if 0 + if (static_cast<account_repitem_t *>(i)->account == + static_cast<account_repitem_t *>(i->next)->account) + merge = true; +#endif + break; + default: + break; + } + + if (merge) { + repitem_t * j = i->next; + + i->next = i->next->next; + if (i->next) + i->next->prev = i; + + for (repitem_t * k = j->contents; k; k = k->next) + k->set_parent(i); + + i->last_content->next = j->contents; + i->last_content = j->last_content; + + j->contents = NULL; + assert(! j->children); + checked_delete(j); + } + } + + if (i->children) + execute(i->children); + } +} + +namespace { +#define REPITEM_FLAGGED 0x1 + + class mark_selected : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + item->flags |= REPITEM_FLAGGED; + } + }; + + class mark_selected_and_ancestors : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + while (item->parent) { + item->flags |= REPITEM_FLAGGED; + item = item->parent; + } + } + }; + + class delete_unmarked : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + if (item->parent && ! (item->flags & REPITEM_FLAGGED)) + checked_delete(item); + } + }; + + class delete_marked : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + if (item->flags & REPITEM_FLAGGED) + checked_delete(item); + } + }; + + class clear_flags : public repitem_t::select_callback_t { + virtual void operator()(xml::document_t& document) { + item->flags = 0; + } + }; +} + +void select_transform::execute(xml::document_t& document) +{ + if (! path) { + items->clear(); + return; + } + mark_selected_and_ancestors cb1; + items->select(path, cb1); + + delete_unmarked cb2; + items->select_all(cb2); + clear_flags cb3; + items->select_all(cb3); +} + +void remove_transform::execute(xml::document_t& document) +{ + if (! path) + return; + mark_selected cb1; + items->select(path, cb1); + + delete_marked cb2; + items->select_all(cb2); + clear_flags cb3; + items->select_all(cb3); +} +#endif + +} // namespace ledger |