summaryrefslogtreecommitdiff
path: root/format.cc
diff options
context:
space:
mode:
Diffstat (limited to 'format.cc')
-rw-r--r--format.cc606
1 files changed, 0 insertions, 606 deletions
diff --git a/format.cc b/format.cc
deleted file mode 100644
index 875b5177..00000000
--- a/format.cc
+++ /dev/null
@@ -1,606 +0,0 @@
-#include "format.h"
-#include "error.h"
-
-namespace ledger {
-
-std::string truncated(const std::string& str, unsigned int width)
-{
- char buf[256];
- std::memset(buf, '\0', 255);
- assert(width < 256);
- std::strncpy(buf, str.c_str(), str.length());
- if (buf[width])
- std::strcpy(&buf[width - 2], "..");
- return buf;
-}
-
-std::string partial_account_name(const account_t& account)
-{
- std::string name;
-
- for (const account_t * acct = &account;
- acct && acct->parent;
- acct = acct->parent) {
- if (account_has_xdata(*acct) &&
- account_xdata(*acct).dflags & ACCOUNT_DISPLAYED)
- break;
-
- if (name.empty())
- name = acct->name;
- else
- name = acct->name + ":" + name;
- }
-
- return name;
-}
-
-std::string format_t::date_format = "%Y/%m/%d";
-value_expr_t * format_t::amount_expr = NULL;
-value_expr_t * format_t::total_expr = NULL;
-
-static struct _init_format {
- ~_init_format();
-} _init_obj;
-
-_init_format::~_init_format()
-{
- if (format_t::amount_expr)
- delete format_t::amount_expr;
- if (format_t::total_expr)
- delete format_t::total_expr;
-}
-
-element_t * format_t::parse_elements(const std::string& fmt)
-{
- std::auto_ptr<element_t> result;
-
- element_t * current = NULL;
-
- char buf[1024];
- char * q = buf;
-
- for (const char * p = fmt.c_str(); *p; p++) {
- if (*p != '%' && *p != '\\') {
- *q++ = *p;
- continue;
- }
-
- if (! result.get()) {
- result.reset(new element_t);
- current = result.get();
- } else {
- current->next = new element_t;
- current = current->next;
- }
-
- if (q != buf) {
- current->type = element_t::STRING;
- current->chars = std::string(buf, q);
- q = buf;
-
- current->next = new element_t;
- current = current->next;
- }
-
- if (*p == '\\') {
- p++;
- current->type = element_t::STRING;
- switch (*p) {
- case 'b': current->chars = "\b"; break;
- case 'f': current->chars = "\f"; break;
- case 'n': current->chars = "\n"; break;
- case 'r': current->chars = "\r"; break;
- case 't': current->chars = "\t"; break;
- case 'v': current->chars = "\v"; break;
- }
- continue;
- }
-
- ++p;
- if (*p == '-') {
- current->align_left = true;
- ++p;
- }
-
- int num = 0;
- while (*p && std::isdigit(*p)) {
- num *= 10;
- num += *p++ - '0';
- }
- current->min_width = num;
-
- if (*p == '.') {
- ++p;
- num = 0;
- while (*p && std::isdigit(*p)) {
- num *= 10;
- num += *p++ - '0';
- }
- current->max_width = num;
- if (current->min_width == 0)
- current->min_width = current->max_width;
- }
-
- switch (*p) {
- case '%':
- current->type = element_t::STRING;
- current->chars = "%";
- break;
-
- case '(': {
- ++p;
- const char * b = p;
- int depth = 1;
- while (*p) {
- if (*p == ')' && --depth == 0)
- break;
- else if (*p == '(')
- ++depth;
- p++;
- }
- if (*p != ')')
- throw format_error("Missing ')'");
-
- current->type = element_t::VALUE_EXPR;
- try {
- current->val_expr = parse_value_expr(std::string(b, p));
- }
- catch (value_expr_error& err) {
- throw value_expr_error(std::string("In format expression '") +
- std::string(b, p) + "': " + err.what());
- }
- break;
- }
-
- case '[': {
- ++p;
- const char * b = p;
- int depth = 1;
- while (*p) {
- if (*p == ']' && --depth == 0)
- break;
- else if (*p == '[')
- ++depth;
- p++;
- }
- if (*p != ']')
- throw format_error("Missing ']'");
-
- current->type = element_t::DATE_STRING;
- current->chars = std::string(b, p);
- break;
- }
-
- case 'D':
- current->type = element_t::DATE_STRING;
- current->chars = format_t::date_format;
- break;
-
- case 'X': current->type = element_t::CLEARED; break;
- case 'C': current->type = element_t::CODE; break;
- case 'P': current->type = element_t::PAYEE; break;
- case 'n': current->type = element_t::ACCOUNT_NAME; break;
- case 'N': current->type = element_t::ACCOUNT_FULLNAME; break;
- case 'o': current->type = element_t::OPT_AMOUNT; break;
- case 't': current->type = element_t::AMOUNT; break;
- case 'T': current->type = element_t::TOTAL; break;
- case '|': current->type = element_t::SPACER; break;
- case '_': current->type = element_t::DEPTH_SPACER; break;
- }
- }
-
- if (q != buf) {
- if (! result.get()) {
- result.reset(new element_t);
- current = result.get();
- } else {
- current->next = new element_t;
- current = current->next;
- }
- current->type = element_t::STRING;
- current->chars = std::string(buf, q);
- }
-
- return result.release();
-}
-
-void format_t::format(std::ostream& out, const details_t& details) const
-{
- for (const element_t * elem = elements; elem; elem = elem->next) {
- if (elem->align_left)
- out << std::left;
- else
- out << std::right;
-
- if (elem->min_width > 0)
- out.width(elem->min_width);
-
- switch (elem->type) {
- case element_t::STRING:
- out << elem->chars;
- break;
-
- case element_t::AMOUNT:
- case element_t::TOTAL:
- case element_t::VALUE_EXPR: {
- value_expr_t * expr = NULL;
- switch (elem->type) {
- case element_t::AMOUNT: expr = amount_expr; break;
- case element_t::TOTAL: expr = total_expr; break;
- case element_t::VALUE_EXPR: expr = elem->val_expr; break;
- default:
- assert(0);
- break;
- }
- if (! expr)
- break;
- value_t value;
- expr->compute(value, details);
- switch (value.type) {
- case value_t::BOOLEAN:
- out << (*((bool *) value.data) ? "1" : "0");
- break;
- case value_t::INTEGER:
- out << *((unsigned int *) value.data);
- break;
- case value_t::AMOUNT:
- out << *((amount_t *) value.data);
- break;
- case value_t::BALANCE:
- ((balance_t *) value.data)->write(out, elem->min_width,
- (elem->max_width > 0 ?
- elem->max_width : elem->min_width));
- break;
- case value_t::BALANCE_PAIR:
- ((balance_pair_t *) value.data)->quantity.write(out, elem->min_width,
- (elem->max_width > 0 ?
- elem->max_width : elem->min_width));
- break;
- default:
- assert(0);
- break;
- }
- break;
- }
-
- case element_t::DATE_STRING:
- if (details.entry && details.entry->date != -1) {
- char buf[256];
- std::strftime(buf, 255, elem->chars.c_str(),
- std::localtime(&details.entry->date));
- out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
- } else {
- out << " ";
- }
- break;
-
- case element_t::CLEARED:
- if (details.entry && details.entry->state == entry_t::CLEARED)
- out << "* ";
- else
- out << "";
- break;
-
- case element_t::CODE: {
- std::string temp;
- if (details.entry && ! details.entry->code.empty()) {
- temp += "(";
- temp += details.entry->code;
- temp += ") ";
- }
- out << temp;
- break;
- }
-
- case element_t::PAYEE:
- if (details.entry)
- out << (elem->max_width == 0 ?
- details.entry->payee : truncated(details.entry->payee,
- elem->max_width));
- break;
-
- case element_t::ACCOUNT_NAME:
- case element_t::ACCOUNT_FULLNAME:
- if (details.account) {
- std::string name = (elem->type == element_t::ACCOUNT_FULLNAME ?
- details.account->fullname() :
- partial_account_name(*details.account));
-
- if (details.xact && details.xact->flags & TRANSACTION_VIRTUAL) {
- if (elem->max_width > 2)
- name = truncated(name, elem->max_width - 2);
-
- if (details.xact->flags & TRANSACTION_BALANCE)
- name = "[" + name + "]";
- else
- name = "(" + name + ")";
- }
- else if (elem->max_width > 0)
- name = truncated(name, elem->max_width);
-
- out << name;
- } else {
- out << " ";
- }
- break;
-
- case element_t::OPT_AMOUNT:
- if (details.xact) {
- std::string disp;
- bool use_disp = false;
-
- if (details.xact->cost) {
- amount_t unit_cost = *details.xact->cost / details.xact->amount;
- std::ostringstream stream;
- stream << details.xact->amount << " @ " << unit_cost;
- disp = stream.str();
- use_disp = true;
- } else {
- unsigned int xacts_count = 0;
- transaction_t * first = NULL;
- transaction_t * last = NULL;
-
- for (transactions_list::const_iterator i
- = details.entry->transactions.begin();
- i != details.entry->transactions.end();
- i++) {
- if (transaction_has_xdata(**i) &&
- transaction_xdata(**i).dflags & TRANSACTION_TO_DISPLAY) {
- xacts_count++;
-
- if (! first)
- first = *i;
- last = *i;
- }
- }
-
- use_disp = (xacts_count == 2 && details.xact == last &&
- first->amount == - last->amount);
- }
-
- if (! use_disp)
- out << details.xact->amount;
- else
- out << disp;
-
- // jww (2004-07-31): this should be handled differently
- if (! details.xact->note.empty())
- out << " ; " << details.xact->note;
- }
- break;
-
- case element_t::SPACER:
- out << " ";
- break;
-
- case element_t::DEPTH_SPACER:
- for (const account_t * acct = details.account;
- acct;
- acct = acct->parent)
- if (account_has_xdata(*acct) &&
- account_xdata(*acct).dflags & ACCOUNT_DISPLAYED) {
- if (elem->min_width > 0 || elem->max_width > 0)
- out.width(elem->min_width > elem->max_width ?
- elem->min_width : elem->max_width);
- out << " ";
- }
- break;
-
- default:
- assert(0);
- break;
- }
- }
-}
-
-format_transactions::format_transactions(std::ostream& _output_stream,
- const std::string& format)
- : output_stream(_output_stream), last_entry(NULL)
-{
- const char * f = format.c_str();
- if (const char * p = std::strstr(f, "%/")) {
- first_line_format.reset(std::string(f, 0, p - f));
- next_lines_format.reset(std::string(p + 2));
- } else {
- first_line_format.reset(format);
- next_lines_format.reset(format);
- }
-}
-
-void format_transactions::operator()(transaction_t& xact)
-{
- if (! transaction_has_xdata(xact) ||
- ! (transaction_xdata(xact).dflags & TRANSACTION_DISPLAYED)) {
- if (last_entry != xact.entry) {
- first_line_format.format(output_stream, details_t(xact));
- last_entry = xact.entry;
- } else {
- next_lines_format.format(output_stream, details_t(xact));
- }
- transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED;
- }
-}
-
-void format_entries::format_last_entry()
-{
- bool first = true;
- for (transactions_list::const_iterator i = last_entry->transactions.begin();
- i != last_entry->transactions.end();
- i++) {
- if (transaction_has_xdata(**i) &&
- transaction_xdata(**i).dflags & TRANSACTION_TO_DISPLAY) {
- if (first) {
- first_line_format.format(output_stream, details_t(**i));
- first = false;
- } else {
- next_lines_format.format(output_stream, details_t(**i));
- }
- transaction_xdata(**i).dflags |= TRANSACTION_DISPLAYED;
- }
- }
-}
-
-void format_entries::operator()(transaction_t& xact)
-{
- if (last_entry && xact.entry != last_entry)
- format_last_entry();
-
- transaction_xdata(xact).dflags |= TRANSACTION_TO_DISPLAY;
-
- last_entry = xact.entry;
-}
-
-bool disp_subaccounts_p(const account_t& account,
- const item_predicate<account_t>& disp_pred,
- const account_t *& to_show)
-{
- bool display = false;
- unsigned int counted = 0;
- bool matches = disp_pred(account);
- value_t acct_total;
- bool computed = false;
- value_t result;
-
- to_show = NULL;
-
- for (accounts_map::const_iterator i = account.accounts.begin();
- i != account.accounts.end();
- i++) {
- if (! disp_pred(*(*i).second))
- continue;
-
- format_t::compute_total(result, details_t(*(*i).second));
- if (! computed) {
- format_t::compute_total(acct_total, details_t(account));
- computed = true;
- }
-
- if ((result != acct_total) || counted > 0) {
- display = matches;
- break;
- }
- to_show = (*i).second;
- counted++;
- }
-
- return display;
-}
-
-bool display_account(const account_t& account,
- const item_predicate<account_t>& disp_pred)
-{
- // Never display an account that has already been displayed.
- if (account_has_xdata(account) &&
- account_xdata(account).dflags & ACCOUNT_DISPLAYED)
- return false;
-
- // At this point, one of two possibilities exists: the account is a
- // leaf which matches the predicate restrictions; or it is a parent
- // and two or more children must be subtotaled; or it is a parent
- // and its child has been hidden by the predicate. So first,
- // determine if it is a parent that must be displayed regardless of
- // the predicate.
-
- const account_t * account_to_show = NULL;
- if (disp_subaccounts_p(account, disp_pred, account_to_show))
- return true;
-
- return ! account_to_show && disp_pred(account);
-}
-
-void format_account::operator()(account_t& account)
-{
- if (display_account(account, disp_pred)) {
- if (! account.parent) {
- account_xdata(account).dflags |= ACCOUNT_TO_DISPLAY;
- } else {
- format.format(output_stream, details_t(account));
- account_xdata(account).dflags |= ACCOUNT_DISPLAYED;
- }
- }
-}
-
-format_equity::format_equity(std::ostream& _output_stream,
- const std::string& _format,
- const std::string& display_predicate)
- : output_stream(_output_stream), disp_pred(display_predicate)
-{
- const char * f = _format.c_str();
- if (const char * p = std::strstr(f, "%/")) {
- first_line_format.reset(std::string(f, 0, p - f));
- next_lines_format.reset(std::string(p + 2));
- } else {
- first_line_format.reset(_format);
- next_lines_format.reset(_format);
- }
-
- entry_t header_entry;
- header_entry.payee = "Opening Balances";
- header_entry.date = std::time(NULL);
- first_line_format.format(output_stream, details_t(header_entry));
-}
-
-void format_equity::flush()
-{
- account_xdata_t xdata;
- xdata.value = total;
- xdata.value.negate();
- account_t summary(NULL, "Equity:Opening Balances");
- summary.data = &xdata;
- next_lines_format.format(output_stream, details_t(summary));
- output_stream.flush();
-}
-
-void format_equity::operator()(account_t& account)
-{
- if (display_account(account, disp_pred)) {
- next_lines_format.format(output_stream, details_t(account));
- if (account_has_xdata(account))
- total += account_xdata(account).value;
- account_xdata(account).dflags |= ACCOUNT_DISPLAYED;
- }
-}
-
-} // namespace ledger
-
-#ifdef USE_BOOST_PYTHON
-
-#include <boost/python.hpp>
-
-using namespace boost::python;
-using namespace ledger;
-
-std::string py_format_1(format_t& format, const details_t& item)
-{
- std::ostringstream out;
- format.format(out, item);
- return out.str();
-}
-
-template <typename T>
-std::string py_format(format_t& format, const T& item)
-{
- std::ostringstream out;
- format.format(out, details_t(item));
- return out.str();
-}
-
-void export_format()
-{
- class_< format_t > ("Format")
- .def(init<std::string>())
- .def("reset", &format_t::reset)
- .def("format", py_format_1)
- .def("format", py_format<account_t>)
- .def("format", py_format<entry_t>)
- .def("format", py_format<transaction_t>)
- ;
-
- def("truncated", truncated);
-#if 0
- def("partial_account_name", partial_account_name);
-#endif
- def("display_account", display_account);
-}
-
-#endif // USE_BOOST_PYTHON