Made separate modules for the csv command, since the prior method was
not fully correct.
This commit is contained in:
parent
db0ef2e257
commit
04dfda2282
14 changed files with 200 additions and 61 deletions
|
|
@ -18,6 +18,7 @@ libledger_la_CXXFLAGS =
|
|||
libledger_la_SOURCES = \
|
||||
binary.cc \
|
||||
config.cc \
|
||||
csv.cc \
|
||||
derive.cc \
|
||||
emacs.cc \
|
||||
format.cc \
|
||||
|
|
@ -63,6 +64,7 @@ pkginclude_HEADERS = \
|
|||
\
|
||||
binary.h \
|
||||
config.h \
|
||||
csv.h \
|
||||
derive.h \
|
||||
emacs.h \
|
||||
error.h \
|
||||
|
|
@ -151,11 +153,11 @@ endif
|
|||
alltests.cc: $(TESTSUITES)
|
||||
test -f $(TESTGEN) && python $(TESTGEN) -o $@ --error-printer $(TESTSUITES)
|
||||
|
||||
alltests: alltests.cc
|
||||
alltests: alltests.cc ledger
|
||||
$(CXXCOMPILE) -I$(CXXTEST_DIR) -lexpat -lgmp -lpcre -o $@ \
|
||||
alltests.cc -L. -L.libs -lamounts -lledger
|
||||
|
||||
runtests: alltests ledger
|
||||
runtests: alltests
|
||||
./alltests && tests/regress && tests/regtest
|
||||
|
||||
verify: runtests
|
||||
|
|
|
|||
4
acprep
4
acprep
|
|
@ -19,9 +19,9 @@ autoconf
|
|||
|
||||
INCDIRS="-I/sw/include -I/usr/local/include/boost-1_33 -I/usr/include/httpd/xml"
|
||||
#INCDIRS="$INCDIRS -I/sw/include/libofx"
|
||||
INCDIRS="$INCDIRS -I/sw/include/python2.4"
|
||||
INCDIRS="$INCDIRS -I/usr/include/python2.3"
|
||||
INCDIRS="$INCDIRS -Wno-long-double"
|
||||
LIBDIRS="-L/sw/lib -L/usr/local/lib -L/sw/lib/python2.4/config"
|
||||
LIBDIRS="-L/sw/lib -L/usr/local/lib -L/usr/lib/python2.3/config"
|
||||
|
||||
if [ "$1" = "--debug" ]; then
|
||||
shift 1
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ config_t::config_t()
|
|||
"%32|%-.22A %12.67t %!12.80T\n");
|
||||
wide_register_format = ("%D %-.35P %-.38A %22.108t %!22.132T\n%/"
|
||||
"%48|%-.38A %22.108t %!22.132T\n");
|
||||
csv_register_format = "\"%D\",\"%P\",\"%A\",\"%t\",\"%T\"\n";
|
||||
plot_amount_format = "%D %(@S(@t))\n";
|
||||
plot_total_format = "%D %(@S(@T))\n";
|
||||
print_format = "\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n";
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -21,7 +21,6 @@ class config_t
|
|||
std::string balance_format;
|
||||
std::string register_format;
|
||||
std::string wide_register_format;
|
||||
std::string csv_register_format;
|
||||
std::string plot_amount_format;
|
||||
std::string plot_total_format;
|
||||
std::string print_format;
|
||||
|
|
|
|||
105
csv.cc
Normal file
105
csv.cc
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#include "csv.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
namespace {
|
||||
inline void write_escaped_string(std::ostream& out, const std::string& xact)
|
||||
{
|
||||
out << "\"";
|
||||
for (std::string::const_iterator i = xact.begin(); i != xact.end(); i++)
|
||||
if (*i == '"') {
|
||||
out << "\\";
|
||||
out << "\"";
|
||||
} else {
|
||||
out << *i;
|
||||
}
|
||||
out << "\"";
|
||||
}
|
||||
}
|
||||
|
||||
void format_csv_transactions::operator()(transaction_t& xact)
|
||||
{
|
||||
if (! transaction_has_xdata(xact) ||
|
||||
! (transaction_xdata_(xact).dflags & TRANSACTION_DISPLAYED)) {
|
||||
|
||||
{
|
||||
format_t fmt("%D");
|
||||
std::ostringstream str;
|
||||
fmt.format(str, details_t(xact));
|
||||
write_escaped_string(out, str.str());
|
||||
}
|
||||
out << ',';
|
||||
|
||||
{
|
||||
format_t fmt("%P");
|
||||
std::ostringstream str;
|
||||
fmt.format(str, details_t(xact));
|
||||
write_escaped_string(out, str.str());
|
||||
}
|
||||
out << ',';
|
||||
|
||||
{
|
||||
format_t fmt("%A");
|
||||
std::ostringstream str;
|
||||
fmt.format(str, details_t(xact));
|
||||
write_escaped_string(out, str.str());
|
||||
}
|
||||
out << ',';
|
||||
|
||||
{
|
||||
format_t fmt("%t");
|
||||
std::ostringstream str;
|
||||
fmt.format(str, details_t(xact));
|
||||
write_escaped_string(out, str.str());
|
||||
}
|
||||
out << ',';
|
||||
|
||||
{
|
||||
format_t fmt("%T");
|
||||
std::ostringstream str;
|
||||
fmt.format(str, details_t(xact));
|
||||
write_escaped_string(out, str.str());
|
||||
}
|
||||
out << ',';
|
||||
|
||||
switch (xact.state) {
|
||||
case transaction_t::CLEARED:
|
||||
write_escaped_string(out, "*");
|
||||
break;
|
||||
case transaction_t::PENDING:
|
||||
write_escaped_string(out, "!");
|
||||
break;
|
||||
default: {
|
||||
transaction_t::state_t state;
|
||||
if (xact.entry->get_state(&state))
|
||||
switch (state) {
|
||||
case transaction_t::CLEARED:
|
||||
write_escaped_string(out, "*");
|
||||
break;
|
||||
case transaction_t::PENDING:
|
||||
write_escaped_string(out, "!");
|
||||
break;
|
||||
default:
|
||||
write_escaped_string(out, "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << ',';
|
||||
|
||||
write_escaped_string(out, xact.entry->code);
|
||||
out << ',';
|
||||
|
||||
{
|
||||
format_t fmt("%N");
|
||||
std::ostringstream str;
|
||||
fmt.format(str, details_t(xact));
|
||||
write_escaped_string(out, str.str());
|
||||
}
|
||||
out << '\n';
|
||||
|
||||
transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
24
csv.h
Normal file
24
csv.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef _CSV_H
|
||||
#define _CSV_H
|
||||
|
||||
#include "journal.h"
|
||||
#include "format.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
class format_csv_transactions : public item_handler<transaction_t>
|
||||
{
|
||||
protected:
|
||||
std::ostream& out;
|
||||
|
||||
public:
|
||||
format_csv_transactions(std::ostream& _out) : out(_out) {}
|
||||
virtual void flush() {
|
||||
out.flush();
|
||||
}
|
||||
virtual void operator()(transaction_t& xact);
|
||||
};
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#endif // _REPORT_H
|
||||
25
format.cc
25
format.cc
|
|
@ -300,27 +300,6 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
return result.release();
|
||||
}
|
||||
|
||||
static bool entry_state(const entry_t * entry, transaction_t::state_t * state)
|
||||
{
|
||||
bool first = true;
|
||||
bool hetero = false;
|
||||
|
||||
for (transactions_list::const_iterator i = entry->transactions.begin();
|
||||
i != entry->transactions.end();
|
||||
i++) {
|
||||
if (first) {
|
||||
*state = (*i)->state;
|
||||
first = false;
|
||||
}
|
||||
else if (*state != (*i)->state) {
|
||||
hetero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ! hetero;
|
||||
}
|
||||
|
||||
namespace {
|
||||
inline void mark_red(std::ostream& out, const element_t * elem) {
|
||||
out.setf(std::ios::left);
|
||||
|
|
@ -643,7 +622,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
case element_t::ENTRY_CLEARED:
|
||||
if (details.entry) {
|
||||
transaction_t::state_t state;
|
||||
if (entry_state(details.entry, &state))
|
||||
if (details.entry->get_state(&state))
|
||||
switch (state) {
|
||||
case transaction_t::CLEARED:
|
||||
out << "* ";
|
||||
|
|
@ -688,7 +667,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
case element_t::OPT_ACCOUNT:
|
||||
if (details.entry && details.xact) {
|
||||
transaction_t::state_t state;
|
||||
if (! entry_state(details.entry, &state))
|
||||
if (! details.entry->get_state(&state))
|
||||
switch (details.xact->state) {
|
||||
case transaction_t::CLEARED:
|
||||
name = "* ";
|
||||
|
|
|
|||
21
journal.cc
21
journal.cc
|
|
@ -281,6 +281,27 @@ entry_t::entry_t(const entry_t& e)
|
|||
(*i)->entry = this;
|
||||
}
|
||||
|
||||
bool entry_t::get_state(transaction_t::state_t * state) const
|
||||
{
|
||||
bool first = true;
|
||||
bool hetero = false;
|
||||
|
||||
for (transactions_list::const_iterator i = transactions.begin();
|
||||
i != transactions.end();
|
||||
i++) {
|
||||
if (first) {
|
||||
*state = (*i)->state;
|
||||
first = false;
|
||||
}
|
||||
else if (*state != (*i)->state) {
|
||||
hetero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ! hetero;
|
||||
}
|
||||
|
||||
void entry_t::add_transaction(transaction_t * xact)
|
||||
{
|
||||
xact->entry = this;
|
||||
|
|
|
|||
|
|
@ -193,6 +193,8 @@ class entry_t : public entry_base_t
|
|||
virtual void add_transaction(transaction_t * xact);
|
||||
|
||||
virtual bool valid() const;
|
||||
|
||||
bool get_state(transaction_t::state_t * state) const;
|
||||
};
|
||||
|
||||
struct entry_finalizer_t {
|
||||
|
|
|
|||
1
ledger.h
1
ledger.h
|
|
@ -19,6 +19,7 @@
|
|||
#include <datetime.h>
|
||||
#include <format.h>
|
||||
#include <emacs.h>
|
||||
#include <csv.h>
|
||||
#include <quotes.h>
|
||||
#include <valexpr.h>
|
||||
#include <walk.h>
|
||||
|
|
|
|||
8
main.cc
8
main.cc
|
|
@ -115,10 +115,8 @@ int parse_and_report(config_t& config, report_t& report,
|
|||
command = "P";
|
||||
else if (command == "pricesdb")
|
||||
command = "D";
|
||||
else if (command == "csv") {
|
||||
config.register_format = config.csv_register_format;
|
||||
command = "r";
|
||||
}
|
||||
else if (command == "csv")
|
||||
command = "c";
|
||||
else if (command == "parse") {
|
||||
value_expr expr(ledger::parse_value_expr(*arg));
|
||||
|
||||
|
|
@ -326,6 +324,8 @@ appending the output of this command to your Ledger file if you so choose."
|
|||
formatter = new format_emacs_transactions(*out);
|
||||
else if (command == "X")
|
||||
formatter = new format_xml_entries(*out, report.show_totals);
|
||||
else if (command == "c")
|
||||
formatter = new format_csv_transactions(*out);
|
||||
else
|
||||
formatter = new format_transactions(*out, *format);
|
||||
|
||||
|
|
|
|||
54
option.cc
54
option.cc
|
|
@ -86,47 +86,56 @@ void process_arguments(option_t * options, int argc, char ** argv,
|
|||
|
||||
// --long-option or -s
|
||||
again:
|
||||
option_t * opt = NULL;
|
||||
char * value = NULL;
|
||||
|
||||
if ((*i)[1] == '-') {
|
||||
if ((*i)[2] == '\0')
|
||||
break;
|
||||
|
||||
char * name = *i + 2;
|
||||
char * name = *i + 2;
|
||||
char * value = NULL;
|
||||
if (char * p = std::strchr(name, '=')) {
|
||||
*p++ = '\0';
|
||||
value = p;
|
||||
}
|
||||
|
||||
opt = search_options(options, name);
|
||||
option_t * opt = search_options(options, name);
|
||||
if (! opt)
|
||||
throw new option_error(std::string("illegal option --") + name);
|
||||
|
||||
if (opt->wants_arg && ! value) {
|
||||
if (opt->wants_arg && value == NULL) {
|
||||
value = *++i;
|
||||
if (! value)
|
||||
if (value == NULL)
|
||||
throw new option_error(std::string("missing option argument for --") +
|
||||
name);
|
||||
}
|
||||
process_option(opt, value);
|
||||
} else {
|
||||
char c = (*i)[1];
|
||||
opt = search_options(options, c);
|
||||
if (! opt)
|
||||
throw new option_error(std::string("illegal option -") + c);
|
||||
}
|
||||
else if ((*i)[1] == '\0') {
|
||||
throw new option_error(std::string("illegal option -"));
|
||||
}
|
||||
else {
|
||||
std::list<option_t *> opt_queue;
|
||||
|
||||
if (opt->wants_arg) {
|
||||
value = *++i;
|
||||
if (! value)
|
||||
throw new option_error(std::string("missing option argument for -") + c);
|
||||
int x = 1;
|
||||
for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) {
|
||||
option_t * opt = search_options(options, c);
|
||||
if (! opt)
|
||||
throw new option_error(std::string("illegal option -") + c);
|
||||
opt_queue.push_back(opt);
|
||||
}
|
||||
|
||||
for (std::list<option_t *>::iterator o = opt_queue.begin();
|
||||
o != opt_queue.end(); o++) {
|
||||
char * value = NULL;
|
||||
if ((*o)->wants_arg) {
|
||||
value = *++i;
|
||||
if (value == NULL)
|
||||
throw new option_error(std::string("missing option argument for -") +
|
||||
(*o)->short_opt);
|
||||
}
|
||||
process_option(*o, value);
|
||||
}
|
||||
}
|
||||
|
||||
assert(opt);
|
||||
assert(! value || opt->wants_arg);
|
||||
process_option(opt, value);
|
||||
|
||||
next:
|
||||
;
|
||||
}
|
||||
|
|
@ -562,10 +571,6 @@ OPT_BEGIN(wide_register_format, ":") {
|
|||
config->wide_register_format = optarg;
|
||||
} OPT_END(wide_register_format);
|
||||
|
||||
OPT_BEGIN(csv_register_format, ":") {
|
||||
config->csv_register_format = optarg;
|
||||
} OPT_END(csv_register_format);
|
||||
|
||||
OPT_BEGIN(plot_amount_format, ":") {
|
||||
config->plot_amount_format = optarg;
|
||||
} OPT_END(plot_amount_format);
|
||||
|
|
@ -977,7 +982,6 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
|
|||
{ "collapse", 'n', false, opt_collapse, false },
|
||||
{ "comm-as-payee", 'x', false, opt_comm_as_payee, false },
|
||||
{ "cost", '\0', false, opt_basis, false },
|
||||
{ "csv-register-format", '\0', true, opt_csv_register_format, false },
|
||||
{ "current", 'c', false, opt_current, false },
|
||||
{ "daily", '\0', false, opt_daily, false },
|
||||
{ "date-format", 'y', true, opt_date_format, false },
|
||||
|
|
|
|||
2
option.h
2
option.h
|
|
@ -38,7 +38,7 @@ class report_t;
|
|||
extern config_t * config;
|
||||
extern report_t * report;
|
||||
|
||||
#define CONFIG_OPTIONS_SIZE 98
|
||||
#define CONFIG_OPTIONS_SIZE 97
|
||||
extern option_t config_options[CONFIG_OPTIONS_SIZE];
|
||||
|
||||
void option_help(std::ostream& out);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@ errors = 0
|
|||
report = sys.argv[1]
|
||||
for line in os.popen("./ledger -f utils/standard.dat -e 2004/4 %s reg %s" %
|
||||
(report, sys.argv[2])):
|
||||
value = clean(line[55:67])
|
||||
total = clean(line[68:])
|
||||
match = re.match("\\s*([-$,0-9.]+)\\s+([-$,0-9.]+)", line[55:])
|
||||
if not match:
|
||||
continue
|
||||
value = clean(match.group(1))
|
||||
total = clean(match.group(2))
|
||||
|
||||
running_total += value
|
||||
diff = abs(running_total - total)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue