184 lines
3.6 KiB
C++
184 lines
3.6 KiB
C++
#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_t::report_line(const item_t * item,
|
|
const item_t * displayed_parent) const
|
|
{
|
|
std::string result;
|
|
|
|
for (const char * p = format_string.c_str(); *p; p++) {
|
|
if (*p == '%') {
|
|
bool leftalign = false;
|
|
int width = 0;
|
|
int strict_width = 0;
|
|
|
|
++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);
|
|
|
|
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(item);
|
|
value.write(out, width, strict_width > 0 ? strict_width : width);
|
|
delete style;
|
|
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 (value_style) {
|
|
balance_t value = compute_value(item);
|
|
value.write(out, width, strict_width > 0 ? strict_width : width);
|
|
}
|
|
break;
|
|
|
|
case 'T':
|
|
if (total_style) {
|
|
balance_t value = 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
|