diff options
Diffstat (limited to 'format.cc')
-rw-r--r-- | format.cc | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/format.cc b/format.cc new file mode 100644 index 00000000..a68852af --- /dev/null +++ b/format.cc @@ -0,0 +1,195 @@ +#include "format.h" + +namespace ledger { + +std::string truncated(const std::string& str, unsigned int width) +{ + char buf[256]; + std::memset(buf, '\0', 255); + assert(width < 256); + std::strncpy(buf, str.c_str(), str.length()); + if (buf[width]) + std::strcpy(&buf[width - 2], ".."); + return buf; +} + +std::string maximal_account_name(const item_t * item, + const item_t * parent) +{ + std::string name = item->account->name; + for (const item_t * i = item->parent; + i && i->account && i != parent; + i = i->parent) + name = i->account->name + ":" + name; + return name; +} + +std::string format_string(const item_t * item, const format_t& format, + const item_t * displayed_parent) +{ + std::string result; + + for (const char * p = format.format_string.c_str(); *p; p++) { + if (*p == '%') { + bool leftalign = false; + bool ignore = false; + int width = 0; + int strict_width = 0; + + ++p; + if (*p == '?') { + ignore = false; //subsequent_line; + ++p; + } + + if (*p == '-') { + leftalign = true; + ++p; + } + + std::string num; + while (*p && std::isdigit(*p)) + num += *p++; + if (! num.empty()) + width = std::atol(num.c_str()); + + if (*p == '.') { + ++p; + num = ""; + while (*p && std::isdigit(*p)) + num += *p++; + if (! num.empty()) { + strict_width = std::atol(num.c_str()); + if (width == 0) + width = strict_width; + } + } + + std::ostringstream out; + + if (leftalign) + out << std::left; + else + out << std::right; + + if (width > 0) + out.width(width); + + if (ignore) { + out << " "; + result += out.str(); + continue; + } + + switch (*p) { + case '%': + out << "%"; + break; + + case '(': { + ++p; + num = ""; + while (*p && *p != ')') + num += *p++; + assert(*p == ')'); + + node_t * style = parse_expr(num, NULL); + balance_t value = style->compute(format.begin(), format.end(), item); + value.write(out, width, strict_width > 0 ? strict_width : width); + break; + } + + case '[': { + ++p; + num = ""; + while (*p && *p != ']') + num += *p++; + assert(*p == ']'); + + if (item->date != -1) { + char buf[256]; + std::strftime(buf, 255, num.c_str(), std::gmtime(&item->date)); + out << (strict_width == 0 ? buf : truncated(buf, strict_width)); + } else { + out << " "; + } + break; + } + + case 'd': { + if (item->date != -1) { + char buf[32]; + std::strftime(buf, 31, "%Y/%m/%d", std::gmtime(&item->date)); + out << (strict_width == 0 ? buf : truncated(buf, strict_width)); + } else { + out << " "; + } + break; + } + + case 'p': + out << (strict_width == 0 ? + item->payee : truncated(item->payee, strict_width)); + break; + + case 'n': + if (item->account) { + std::string name = maximal_account_name(item, displayed_parent); + out << (strict_width == 0 ? name : truncated(name, strict_width)); + } else { + out << " "; + } + break; + + case 'N': + if (item->account) + out << (strict_width == 0 ? + item->account->fullname() : + truncated(item->account->fullname(), strict_width)); + else + out << " "; + break; + + case 't': + if (format.value_style) { + balance_t value = format.compute_value(item); + value.write(out, width, strict_width > 0 ? strict_width : width); + } + break; + + case 'T': + if (format.total_style) { + balance_t value = format.compute_total(item); + value.write(out, width, strict_width > 0 ? strict_width : width); + } + break; + + case '_': { + int depth = 0; + for (const item_t * i = item; i->parent; i = i->parent) + depth++; + + for (const item_t * i = item->parent; + i && i->account && i != displayed_parent; + i = i->parent) + depth--; + + while (--depth >= 0) { + if (width > 0 || strict_width > 0) + out.width(width > strict_width ? width : strict_width); + out << " "; + } + break; + } + } + + result += out.str(); + } else { + result += *p; + } + } + + return result; +} + +} // namespace ledger |