*** empty log message ***

This commit is contained in:
John Wiegley 2003-10-11 21:39:09 +00:00
parent 4e8bd8cc5b
commit 9a14d6322c
5 changed files with 151 additions and 185 deletions

View file

@ -1,8 +1,8 @@
CODE = amount.cc ledger.cc parse.cc reports.cc
OBJS = $(patsubst %.cc,%.o,$(CODE))
CFLAGS = -Wall -ansi -pedantic
DFLAGS = -O3 -fomit-frame-pointer -mcpu=pentium
#DFLAGS = -g -DDEBUG=1
#DFLAGS = -O3 -fomit-frame-pointer -mcpu=pentium
DFLAGS = -g -DDEBUG=1
INCS =
LIBS = -lgmpxx -lgmp -lpcre

View file

@ -212,19 +212,6 @@ const std::string account::as_str() const
return full_name;
}
// Print out the entire ledger that was read in, sorted by date.
// This can be used to "wash" ugly ledger files.
void book::print(std::ostream& out, regexps_map& regexps,
bool shortcut) const
{
for (entries_list_const_iterator i = entries.begin();
i != entries.end();
i++)
if ((*i)->matches(regexps))
(*i)->print(out, shortcut);
}
mask::mask(const std::string& pat) : exclude(false)
{
const char * p = pat.c_str();

View file

@ -1,5 +1,5 @@
#ifndef _LEDGER_H
#define _LEDGER_H "$Revision: 1.24 $"
#define _LEDGER_H "$Revision: 1.25 $"
//////////////////////////////////////////////////////////////////////
//
@ -294,6 +294,20 @@ inline commodity::commodity(const std::string& sym, bool pre, bool sep,
assert(result.second);
}
// Parsing routines
extern book * parse_ledger(std::istream& in, regexps_map& regexps,
bool compute_balances);
#ifdef READ_GNUCASH
extern book * parse_gnucash(std::istream& in, bool compute_balances);
#endif
extern bool parse_date_mask(const char * date_str,
struct std::tm * result);
extern bool parse_date(const char * date_str, std::time_t * result,
const int year = -1);
extern void parse_price_setting(const std::string& setting);
} // namespace ledger
#endif // _LEDGER_H

View file

@ -49,38 +49,42 @@ static const char *formats[] = {
NULL
};
bool parse_date(const char * date_str, std::time_t * result,
const int year = -1)
bool parse_date_mask(const char * date_str, struct std::tm * result)
{
for (const char ** f = formats; *f; f++) {
memset(result, INT_MAX, sizeof(struct std::tm));
if (strptime(date_str, *f, result))
return true;
}
return false;
}
bool parse_date(const char * date_str, std::time_t * result, const int year)
{
struct std::tm when;
std::time_t now = std::time(NULL);
struct std::tm * now_tm = std::localtime(&now);
if (! parse_date_mask(date_str, &when))
return false;
for (const char ** f = formats; *f; f++) {
memset(&when, INT_MAX, sizeof(struct std::tm));
if (strptime(date_str, *f, &when)) {
when.tm_hour = 0;
when.tm_min = 0;
when.tm_sec = 0;
static std::time_t now = std::time(NULL);
static struct std::tm * now_tm = std::localtime(&now);
if (when.tm_year == -1)
when.tm_year = year == -1 ? now_tm->tm_year : year - 1900;
when.tm_hour = 0;
when.tm_min = 0;
when.tm_sec = 0;
if (std::strcmp(*f, "%Y") == 0) {
when.tm_mon = 0;
when.tm_mday = 1;
} else {
if (when.tm_mon == -1)
when.tm_mon = now_tm->tm_mon;
if (when.tm_mday == -1)
when.tm_mday = now_tm->tm_mday;
}
*result = std::mktime(&when);
return true;
}
}
return false;
if (when.tm_year == -1)
when.tm_year = ((year == -1) ? now_tm->tm_year : (year - 1900));
if (when.tm_mon == -1)
when.tm_mon = now_tm->tm_mon;
if (when.tm_mday == -1)
when.tm_mday = now_tm->tm_mday;
*result = std::mktime(&when);
return true;
}
void parse_price_setting(const std::string& setting)

View file

@ -1,37 +1,64 @@
#include "ledger.h"
#define LEDGER_VERSION "1.1"
#define LEDGER_VERSION "1.2"
#include <fstream>
#include <unistd.h>
namespace ledger {
extern book * parse_ledger(std::istream& in, regexps_map& regexps,
bool compute_balances);
#ifdef READ_GNUCASH
extern book * parse_gnucash(std::istream& in, bool compute_balances);
#endif
extern bool parse_date(const char * date_str, std::time_t * result,
const int year = -1);
extern void parse_price_setting(const std::string& setting);
static bool show_cleared;
static bool show_virtual;
static bool get_quotes;
static bool show_children;
static bool show_sorted;
static bool show_empty;
static bool show_subtotals;
static bool full_names;
static bool show_cleared = false;
static bool show_virtual = true;
static bool get_quotes = false;
static bool show_children = false;
static bool show_sorted = false;
static bool show_empty = false;
static bool show_subtotals = true;
static bool full_names = false;
static std::time_t begin_date;
static bool have_beginning;
static std::time_t end_date;
static bool have_ending;
static bool have_beginning = false;
static std::time_t end_date;
static bool have_ending = false;
static struct std::tm date_mask;
static bool have_date_mask = false;
static bool matches_date_range(entry * ent)
{
if (have_beginning && difftime(ent->date, begin_date) < 0)
return false;
if (have_ending && difftime(ent->date, end_date) >= 0)
return false;
if (have_date_mask) {
struct std::tm * then = std::localtime(&ent->date);
if (date_mask.tm_mon != -1 &&
date_mask.tm_mon != then->tm_mon)
return false;
if (date_mask.tm_mday != -1 &&
date_mask.tm_mday != then->tm_mday)
return false;
#if 0
// jww (2003-10-10): This causes only certain days of the week to
// print, even when it was not included in the mask.
if (date_mask.tm_wday != -1 &&
date_mask.tm_wday != then->tm_wday)
return false;
#endif
if (date_mask.tm_year != -1 &&
date_mask.tm_year != then->tm_year)
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////
//
@ -78,9 +105,7 @@ void report_balances(std::ostream& out, regexps_map& regexps)
for (entries_list_iterator i = main_ledger->entries.begin();
i != main_ledger->entries.end();
i++) {
if ((show_cleared && ! (*i)->cleared) ||
(have_beginning && difftime((*i)->date, begin_date) < 0) ||
(have_ending && difftime((*i)->date, end_date) >= 0))
if ((show_cleared && ! (*i)->cleared) || ! matches_date_range(*i))
continue;
for (std::list<transaction *>::iterator x = (*i)->xacts.begin();
@ -177,17 +202,15 @@ void print_register(const std::string& acct_name, std::ostream& out,
for (entries_list_iterator i = main_ledger->entries.begin();
i != main_ledger->entries.end();
i++) {
if (! (*i)->matches(regexps))
if ((! have_beginning && ! have_ending && ! have_date_mask &&
! show_cleared && (*i)->cleared) ||
! matches_date_range(*i) || ! (*i)->matches(regexps))
continue;
for (std::list<transaction *>::iterator x = (*i)->xacts.begin();
x != (*i)->xacts.end();
x++) {
if ((! have_beginning && ! have_ending &&
! show_cleared && (*i)->cleared) ||
(have_beginning && difftime((*i)->date, begin_date) < 0) ||
(have_ending && difftime((*i)->date, end_date) >= 0) ||
(! acct_regex.match((*x)->acct->as_str())))
if (! acct_regex.match((*x)->acct->as_str()))
continue;
char buf[32];
@ -334,6 +357,25 @@ void equity_ledger(std::ostream& out, regexps_map& regexps)
equity_entry((*i).second, regexps, out);
}
// Print out the entire ledger that was read in, sorted by date.
// This can be used to "wash" ugly ledger files. It's written here,
// instead of ledger.cc, in order to access the static globals above.
void book::print(std::ostream& out, regexps_map& regexps,
bool shortcut) const
{
for (entries_list_const_iterator i = entries.begin();
i != entries.end();
i++) {
if ((show_cleared && ! (*i)->cleared) ||
! matches_date_range(*i) ||
! (*i)->matches(regexps))
continue;
(*i)->print(out, shortcut);
}
}
} // namespace ledger
using namespace ledger;
@ -344,35 +386,28 @@ static void show_help(std::ostream& out)
<< "usage: ledger [options] COMMAND [options] [REGEXPS]" << std::endl
<< std::endl
<< "ledger options:" << std::endl
<< " -C also show cleared transactions" << std::endl
<< " -d DATE specify an implicit date range (e.g., -d april)"
<< std::endl
<< " -b DATE specify a beginning date" << std::endl
<< " -e DATE specify an ending date" << std::endl
<< " -c do not show future entries (same as -e TODAY)" << std::endl
<< " -C also show cleared transactions" << std::endl
<< " -d DATE specify a date mask ('-d mon', for all mondays)" << std::endl
<< " -f FILE specify pathname of ledger data file" << std::endl
<< " -F print each account's full name" << std::endl
<< " -h display this help text" << std::endl
<< " -R do not factor any virtual transactions" << std::endl
<< " -V FILE use virtual mappings listed in FILE" << std::endl
<< " -i FILE read the list of inclusion regexps from FILE" << std::endl
<< " -p FILE read the list of prices from FILE" << std::endl
<< " -n do not generate totals for parent accounts" << std::endl
<< " -p ARG set a price, or read prices from a file" << std::endl
<< " -P download price quotes from the Internet" << std::endl
<< " (works by running the command \"getquote SYMBOL\")"
<< std::endl
<< " -v display version information" << std::endl
<< " -w print out warnings where applicable" << std::endl
<< std::endl
<< " (works by running the command \"getquote SYMBOL\")" << std::endl
<< " -R do not factor in virtual transactions" << std::endl
<< " -s show sub-accounts in balance totals" << std::endl
<< " -S show empty accounts in balance totals" << std::endl
<< " -v display version information" << std::endl << std::endl
<< "commands:" << std::endl
<< " balance show balance totals" << std::endl
<< " register display a register for ACCOUNT" << std::endl
<< " print print all ledger entries" << std::endl
<< " equity generate equity ledger for all entries" << std::endl
<< std::endl
<< "`balance' options:" << std::endl
<< " -F print each account's full name" << std::endl
<< " -n do not generate totals for parent accounts" << std::endl
<< " -s show sub-accounts in balance totals" << std::endl
<< " -S show empty accounts in balance totals" << std::endl;
<< " equity generate equity ledger for all entries" << std::endl;
}
//////////////////////////////////////////////////////////////////////
@ -387,94 +422,40 @@ int main(int argc, char * argv[])
regexps_map regexps;
int index;
have_beginning = false;
have_ending = false;
show_cleared = false;
show_virtual = true;
show_children = false;
show_sorted = false;
show_empty = false;
show_subtotals = true;
full_names = false;
// Parse the command-line options
int c;
while (-1 != (c = getopt(argc, argv, "+b:e:d:cChRV:f:i:p:PvsSEnF"))) {
switch (char(c)) {
case 'b':
case 'e': {
std::time_t when;
if (! parse_date(optarg, &when)) {
std::cerr << "Error: Bad date string: " << optarg << std::endl;
return 1;
}
if (c == 'b') {
begin_date = when;
have_beginning = true;
} else {
end_date = when;
have_ending = true;
}
break;
}
#if 0
case 'd': {
if (! parse_date(optarg, &begin_date)) {
std::cerr << "Error: Bad date string: " << optarg << std::endl;
return 1;
}
have_beginning = true;
struct std::tm when, then;
std::memset(&then, 0, sizeof(struct std::tm));
std::time_t now = std::time(NULL);
struct std::tm * now_tm = std::localtime(&now);
for (const char ** f = formats; *f; f++) {
memset(&when, INT_MAX, sizeof(struct std::tm));
if (strptime(optarg, *f, &when)) {
then.tm_hour = 0;
then.tm_min = 0;
then.tm_sec = 0;
if (when.tm_year != -1)
then.tm_year = when.tm_year + 1;
else
then.tm_year = now_tm->tm_year;
if (std::strcmp(*f, "%Y") == 0) {
then.tm_mon = 0;
then.tm_mday = 1;
} else {
if (when.tm_mon != -1)
then.tm_mon = when.tm_mon + 1;
else
then.tm_mon = now_tm->tm_mon;
if (when.tm_mday != -1)
then.tm_mday = when.tm_mday + 1;
else
then.tm_mday = now_tm->tm_mday;
}
end_date = std::mktime(&then);
have_ending = true;
break;
}
if (! parse_date(optarg, &begin_date)) {
std::cerr << "Error: Bad begin date: " << optarg << std::endl;
return 1;
}
break;
case 'e':
have_ending = true;
if (! parse_date(optarg, &end_date)) {
std::cerr << "Error: Bad end date: " << optarg << std::endl;
return 1;
}
break;
}
#endif
case 'c':
end_date = std::time(NULL);
have_ending = true;
break;
case 'd':
have_date_mask = true;
if (! parse_date_mask(optarg, &date_mask)) {
std::cerr << "Error: Bad date mask: " << optarg << std::endl;
return 1;
}
break;
case 'h': show_help(std::cout); break;
case 'f': file = new std::ifstream(optarg); break;
@ -522,26 +503,6 @@ int main(int argc, char * argv[])
index = optind;
#if 0
if (have_beginning || have_ending) {
std::cout << "Reporting";
if (have_beginning) {
char buf[32];
std::strftime(buf, 31, "%Y.%m.%d", std::localtime(&begin_date));
std::cout << " from " << buf;
}
if (have_ending) {
char buf[32];
std::strftime(buf, 31, "%Y.%m.%d", std::localtime(&end_date));
std::cout << " until " << buf;
}
std::cout << std::endl;
}
#endif
// A ledger data file must be specified
if (! file) {