several significant speed improvements (removed excessive copying of strings)
This commit is contained in:
parent
9e235d04a1
commit
325cf53ea7
8 changed files with 86 additions and 118 deletions
6
Makefile
6
Makefile
|
|
@ -42,12 +42,6 @@ all: make.deps ledger
|
||||||
|
|
||||||
docs: ledger.info ledger.pdf
|
docs: ledger.info ledger.pdf
|
||||||
|
|
||||||
install:
|
|
||||||
make clean
|
|
||||||
make DFLAGS="-O3 -fomit-frame-pointer"
|
|
||||||
cp ledger $(HOME)/bin
|
|
||||||
strip $(HOME)/bin/ledger
|
|
||||||
|
|
||||||
libledger.a: $(OBJS)
|
libledger.a: $(OBJS)
|
||||||
ar rv $@ $?
|
ar rv $@ $?
|
||||||
ranlib $@
|
ranlib $@
|
||||||
|
|
|
||||||
38
amount.cc
38
amount.cc
|
|
@ -1,6 +1,5 @@
|
||||||
#include "amount.h"
|
#include "ledger.h"
|
||||||
|
#include "util.h"
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "gmp.h"
|
#include "gmp.h"
|
||||||
|
|
||||||
|
|
@ -585,43 +584,30 @@ static inline char peek_next_nonws(std::istream& in)
|
||||||
|
|
||||||
void parse_quantity(std::istream& in, std::string& value)
|
void parse_quantity(std::istream& in, std::string& value)
|
||||||
{
|
{
|
||||||
|
static char buf[256];
|
||||||
char c = peek_next_nonws(in);
|
char c = peek_next_nonws(in);
|
||||||
while (std::isdigit(c) || c == '-' || c == '.' || c == ',') {
|
READ_INTO(in, buf, 256, c,
|
||||||
in.get(c);
|
std::isdigit(c) || c == '-' || c == '.' || c == ',');
|
||||||
if (in.eof())
|
value = buf;
|
||||||
break;
|
|
||||||
value += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_commodity(std::istream& in, std::string& symbol)
|
void parse_commodity(std::istream& in, std::string& symbol)
|
||||||
{
|
{
|
||||||
|
static char buf[256];
|
||||||
|
|
||||||
char c = peek_next_nonws(in);
|
char c = peek_next_nonws(in);
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
c = in.peek();
|
READ_INTO(in, buf, 256, c, c != '"');
|
||||||
while (! in.eof() && c != '"') {
|
|
||||||
in.get(c);
|
|
||||||
if (c == '\\')
|
|
||||||
in.get(c);
|
|
||||||
symbol += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"')
|
if (c == '"')
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
assert(0);
|
assert(0);
|
||||||
} else {
|
} else {
|
||||||
while (! std::isspace(c) && ! std::isdigit(c) && c != '-' && c != '.') {
|
READ_INTO(in, buf, 256, c, ! std::isspace(c) && ! std::isdigit(c) &&
|
||||||
in.get(c);
|
c != '-' && c != '.');
|
||||||
if (in.eof())
|
|
||||||
break;
|
|
||||||
symbol += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
symbol = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void amount_t::parse(std::istream& in)
|
void amount_t::parse(std::istream& in)
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,6 @@ config_t::config_t()
|
||||||
{
|
{
|
||||||
if (const char * p = std::getenv("HOME"))
|
if (const char * p = std::getenv("HOME"))
|
||||||
init_file = cache_file = price_db = p;
|
init_file = cache_file = price_db = p;
|
||||||
else
|
|
||||||
init_file = cache_file = price_db = "";
|
|
||||||
|
|
||||||
init_file += "/.ledgerrc";
|
init_file += "/.ledgerrc";
|
||||||
cache_file += "/.ledger";
|
cache_file += "/.ledger";
|
||||||
|
|
|
||||||
59
format.cc
59
format.cc
|
|
@ -47,7 +47,9 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
{
|
{
|
||||||
element_t * result = NULL;
|
element_t * result = NULL;
|
||||||
element_t * current = NULL;
|
element_t * current = NULL;
|
||||||
std::string str;
|
|
||||||
|
static char buf[1024];
|
||||||
|
char * q = buf;
|
||||||
|
|
||||||
for (const char * p = fmt.c_str(); *p; p++) {
|
for (const char * p = fmt.c_str(); *p; p++) {
|
||||||
if (*p == '%') {
|
if (*p == '%') {
|
||||||
|
|
@ -58,10 +60,10 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! str.empty()) {
|
if (q != buf) {
|
||||||
current->type = element_t::STRING;
|
current->type = element_t::STRING;
|
||||||
current->chars = str;
|
current->chars = std::string(buf, q);
|
||||||
str = "";
|
q = buf;
|
||||||
|
|
||||||
current->next = new element_t;
|
current->next = new element_t;
|
||||||
current = current->next;
|
current = current->next;
|
||||||
|
|
@ -73,22 +75,23 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string num;
|
int num = 0;
|
||||||
while (*p && std::isdigit(*p))
|
while (*p && std::isdigit(*p)) {
|
||||||
num += *p++;
|
num *= 10;
|
||||||
if (! num.empty())
|
num += *p++ - '0';
|
||||||
current->min_width = std::atol(num.c_str());
|
}
|
||||||
|
current->min_width = num;
|
||||||
|
|
||||||
if (*p == '.') {
|
if (*p == '.') {
|
||||||
++p;
|
++p;
|
||||||
num = "";
|
num = 0;
|
||||||
while (*p && std::isdigit(*p))
|
while (*p && std::isdigit(*p)) {
|
||||||
num += *p++;
|
num *= 10;
|
||||||
if (! num.empty()) {
|
num += *p++ - '0';
|
||||||
current->max_width = std::atol(num.c_str());
|
|
||||||
if (current->min_width == 0)
|
|
||||||
current->min_width = current->max_width;
|
|
||||||
}
|
}
|
||||||
|
current->max_width = num;
|
||||||
|
if (current->min_width == 0)
|
||||||
|
current->min_width = current->max_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
|
|
@ -97,29 +100,31 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
current->chars = "%";
|
current->chars = "%";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '(':
|
case '(': {
|
||||||
++p;
|
++p;
|
||||||
num = "";
|
const char * b = p;
|
||||||
while (*p && *p != ')')
|
while (*p && *p != ')')
|
||||||
num += *p++;
|
p++;
|
||||||
if (*p != ')')
|
if (*p != ')')
|
||||||
throw format_error("Missing ')'");
|
throw format_error("Missing ')'");
|
||||||
|
|
||||||
current->type = element_t::VALUE_EXPR;
|
current->type = element_t::VALUE_EXPR;
|
||||||
current->val_expr = parse_value_expr(num);
|
current->val_expr = parse_value_expr(std::string(b, p));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case '[':
|
case '[': {
|
||||||
++p;
|
++p;
|
||||||
num = "";
|
const char * b = p;
|
||||||
while (*p && *p != ']')
|
while (*p && *p != ']')
|
||||||
num += *p++;
|
p++;
|
||||||
if (*p != ']')
|
if (*p != ']')
|
||||||
throw format_error("Missing ']'");
|
throw format_error("Missing ']'");
|
||||||
|
|
||||||
current->type = element_t::DATE_STRING;
|
current->type = element_t::DATE_STRING;
|
||||||
current->chars = num;
|
current->chars = std::string(b, p);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
current->type = element_t::DATE_STRING;
|
current->type = element_t::DATE_STRING;
|
||||||
|
|
@ -137,11 +142,11 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
case '_': current->type = element_t::SPACER; break;
|
case '_': current->type = element_t::SPACER; break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
str += *p;
|
*q++ = *p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! str.empty()) {
|
if (q != buf) {
|
||||||
if (! result) {
|
if (! result) {
|
||||||
current = result = new element_t;
|
current = result = new element_t;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -149,7 +154,7 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
current->type = element_t::STRING;
|
current->type = element_t::STRING;
|
||||||
current->chars = str;
|
current->chars = std::string(buf, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
21
option.cc
21
option.cc
|
|
@ -1,4 +1,5 @@
|
||||||
#include "option.h"
|
#include "option.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
|
@ -9,11 +10,16 @@ option_handler::option_handler(const std::string& label,
|
||||||
{
|
{
|
||||||
option_t opt;
|
option_t opt;
|
||||||
|
|
||||||
|
static char buf[128];
|
||||||
|
char * p = buf;
|
||||||
for (const char * q = label.c_str(); *q; q++)
|
for (const char * q = label.c_str(); *q; q++)
|
||||||
if (*q == '_')
|
if (*q == '_')
|
||||||
opt.long_opt += '-';
|
*p++ = '-';
|
||||||
else
|
else
|
||||||
opt.long_opt += *q;
|
*p++ = *q;
|
||||||
|
assert(p < buf + 127);
|
||||||
|
*p = '\0';
|
||||||
|
opt.long_opt = buf;
|
||||||
|
|
||||||
handlers.insert(option_handler_pair(opt.long_opt, this));
|
handlers.insert(option_handler_pair(opt.long_opt, this));
|
||||||
|
|
||||||
|
|
@ -130,15 +136,18 @@ void process_environment(char ** envp, const std::string& tag)
|
||||||
{
|
{
|
||||||
for (char ** p = envp; *p; p++)
|
for (char ** p = envp; *p; p++)
|
||||||
if (std::strncmp(*p, tag.c_str(), 7) == 0) {
|
if (std::strncmp(*p, tag.c_str(), 7) == 0) {
|
||||||
std::string opt;
|
|
||||||
char * q;
|
char * q;
|
||||||
|
static char buf[128];
|
||||||
|
char * r = buf;
|
||||||
for (q = *p + 7; *q && *q != '='; q++)
|
for (q = *p + 7; *q && *q != '='; q++)
|
||||||
if (*q == '_')
|
if (*q == '_')
|
||||||
opt += '-';
|
*r++ += '-';
|
||||||
else
|
else
|
||||||
opt += std::tolower(*q);
|
*r++ += std::tolower(*q);
|
||||||
|
assert(r < buf + 127);
|
||||||
|
*r = '\0';
|
||||||
|
|
||||||
if (*q == '=')
|
if (*q == '=')
|
||||||
process_option(opt, q + 1);
|
process_option(buf, q + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -385,13 +385,12 @@ unsigned int parse_textual_journal(std::istream& in, journal_t * journal,
|
||||||
in >> c;
|
in >> c;
|
||||||
in >> date;
|
in >> date;
|
||||||
in >> time;
|
in >> time;
|
||||||
|
date += " ";
|
||||||
|
date += time;
|
||||||
|
|
||||||
in.getline(line, MAX_LINE);
|
in.getline(line, MAX_LINE);
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
date += " ";
|
|
||||||
date += time;
|
|
||||||
|
|
||||||
struct std::tm when;
|
struct std::tm when;
|
||||||
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
|
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
|
||||||
entry_t * curr = new entry_t;
|
entry_t * curr = new entry_t;
|
||||||
|
|
|
||||||
71
valexpr.cc
71
valexpr.cc
|
|
@ -1,6 +1,8 @@
|
||||||
#include "valexpr.h"
|
#include "valexpr.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "datetime.h"
|
#include "datetime.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -344,32 +346,20 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
|
|
||||||
char c = peek_next_nonws(in);
|
char c = peek_next_nonws(in);
|
||||||
if (std::isdigit(c) || c == '.' || c == '{') {
|
if (std::isdigit(c) || c == '.' || c == '{') {
|
||||||
std::string ident;
|
static char buf[2048];
|
||||||
|
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
c = in.peek();
|
READ_INTO(in, buf, 2048, c, c != '}');
|
||||||
while (! in.eof() && c != '}') {
|
|
||||||
in.get(c);
|
|
||||||
ident += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
throw value_expr_error("Missing '}'");
|
throw value_expr_error("Missing '}'");
|
||||||
} else {
|
} else {
|
||||||
while (! in.eof() && std::isdigit(c) || c == '.') {
|
READ_INTO(in, buf, 2048, c, std::isdigit(c) || c == '.');
|
||||||
in.get(c);
|
|
||||||
ident += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! ident.empty()) {
|
node = new value_expr_t(value_expr_t::CONSTANT_A);
|
||||||
node = new value_expr_t(value_expr_t::CONSTANT_A);
|
node->constant_a.parse(buf);
|
||||||
node->constant_a.parse(ident);
|
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,7 +433,6 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
case '/': {
|
case '/': {
|
||||||
std::string ident;
|
|
||||||
bool payee_mask = false;
|
bool payee_mask = false;
|
||||||
|
|
||||||
c = peek_next_nonws(in);
|
c = peek_next_nonws(in);
|
||||||
|
|
@ -453,22 +442,15 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
c = in.peek();
|
c = in.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (! in.eof() && c != '/') {
|
static char buf[4096];
|
||||||
in.get(c);
|
READ_INTO(in, buf, 4096, c, c != '/');
|
||||||
if (c == '\\')
|
if (c != '/')
|
||||||
in.get(c);
|
|
||||||
ident += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/') {
|
|
||||||
in.get(c);
|
|
||||||
node = new value_expr_t(payee_mask ?
|
|
||||||
value_expr_t::F_PAYEE_MASK : value_expr_t::F_ACCOUNT_MASK);
|
|
||||||
node->mask = new mask_t(ident);
|
|
||||||
} else {
|
|
||||||
throw value_expr_error("Missing closing '/'");
|
throw value_expr_error("Missing closing '/'");
|
||||||
}
|
|
||||||
|
in.get(c);
|
||||||
|
node = new value_expr_t(payee_mask ? value_expr_t::F_PAYEE_MASK :
|
||||||
|
value_expr_t::F_ACCOUNT_MASK);
|
||||||
|
node->mask = new mask_t(buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -481,22 +463,15 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '[': {
|
case '[': {
|
||||||
std::string ident;
|
static char buf[1024];
|
||||||
|
READ_INTO(in, buf, 1024, c, c != ']');
|
||||||
c = in.peek();
|
if (c != ']')
|
||||||
while (! in.eof() && c != ']') {
|
|
||||||
in.get(c);
|
|
||||||
ident += c;
|
|
||||||
c = in.peek();
|
|
||||||
}
|
|
||||||
if (c == ']') {
|
|
||||||
in.get(c);
|
|
||||||
node = new value_expr_t(value_expr_t::CONSTANT_T);
|
|
||||||
if (! parse_date(ident.c_str(), &node->constant_t))
|
|
||||||
throw value_expr_error("Failed to parse date");
|
|
||||||
} else {
|
|
||||||
throw value_expr_error("Missing ']'");
|
throw value_expr_error("Missing ']'");
|
||||||
}
|
|
||||||
|
in.get(c);
|
||||||
|
node = new value_expr_t(value_expr_t::CONSTANT_T);
|
||||||
|
if (! parse_date(buf, &node->constant_t))
|
||||||
|
throw value_expr_error("Failed to parse date");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,9 +133,11 @@ class item_predicate
|
||||||
predicate = NULL;
|
predicate = NULL;
|
||||||
if (! _predicate.empty()) {
|
if (! _predicate.empty()) {
|
||||||
try {
|
try {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
DEBUG_CLASS("valexpr.predicate.parse");
|
DEBUG_CLASS("valexpr.predicate.parse");
|
||||||
|
|
||||||
DEBUG_PRINT_("parsing: '" << _predicate << "'");
|
DEBUG_PRINT_("parsing: '" << _predicate << "'");
|
||||||
|
#endif
|
||||||
predicate = parse_value_expr(_predicate);
|
predicate = parse_value_expr(_predicate);
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue