Made separate modules for the csv command, since the prior method was

not fully correct.
This commit is contained in:
John Wiegley 2006-08-22 00:52:08 +00:00
parent db0ef2e257
commit 04dfda2282
14 changed files with 200 additions and 61 deletions

View file

@ -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
View file

@ -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

View file

@ -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";

View file

@ -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
View 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
View 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

View file

@ -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 = "* ";

View file

@ -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;

View file

@ -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 {

View file

@ -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>

View file

@ -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);

View file

@ -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 },

View file

@ -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);

View file

@ -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)