several fixes

This commit is contained in:
John Wiegley 2004-08-19 22:03:23 -04:00
parent 9d4f839263
commit a9b207205f
10 changed files with 98 additions and 1664 deletions

View file

@ -10,6 +10,7 @@ CODE = account.cc \
format.cc \ format.cc \
ledger.cc \ ledger.cc \
option.cc \ option.cc \
parser.cc \
qif.cc \ qif.cc \
quotes.cc \ quotes.cc \
textual.cc \ textual.cc \

70
NEWS
View file

@ -15,31 +15,28 @@
operators are supported, as well as a few useful functions. See the operators are supported, as well as a few useful functions. See the
README. README.
- If the environment variable LEDGER is used, a binary cache of that - If the environment variable LEDGER (or LEDGER_FILE) is used, a
current ledger will be kept, to speed up later queries of the same binary cache of that ledger will be kept in ~/.ledger (or
data. The default location is in ~/.ledger, but this can be changed LEDGER_CACHE), to speed up later queries of the same data. This
with the environment variable LEDGER_CACHE. This only happens if no happens only when "-f" or "--file" is not used.
"-f" flag was seen (i.e., if the LEDGER environment variable is
used).
- New "-o FILE" option will output data to the given FILE. If FILE is - New options:
"-", the output is the same as the default (stdout).
- New -j and -J options replace the old -G (gnuplot) option. -j "-o FILE" outputs data to the given FILE. If "-", the output is the
reports the values column in a way gnuplot can consume, and -J same as the default (stdout).
reports the totals column. An example can be found in
scripts/report.
- New "-y DATEFMT" options will change the date format used throughout -j and -J options replace previous -G (gnuplot) option. -j reports
ledger. The default is "%Y/%m/%d". the values column in a way gnuplot can consume, and -J reports the
totals column. An example can be found in scripts/report.
- New -Y and -W options prints yearly and weekly subtotals, just as "-y DATEFMT" changes the date format used in register reports. The
the -M option printed monthly subtotals in the previous version. default is "%Y/%m/%d".
- New -w report will show cumulative totals for each of the days of -Y and -W print yearly and weekly subtotals, just as the -M option
the week. printed monthly subtotals in the previous version.
-w shows cumulative totals for each of the days of the week.
- New "-z INTERVAL" allows for more flexible interval reporting. The "-z INTERVAL" allows more flexible interval reporting. The
sublanguage used will probably mature over time, but for now it sublanguage used will probably mature over time, but for now it
supports expression like: supports expression like:
@ -48,9 +45,14 @@
every 3 quarters every 3 quarters
weekly from 12/20 weekly from 12/20
Note that when using the "from" date, this does not constrain the -O shows base values (this is the default, and old behavior)
report. It is only used for aligning report dates, for example if -B shows basis cost of commodities
you wish weekly reporting to start on Sundays. -V show market value of commodities
-G reports net gain/loss (shows commodity changes only)
-A reports average value (arithmetic mean)
-D reports deviation from the average value
-X reports the trend (average rate of change)
-Z reports the trend, with older values affecting the trend less
- Regexps specified after the command name now apply to account names - Regexps specified after the command name now apply to account names
only. To search on a payee, use "--" to separate the two kinds of only. To search on a payee, use "--" to separate the two kinds of
@ -79,19 +81,6 @@
option also works for balance reports, where it will show all the option also works for balance reports, where it will show all the
account totals related to your query. account totals related to your query.
- There are several new default reporting styles, which work both in
the balance and register reports:
-O Show base values (this is the default, and old behavior)
-B Show the basis cost of commodities
-V Show the last known market value of commodities
-G Report net gain/loss (shows commodity changes only)
-A Report average value (arithmetic mean)
-D Report deviation from the average value
-Z Report the trend (average rate of change)
-W Report the trend, with older values affecting the trend less
-X Report expected amount for the next transaction
- Automated transactions now use a single value expression as a - Automated transactions now use a single value expression as a
predicate. This means the new syntax is: predicate. This means the new syntax is:
@ -105,15 +94,10 @@
- The use of "+" and "-" in ledger files (to specify permanent - The use of "+" and "-" in ledger files (to specify permanent
regexps) has been removed. regexps) has been removed.
- The -G switch no longer generates gnuplot-safe data. It now reports - -l now takes a value expression as the "calculation predicate".
totals in terms of net gain/loss. To mimic the old behavior of "-l \$100", use: -d "AT<{\$100}"
- The -l flag now takes an expression string as a "predicate". - The -S flag takes a value expression string, which yields the value
Therefore, to equal the old behavior of "-l $100", you would use:
-l AT<{$100}
- The -S flag now takes an expression string, which yields the value
that will be sorted on. that will be sorted on.
---------------------------------------------------------------------- ----------------------------------------------------------------------

1550
README

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
#include "ledger.h" #include "ledger.h"
#include "binary.h"
#include <vector> #include <vector>
#include <fstream> #include <fstream>
@ -16,6 +17,15 @@ namespace ledger {
const unsigned long binary_magic_number = 0xFFEED765; const unsigned long binary_magic_number = 0xFFEED765;
static const unsigned long format_version = 0x0002000b; static const unsigned long format_version = 0x0002000b;
bool binary_parser_t::test(std::istream& in) const
{
unsigned long magic;
in.read((char *)&magic, sizeof(magic));
in.seekg(0);
return magic == binary_magic_number;
}
static std::vector<account_t *> accounts; static std::vector<account_t *> accounts;
static account_t::ident_t ident; static account_t::ident_t ident;
static std::vector<commodity_t *> commodities; static std::vector<commodity_t *> commodities;
@ -118,7 +128,7 @@ entry_t * read_binary_entry(std::istream& in, journal_t * journal)
i < count; i < count;
i++) { i++) {
transaction_t * xact = read_binary_transaction(in, entry); transaction_t * xact = read_binary_transaction(in, entry);
entry->transactions.push_back(xact); entry->add_transaction(xact);
} }
return entry; return entry;
@ -252,6 +262,14 @@ unsigned int read_binary_journal(std::istream& in,
return count; return count;
} }
unsigned int binary_parser_t::parse(std::istream& in,
journal_t * journal,
account_t * master,
const std::string * original_file)
{
return read_binary_journal(in, original_file ? *original_file : "",
journal, master);
}
#if RELEASE_LEVEL >= ALPHA #if RELEASE_LEVEL >= ALPHA
#define write_binary_guard(in, id) { \ #define write_binary_guard(in, id) { \

View file

@ -127,7 +127,6 @@ class format_transactions : public item_handler<transaction_t>
} }
xact->dflags |= TRANSACTION_DISPLAYED; xact->dflags |= TRANSACTION_DISPLAYED;
} }
flush();
} }
}; };

View file

@ -174,34 +174,4 @@ entry_t * journal_t::derive_entry(strings_list::iterator i,
return added.release(); return added.release();
} }
int parse_journal_file(const std::string& path,
journal_t * journal,
account_t * master,
const std::string * original_file)
{
journal->sources.push_back(path);
if (access(path.c_str(), R_OK) == -1)
return 0;
std::ifstream stream(path.c_str());
char magic[sizeof(unsigned int) + 1];
stream.read(magic, sizeof(unsigned int));
magic[sizeof(unsigned int)] = '\0';
stream.seekg(0);
if (*((unsigned int *) magic) == binary_magic_number)
return read_binary_journal(stream, original_file ? *original_file : "",
journal, master ? master : journal->master);
else if (std::strcmp(magic, "!Typ") == 0 ||
std::strcmp(magic, "\n!Ty") == 0 ||
std::strcmp(magic, "\r\n!T") == 0)
return parse_qif_file(stream, journal, master ? master : journal->master,
commodity_t::find_commodity("$", true));
else
return parse_textual_journal(stream, journal,
master ? master : journal->master);
}
} // namespace ledger } // namespace ledger

View file

@ -223,30 +223,6 @@ class journal_t
strings_list::iterator end) const; strings_list::iterator end) const;
}; };
int parse_journal_file(const std::string& path,
journal_t * journal,
account_t * master = NULL,
const std::string * original_file = NULL);
unsigned int parse_textual_journal(std::istream& in,
journal_t * ledger,
account_t * master = NULL);
extern const unsigned long binary_magic_number;
unsigned int read_binary_journal(std::istream& in,
const std::string& file,
journal_t * journal,
account_t * master = NULL);
void write_binary_journal(std::ostream& out,
journal_t * journal,
strings_list * files = NULL);
unsigned int parse_qif_file(std::istream& in, journal_t * journal,
account_t * master,
commodity_t * def_commodity = NULL);
extern const std::string version; extern const std::string version;
} // namespace ledger } // namespace ledger

27
main.cc
View file

@ -1,5 +1,8 @@
#include "ledger.h" #include "ledger.h"
#include "error.h" #include "parser.h"
#include "textual.h"
#include "binary.h"
#include "qif.h"
#include "valexpr.h" #include "valexpr.h"
#include "format.h" #include "format.h"
#include "walk.h" #include "walk.h"
@ -7,6 +10,7 @@
#include "option.h" #include "option.h"
#include "config.h" #include "config.h"
#include "timing.h" #include "timing.h"
#include "error.h"
using namespace ledger; using namespace ledger;
@ -178,16 +182,25 @@ int main(int argc, char * argv[], char * envp[])
TIMER_START(parse_files); TIMER_START(parse_files);
// Setup the parsers
std::auto_ptr<binary_parser_t> bin_parser(new binary_parser_t);
std::auto_ptr<qif_parser_t> qif_parser(new qif_parser_t);
std::auto_ptr<textual_parser_t> text_parser(new textual_parser_t);
parser_t::parsers.push_back(bin_parser.get());
parser_t::parsers.push_back(qif_parser.get());
parser_t::parsers.push_back(text_parser.get());
int entry_count = 0; int entry_count = 0;
try { try {
if (! config->init_file.empty()) if (! config->init_file.empty())
if (parse_journal_file(config->init_file, journal.get())) if (parser_t::parse(config->init_file, journal.get()))
throw error("Entries not allowed in initialization file"); throw error("Entries not allowed in initialization file");
if (use_cache && ! config->cache_file.empty() && if (use_cache && ! config->cache_file.empty() &&
! config->data_file.empty()) { ! config->data_file.empty()) {
entry_count += parse_journal_file(config->cache_file, journal.get(), entry_count += parser_t::parse(config->cache_file, journal.get(),
NULL, &config->data_file); NULL, &config->data_file);
journal->sources.pop_front(); // remove cache_file journal->sources.pop_front(); // remove cache_file
@ -206,14 +219,14 @@ int main(int argc, char * argv[], char * envp[])
if (config->data_file == "-") { if (config->data_file == "-") {
use_cache = false; use_cache = false;
entry_count += parse_textual_journal(std::cin, journal.get(), account); entry_count += text_parser->parse(std::cin, journal.get(), account);
} else { } else {
entry_count += parse_journal_file(config->data_file, journal.get(), entry_count += parser_t::parse(config->data_file, journal.get(),
account); account);
} }
if (! config->price_db.empty()) if (! config->price_db.empty())
if (parse_journal_file(config->price_db, journal.get())) if (parser_t::parse(config->price_db, journal.get()))
throw error("Entries not allowed in price history file"); throw error("Entries not allowed in price history file");
} }
@ -226,7 +239,7 @@ int main(int argc, char * argv[], char * envp[])
if (i != -1) { if (i != -1) {
conversion[i] = ' '; conversion[i] = ' ';
std::istringstream stream(conversion); std::istringstream stream(conversion);
parse_textual_journal(stream, journal.get(), journal->master); text_parser->parse(stream, journal.get(), journal->master);
} }
} }
} }

27
qif.cc
View file

@ -1,4 +1,5 @@
#include "ledger.h" #include "ledger.h"
#include "qif.h"
#include "datetime.h" #include "datetime.h"
#include "error.h" #include "error.h"
#include "util.h" #include "util.h"
@ -22,14 +23,29 @@ static inline char * get_line(std::istream& in) {
return line; return line;
} }
unsigned int parse_qif_file(std::istream& in, journal_t * journal, bool qif_parser_t::test(std::istream& in) const
account_t * master, commodity_t * def_commodity) {
char magic[sizeof(unsigned int) + 1];
in.read(magic, sizeof(unsigned int));
magic[sizeof(unsigned int)] = '\0';
in.seekg(0);
return (std::strcmp(magic, "!Typ") == 0 ||
std::strcmp(magic, "\n!Ty") == 0 ||
std::strcmp(magic, "\r\n!T") == 0);
}
unsigned int qif_parser_t::parse(std::istream& in,
journal_t * journal,
account_t * master,
const std::string * original_file)
{ {
std::auto_ptr<entry_t> entry; std::auto_ptr<entry_t> entry;
std::auto_ptr<amount_t> amount; std::auto_ptr<amount_t> amount;
transaction_t * xact; transaction_t * xact;
account_t * misc = journal->find_account("Miscellaneous");
unsigned int count; unsigned int count;
account_t * misc = NULL;
commodity_t * def_commodity = NULL;
entry.reset(new entry_t); entry.reset(new entry_t);
xact = new transaction_t(master); xact = new transaction_t(master);
@ -78,7 +94,8 @@ unsigned int parse_qif_file(std::istream& in, journal_t * journal,
case '$': case '$':
in >> line; in >> line;
xact->amount.parse(line); xact->amount.parse(line);
if (def_commodity) if (! def_commodity)
def_commodity = commodity_t::find_commodity("$", true);
xact->amount.commodity = def_commodity; xact->amount.commodity = def_commodity;
if (c == '$') if (c == '$')
xact->amount.negate(); xact->amount.negate();
@ -143,6 +160,8 @@ unsigned int parse_qif_file(std::istream& in, journal_t * journal,
case '^': case '^':
if (xact->account == master) { if (xact->account == master) {
if (! misc)
misc = master->find_account("Miscellaneous");
transaction_t * nxact = new transaction_t(misc); transaction_t * nxact = new transaction_t(misc);
entry->add_transaction(nxact); entry->add_transaction(nxact);
nxact->amount = nxact->cost = - xact->amount; nxact->amount = nxact->cost = - xact->amount;

View file

@ -1,3 +1,5 @@
#include "ledger.h"
#include "textual.h"
#include "datetime.h" #include "datetime.h"
#include "autoxact.h" #include "autoxact.h"
#include "valexpr.h" #include "valexpr.h"
@ -292,8 +294,10 @@ struct push_var {
~push_var() { var = prev; } ~push_var() { var = prev; }
}; };
unsigned int parse_textual_journal(std::istream& in, journal_t * journal, unsigned int textual_parser_t::parse(std::istream& in,
account_t * master) journal_t * journal,
account_t * master,
const std::string * original_file)
{ {
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
char c; char c;
@ -529,8 +533,8 @@ unsigned int parse_textual_journal(std::istream& in, journal_t * journal,
push_var<unsigned int> save_linenum(linenum); push_var<unsigned int> save_linenum(linenum);
push_var<std::string> save_path(path); push_var<std::string> save_path(path);
count += parse_journal_file(skip_ws(line), journal, count += parser_t::parse(skip_ws(line), journal,
account_stack.front()); account_stack.front());
} }
break; break;