summaryrefslogtreecommitdiff
path: root/format.cc
diff options
context:
space:
mode:
Diffstat (limited to 'format.cc')
-rw-r--r--format.cc195
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