Simplified the format_t code so that it no longer references any particulars
about journal objects. This is all done through value expressions now.
This commit is contained in:
parent
e5048ec71b
commit
567902b173
6 changed files with 550 additions and 600 deletions
532
format.cc
532
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;
|
||||
namespace {
|
||||
string partial_account_name(const account_t& account)
|
||||
{
|
||||
string name;
|
||||
|
||||
assert(width < 4095);
|
||||
for (const account_t * acct = &account;
|
||||
acct && acct->parent;
|
||||
acct = acct->parent) {
|
||||
if (account_has_xdata(*acct) &&
|
||||
account_xdata_(*acct).dflags & ACCOUNT_DISPLAYED)
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (newlen > width) {
|
||||
result += string(*i, 0, abbrev_length);
|
||||
result += ":";
|
||||
newlen -= (*i).length() - abbrev_length;
|
||||
} else {
|
||||
result += *i;
|
||||
result += ":";
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
string format_t::truncate(const string& str, unsigned int width,
|
||||
const bool is_account)
|
||||
{
|
||||
TRACE_CTOR(format_xacts, "std::ostream&, const string&");
|
||||
const unsigned int len = str.length();
|
||||
if (len <= width)
|
||||
return str;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
assert(width < 4095);
|
||||
|
||||
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);
|
||||
}
|
||||
char buf[4096];
|
||||
|
||||
xact_xdata(xact).dflags |= XACT_DISPLAYED;
|
||||
last_xact = &xact;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
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));
|
||||
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;
|
||||
}
|
||||
|
||||
if (newlen > width) {
|
||||
result += string(*i, 0, abbrev_length);
|
||||
result += ":";
|
||||
newlen -= (*i).length() - abbrev_length;
|
||||
} else {
|
||||
result += *i;
|
||||
result += ":";
|
||||
}
|
||||
}
|
||||
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;
|
||||
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++;
|
||||
// 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;
|
||||
}
|
||||
#endif
|
||||
buf[width] = '\0';
|
||||
|
||||
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
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
238
format.h
238
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);
|
||||
}
|
||||
|
||||
friend 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);
|
||||
}
|
||||
};
|
||||
|
||||
kind_t type;
|
||||
unsigned char flags;
|
||||
string chars;
|
||||
unsigned char min_width;
|
||||
unsigned char max_width;
|
||||
expr_t val_expr;
|
||||
|
||||
struct element_t * next;
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
259
report.cc
259
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
|
||||
|
|
|
|||
117
report.h
117
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
|
||||
|
|
|
|||
2
xml.h
2
xml.h
|
|
@ -2,7 +2,7 @@
|
|||
#define _XML_H
|
||||
|
||||
#include "journal.h"
|
||||
#include "format.h"
|
||||
#include "report.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue