summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2008-08-01 01:37:20 -0400
committerJohn Wiegley <johnw@newartisans.com>2008-08-01 01:37:58 -0400
commit567902b1731db6f1ace85a7bc384b55ffd0948ab (patch)
tree6073b110e309781eea7e05163b57ff90bec88d5f
parente5048ec71bf114c351c62844b7603893195df4d4 (diff)
downloadfork-ledger-567902b1731db6f1ace85a7bc384b55ffd0948ab.tar.gz
fork-ledger-567902b1731db6f1ace85a7bc384b55ffd0948ab.tar.bz2
fork-ledger-567902b1731db6f1ace85a7bc384b55ffd0948ab.zip
Simplified the format_t code so that it no longer references any particulars
about journal objects. This is all done through value expressions now.
-rw-r--r--format.cc526
-rw-r--r--format.h234
-rw-r--r--gnucash.cc2
-rw-r--r--report.cc259
-rw-r--r--report.h117
-rw-r--r--xml.h2
6 files changed, 545 insertions, 595 deletions
diff --git a/format.cc b/format.cc
index 2f457ea7..61c3eb5c 100644
--- a/format.cc
+++ b/format.cc
@@ -6,119 +6,36 @@
namespace ledger {
-format_t::elision_style_t format_t::elision_style = ABBREVIATE;
-int format_t::abbrev_length = 2;
+format_t::elision_style_t
+ format_t::elision_style = ABBREVIATE;
+int format_t::abbrev_length = 2;
-bool format_t::ansi_codes = false;
-bool format_t::ansi_invert = false;
+bool format_t::ansi_codes = false;
+bool format_t::ansi_invert = false;
-string format_t::truncate(const string& str, unsigned int width,
- const bool is_account)
-{
- const unsigned int len = str.length();
- if (len <= width)
- return str;
-
- assert(width < 4095);
-
- char buf[4096];
-
- switch (elision_style) {
- case TRUNCATE_LEADING:
- // This method truncates at the beginning.
- std::strncpy(buf, str.c_str() + (len - width), width);
- buf[0] = '.';
- buf[1] = '.';
- break;
-
- case TRUNCATE_MIDDLE:
- // This method truncates in the middle.
- std::strncpy(buf, str.c_str(), width / 2);
- std::strncpy(buf + width / 2,
- str.c_str() + (len - (width / 2 + width % 2)),
- width / 2 + width % 2);
- buf[width / 2 - 1] = '.';
- buf[width / 2] = '.';
- break;
-
- case ABBREVIATE:
- if (is_account) {
- std::list<string> parts;
- string::size_type beg = 0;
- for (string::size_type pos = str.find(':');
- pos != string::npos;
- beg = pos + 1, pos = str.find(':', beg))
- parts.push_back(string(str, beg, pos - beg));
- parts.push_back(string(str, beg));
-
- string result;
- unsigned int newlen = len;
- for (std::list<string>::iterator i = parts.begin();
- i != parts.end();
- i++) {
- // Don't contract the last element
- std::list<string>::iterator x = i;
- if (++x == parts.end()) {
- result += *i;
- break;
- }
+namespace {
+ string partial_account_name(const account_t& account)
+ {
+ string name;
- if (newlen > width) {
- result += string(*i, 0, abbrev_length);
- result += ":";
- newlen -= (*i).length() - abbrev_length;
- } else {
- result += *i;
- result += ":";
- }
- }
+ 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 (newlen > width) {
- // Even abbreviated its too big to show the last account, so
- // abbreviate all but the last and truncate at the beginning.
- std::strncpy(buf, result.c_str() + (result.length() - width), width);
- buf[0] = '.';
- buf[1] = '.';
- } else {
- std::strcpy(buf, result.c_str());
- }
- break;
+ if (name.empty())
+ name = acct->name;
+ else
+ name = acct->name + ":" + name;
}
- // fall through...
- case TRUNCATE_TRAILING:
- // This method truncates at the end (the default).
- std::strncpy(buf, str.c_str(), width - 2);
- buf[width - 2] = '.';
- buf[width - 1] = '.';
- break;
+ return name;
}
- buf[width] = '\0';
-
- return buf;
}
-string partial_account_name(const account_t& account)
-{
- 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;
-}
-
-element_t * format_t::parse_elements(const string& fmt)
+format_t::element_t * format_t::parse_elements(const string& fmt)
{
std::auto_ptr<element_t> result;
@@ -137,8 +54,8 @@ element_t * format_t::parse_elements(const string& fmt)
result.reset(new element_t);
current = result.get();
} else {
- current->next = new element_t;
- current = current->next;
+ current->next.reset(new element_t);
+ current = current->next.get();
}
if (q != buf) {
@@ -146,8 +63,8 @@ element_t * format_t::parse_elements(const string& fmt)
current->chars = string(buf, q);
q = buf;
- current->next = new element_t;
- current = current->next;
+ current->next.reset(new element_t);
+ current = current->next.get();
}
if (*p == '\\') {
@@ -202,46 +119,17 @@ element_t * format_t::parse_elements(const string& fmt)
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;
-
- assert(! current->val_expr);
- current->val_expr.parse(string(b, p));
- break;
- }
-
+ case '(':
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 = string(b, p);
+ std::istringstream str(p);
+ current->type = element_t::EXPR;
+ current->expr.parse(str);
+ current->expr.set_text(string(p, p + str.tellg()));
+ p += str.tellg();
break;
}
+#if 0
case 'x':
switch (*++p) {
case 'B': current->type = element_t::XACT_BEG_POS; break;
@@ -281,17 +169,20 @@ element_t * format_t::parse_elements(const string& fmt)
case 'n': current->type = element_t::OPT_NOTE; break;
case '|': current->type = element_t::SPACER; break;
case '_': current->type = element_t::DEPTH_SPACER; break;
+#endif
}
}
+#if 0
END:
+#endif
if (q != buf) {
if (! result.get()) {
result.reset(new element_t);
current = result.get();
} else {
- current->next = new element_t;
- current = current->next;
+ current->next.reset(new element_t);
+ current = current->next.get();
}
current->type = element_t::STRING;
current->chars = string(buf, q);
@@ -301,20 +192,6 @@ element_t * format_t::parse_elements(const string& fmt)
}
namespace {
- inline void mark_red(std::ostream& out, const element_t * elem) {
- out.setf(std::ios::left);
- out.width(0);
- out << "\e[31m";
-
- if (elem->flags & ELEMENT_ALIGN_LEFT)
- out << std::left;
- else
- out << std::right;
-
- if (elem->min_width > 0)
- out.width(elem->min_width);
- }
-
inline void mark_plain(std::ostream& out) {
out << "\e[0m";
}
@@ -322,7 +199,7 @@ namespace {
void format_t::format(std::ostream& out_str, scope_t& scope) const
{
- for (const element_t * elem = elements; elem; elem = elem->next) {
+ for (const element_t * elem = elements.get(); elem; elem = elem->next.get()) {
std::ostringstream out;
string name;
bool ignore_max_width = false;
@@ -340,10 +217,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
out << elem->chars;
break;
- case element_t::AMOUNT:
- out << scope.resolve("amount");
+ case element_t::EXPR:
+ out << elem->expr.calc(scope);
break;
+#if 0
case element_t::ACCOUNT_FULLNAME:
scope.resolve("account").dump(out, elem->min_width);
break;
@@ -351,12 +229,15 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
scope.resolve("account_base").dump(out, elem->min_width);
break;
+ case element_t::AMOUNT:
+ out << "a";
+ //out << scope.resolve("amount");
+ break;
case element_t::TOTAL:
out << "T";
//out << scope.resolve("total");
break;
-#if 0
case element_t::VALUE_EXPR: {
expr_t * calc;
switch (elem->type) {
@@ -579,13 +460,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
if (details.xact)
out << details.xact->end_line;
break;
-#endif
case element_t::DATE_STRING:
out << format_datetime(scope.resolve("date").as_datetime());
break;
-#if 0
case element_t::COMPLETE_DATE_STRING: {
datetime_t actual_date;
datetime_t effective_date;
@@ -670,13 +549,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
out << temp;
break;
}
-#endif
case element_t::PAYEE:
scope.resolve("payee").dump(out, elem->min_width);
break;
-#if 0
case element_t::OPT_NOTE:
if (details.xact && details.xact->note)
out << " ; ";
@@ -731,12 +608,10 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
}
break;
-#endif
case element_t::SPACER:
out << " ";
break;
-#if 0
case element_t::DEPTH_SPACER:
for (const account_t * acct = details.account;
acct;
@@ -764,261 +639,90 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
}
}
-format_xacts::format_xacts(std::ostream& _output_stream,
- const string& format)
- : output_stream(_output_stream), last_entry(NULL), last_xact(NULL)
-{
- TRACE_CTOR(format_xacts, "std::ostream&, const string&");
-
- const char * f = format.c_str();
- if (const char * p = std::strstr(f, "%/")) {
- first_line_format.reset(string(f, 0, p - f));
- next_lines_format.reset(string(p + 2));
- } else {
- first_line_format.reset(format);
- next_lines_format.reset(format);
- }
-}
-
-void format_xacts::operator()(xact_t& xact)
-{
- if (! xact_has_xdata(xact) ||
- ! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) {
- if (last_entry != xact.entry) {
- first_line_format.format(output_stream, xact);
- last_entry = xact.entry;
- }
- else if (last_xact && last_xact->date() != xact.date()) {
- first_line_format.format(output_stream, xact);
- }
- else {
- next_lines_format.format(output_stream, xact);
- }
-
- xact_xdata(xact).dflags |= XACT_DISPLAYED;
- last_xact = &xact;
- }
-}
-
-void format_entries::format_last_entry()
-{
-#if 0
- bool first = true;
- foreach (const transaction_t * xact, last_entry->xacts) {
- if (xact_has_xdata(*xact) &&
- xact_xdata_(*xact).dflags & XACT_TO_DISPLAY) {
- if (first) {
- first_line_format.format(output_stream, details_t(*xact));
- first = false;
- } else {
- next_lines_format.format(output_stream, details_t(*xact));
- }
- xact_xdata_(*xact).dflags |= XACT_DISPLAYED;
- }
- }
-#endif
-}
-
-void format_entries::operator()(xact_t& xact)
-{
- xact_xdata(xact).dflags |= XACT_TO_DISPLAY;
-
- if (last_entry && xact.entry != last_entry)
- format_last_entry();
-
- last_entry = xact.entry;
-}
-
-void print_entry(std::ostream& out, const entry_base_t& entry_base,
- const string& prefix)
+string format_t::truncate(const string& str, unsigned int width,
+ const bool is_account)
{
- string print_format;
+ const unsigned int len = str.length();
+ if (len <= width)
+ return str;
- if (dynamic_cast<const entry_t *>(&entry_base)) {
- print_format = (prefix + "%D %X%C%P\n" +
- prefix + " %-34A %12o\n%/" +
- prefix + " %-34A %12o\n");
- }
- else if (const auto_entry_t * entry =
- dynamic_cast<const auto_entry_t *>(&entry_base)) {
- out << "= " << entry->predicate.predicate.text() << '\n';
- print_format = prefix + " %-34A %12o\n";
- }
- else if (const period_entry_t * entry =
- dynamic_cast<const period_entry_t *>(&entry_base)) {
- out << "~ " << entry->period_string << '\n';
- print_format = prefix + " %-34A %12o\n";
- }
- else {
- assert(false);
- }
+ assert(width < 4095);
-#if 0
- format_entries formatter(out, print_format);
- walk_xacts(const_cast<xacts_list&>(entry_base.xacts), formatter);
- formatter.flush();
+ char buf[4096];
- clear_xact_xdata cleaner;
- walk_xacts(const_cast<xacts_list&>(entry_base.xacts), cleaner);
-#endif
-}
+ switch (elision_style) {
+ case TRUNCATE_LEADING:
+ // This method truncates at the beginning.
+ std::strncpy(buf, str.c_str() + (len - width), width);
+ buf[0] = '.';
+ buf[1] = '.';
+ break;
-bool disp_subaccounts_p(const account_t& account,
- const optional<item_predicate<account_t> >& disp_pred,
- const account_t *& to_show)
-{
- bool display = false;
-#if 0
- unsigned int counted = 0;
- bool matches = disp_pred ? (*disp_pred)(account) : true;
- bool computed = false;
-#endif
- value_t acct_total;
- value_t result;
+ case TRUNCATE_MIDDLE:
+ // This method truncates in the middle.
+ std::strncpy(buf, str.c_str(), width / 2);
+ std::strncpy(buf + width / 2,
+ str.c_str() + (len - (width / 2 + width % 2)),
+ width / 2 + width % 2);
+ buf[width / 2 - 1] = '.';
+ buf[width / 2] = '.';
+ break;
- to_show = NULL;
+ case ABBREVIATE:
+ if (is_account) {
+ std::list<string> parts;
+ string::size_type beg = 0;
+ for (string::size_type pos = str.find(':');
+ pos != string::npos;
+ beg = pos + 1, pos = str.find(':', beg))
+ parts.push_back(string(str, beg, pos - beg));
+ parts.push_back(string(str, beg));
-#if 0
- for (accounts_map::value_type pair, account.accounts) {
- if (disp_pred && ! (*disp_pred)(*pair.second))
- continue;
+ string result;
+ unsigned int newlen = len;
+ for (std::list<string>::iterator i = parts.begin();
+ i != parts.end();
+ i++) {
+ // Don't contract the last element
+ std::list<string>::iterator x = i;
+ if (++x == parts.end()) {
+ result += *i;
+ break;
+ }
- compute_total(result, details_t(*pair.second));
- if (! computed) {
- compute_total(acct_total, details_t(account));
- computed = true;
- }
+ if (newlen > width) {
+ result += string(*i, 0, abbrev_length);
+ result += ":";
+ newlen -= (*i).length() - abbrev_length;
+ } else {
+ result += *i;
+ result += ":";
+ }
+ }
- if ((result != acct_total) || counted > 0) {
- display = matches;
+ if (newlen > width) {
+ // Even abbreviated its too big to show the last account, so
+ // abbreviate all but the last and truncate at the beginning.
+ std::strncpy(buf, result.c_str() + (result.length() - width), width);
+ buf[0] = '.';
+ buf[1] = '.';
+ } else {
+ std::strcpy(buf, result.c_str());
+ }
break;
}
- to_show = pair.second;
- counted++;
- }
-#endif
-
- return display;
-}
-
-bool display_account(const account_t& account,
- const optional<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 || (*disp_pred)(const_cast<account_t&>(account))));
-}
-
-void format_accounts::operator()(account_t& account)
-{
-#if 0
- 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;
- }
- }
-#endif
-}
-
-format_equity::format_equity(std::ostream& _output_stream,
- const string& _format,
- const string& display_predicate)
- : output_stream(_output_stream), disp_pred(display_predicate)
-{
-#if 0
- const char * f = _format.c_str();
- if (const char * p = std::strstr(f, "%/")) {
- first_line_format.reset(string(f, 0, p - f));
- next_lines_format.reset(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 = current_moment;
- first_line_format.format(output_stream, details_t(header_entry));
-#endif
-}
-
-void format_equity::flush()
-{
-#if 0
- account_xdata_t xdata;
- xdata.value = total;
- xdata.value.negate();
- account_t summary(NULL, "Equity:Opening Balances");
- summary.data = &xdata;
-
- if (total.type() >= value_t::BALANCE) {
- const balance_t * bal;
- if (total.is_type(value_t::BALANCE))
- bal = &(total.as_balance());
- else if (total.is_type(value_t::BALANCE_PAIR))
- bal = &(total.as_balance_pair().quantity());
- else
- assert(false);
+ // fall through...
- for (balance_t::amounts_map::value_type pair, bal->amounts) {
- xdata.value = pair.second;
- xdata.value.negate();
- next_lines_format.format(output_stream, details_t(summary));
- }
- } else {
- next_lines_format.format(output_stream, details_t(summary));
+ case TRUNCATE_TRAILING:
+ // This method truncates at the end (the default).
+ std::strncpy(buf, str.c_str(), width - 2);
+ buf[width - 2] = '.';
+ buf[width - 1] = '.';
+ break;
}
- output_stream.flush();
-#endif
-}
+ buf[width] = '\0';
-void format_equity::operator()(account_t& account)
-{
-#if 0
- if (display_account(account, disp_pred)) {
- if (account_has_xdata(account)) {
- value_t val = account_xdata_(account).value;
-
- if (val.type() >= value_t::BALANCE) {
- const balance_t * bal;
- if (val.is_type(value_t::BALANCE))
- bal = &(val.as_balance());
- else if (val.is_type(value_t::BALANCE_PAIR))
- bal = &(val.as_balance_pair().quantity());
- else
- assert(false);
-
- for (balance_t::amounts_map::value_type pair, bal->amounts) {
- account_xdata_(account).value = pair.second;
- next_lines_format.format(output_stream, details_t(account));
- }
- account_xdata_(account).value = val;
- } else {
- next_lines_format.format(output_stream, details_t(account));
- }
- total += val;
- }
- account_xdata(account).dflags |= ACCOUNT_DISPLAYED;
- }
-#endif
+ return buf;
}
} // namespace ledger
diff --git a/format.h b/format.h
index 8348e863..ebff2a65 100644
--- a/format.h
+++ b/format.h
@@ -7,71 +7,58 @@
namespace ledger {
-string truncated(const string& str, unsigned int width,
- const int style = 2);
-
-string partial_account_name(const account_t& account,
- const unsigned int start_depth);
+DECLARE_EXCEPTION(format_error, std::runtime_error);
+class format_t : public noncopyable
+{
+ struct element_t : public noncopyable
+ {
#define ELEMENT_ALIGN_LEFT 0x01
#define ELEMENT_HIGHLIGHT 0x02
-struct element_t : public noncopyable
-{
- enum kind_t {
- STRING,
- VALUE_EXPR,
- SOURCE,
- ENTRY_BEG_POS,
- ENTRY_BEG_LINE,
- ENTRY_END_POS,
- ENTRY_END_LINE,
- XACT_BEG_POS,
- XACT_BEG_LINE,
- XACT_END_POS,
- XACT_END_LINE,
- DATE_STRING,
- COMPLETE_DATE_STRING,
- CLEARED,
- ENTRY_CLEARED,
- CODE,
- PAYEE,
- OPT_ACCOUNT,
- ACCOUNT_NAME,
- ACCOUNT_FULLNAME,
- AMOUNT,
- OPT_AMOUNT,
- TOTAL,
- NOTE,
- OPT_NOTE,
- SPACER,
- DEPTH_SPACER
- };
+ enum kind_t {
+ STRING,
+ EXPR,
+#if 0
+ SPACER,
+ DEPTH_SPACER
+#endif
+ };
+
+ kind_t type;
+ unsigned char flags;
+ unsigned char min_width;
+ unsigned char max_width;
+ string chars;
+ expr_t expr;
+
+ scoped_ptr<struct element_t> next;
+
+ element_t()
+ : type(STRING), flags(false), min_width(0), max_width(0) {
+ TRACE_CTOR(element_t, "");
+ }
+ ~element_t() {
+ TRACE_DTOR(element_t);
+ }
- kind_t type;
- unsigned char flags;
- string chars;
- unsigned char min_width;
- unsigned char max_width;
- expr_t val_expr;
+ friend inline void mark_red(std::ostream& out, const element_t * elem) {
+ out.setf(std::ios::left);
+ out.width(0);
+ out << "\e[31m";
- struct element_t * next;
+ if (elem->flags & ELEMENT_ALIGN_LEFT)
+ out << std::left;
+ else
+ out << std::right;
- element_t() : type(STRING), flags(false),
- min_width(0), max_width(0), next(NULL) {
- TRACE_CTOR(element_t, "");
- }
-
- ~element_t() {
- TRACE_DTOR(element_t);
- if (next) checked_delete(next); // recursive, but not too deep
- }
-};
+ if (elem->min_width > 0)
+ out.width(elem->min_width);
+ }
+ };
-struct format_t : public noncopyable
-{
- string format_string;
- element_t * elements;
+ string format_string;
+ scoped_ptr<element_t> elements;
enum elision_style_t {
TRUNCATE_TRAILING,
@@ -81,146 +68,37 @@ struct format_t : public noncopyable
};
static elision_style_t elision_style;
- static int abbrev_length;
+ static int abbrev_length;
- static bool ansi_codes;
- static bool ansi_invert;
+ static bool ansi_codes;
+ static bool ansi_invert;
- format_t() : elements(NULL) {
+public:
+ format_t() {
TRACE_CTOR(format_t, "");
}
- format_t(const string& _format) : elements(NULL) {
+ format_t(const string& _format) {
TRACE_CTOR(format_t, "const string&");
- reset(_format);
+ parse(_format);
}
~format_t() {
TRACE_DTOR(format_t);
- if (elements) checked_delete(elements);
}
- void reset(const string& _format) {
- if (elements)
- checked_delete(elements);
- elements = parse_elements(_format);
+ void parse(const string& _format) {
+ elements.reset(parse_elements(_format));
format_string = _format;
}
+ void format(std::ostream& out, scope_t& scope) const;
+
+private:
static element_t * parse_elements(const string& fmt);
static string truncate(const string& str, unsigned int width,
const bool is_account = false);
-
- void format(std::ostream& out, scope_t& scope) const;
-};
-
-class format_xacts : public item_handler<xact_t>
-{
-protected:
- std::ostream& output_stream;
- format_t first_line_format;
- format_t next_lines_format;
- entry_t * last_entry;
- xact_t * last_xact;
-
-public:
- format_xacts(std::ostream& _output_stream,
- const string& format);
- ~format_xacts() throw() {
- TRACE_DTOR(format_xacts);
- }
-
- virtual void flush() {
- output_stream.flush();
- }
- virtual void operator()(xact_t& xact);
-};
-
-class format_entries : public format_xacts
-{
- public:
- format_entries(std::ostream& output_stream, const string& format)
- : format_xacts(output_stream, format) {
- TRACE_CTOR(format_entries, "std::ostream&, const string&");
- }
- ~format_entries() throw() {
- TRACE_DTOR(format_entries);
- }
-
- virtual void format_last_entry();
-
- virtual void flush() {
- if (last_entry) {
- format_last_entry();
- last_entry = NULL;
- }
- format_xacts::flush();
- }
- virtual void operator()(xact_t& xact);
-};
-
-void print_entry(std::ostream& out, const entry_base_t& entry,
- const string& prefix = "");
-
-bool disp_subaccounts_p(const account_t& account,
- const optional<item_predicate<account_t> >& disp_pred,
- const account_t *& to_show);
-
-inline bool disp_subaccounts_p(const account_t& account) {
- const account_t * temp;
- return disp_subaccounts_p(account, none, temp);
-}
-
-bool display_account(const account_t& account,
- const optional<item_predicate<account_t> >& disp_pred);
-
-class format_accounts : public item_handler<account_t>
-{
- std::ostream& output_stream;
-
- item_predicate<account_t> disp_pred;
-
- public:
- format_t format;
-
- format_accounts(std::ostream& _output_stream,
- const string& _format,
- const string& display_predicate = NULL)
- : output_stream(_output_stream), disp_pred(display_predicate),
- format(_format) {
- TRACE_CTOR(format_accounts, "std::ostream&, const string&, const string&");
- }
- ~format_accounts() throw() {
- TRACE_DTOR(format_accounts);
- }
-
- virtual void flush() {
- output_stream.flush();
- }
-
- virtual void operator()(account_t& account);
};
-class format_equity : public item_handler<account_t>
-{
- std::ostream& output_stream;
- format_t first_line_format;
- format_t next_lines_format;
-
- item_predicate<account_t> disp_pred;
-
- mutable value_t total;
-
- public:
- format_equity(std::ostream& _output_stream,
- const string& _format,
- const string& display_predicate);
-
- virtual void flush();
- virtual void operator()(account_t& account);
-};
-
-DECLARE_EXCEPTION(format_error, std::runtime_error);
-
} // namespace ledger
#endif // _FORMAT_H
diff --git a/gnucash.cc b/gnucash.cc
index 0be5661e..7849f81f 100644
--- a/gnucash.cc
+++ b/gnucash.cc
@@ -138,7 +138,9 @@ static void endElement(void *userData, const char *name)
// Add the new entry (what gnucash calls a 'xact') to the
// journal
if (! curr_journal->add_entry(curr_entry)) {
+#if 0
print_entry(std::cerr, *curr_entry);
+#endif
have_error = "The above entry does not balance";
checked_delete(curr_entry);
} else {
diff --git a/report.cc b/report.cc
index 83acc179..35b4649e 100644
--- a/report.cc
+++ b/report.cc
@@ -456,4 +456,263 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
return session.lookup(name);
}
+// jww (2008-08-01): Find a home for this code
+
+format_xacts::format_xacts(std::ostream& _output_stream,
+ const string& format)
+ : output_stream(_output_stream), last_entry(NULL), last_xact(NULL)
+{
+ TRACE_CTOR(format_xacts, "std::ostream&, const string&");
+
+ const char * f = format.c_str();
+ if (const char * p = std::strstr(f, "%/")) {
+ first_line_format.parse(string(f, 0, p - f));
+ next_lines_format.parse(string(p + 2));
+ } else {
+ first_line_format.parse(format);
+ next_lines_format.parse(format);
+ }
+}
+
+void format_xacts::operator()(xact_t& xact)
+{
+ if (! xact_has_xdata(xact) ||
+ ! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) {
+ if (last_entry != xact.entry) {
+ first_line_format.format(output_stream, xact);
+ last_entry = xact.entry;
+ }
+ else if (last_xact && last_xact->date() != xact.date()) {
+ first_line_format.format(output_stream, xact);
+ }
+ else {
+ next_lines_format.format(output_stream, xact);
+ }
+
+ xact_xdata(xact).dflags |= XACT_DISPLAYED;
+ last_xact = &xact;
+ }
+}
+
+void format_entries::format_last_entry()
+{
+#if 0
+ bool first = true;
+ foreach (const transaction_t * xact, last_entry->xacts) {
+ if (xact_has_xdata(*xact) &&
+ xact_xdata_(*xact).dflags & XACT_TO_DISPLAY) {
+ if (first) {
+ first_line_format.format(output_stream, details_t(*xact));
+ first = false;
+ } else {
+ next_lines_format.format(output_stream, details_t(*xact));
+ }
+ xact_xdata_(*xact).dflags |= XACT_DISPLAYED;
+ }
+ }
+#endif
+}
+
+void format_entries::operator()(xact_t& xact)
+{
+ xact_xdata(xact).dflags |= XACT_TO_DISPLAY;
+
+ if (last_entry && xact.entry != last_entry)
+ format_last_entry();
+
+ last_entry = xact.entry;
+}
+
+void print_entry(std::ostream& out, const entry_base_t& entry_base,
+ const string& prefix)
+{
+ string print_format;
+
+ if (dynamic_cast<const entry_t *>(&entry_base)) {
+ print_format = (prefix + "%D %X%C%P\n" +
+ prefix + " %-34A %12o\n%/" +
+ prefix + " %-34A %12o\n");
+ }
+ else if (const auto_entry_t * entry =
+ dynamic_cast<const auto_entry_t *>(&entry_base)) {
+ out << "= " << entry->predicate.predicate.text() << '\n';
+ print_format = prefix + " %-34A %12o\n";
+ }
+ else if (const period_entry_t * entry =
+ dynamic_cast<const period_entry_t *>(&entry_base)) {
+ out << "~ " << entry->period_string << '\n';
+ print_format = prefix + " %-34A %12o\n";
+ }
+ else {
+ assert(false);
+ }
+
+#if 0
+ format_entries formatter(out, print_format);
+ walk_xacts(const_cast<xacts_list&>(entry_base.xacts), formatter);
+ formatter.flush();
+
+ clear_xact_xdata cleaner;
+ walk_xacts(const_cast<xacts_list&>(entry_base.xacts), cleaner);
+#endif
+}
+
+bool disp_subaccounts_p(const account_t& account,
+ const optional<item_predicate<account_t> >& disp_pred,
+ const account_t *& to_show)
+{
+ bool display = false;
+#if 0
+ unsigned int counted = 0;
+ bool matches = disp_pred ? (*disp_pred)(account) : true;
+ bool computed = false;
+#endif
+ value_t acct_total;
+ value_t result;
+
+ to_show = NULL;
+
+#if 0
+ for (accounts_map::value_type pair, account.accounts) {
+ if (disp_pred && ! (*disp_pred)(*pair.second))
+ continue;
+
+ compute_total(result, details_t(*pair.second));
+ if (! computed) {
+ compute_total(acct_total, details_t(account));
+ computed = true;
+ }
+
+ if ((result != acct_total) || counted > 0) {
+ display = matches;
+ break;
+ }
+ to_show = pair.second;
+ counted++;
+ }
+#endif
+
+ return display;
+}
+
+bool display_account(const account_t& account,
+ const optional<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 || (*disp_pred)(const_cast<account_t&>(account))));
+}
+
+void format_accounts::operator()(account_t& account)
+{
+#if 0
+ 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;
+ }
+ }
+#endif
+}
+
+format_equity::format_equity(std::ostream& _output_stream,
+ const string& _format,
+ const string& display_predicate)
+ : output_stream(_output_stream), disp_pred(display_predicate)
+{
+#if 0
+ const char * f = _format.c_str();
+ if (const char * p = std::strstr(f, "%/")) {
+ first_line_format.reset(string(f, 0, p - f));
+ next_lines_format.reset(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 = current_moment;
+ first_line_format.format(output_stream, details_t(header_entry));
+#endif
+}
+
+void format_equity::flush()
+{
+#if 0
+ account_xdata_t xdata;
+ xdata.value = total;
+ xdata.value.negate();
+ account_t summary(NULL, "Equity:Opening Balances");
+ summary.data = &xdata;
+
+ if (total.type() >= value_t::BALANCE) {
+ const balance_t * bal;
+ if (total.is_type(value_t::BALANCE))
+ bal = &(total.as_balance());
+ else if (total.is_type(value_t::BALANCE_PAIR))
+ bal = &(total.as_balance_pair().quantity());
+ else
+ assert(false);
+
+ for (balance_t::amounts_map::value_type pair, bal->amounts) {
+ xdata.value = pair.second;
+ xdata.value.negate();
+ next_lines_format.format(output_stream, details_t(summary));
+ }
+ } else {
+ next_lines_format.format(output_stream, details_t(summary));
+ }
+ output_stream.flush();
+#endif
+}
+
+void format_equity::operator()(account_t& account)
+{
+#if 0
+ if (display_account(account, disp_pred)) {
+ if (account_has_xdata(account)) {
+ value_t val = account_xdata_(account).value;
+
+ if (val.type() >= value_t::BALANCE) {
+ const balance_t * bal;
+ if (val.is_type(value_t::BALANCE))
+ bal = &(val.as_balance());
+ else if (val.is_type(value_t::BALANCE_PAIR))
+ bal = &(val.as_balance_pair().quantity());
+ else
+ assert(false);
+
+ for (balance_t::amounts_map::value_type pair, bal->amounts) {
+ account_xdata_(account).value = pair.second;
+ next_lines_format.format(output_stream, details_t(account));
+ }
+ account_xdata_(account).value = val;
+ } else {
+ next_lines_format.format(output_stream, details_t(account));
+ }
+ total += val;
+ }
+ account_xdata(account).dflags |= ACCOUNT_DISPLAYED;
+ }
+#endif
+}
+
} // namespace ledger
diff --git a/report.h b/report.h
index 79d18f3c..619c4bdd 100644
--- a/report.h
+++ b/report.h
@@ -33,6 +33,7 @@
#define _REPORT_H
#include "session.h"
+#include "format.h"
#include "walk.h"
namespace ledger {
@@ -207,9 +208,7 @@ public:
//
void eval(const string& expr) {
-#if 0
- expr(expr).compile((xml::document_t *)NULL, this);
-#endif
+ expr_t(expr).calc(*this);
}
value_t option_eval(call_scope_t& args) {
eval(args[0].as_string());
@@ -230,12 +229,12 @@ public:
return NULL_VALUE;
}
- value_t option_raw(call_scope_t& args) {
+ value_t option_raw(call_scope_t&) {
raw_mode = true;
return NULL_VALUE;
}
- value_t option_foo(call_scope_t& args) {
+ value_t option_foo(call_scope_t&) {
std::cout << "This is foo" << std::endl;
return NULL_VALUE;
}
@@ -302,6 +301,114 @@ public:
string abbrev(const string& str, unsigned int width,
const bool is_account);
+// jww (2008-08-01): Where does this code belong?
+
+class format_xacts : public item_handler<xact_t>
+{
+protected:
+ std::ostream& output_stream;
+ format_t first_line_format;
+ format_t next_lines_format;
+ entry_t * last_entry;
+ xact_t * last_xact;
+
+public:
+ format_xacts(std::ostream& _output_stream,
+ const string& format);
+ ~format_xacts() throw() {
+ TRACE_DTOR(format_xacts);
+ }
+
+ virtual void flush() {
+ output_stream.flush();
+ }
+ virtual void operator()(xact_t& xact);
+};
+
+class format_entries : public format_xacts
+{
+ public:
+ format_entries(std::ostream& output_stream, const string& format)
+ : format_xacts(output_stream, format) {
+ TRACE_CTOR(format_entries, "std::ostream&, const string&");
+ }
+ ~format_entries() throw() {
+ TRACE_DTOR(format_entries);
+ }
+
+ virtual void format_last_entry();
+
+ virtual void flush() {
+ if (last_entry) {
+ format_last_entry();
+ last_entry = NULL;
+ }
+ format_xacts::flush();
+ }
+ virtual void operator()(xact_t& xact);
+};
+
+void print_entry(std::ostream& out, const entry_base_t& entry,
+ const string& prefix = "");
+
+bool disp_subaccounts_p(const account_t& account,
+ const optional<item_predicate<account_t> >& disp_pred,
+ const account_t *& to_show);
+
+inline bool disp_subaccounts_p(const account_t& account) {
+ const account_t * temp;
+ return disp_subaccounts_p(account, none, temp);
+}
+
+bool display_account(const account_t& account,
+ const optional<item_predicate<account_t> >& disp_pred);
+
+class format_accounts : public item_handler<account_t>
+{
+ std::ostream& output_stream;
+
+ item_predicate<account_t> disp_pred;
+
+ public:
+ format_t format;
+
+ format_accounts(std::ostream& _output_stream,
+ const string& _format,
+ const string& display_predicate = NULL)
+ : output_stream(_output_stream), disp_pred(display_predicate),
+ format(_format) {
+ TRACE_CTOR(format_accounts, "std::ostream&, const string&, const string&");
+ }
+ ~format_accounts() throw() {
+ TRACE_DTOR(format_accounts);
+ }
+
+ virtual void flush() {
+ output_stream.flush();
+ }
+
+ virtual void operator()(account_t& account);
+};
+
+class format_equity : public item_handler<account_t>
+{
+ std::ostream& output_stream;
+ format_t first_line_format;
+ format_t next_lines_format;
+
+ item_predicate<account_t> disp_pred;
+
+ mutable value_t total;
+
+ public:
+ format_equity(std::ostream& _output_stream,
+ const string& _format,
+ const string& display_predicate);
+
+ virtual void flush();
+ virtual void operator()(account_t& account);
+};
+
} // namespace ledger
#endif // _REPORT_H
diff --git a/xml.h b/xml.h
index fec25c85..006c3a2b 100644
--- a/xml.h
+++ b/xml.h
@@ -2,7 +2,7 @@
#define _XML_H
#include "journal.h"
-#include "format.h"
+#include "report.h"
namespace ledger {