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 {
|
namespace ledger {
|
||||||
|
|
||||||
format_t::elision_style_t format_t::elision_style = ABBREVIATE;
|
format_t::elision_style_t
|
||||||
int format_t::abbrev_length = 2;
|
format_t::elision_style = ABBREVIATE;
|
||||||
|
int format_t::abbrev_length = 2;
|
||||||
|
|
||||||
bool format_t::ansi_codes = false;
|
bool format_t::ansi_codes = false;
|
||||||
bool format_t::ansi_invert = false;
|
bool format_t::ansi_invert = false;
|
||||||
|
|
||||||
string format_t::truncate(const string& str, unsigned int width,
|
namespace {
|
||||||
const bool is_account)
|
string partial_account_name(const account_t& account)
|
||||||
{
|
{
|
||||||
const unsigned int len = str.length();
|
string name;
|
||||||
if (len <= width)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
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];
|
if (name.empty())
|
||||||
|
name = acct->name;
|
||||||
switch (elision_style) {
|
else
|
||||||
case TRUNCATE_LEADING:
|
name = acct->name + ":" + name;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
// fall through...
|
|
||||||
|
|
||||||
case TRUNCATE_TRAILING:
|
return name;
|
||||||
// This method truncates at the end (the default).
|
|
||||||
std::strncpy(buf, str.c_str(), width - 2);
|
|
||||||
buf[width - 2] = '.';
|
|
||||||
buf[width - 1] = '.';
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
buf[width] = '\0';
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string partial_account_name(const account_t& account)
|
format_t::element_t * format_t::parse_elements(const string& fmt)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
std::auto_ptr<element_t> result;
|
std::auto_ptr<element_t> result;
|
||||||
|
|
||||||
|
|
@ -137,8 +54,8 @@ element_t * format_t::parse_elements(const string& fmt)
|
||||||
result.reset(new element_t);
|
result.reset(new element_t);
|
||||||
current = result.get();
|
current = result.get();
|
||||||
} else {
|
} else {
|
||||||
current->next = new element_t;
|
current->next.reset(new element_t);
|
||||||
current = current->next;
|
current = current->next.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q != buf) {
|
if (q != buf) {
|
||||||
|
|
@ -146,8 +63,8 @@ element_t * format_t::parse_elements(const string& fmt)
|
||||||
current->chars = string(buf, q);
|
current->chars = string(buf, q);
|
||||||
q = buf;
|
q = buf;
|
||||||
|
|
||||||
current->next = new element_t;
|
current->next.reset(new element_t);
|
||||||
current = current->next;
|
current = current->next.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == '\\') {
|
if (*p == '\\') {
|
||||||
|
|
@ -202,46 +119,17 @@ element_t * format_t::parse_elements(const string& fmt)
|
||||||
current->chars = "%";
|
current->chars = "%";
|
||||||
break;
|
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::VALUE_EXPR;
|
|
||||||
|
|
||||||
assert(! current->val_expr);
|
|
||||||
current->val_expr.parse(string(b, p));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case '[': {
|
case '[': {
|
||||||
++p;
|
std::istringstream str(p);
|
||||||
const char * b = p;
|
current->type = element_t::EXPR;
|
||||||
int depth = 1;
|
current->expr.parse(str);
|
||||||
while (*p) {
|
current->expr.set_text(string(p, p + str.tellg()));
|
||||||
if (*p == ']' && --depth == 0)
|
p += str.tellg();
|
||||||
break;
|
|
||||||
else if (*p == '[')
|
|
||||||
++depth;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (*p != ']')
|
|
||||||
throw format_error("Missing ']'");
|
|
||||||
|
|
||||||
current->type = element_t::DATE_STRING;
|
|
||||||
current->chars = string(b, p);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
case 'x':
|
case 'x':
|
||||||
switch (*++p) {
|
switch (*++p) {
|
||||||
case 'B': current->type = element_t::XACT_BEG_POS; break;
|
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 'n': current->type = element_t::OPT_NOTE; break;
|
||||||
case '|': current->type = element_t::SPACER; break;
|
case '|': current->type = element_t::SPACER; break;
|
||||||
case '_': current->type = element_t::DEPTH_SPACER; break;
|
case '_': current->type = element_t::DEPTH_SPACER; break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
END:
|
END:
|
||||||
|
#endif
|
||||||
if (q != buf) {
|
if (q != buf) {
|
||||||
if (! result.get()) {
|
if (! result.get()) {
|
||||||
result.reset(new element_t);
|
result.reset(new element_t);
|
||||||
current = result.get();
|
current = result.get();
|
||||||
} else {
|
} else {
|
||||||
current->next = new element_t;
|
current->next.reset(new element_t);
|
||||||
current = current->next;
|
current = current->next.get();
|
||||||
}
|
}
|
||||||
current->type = element_t::STRING;
|
current->type = element_t::STRING;
|
||||||
current->chars = string(buf, q);
|
current->chars = string(buf, q);
|
||||||
|
|
@ -301,20 +192,6 @@ element_t * format_t::parse_elements(const string& fmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
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) {
|
inline void mark_plain(std::ostream& out) {
|
||||||
out << "\e[0m";
|
out << "\e[0m";
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +199,7 @@ namespace {
|
||||||
|
|
||||||
void format_t::format(std::ostream& out_str, scope_t& scope) const
|
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;
|
std::ostringstream out;
|
||||||
string name;
|
string name;
|
||||||
bool ignore_max_width = false;
|
bool ignore_max_width = false;
|
||||||
|
|
@ -340,10 +217,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
|
||||||
out << elem->chars;
|
out << elem->chars;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case element_t::AMOUNT:
|
case element_t::EXPR:
|
||||||
out << scope.resolve("amount");
|
out << elem->expr.calc(scope);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if 0
|
||||||
case element_t::ACCOUNT_FULLNAME:
|
case element_t::ACCOUNT_FULLNAME:
|
||||||
scope.resolve("account").dump(out, elem->min_width);
|
scope.resolve("account").dump(out, elem->min_width);
|
||||||
break;
|
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);
|
scope.resolve("account_base").dump(out, elem->min_width);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case element_t::AMOUNT:
|
||||||
|
out << "a";
|
||||||
|
//out << scope.resolve("amount");
|
||||||
|
break;
|
||||||
case element_t::TOTAL:
|
case element_t::TOTAL:
|
||||||
out << "T";
|
out << "T";
|
||||||
//out << scope.resolve("total");
|
//out << scope.resolve("total");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0
|
|
||||||
case element_t::VALUE_EXPR: {
|
case element_t::VALUE_EXPR: {
|
||||||
expr_t * calc;
|
expr_t * calc;
|
||||||
switch (elem->type) {
|
switch (elem->type) {
|
||||||
|
|
@ -579,13 +460,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
|
||||||
if (details.xact)
|
if (details.xact)
|
||||||
out << details.xact->end_line;
|
out << details.xact->end_line;
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case element_t::DATE_STRING:
|
case element_t::DATE_STRING:
|
||||||
out << format_datetime(scope.resolve("date").as_datetime());
|
out << format_datetime(scope.resolve("date").as_datetime());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0
|
|
||||||
case element_t::COMPLETE_DATE_STRING: {
|
case element_t::COMPLETE_DATE_STRING: {
|
||||||
datetime_t actual_date;
|
datetime_t actual_date;
|
||||||
datetime_t effective_date;
|
datetime_t effective_date;
|
||||||
|
|
@ -670,13 +549,11 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
|
||||||
out << temp;
|
out << temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
case element_t::PAYEE:
|
case element_t::PAYEE:
|
||||||
scope.resolve("payee").dump(out, elem->min_width);
|
scope.resolve("payee").dump(out, elem->min_width);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0
|
|
||||||
case element_t::OPT_NOTE:
|
case element_t::OPT_NOTE:
|
||||||
if (details.xact && details.xact->note)
|
if (details.xact && details.xact->note)
|
||||||
out << " ; ";
|
out << " ; ";
|
||||||
|
|
@ -731,12 +608,10 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endif
|
|
||||||
case element_t::SPACER:
|
case element_t::SPACER:
|
||||||
out << " ";
|
out << " ";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0
|
|
||||||
case element_t::DEPTH_SPACER:
|
case element_t::DEPTH_SPACER:
|
||||||
for (const account_t * acct = details.account;
|
for (const account_t * acct = details.account;
|
||||||
acct;
|
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,
|
string format_t::truncate(const string& str, unsigned int width,
|
||||||
const string& format)
|
const bool is_account)
|
||||||
: output_stream(_output_stream), last_entry(NULL), last_xact(NULL)
|
|
||||||
{
|
{
|
||||||
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();
|
assert(width < 4095);
|
||||||
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)
|
char buf[4096];
|
||||||
{
|
|
||||||
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;
|
switch (elision_style) {
|
||||||
last_xact = &xact;
|
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()
|
case TRUNCATE_MIDDLE:
|
||||||
{
|
// This method truncates in the middle.
|
||||||
#if 0
|
std::strncpy(buf, str.c_str(), width / 2);
|
||||||
bool first = true;
|
std::strncpy(buf + width / 2,
|
||||||
foreach (const transaction_t * xact, last_entry->xacts) {
|
str.c_str() + (len - (width / 2 + width % 2)),
|
||||||
if (xact_has_xdata(*xact) &&
|
width / 2 + width % 2);
|
||||||
xact_xdata_(*xact).dflags & XACT_TO_DISPLAY) {
|
buf[width / 2 - 1] = '.';
|
||||||
if (first) {
|
buf[width / 2] = '.';
|
||||||
first_line_format.format(output_stream, details_t(*xact));
|
break;
|
||||||
first = false;
|
|
||||||
} else {
|
case ABBREVIATE:
|
||||||
next_lines_format.format(output_stream, details_t(*xact));
|
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)
|
if (newlen > width) {
|
||||||
{
|
// Even abbreviated its too big to show the last account, so
|
||||||
xact_xdata(xact).dflags |= XACT_TO_DISPLAY;
|
// abbreviate all but the last and truncate at the beginning.
|
||||||
|
std::strncpy(buf, result.c_str() + (result.length() - width), width);
|
||||||
if (last_entry && xact.entry != last_entry)
|
buf[0] = '.';
|
||||||
format_last_entry();
|
buf[1] = '.';
|
||||||
|
} else {
|
||||||
last_entry = xact.entry;
|
std::strcpy(buf, result.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
to_show = pair.second;
|
// fall through...
|
||||||
counted++;
|
|
||||||
|
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;
|
return buf;
|
||||||
}
|
|
||||||
|
|
||||||
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
|
} // namespace ledger
|
||||||
|
|
|
||||||
238
format.h
238
format.h
|
|
@ -7,71 +7,58 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
string truncated(const string& str, unsigned int width,
|
DECLARE_EXCEPTION(format_error, std::runtime_error);
|
||||||
const int style = 2);
|
|
||||||
|
|
||||||
string partial_account_name(const account_t& account,
|
|
||||||
const unsigned int start_depth);
|
|
||||||
|
|
||||||
|
class format_t : public noncopyable
|
||||||
|
{
|
||||||
|
struct element_t : public noncopyable
|
||||||
|
{
|
||||||
#define ELEMENT_ALIGN_LEFT 0x01
|
#define ELEMENT_ALIGN_LEFT 0x01
|
||||||
#define ELEMENT_HIGHLIGHT 0x02
|
#define ELEMENT_HIGHLIGHT 0x02
|
||||||
|
|
||||||
struct element_t : public noncopyable
|
enum kind_t {
|
||||||
{
|
STRING,
|
||||||
enum kind_t {
|
EXPR,
|
||||||
STRING,
|
#if 0
|
||||||
VALUE_EXPR,
|
SPACER,
|
||||||
SOURCE,
|
DEPTH_SPACER
|
||||||
ENTRY_BEG_POS,
|
#endif
|
||||||
ENTRY_BEG_LINE,
|
};
|
||||||
ENTRY_END_POS,
|
|
||||||
ENTRY_END_LINE,
|
kind_t type;
|
||||||
XACT_BEG_POS,
|
unsigned char flags;
|
||||||
XACT_BEG_LINE,
|
unsigned char min_width;
|
||||||
XACT_END_POS,
|
unsigned char max_width;
|
||||||
XACT_END_LINE,
|
string chars;
|
||||||
DATE_STRING,
|
expr_t expr;
|
||||||
COMPLETE_DATE_STRING,
|
|
||||||
CLEARED,
|
scoped_ptr<struct element_t> next;
|
||||||
ENTRY_CLEARED,
|
|
||||||
CODE,
|
element_t()
|
||||||
PAYEE,
|
: type(STRING), flags(false), min_width(0), max_width(0) {
|
||||||
OPT_ACCOUNT,
|
TRACE_CTOR(element_t, "");
|
||||||
ACCOUNT_NAME,
|
}
|
||||||
ACCOUNT_FULLNAME,
|
~element_t() {
|
||||||
AMOUNT,
|
TRACE_DTOR(element_t);
|
||||||
OPT_AMOUNT,
|
}
|
||||||
TOTAL,
|
|
||||||
NOTE,
|
friend inline void mark_red(std::ostream& out, const element_t * elem) {
|
||||||
OPT_NOTE,
|
out.setf(std::ios::left);
|
||||||
SPACER,
|
out.width(0);
|
||||||
DEPTH_SPACER
|
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;
|
string format_string;
|
||||||
unsigned char flags;
|
scoped_ptr<element_t> elements;
|
||||||
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;
|
|
||||||
|
|
||||||
enum elision_style_t {
|
enum elision_style_t {
|
||||||
TRUNCATE_TRAILING,
|
TRUNCATE_TRAILING,
|
||||||
|
|
@ -81,146 +68,37 @@ struct format_t : public noncopyable
|
||||||
};
|
};
|
||||||
|
|
||||||
static elision_style_t elision_style;
|
static elision_style_t elision_style;
|
||||||
static int abbrev_length;
|
static int abbrev_length;
|
||||||
|
|
||||||
static bool ansi_codes;
|
static bool ansi_codes;
|
||||||
static bool ansi_invert;
|
static bool ansi_invert;
|
||||||
|
|
||||||
format_t() : elements(NULL) {
|
public:
|
||||||
|
format_t() {
|
||||||
TRACE_CTOR(format_t, "");
|
TRACE_CTOR(format_t, "");
|
||||||
}
|
}
|
||||||
format_t(const string& _format) : elements(NULL) {
|
format_t(const string& _format) {
|
||||||
TRACE_CTOR(format_t, "const string&");
|
TRACE_CTOR(format_t, "const string&");
|
||||||
reset(_format);
|
parse(_format);
|
||||||
}
|
}
|
||||||
~format_t() {
|
~format_t() {
|
||||||
TRACE_DTOR(format_t);
|
TRACE_DTOR(format_t);
|
||||||
if (elements) checked_delete(elements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset(const string& _format) {
|
void parse(const string& _format) {
|
||||||
if (elements)
|
elements.reset(parse_elements(_format));
|
||||||
checked_delete(elements);
|
|
||||||
elements = parse_elements(_format);
|
|
||||||
format_string = _format;
|
format_string = _format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void format(std::ostream& out, scope_t& scope) const;
|
||||||
|
|
||||||
|
private:
|
||||||
static element_t * parse_elements(const string& fmt);
|
static element_t * parse_elements(const string& fmt);
|
||||||
|
|
||||||
static string truncate(const string& str, unsigned int width,
|
static string truncate(const string& str, unsigned int width,
|
||||||
const bool is_account = false);
|
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
|
} // namespace ledger
|
||||||
|
|
||||||
#endif // _FORMAT_H
|
#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
|
// Add the new entry (what gnucash calls a 'xact') to the
|
||||||
// journal
|
// journal
|
||||||
if (! curr_journal->add_entry(curr_entry)) {
|
if (! curr_journal->add_entry(curr_entry)) {
|
||||||
|
#if 0
|
||||||
print_entry(std::cerr, *curr_entry);
|
print_entry(std::cerr, *curr_entry);
|
||||||
|
#endif
|
||||||
have_error = "The above entry does not balance";
|
have_error = "The above entry does not balance";
|
||||||
checked_delete(curr_entry);
|
checked_delete(curr_entry);
|
||||||
} else {
|
} 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);
|
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
|
} // namespace ledger
|
||||||
|
|
|
||||||
117
report.h
117
report.h
|
|
@ -33,6 +33,7 @@
|
||||||
#define _REPORT_H
|
#define _REPORT_H
|
||||||
|
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
#include "format.h"
|
||||||
#include "walk.h"
|
#include "walk.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
@ -207,9 +208,7 @@ public:
|
||||||
//
|
//
|
||||||
|
|
||||||
void eval(const string& expr) {
|
void eval(const string& expr) {
|
||||||
#if 0
|
expr_t(expr).calc(*this);
|
||||||
expr(expr).compile((xml::document_t *)NULL, this);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
value_t option_eval(call_scope_t& args) {
|
value_t option_eval(call_scope_t& args) {
|
||||||
eval(args[0].as_string());
|
eval(args[0].as_string());
|
||||||
|
|
@ -230,12 +229,12 @@ public:
|
||||||
return NULL_VALUE;
|
return NULL_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t option_raw(call_scope_t& args) {
|
value_t option_raw(call_scope_t&) {
|
||||||
raw_mode = true;
|
raw_mode = true;
|
||||||
return NULL_VALUE;
|
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;
|
std::cout << "This is foo" << std::endl;
|
||||||
return NULL_VALUE;
|
return NULL_VALUE;
|
||||||
}
|
}
|
||||||
|
|
@ -302,6 +301,114 @@ public:
|
||||||
string abbrev(const string& str, unsigned int width,
|
string abbrev(const string& str, unsigned int width,
|
||||||
const bool is_account);
|
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
|
} // namespace ledger
|
||||||
|
|
||||||
#endif // _REPORT_H
|
#endif // _REPORT_H
|
||||||
|
|
|
||||||
2
xml.h
2
xml.h
|
|
@ -2,7 +2,7 @@
|
||||||
#define _XML_H
|
#define _XML_H
|
||||||
|
|
||||||
#include "journal.h"
|
#include "journal.h"
|
||||||
#include "format.h"
|
#include "report.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue