*** no comment ***

This commit is contained in:
John Wiegley 2006-02-25 10:55:49 +00:00
parent 793dbf26d9
commit 13f375ae58
13 changed files with 273 additions and 90 deletions

View file

@ -7,7 +7,6 @@ libledger_la_SOURCES = \
config.cc \ config.cc \
datetime.cc \ datetime.cc \
derive.cc \ derive.cc \
emacs.cc \
format.cc \ format.cc \
journal.cc \ journal.cc \
mask.cc \ mask.cc \
@ -21,6 +20,10 @@ libledger_la_SOURCES = \
valexpr.cc \ valexpr.cc \
value.cc \ value.cc \
walk.cc walk.cc
if USE_EDITOR
libledger_la_CXXFLAGS += -DUSE_EDITOR=1
libledger_la_SOURCES += emacs.cc
endif
if HAVE_EXPAT if HAVE_EXPAT
libledger_la_CXXFLAGS += -DHAVE_EXPAT=1 libledger_la_CXXFLAGS += -DHAVE_EXPAT=1
libledger_la_SOURCES += gnucash.cc xml.cc libledger_la_SOURCES += gnucash.cc xml.cc

6
NEWS
View file

@ -3,6 +3,12 @@
* 2.5 * 2.5
- A new configure option "--disable-emacs" will disable generation of
transaction and entry location info, which is used by ledger.el and
the "write" command. If you use neither of these, then disabling
them will cut textual parsing time in half, and binary loading time
by a third.
- Added a new "csv" command, for outputting results in CSV format. - Added a new "csv" command, for outputting results in CSV format.
- Added a new value expression regexp command: - Added a new value expression regexp command:

4
acprep
View file

@ -23,13 +23,13 @@ LIBDIRS="-L/sw/lib -L/usr/local/lib"
if [ "$1" = "--debug" ]; then if [ "$1" = "--debug" ]; then
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g" \ ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g" \
--enable-debug --enable-debug --disable-emacs
elif [ "$1" = "--opt" ]; then elif [ "$1" = "--opt" ]; then
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \ ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC" CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC"
elif [ "$1" = "--flat-opt" ]; then elif [ "$1" = "--flat-opt" ]; then
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \ ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450" CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450" --disable-emacs
elif [ "$1" = "--safe-opt" ]; then elif [ "$1" = "--safe-opt" ]; then
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \ ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC -DDEBUG_LEVEL=1" CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC -DDEBUG_LEVEL=1"

243
binary.cc
View file

@ -11,11 +11,19 @@
namespace ledger { namespace ledger {
static unsigned long binary_magic_number = 0xFFEED765; static unsigned long binary_magic_number = 0xFFEED765;
#ifdef USE_EDITOR
#ifdef DEBUG_ENABLED
static unsigned long format_version = 0x00020583;
#else
static unsigned long format_version = 0x00020582;
#endif
#else
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
static unsigned long format_version = 0x00020503; static unsigned long format_version = 0x00020503;
#else #else
static unsigned long format_version = 0x00020502; static unsigned long format_version = 0x00020502;
#endif #endif
#endif
static account_t ** accounts; static account_t ** accounts;
static account_t ** accounts_next; static account_t ** accounts_next;
@ -45,6 +53,30 @@ inline void read_binary_number(std::istream& in, T& num) {
in.read((char *)&num, sizeof(num)); in.read((char *)&num, sizeof(num));
} }
template <typename T>
inline void read_binary_long(std::istream& in, T& num) {
unsigned char len;
in.read((char *)&len, sizeof(unsigned char));
num = 0;
unsigned char temp;
if (len > 3) {
in.read((char *)&temp, sizeof(unsigned char));
num |= ((unsigned long)temp) << 24;
}
if (len > 2) {
in.read((char *)&temp, sizeof(unsigned char));
num |= ((unsigned long)temp) << 16;
}
if (len > 1) {
in.read((char *)&temp, sizeof(unsigned char));
num |= ((unsigned long)temp) << 8;
}
in.read((char *)&temp, sizeof(unsigned char));
num |= ((unsigned long)temp);
}
template <typename T> template <typename T>
inline T read_binary_number(std::istream& in) { inline T read_binary_number(std::istream& in) {
T num; T num;
@ -52,6 +84,13 @@ inline T read_binary_number(std::istream& in) {
return num; return num;
} }
template <typename T>
inline T read_binary_long(std::istream& in) {
T num;
read_binary_long(in, num);
return num;
}
inline void read_binary_string(std::istream& in, std::string& str) inline void read_binary_string(std::istream& in, std::string& str)
{ {
read_binary_guard(in, 0x3001); read_binary_guard(in, 0x3001);
@ -92,6 +131,29 @@ inline void read_binary_number(char *& data, T& num) {
data += sizeof(T); data += sizeof(T);
} }
template <typename T>
inline void read_binary_long(char *& data, T& num) {
unsigned char len = *((unsigned char *)data++);
num = 0;
unsigned char temp;
if (len > 3) {
temp = *((unsigned char *)data++);
num |= ((unsigned long)temp) << 24;
}
if (len > 2) {
temp = *((unsigned char *)data++);
num |= ((unsigned long)temp) << 16;
}
if (len > 1) {
temp = *((unsigned char *)data++);
num |= ((unsigned long)temp) << 8;
}
temp = *((unsigned char *)data++);
num |= ((unsigned long)temp);
}
template <typename T> template <typename T>
inline T read_binary_number(char *& data) { inline T read_binary_number(char *& data) {
T num; T num;
@ -99,6 +161,13 @@ inline T read_binary_number(char *& data) {
return num; return num;
} }
template <typename T>
inline T read_binary_long(char *& data) {
T num;
read_binary_long(data, num);
return num;
}
inline void read_binary_string(char *& data, std::string& str) inline void read_binary_string(char *& data, std::string& str)
{ {
#if DEBUG_LEVEL >= ALPHA #if DEBUG_LEVEL >= ALPHA
@ -169,7 +238,7 @@ inline void read_binary_string(char *& data, std::string * str)
inline void read_binary_amount(char *& data, amount_t& amt) inline void read_binary_amount(char *& data, amount_t& amt)
{ {
commodity_t::ident_t ident; commodity_t::ident_t ident;
read_binary_number(data, ident); read_binary_long(data, ident);
if (ident == 0xffffffff) if (ident == 0xffffffff)
amt.commodity_ = NULL; amt.commodity_ = NULL;
else if (ident == 0) else if (ident == 0)
@ -182,9 +251,9 @@ inline void read_binary_amount(char *& data, amount_t& amt)
inline void read_binary_transaction(char *& data, transaction_t * xact) inline void read_binary_transaction(char *& data, transaction_t * xact)
{ {
read_binary_number(data, xact->_date); read_binary_long(data, xact->_date);
read_binary_number(data, xact->_date_eff); read_binary_long(data, xact->_date_eff);
xact->account = accounts[read_binary_number<account_t::ident_t>(data) - 1]; xact->account = accounts[read_binary_long<account_t::ident_t>(data) - 1];
read_binary_amount(data, xact->amount); read_binary_amount(data, xact->amount);
if (*data++ == 1) { if (*data++ == 1) {
@ -198,10 +267,13 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
read_binary_number(data, xact->flags); read_binary_number(data, xact->flags);
xact->flags |= TRANSACTION_BULK_ALLOC; xact->flags |= TRANSACTION_BULK_ALLOC;
read_binary_string(data, &xact->note); read_binary_string(data, &xact->note);
read_binary_number(data, xact->beg_pos);
read_binary_number(data, xact->beg_line); #ifdef USE_EDITOR
read_binary_number(data, xact->end_pos); xact->beg_pos = read_binary_long<unsigned long>(data);
read_binary_number(data, xact->end_line); read_binary_long(data, xact->beg_line);
xact->end_pos = read_binary_long<unsigned long>(data);
read_binary_long(data, xact->end_line);
#endif
xact->data = NULL; xact->data = NULL;
} }
@ -209,13 +281,15 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
inline void read_binary_entry_base(char *& data, entry_base_t * entry, inline void read_binary_entry_base(char *& data, entry_base_t * entry,
transaction_t *& xact_pool) transaction_t *& xact_pool)
{ {
read_binary_number(data, entry->src_idx); #ifdef USE_EDITOR
read_binary_number(data, entry->beg_pos); read_binary_long(data, entry->src_idx);
read_binary_number(data, entry->beg_line); entry->beg_pos = read_binary_long<unsigned long>(data);
read_binary_number(data, entry->end_pos); read_binary_long(data, entry->beg_line);
read_binary_number(data, entry->end_line); entry->end_pos = read_binary_long<unsigned long>(data);
read_binary_long(data, entry->end_line);
#endif
for (unsigned long i = 0, count = read_binary_number<unsigned long>(data); for (unsigned long i = 0, count = read_binary_long<unsigned long>(data);
i < count; i < count;
i++) { i++) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
@ -228,8 +302,8 @@ inline void read_binary_entry(char *& data, entry_t * entry,
transaction_t *& xact_pool) transaction_t *& xact_pool)
{ {
read_binary_entry_base(data, entry, xact_pool); read_binary_entry_base(data, entry, xact_pool);
read_binary_number(data, entry->_date); read_binary_long(data, entry->_date);
read_binary_number(data, entry->_date_eff); read_binary_long(data, entry->_date_eff);
read_binary_string(data, &entry->code); read_binary_string(data, &entry->code);
read_binary_string(data, &entry->payee); read_binary_string(data, &entry->payee);
} }
@ -262,7 +336,7 @@ inline commodity_t * read_binary_commodity(char *& data)
read_binary_string(data, commodity->note); read_binary_string(data, commodity->note);
read_binary_number(data, commodity->precision); read_binary_number(data, commodity->precision);
read_binary_number(data, commodity->flags); read_binary_number(data, commodity->flags);
read_binary_number(data, commodity->ident); read_binary_long(data, commodity->ident);
return commodity; return commodity;
} }
@ -272,11 +346,11 @@ inline void read_binary_commodity_extra(char *& data,
{ {
commodity_t * commodity = commodities[ident]; commodity_t * commodity = commodities[ident];
for (unsigned long i = 0, count = read_binary_number<unsigned long>(data); for (unsigned long i = 0, count = read_binary_long<unsigned long>(data);
i < count; i < count;
i++) { i++) {
std::time_t when; std::time_t when;
read_binary_number(data, when); read_binary_long(data, when);
amount_t amt; amount_t amt;
read_binary_amount(data, amt); read_binary_amount(data, amt);
@ -288,7 +362,7 @@ inline void read_binary_commodity_extra(char *& data,
commodity->history->prices.insert(history_pair(when, amt)); commodity->history->prices.insert(history_pair(when, amt));
} }
if (commodity->history) if (commodity->history)
read_binary_number(data, commodity->history->last_lookup); read_binary_long(data, commodity->history->last_lookup);
unsigned char flag; unsigned char flag;
@ -314,11 +388,11 @@ account_t * read_binary_account(char *& data, journal_t * journal,
account_t * acct = new account_t(NULL); account_t * acct = new account_t(NULL);
*accounts_next++ = acct; *accounts_next++ = acct;
acct->ident = read_binary_number<account_t::ident_t>(data); acct->ident = read_binary_long<account_t::ident_t>(data);
acct->journal = journal; acct->journal = journal;
account_t::ident_t id; account_t::ident_t id;
read_binary_number(data, id); // parent id read_binary_long(data, id); // parent id
if (id == 0xffffffff) if (id == 0xffffffff)
acct->parent = NULL; acct->parent = NULL;
else else
@ -338,7 +412,7 @@ account_t * read_binary_account(char *& data, journal_t * journal,
} }
for (account_t::ident_t i = 0, for (account_t::ident_t i = 0,
count = read_binary_number<account_t::ident_t>(data); count = read_binary_long<account_t::ident_t>(data);
i < count; i < count;
i++) { i++) {
account_t * child = read_binary_account(data, journal); account_t * child = read_binary_account(data, journal);
@ -370,7 +444,7 @@ unsigned int read_binary_journal(std::istream& in,
return 0; return 0;
std::time_t old_mtime; std::time_t old_mtime;
read_binary_number(in, old_mtime); read_binary_long(in, old_mtime);
struct stat info; struct stat info;
stat(path.c_str(), &info); stat(path.c_str(), &info);
if (std::difftime(info.st_mtime, old_mtime) > 0) if (std::difftime(info.st_mtime, old_mtime) > 0)
@ -397,19 +471,19 @@ unsigned int read_binary_journal(std::istream& in,
// Read in the accounts // Read in the accounts
account_t::ident_t a_count = read_binary_number<account_t::ident_t>(data); account_t::ident_t a_count = read_binary_long<account_t::ident_t>(data);
accounts = accounts_next = new account_t *[a_count]; accounts = accounts_next = new account_t *[a_count];
journal->master = read_binary_account(data, journal, master); journal->master = read_binary_account(data, journal, master);
if (read_binary_number<bool>(data)) if (read_binary_number<bool>(data))
journal->basket = accounts[read_binary_number<account_t::ident_t>(data) - 1]; journal->basket = accounts[read_binary_long<account_t::ident_t>(data) - 1];
// Allocate the memory needed for the entries and transactions in // Allocate the memory needed for the entries and transactions in
// one large block, which is then chopped up and custom constructed // one large block, which is then chopped up and custom constructed
// as necessary. // as necessary.
unsigned long count = read_binary_number<unsigned long>(data); unsigned long count = read_binary_long<unsigned long>(data);
unsigned long auto_count = read_binary_number<unsigned long>(data); unsigned long auto_count = read_binary_long<unsigned long>(data);
unsigned long period_count = read_binary_number<unsigned long>(data); unsigned long period_count = read_binary_long<unsigned long>(data);
unsigned long xact_count = read_binary_number<unsigned long>(data); unsigned long xact_count = read_binary_number<unsigned long>(data);
unsigned long bigint_count = read_binary_number<unsigned long>(data); unsigned long bigint_count = read_binary_number<unsigned long>(data);
@ -428,7 +502,7 @@ unsigned int read_binary_journal(std::istream& in,
// Read in the commodities // Read in the commodities
commodity_t::ident_t c_count = read_binary_number<commodity_t::ident_t>(data); commodity_t::ident_t c_count = read_binary_long<commodity_t::ident_t>(data);
commodities = commodities_next = new commodity_t *[c_count]; commodities = commodities_next = new commodity_t *[c_count];
for (commodity_t::ident_t i = 0; i < c_count; i++) { for (commodity_t::ident_t i = 0; i < c_count; i++) {
commodity_t * commodity = read_binary_commodity(data); commodity_t * commodity = read_binary_commodity(data);
@ -446,7 +520,7 @@ unsigned int read_binary_journal(std::istream& in,
read_binary_commodity_extra(data, i); read_binary_commodity_extra(data, i);
commodity_t::ident_t ident; commodity_t::ident_t ident;
read_binary_number(data, ident); read_binary_long(data, ident);
if (ident == 0xffffffff || ident == 0) if (ident == 0xffffffff || ident == 0)
commodity_t::default_commodity = NULL; commodity_t::default_commodity = NULL;
else else
@ -490,7 +564,7 @@ unsigned int read_binary_journal(std::istream& in,
bool binary_parser_t::test(std::istream& in) const bool binary_parser_t::test(std::istream& in) const
{ {
if (read_binary_number<unsigned long>(in) == binary_magic_number && if (read_binary_number<unsigned long>(in) == binary_magic_number &&
read_binary_number<unsigned long>(in) == format_version) read_binary_long<unsigned long>(in) == format_version)
return true; return true;
in.clear(); in.clear();
@ -522,6 +596,34 @@ inline void write_binary_number(std::ostream& out, T num) {
out.write((char *)&num, sizeof(num)); out.write((char *)&num, sizeof(num));
} }
template <typename T>
inline void write_binary_long(std::ostream& out, T num) {
unsigned char len = 4;
if (((unsigned long)num) < 0x00000100UL)
len = 1;
else if (((unsigned long)num) < 0x00010000UL)
len = 2;
else if (((unsigned long)num) < 0x01000000UL)
len = 3;
out.write((char *)&len, sizeof(unsigned char));
if (len > 3) {
unsigned char temp = (((unsigned long)num) & 0xFF000000UL) >> 24;
out.write((char *)&temp, sizeof(unsigned char));
}
if (len > 2) {
unsigned char temp = (((unsigned long)num) & 0x00FF0000UL) >> 16;
out.write((char *)&temp, sizeof(unsigned char));
}
if (len > 1) {
unsigned char temp = (((unsigned long)num) & 0x0000FF00UL) >> 8;
out.write((char *)&temp, sizeof(unsigned char));
}
unsigned char temp = (((unsigned long)num) & 0x000000FFUL);
out.write((char *)&temp, sizeof(unsigned char));
}
inline void write_binary_string(std::ostream& out, const std::string& str) inline void write_binary_string(std::ostream& out, const std::string& str)
{ {
write_binary_guard(out, 0x3001); write_binary_guard(out, 0x3001);
@ -544,18 +646,18 @@ inline void write_binary_string(std::ostream& out, const std::string& str)
void write_binary_amount(std::ostream& out, const amount_t& amt) void write_binary_amount(std::ostream& out, const amount_t& amt)
{ {
if (amt.commodity_) if (amt.commodity_)
write_binary_number(out, amt.commodity().ident); write_binary_long(out, amt.commodity().ident);
else else
write_binary_number<commodity_t::ident_t>(out, 0xffffffff); write_binary_long<commodity_t::ident_t>(out, 0xffffffff);
amt.write_quantity(out); amt.write_quantity(out);
} }
void write_binary_transaction(std::ostream& out, transaction_t * xact) void write_binary_transaction(std::ostream& out, transaction_t * xact)
{ {
write_binary_number(out, xact->_date); write_binary_long(out, xact->_date);
write_binary_number(out, xact->_date_eff); write_binary_long(out, xact->_date_eff);
write_binary_number(out, xact->account->ident); write_binary_long(out, xact->account->ident);
write_binary_amount(out, xact->amount); write_binary_amount(out, xact->amount);
if (xact->cost) { if (xact->cost) {
@ -568,21 +670,26 @@ void write_binary_transaction(std::ostream& out, transaction_t * xact)
write_binary_number(out, xact->state); write_binary_number(out, xact->state);
write_binary_number(out, xact->flags); write_binary_number(out, xact->flags);
write_binary_string(out, xact->note); write_binary_string(out, xact->note);
write_binary_number<istream_pos_type>(out, xact->beg_pos);
write_binary_number<unsigned long>(out, xact->beg_line); #ifdef USE_EDITOR
write_binary_number<istream_pos_type>(out, xact->end_pos); write_binary_long(out, xact->beg_pos);
write_binary_number<unsigned long>(out, xact->end_line); write_binary_long(out, xact->beg_line);
write_binary_long(out, xact->end_pos);
write_binary_long(out, xact->end_line);
#endif
} }
void write_binary_entry_base(std::ostream& out, entry_base_t * entry) void write_binary_entry_base(std::ostream& out, entry_base_t * entry)
{ {
write_binary_number<unsigned long>(out, entry->src_idx); #ifdef USE_EDITOR
write_binary_number<istream_pos_type>(out, entry->beg_pos); write_binary_long(out, entry->src_idx);
write_binary_number<unsigned long>(out, entry->beg_line); write_binary_long(out, entry->beg_pos);
write_binary_number<istream_pos_type>(out, entry->end_pos); write_binary_long(out, entry->beg_line);
write_binary_number<unsigned long>(out, entry->end_line); write_binary_long(out, entry->end_pos);
write_binary_long(out, entry->end_line);
#endif
write_binary_number<unsigned long>(out, entry->transactions.size()); write_binary_long(out, entry->transactions.size());
for (transactions_list::const_iterator i = entry->transactions.begin(); for (transactions_list::const_iterator i = entry->transactions.begin();
i != entry->transactions.end(); i != entry->transactions.end();
i++) i++)
@ -592,8 +699,8 @@ void write_binary_entry_base(std::ostream& out, entry_base_t * entry)
void write_binary_entry(std::ostream& out, entry_t * entry) void write_binary_entry(std::ostream& out, entry_t * entry)
{ {
write_binary_entry_base(out, entry); write_binary_entry_base(out, entry);
write_binary_number(out, entry->_date); write_binary_long(out, entry->_date);
write_binary_number(out, entry->_date_eff); write_binary_long(out, entry->_date_eff);
write_binary_string(out, entry->code); write_binary_string(out, entry->code);
write_binary_string(out, entry->payee); write_binary_string(out, entry->payee);
} }
@ -619,22 +726,22 @@ void write_binary_commodity(std::ostream& out, commodity_t * commodity)
write_binary_number(out, commodity->precision); write_binary_number(out, commodity->precision);
write_binary_number(out, commodity->flags); write_binary_number(out, commodity->flags);
commodity->ident = ++commodity_index; commodity->ident = ++commodity_index;
write_binary_number(out, commodity->ident); write_binary_long(out, commodity->ident);
} }
void write_binary_commodity_extra(std::ostream& out, commodity_t * commodity) void write_binary_commodity_extra(std::ostream& out, commodity_t * commodity)
{ {
if (! commodity->history) { if (! commodity->history) {
write_binary_number<unsigned long>(out, 0); write_binary_long<unsigned long>(out, 0);
} else { } else {
write_binary_number<unsigned long>(out, commodity->history->prices.size()); write_binary_long<unsigned long>(out, commodity->history->prices.size());
for (history_map::const_iterator i = commodity->history->prices.begin(); for (history_map::const_iterator i = commodity->history->prices.begin();
i != commodity->history->prices.end(); i != commodity->history->prices.end();
i++) { i++) {
write_binary_number(out, (*i).first); write_binary_long(out, (*i).first);
write_binary_amount(out, (*i).second); write_binary_amount(out, (*i).second);
} }
write_binary_number(out, commodity->history->last_lookup); write_binary_long(out, commodity->history->last_lookup);
} }
if (commodity->smaller) { if (commodity->smaller) {
@ -668,17 +775,17 @@ void write_binary_account(std::ostream& out, account_t * account)
{ {
account->ident = ++account_index; account->ident = ++account_index;
write_binary_number(out, account->ident); write_binary_long(out, account->ident);
if (account->parent) if (account->parent)
write_binary_number(out, account->parent->ident); write_binary_long(out, account->parent->ident);
else else
write_binary_number<account_t::ident_t>(out, 0xffffffff); write_binary_long<account_t::ident_t>(out, 0xffffffff);
write_binary_string(out, account->name); write_binary_string(out, account->name);
write_binary_string(out, account->note); write_binary_string(out, account->note);
write_binary_number(out, account->depth); write_binary_number(out, account->depth);
write_binary_number<account_t::ident_t>(out, account->accounts.size()); write_binary_long<account_t::ident_t>(out, account->accounts.size());
for (accounts_map::iterator i = account->accounts.begin(); for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end(); i != account->accounts.end();
i++) i++)
@ -691,7 +798,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
commodity_index = 0; commodity_index = 0;
write_binary_number(out, binary_magic_number); write_binary_number(out, binary_magic_number);
write_binary_number(out, format_version); write_binary_long(out, format_version);
// Write out the files that participated in this journal, so that // Write out the files that participated in this journal, so that
// they can be checked for changes on reading. // they can be checked for changes on reading.
@ -706,7 +813,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
write_binary_string(out, *i); write_binary_string(out, *i);
struct stat info; struct stat info;
stat((*i).c_str(), &info); stat((*i).c_str(), &info);
write_binary_number(out, std::time_t(info.st_mtime)); write_binary_long(out, std::time_t(info.st_mtime));
} }
// Write out the price database that relates to this data file, so // Write out the price database that relates to this data file, so
@ -719,21 +826,21 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
// Write out the accounts // Write out the accounts
write_binary_number<account_t::ident_t>(out, count_accounts(journal->master)); write_binary_long<account_t::ident_t>(out, count_accounts(journal->master));
write_binary_account(out, journal->master); write_binary_account(out, journal->master);
if (journal->basket) { if (journal->basket) {
write_binary_number<bool>(out, true); write_binary_number<bool>(out, true);
write_binary_number(out, journal->basket->ident); write_binary_long(out, journal->basket->ident);
} else { } else {
write_binary_number<bool>(out, false); write_binary_number<bool>(out, false);
} }
// Write out the number of entries, transactions, and amounts // Write out the number of entries, transactions, and amounts
write_binary_number<unsigned long>(out, journal->entries.size()); write_binary_long<unsigned long>(out, journal->entries.size());
write_binary_number<unsigned long>(out, journal->auto_entries.size()); write_binary_long<unsigned long>(out, journal->auto_entries.size());
write_binary_number<unsigned long>(out, journal->period_entries.size()); write_binary_long<unsigned long>(out, journal->period_entries.size());
ostream_pos_type xacts_val = out.tellp(); ostream_pos_type xacts_val = out.tellp();
@ -744,7 +851,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
// Write out the commodities // Write out the commodities
write_binary_number<commodity_t::ident_t> write_binary_long<commodity_t::ident_t>
(out, commodity_t::commodities.size() - 1); (out, commodity_t::commodities.size() - 1);
for (commodities_map::const_iterator i = commodity_t::commodities.begin(); for (commodities_map::const_iterator i = commodity_t::commodities.begin();
@ -762,9 +869,9 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
write_binary_commodity_extra(out, (*i).second); write_binary_commodity_extra(out, (*i).second);
if (commodity_t::default_commodity) if (commodity_t::default_commodity)
write_binary_number(out, commodity_t::default_commodity->ident); write_binary_long(out, commodity_t::default_commodity->ident);
else else
write_binary_number<commodity_t::ident_t>(out, 0xffffffff); write_binary_long<commodity_t::ident_t>(out, 0xffffffff);
// Write out the entries and transactions // Write out the entries and transactions

View file

@ -200,6 +200,15 @@ AC_ARG_ENABLE(debug,
esac],[debug=false]) esac],[debug=false])
AM_CONDITIONAL(DEBUG, test x$debug = xtrue) AM_CONDITIONAL(DEBUG, test x$debug = xtrue)
AC_ARG_ENABLE(emacs,
[ --enable-emacs Turn on Emacs support],
[case "${enableval}" in
yes) emacs=true ;;
no) emacs=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-emacs) ;;
esac],[emacs=true])
AM_CONDITIONAL(USE_EDITOR, test x$emacs = xtrue)
# Checks for header files. # Checks for header files.
AC_STDC_HEADERS AC_STDC_HEADERS
AC_HAVE_HEADERS(sys/stat.h) AC_HAVE_HEADERS(sys/stat.h)

View file

@ -388,6 +388,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
} }
break; break;
#ifdef USE_EDITOR
case element_t::SOURCE: case element_t::SOURCE:
if (details.entry && details.entry->journal) { if (details.entry && details.entry->journal) {
int idx = details.entry->src_idx; int idx = details.entry->src_idx;
@ -440,6 +441,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
if (details.xact) if (details.xact)
out << details.xact->end_line; out << details.xact->end_line;
break; break;
#endif
case element_t::DATE_STRING: { case element_t::DATE_STRING: {
std::time_t date = 0; std::time_t date = 0;

View file

@ -45,9 +45,11 @@ static std::istream * instreamp;
static unsigned int offset; static unsigned int offset;
static XML_Parser parser; static XML_Parser parser;
static std::string path; static std::string path;
#ifdef USE_EDITOR
static unsigned int src_idx; static unsigned int src_idx;
static istream_pos_type beg_pos; static istream_pos_type beg_pos;
static unsigned long beg_line; static unsigned long beg_line;
#endif
static transaction_t::state_t curr_state; static transaction_t::state_t curr_state;
@ -146,11 +148,13 @@ static void endElement(void *userData, const char *name)
have_error = "The above entry does not balance"; have_error = "The above entry does not balance";
delete curr_entry; delete curr_entry;
} else { } else {
#ifdef USE_EDITOR
curr_entry->src_idx = src_idx; curr_entry->src_idx = src_idx;
curr_entry->beg_pos = beg_pos; curr_entry->beg_pos = beg_pos;
curr_entry->beg_line = beg_line; curr_entry->beg_line = beg_line;
curr_entry->end_pos = instreamp->tellg(); curr_entry->end_pos = instreamp->tellg();
curr_entry->end_line = XML_GetCurrentLineNumber(parser) - offset; curr_entry->end_line = XML_GetCurrentLineNumber(parser) - offset;
#endif
count++; count++;
} }
@ -189,10 +193,12 @@ static void endElement(void *userData, const char *name)
if (value != curr_value) if (value != curr_value)
xact->cost = new amount_t(curr_value); xact->cost = new amount_t(curr_value);
#ifdef USE_EDITOR
xact->beg_pos = beg_pos; xact->beg_pos = beg_pos;
xact->beg_line = beg_line; xact->beg_line = beg_line;
xact->end_pos = instreamp->tellg(); xact->end_pos = instreamp->tellg();
xact->end_line = XML_GetCurrentLineNumber(parser) - offset; xact->end_line = XML_GetCurrentLineNumber(parser) - offset;
#endif
// Clear the relevant variables for the next run // Clear the relevant variables for the next run
curr_state = transaction_t::UNCLEARED; curr_state = transaction_t::UNCLEARED;
@ -376,7 +382,9 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
instreamp = &in; instreamp = &in;
path = original_file ? *original_file : "<gnucash>"; path = original_file ? *original_file : "<gnucash>";
#ifdef USE_EDITOR
src_idx = journal->sources.size() - 1; src_idx = journal->sources.size() - 1;
#endif
// GnuCash uses the USD commodity without defining it, which really // GnuCash uses the USD commodity without defining it, which really
// means $. // means $.
@ -393,8 +401,10 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
XML_SetCharacterDataHandler(parser, dataHandler); XML_SetCharacterDataHandler(parser, dataHandler);
while (in.good() && ! in.eof()) { while (in.good() && ! in.eof()) {
#ifdef USE_EDITOR
beg_pos = in.tellg(); beg_pos = in.tellg();
beg_line = (XML_GetCurrentLineNumber(parser) - offset) + 1; beg_line = (XML_GetCurrentLineNumber(parser) - offset) + 1;
#endif
in.getline(buf, BUFSIZ - 1); in.getline(buf, BUFSIZ - 1);
std::strcat(buf, "\n"); std::strcat(buf, "\n");

View file

@ -40,10 +40,12 @@ class transaction_t
state_t state; state_t state;
unsigned short flags; unsigned short flags;
std::string note; std::string note;
#ifdef USE_EDITOR
istream_pos_type beg_pos; istream_pos_type beg_pos;
unsigned long beg_line; unsigned long beg_line;
istream_pos_type end_pos; istream_pos_type end_pos;
unsigned long end_line; unsigned long end_line;
#endif
mutable void * data; mutable void * data;
static bool use_effective_date; static bool use_effective_date;
@ -51,7 +53,10 @@ class transaction_t
transaction_t(account_t * _account = NULL) transaction_t(account_t * _account = NULL)
: entry(NULL), _date(0), _date_eff(0), account(_account), : entry(NULL), _date(0), _date_eff(0), account(_account),
cost(NULL), state(UNCLEARED), flags(TRANSACTION_NORMAL), cost(NULL), state(UNCLEARED), flags(TRANSACTION_NORMAL),
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { #ifdef USE_EDITOR
beg_pos(0), beg_line(0), end_pos(0), end_line(0),
#endif
data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
} }
@ -61,7 +66,10 @@ class transaction_t
const std::string& _note = "") const std::string& _note = "")
: entry(NULL), _date(0), _date_eff(0), account(_account), : entry(NULL), _date(0), _date_eff(0), account(_account),
amount(_amount), cost(NULL), state(UNCLEARED), flags(_flags), amount(_amount), cost(NULL), state(UNCLEARED), flags(_flags),
note(_note), beg_pos(0), beg_line(0), end_pos(0), end_line(0), note(_note),
#ifdef USE_EDITOR
beg_pos(0), beg_line(0), end_pos(0), end_line(0),
#endif
data(NULL) { data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
} }
@ -71,7 +79,10 @@ class transaction_t
account(xact.account), amount(xact.amount), account(xact.account), amount(xact.amount),
cost(xact.cost ? new amount_t(*xact.cost) : NULL), cost(xact.cost ? new amount_t(*xact.cost) : NULL),
state(xact.state), flags(xact.flags), note(xact.note), state(xact.state), flags(xact.flags), note(xact.note),
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) { #ifdef USE_EDITOR
beg_pos(0), beg_line(0), end_pos(0), end_line(0),
#endif
data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t"); DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
} }
@ -108,11 +119,13 @@ class entry_base_t
{ {
public: public:
journal_t * journal; journal_t * journal;
#ifdef USE_EDITOR
unsigned long src_idx; unsigned long src_idx;
istream_pos_type beg_pos; istream_pos_type beg_pos;
unsigned long beg_line; unsigned long beg_line;
istream_pos_type end_pos; istream_pos_type end_pos;
unsigned long end_line; unsigned long end_line;
#endif
transactions_list transactions; transactions_list transactions;
entry_base_t() : journal(NULL) { entry_base_t() : journal(NULL) {

View file

@ -229,7 +229,6 @@ dropped."
(forward-line) (forward-line)
(while (looking-at "[ \t]") (while (looking-at "[ \t]")
(skip-chars-forward " \t") (skip-chars-forward " \t")
(assert (not (looking-at "[!*]")))
(insert cleared " ") (insert cleared " ")
(if (search-forward " " (line-end-position) t) (if (search-forward " " (line-end-position) t)
(delete-char 2)) (delete-char 2))

15
main.cc
View file

@ -28,6 +28,7 @@ namespace {
TIMER_DEF_(process); TIMER_DEF_(process);
TIMER_DEF_(walk); TIMER_DEF_(walk);
TIMER_DEF_(cleanup); TIMER_DEF_(cleanup);
TIMER_DEF_(cache_write);
} }
int parse_and_report(int argc, char * argv[], char * envp[]) int parse_and_report(int argc, char * argv[], char * envp[])
@ -105,8 +106,10 @@ int parse_and_report(int argc, char * argv[], char * envp[])
command = "p"; command = "p";
else if (command == "output") else if (command == "output")
command = "w"; command = "w";
#ifdef USE_EDITOR
else if (command == "emacs") else if (command == "emacs")
command = "x"; command = "x";
#endif
else if (command == "xml") else if (command == "xml")
command = "X"; command = "X";
else if (command == "entry") else if (command == "entry")
@ -244,8 +247,10 @@ int parse_and_report(int argc, char * argv[], char * envp[])
formatter = new set_account_value; formatter = new set_account_value;
else if (command == "p" || command == "e") else if (command == "p" || command == "e")
formatter = new format_entries(*out, *format); formatter = new format_entries(*out, *format);
#ifdef USE_EDITOR
else if (command == "x") else if (command == "x")
formatter = new format_emacs_transactions(*out); formatter = new format_emacs_transactions(*out);
#endif
else if (command == "X") { else if (command == "X") {
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
formatter = new format_xml_entries(*out, config.show_totals); formatter = new format_xml_entries(*out, config.show_totals);
@ -256,8 +261,10 @@ int parse_and_report(int argc, char * argv[], char * envp[])
formatter = new format_transactions(*out, *format); formatter = new format_transactions(*out, *format);
if (command == "w") { if (command == "w") {
#ifdef USE_EDITOR
write_textual_journal(*journal, first_arg, *formatter, write_textual_journal(*journal, first_arg, *formatter,
config.write_hdr_format, *out); config.write_hdr_format, *out);
#endif
} else { } else {
formatter = config.chain_xact_handlers(command, formatter, journal.get(), formatter = config.chain_xact_handlers(command, formatter, journal.get(),
journal->master, formatter_ptrs); journal->master, formatter_ptrs);
@ -318,13 +325,19 @@ int parse_and_report(int argc, char * argv[], char * envp[])
formatter_ptrs.clear(); formatter_ptrs.clear();
#endif #endif
TIMER_STOP(cleanup);
// Write out the binary cache, if need be // Write out the binary cache, if need be
TIMER_START(cache_write);
if (config.use_cache && config.cache_dirty && ! config.cache_file.empty()) { if (config.use_cache && config.cache_dirty && ! config.cache_file.empty()) {
std::ofstream stream(config.cache_file.c_str()); std::ofstream stream(config.cache_file.c_str());
write_binary_journal(stream, journal.get()); write_binary_journal(stream, journal.get());
} }
TIMER_STOP(cache_write);
#ifdef HAVE_UNIX_PIPES #ifdef HAVE_UNIX_PIPES
if (! config.pager.empty()) { if (! config.pager.empty()) {
delete out; delete out;
@ -337,8 +350,6 @@ int parse_and_report(int argc, char * argv[], char * envp[])
} }
#endif #endif
TIMER_STOP(cleanup);
return 0; return 0;
} }

View file

@ -129,7 +129,6 @@ unsigned int parse_ledger_data(config_t& config,
! config.data_file.empty()) { ! config.data_file.empty()) {
DEBUG_PRINT("ledger.config.cache", DEBUG_PRINT("ledger.config.cache",
"using_cache " << config.cache_file); "using_cache " << config.cache_file);
if (config.cache_dirty)
config.cache_dirty = true; config.cache_dirty = true;
if (access(config.cache_file.c_str(), R_OK) != -1) { if (access(config.cache_file.c_str(), R_OK) != -1) {
std::ifstream stream(config.cache_file.c_str()); std::ifstream stream(config.cache_file.c_str());
@ -138,15 +137,13 @@ unsigned int parse_ledger_data(config_t& config,
journal->price_db = config.price_db; journal->price_db = config.price_db;
entry_count += cache_parser->parse(stream, config, journal, entry_count += cache_parser->parse(stream, config, journal,
NULL, &config.data_file); NULL, &config.data_file);
if (entry_count > 0) { if (entry_count > 0)
if (config.cache_dirty)
config.cache_dirty = false; config.cache_dirty = false;
} else { else
journal->price_db = price_db_orig; journal->price_db = price_db_orig;
} }
} }
} }
}
if (entry_count == 0 && ! config.data_file.empty()) { if (entry_count == 0 && ! config.data_file.empty()) {
account_t * acct = NULL; account_t * acct = NULL;

8
qif.cc
View file

@ -63,6 +63,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
src_idx = journal->sources.size() - 1; src_idx = journal->sources.size() - 1;
linenum = 1; linenum = 1;
#ifdef USE_EDITOR
istream_pos_type beg_pos = 0; istream_pos_type beg_pos = 0;
unsigned long beg_line = 0; unsigned long beg_line = 0;
@ -71,6 +72,9 @@ unsigned int qif_parser_t::parse(std::istream& in,
beg_pos = in.tellg(); \ beg_pos = in.tellg(); \
beg_line = linenum; \ beg_line = linenum; \
} }
#else
#define SET_BEG_POS_AND_LINE()
#endif
while (in.good() && ! in.eof()) { while (in.good() && ! in.eof()) {
char c; char c;
@ -217,11 +221,13 @@ unsigned int qif_parser_t::parse(std::istream& in,
} }
if (journal->add_entry(entry.get())) { if (journal->add_entry(entry.get())) {
#ifdef USE_EDITOR
entry->src_idx = src_idx; entry->src_idx = src_idx;
entry->beg_pos = beg_pos; entry->beg_pos = beg_pos;
entry->beg_line = beg_line; entry->beg_line = beg_line;
entry->end_pos = in.tellg(); entry->end_pos = in.tellg();
entry->end_line = linenum; entry->end_line = linenum;
#endif
entry.release(); entry.release();
count++; count++;
} }
@ -234,7 +240,9 @@ unsigned int qif_parser_t::parse(std::istream& in,
saw_splits = false; saw_splits = false;
saw_category = false; saw_category = false;
total = NULL; total = NULL;
#ifdef USE_EDITOR
beg_line = 0; beg_line = 0;
#endif
break; break;
} }

View file

@ -335,6 +335,7 @@ bool parse_transactions(std::istream& in,
} }
namespace { namespace {
TIMER_DEF(parsing_total, "total parsing time");
TIMER_DEF(entry_xacts, "parsing transactions"); TIMER_DEF(entry_xacts, "parsing transactions");
TIMER_DEF(entry_details, "parsing entry details"); TIMER_DEF(entry_details, "parsing entry details");
TIMER_DEF(entry_date, "parsing entry date"); TIMER_DEF(entry_date, "parsing entry date");
@ -401,8 +402,10 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
TIMER_START(entry_xacts); TIMER_START(entry_xacts);
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) { while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) {
#ifdef USE_EDITOR
istream_pos_type beg_pos = in.tellg(); istream_pos_type beg_pos = in.tellg();
unsigned long beg_line = linenum; unsigned long beg_line = linenum;
#endif
line[0] = '\0'; line[0] = '\0';
in.getline(line, MAX_LINE); in.getline(line, MAX_LINE);
@ -421,10 +424,12 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
xact->state == transaction_t::UNCLEARED) xact->state == transaction_t::UNCLEARED)
xact->state = state; xact->state = state;
#ifdef USE_EDITOR
xact->beg_pos = beg_pos; xact->beg_pos = beg_pos;
xact->beg_line = beg_line; xact->beg_line = beg_line;
xact->end_pos = in.tellg(); xact->end_pos = in.tellg();
xact->end_line = linenum; xact->end_line = linenum;
#endif
curr->add_transaction(xact); curr->add_transaction(xact);
} }
@ -524,6 +529,8 @@ unsigned int textual_parser_t::parse(std::istream& in,
unsigned int count = 0; unsigned int count = 0;
unsigned int errors = 0; unsigned int errors = 0;
TIMER_START(parsing_total);
std::list<account_t *> account_stack; std::list<account_t *> account_stack;
auto_entry_finalizer_t auto_entry_finalizer(journal); auto_entry_finalizer_t auto_entry_finalizer(journal);
@ -538,8 +545,10 @@ unsigned int textual_parser_t::parse(std::istream& in,
while (in.good() && ! in.eof()) { while (in.good() && ! in.eof()) {
try { try {
#ifdef USE_EDITOR
istream_pos_type beg_pos = in.tellg(); istream_pos_type beg_pos = in.tellg();
unsigned long beg_line = linenum; unsigned long beg_line = linenum;
#endif
in.getline(line, MAX_LINE); in.getline(line, MAX_LINE);
if (in.eof()) if (in.eof())
@ -693,11 +702,13 @@ unsigned int textual_parser_t::parse(std::istream& in,
auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1)); auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1));
if (parse_transactions(in, account_stack.front(), *ae, "automated")) { if (parse_transactions(in, account_stack.front(), *ae, "automated")) {
journal->auto_entries.push_back(ae); journal->auto_entries.push_back(ae);
#ifdef USE_EDITOR
ae->src_idx = src_idx; ae->src_idx = src_idx;
ae->beg_pos = beg_pos; ae->beg_pos = beg_pos;
ae->beg_line = beg_line; ae->beg_line = beg_line;
ae->end_pos = in.tellg(); ae->end_pos = in.tellg();
ae->end_line = linenum; ae->end_line = linenum;
#endif
} }
break; break;
} }
@ -712,11 +723,13 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (pe->finalize()) { if (pe->finalize()) {
extend_entry_base(journal, *pe); extend_entry_base(journal, *pe);
journal->period_entries.push_back(pe); journal->period_entries.push_back(pe);
#ifdef USE_EDITOR
pe->src_idx = src_idx; pe->src_idx = src_idx;
pe->beg_pos = beg_pos; pe->beg_pos = beg_pos;
pe->beg_line = beg_line; pe->beg_line = beg_line;
pe->end_pos = in.tellg(); pe->end_pos = in.tellg();
pe->end_line = linenum; pe->end_line = linenum;
#endif
} else { } else {
throw parse_error(path, linenum, "Period entry failed to balance"); throw parse_error(path, linenum, "Period entry failed to balance");
} }
@ -781,11 +794,13 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (entry_t * entry = parse_entry(in, line, account_stack.front(), if (entry_t * entry = parse_entry(in, line, account_stack.front(),
*this)) { *this)) {
if (journal->add_entry(entry)) { if (journal->add_entry(entry)) {
#ifdef USE_EDITOR
entry->src_idx = src_idx; entry->src_idx = src_idx;
entry->beg_pos = beg_pos; entry->beg_pos = beg_pos;
entry->beg_line = beg_line; entry->beg_line = beg_line;
entry->end_pos = in.tellg(); entry->end_pos = in.tellg();
entry->end_line = linenum; entry->end_line = linenum;
#endif
count++; count++;
} else { } else {
print_entry(std::cerr, *entry); print_entry(std::cerr, *entry);
@ -832,9 +847,13 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (errors > 0) if (errors > 0)
throw error(std::string("Errors parsing file '") + path + "'"); throw error(std::string("Errors parsing file '") + path + "'");
TIMER_STOP(parsing_total);
return count; return count;
} }
#ifdef USE_EDITOR
void write_textual_journal(journal_t& journal, std::string path, void write_textual_journal(journal_t& journal, std::string path,
item_handler<transaction_t>& formatter, item_handler<transaction_t>& formatter,
const std::string& write_hdr_format, const std::string& write_hdr_format,
@ -885,18 +904,15 @@ void write_textual_journal(journal_t& journal, std::string path,
while (! in.eof()) { while (! in.eof()) {
entry_base_t * base = NULL; entry_base_t * base = NULL;
if (el != journal.entries.end() && if (el != journal.entries.end() && pos == (*el)->beg_pos) {
pos == (*el)->beg_pos) {
hdr_fmt.format(out, details_t(**el)); hdr_fmt.format(out, details_t(**el));
base = *el++; base = *el++;
} }
else if (al != journal.auto_entries.end() && else if (al != journal.auto_entries.end() && pos == (*al)->beg_pos) {
pos == (*al)->beg_pos) {
out << "= " << (*al)->predicate_string << '\n'; out << "= " << (*al)->predicate_string << '\n';
base = *al++; base = *al++;
} }
else if (pl != journal.period_entries.end() && else if (pl != journal.period_entries.end() && pos == (*pl)->beg_pos) {
pos == (*pl)->beg_pos) {
out << "~ " << (*pl)->period_string << '\n'; out << "~ " << (*pl)->period_string << '\n';
base = *pl++; base = *pl++;
} }
@ -924,4 +940,6 @@ void write_textual_journal(journal_t& journal, std::string path,
} }
} }
#endif // USE_EDITOR
} // namespace ledger } // namespace ledger