Reworked the way date/times are handled.
This commit is contained in:
parent
c3c401ac0f
commit
5a93d4819e
33 changed files with 1043 additions and 764 deletions
51
amount.cc
51
amount.cc
|
|
@ -1,5 +1,4 @@
|
|||
#include "amount.h"
|
||||
#include "datetime.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <list>
|
||||
|
|
@ -607,7 +606,7 @@ bool amount_t::realzero() const
|
|||
return mpz_sgn(MPZ(quantity)) == 0;
|
||||
}
|
||||
|
||||
amount_t amount_t::value(const std::time_t moment) const
|
||||
amount_t amount_t::value(const datetime_t& moment) const
|
||||
{
|
||||
if (quantity) {
|
||||
amount_t amt(commodity().value(moment));
|
||||
|
|
@ -999,7 +998,7 @@ void parse_commodity(std::istream& in, std::string& symbol)
|
|||
}
|
||||
|
||||
void parse_annotations(std::istream& in, amount_t& price,
|
||||
std::time_t& date, std::string& tag)
|
||||
datetime_t& date, std::string& tag)
|
||||
{
|
||||
do {
|
||||
char buf[256];
|
||||
|
|
@ -1036,7 +1035,7 @@ void parse_annotations(std::istream& in, amount_t& price,
|
|||
else
|
||||
throw new amount_error("Commodity date lacks closing bracket");
|
||||
|
||||
parse_date(buf, &date);
|
||||
date = buf;
|
||||
}
|
||||
else if (c == '(') {
|
||||
if (! tag.empty())
|
||||
|
|
@ -1073,7 +1072,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
|||
std::string symbol;
|
||||
std::string quant;
|
||||
amount_t price;
|
||||
std::time_t date = 0;
|
||||
datetime_t date;
|
||||
std::string tag;
|
||||
unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS;
|
||||
bool negative = false;
|
||||
|
|
@ -1378,7 +1377,7 @@ bool amount_t::valid() const
|
|||
}
|
||||
|
||||
void amount_t::annotate_commodity(const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag)
|
||||
{
|
||||
const commodity_t * this_base;
|
||||
|
|
@ -1401,7 +1400,7 @@ void amount_t::annotate_commodity(const amount_t& price,
|
|||
commodity_t * ann_comm =
|
||||
annotated_commodity_t::find_or_create
|
||||
(*this_base, ! price && this_ann ? this_ann->price : price,
|
||||
date == 0 && this_ann ? this_ann->date : date,
|
||||
! date && this_ann ? this_ann->date : date,
|
||||
tag.empty() && this_ann ? this_ann->tag : tag);
|
||||
if (ann_comm)
|
||||
set_commodity(*ann_comm);
|
||||
|
|
@ -1435,7 +1434,8 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
|
|||
{
|
||||
new_comm = annotated_commodity_t::find_or_create
|
||||
(*ann_comm.ptr, _keep_price ? ann_comm.price : amount_t(),
|
||||
_keep_date ? ann_comm.date : 0, _keep_tag ? ann_comm.tag : "");
|
||||
_keep_date ? ann_comm.date : datetime_t(),
|
||||
_keep_tag ? ann_comm.tag : "");
|
||||
} else {
|
||||
new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
|
||||
}
|
||||
|
|
@ -1461,7 +1461,7 @@ amount_t amount_t::price() const
|
|||
return *this;
|
||||
}
|
||||
|
||||
std::time_t amount_t::date() const
|
||||
datetime_t amount_t::date() const
|
||||
{
|
||||
if (commodity_ && commodity_->annotated) {
|
||||
DEBUG_PRINT("amounts.commodities",
|
||||
|
|
@ -1473,7 +1473,8 @@ std::time_t amount_t::date() const
|
|||
}
|
||||
|
||||
|
||||
void commodity_base_t::add_price(const std::time_t date, const amount_t& price)
|
||||
void commodity_base_t::add_price(const datetime_t& date,
|
||||
const amount_t& price)
|
||||
{
|
||||
if (! history)
|
||||
history = new history_t;
|
||||
|
|
@ -1488,7 +1489,7 @@ void commodity_base_t::add_price(const std::time_t date, const amount_t& price)
|
|||
}
|
||||
}
|
||||
|
||||
bool commodity_base_t::remove_price(const std::time_t date)
|
||||
bool commodity_base_t::remove_price(const datetime_t& date)
|
||||
{
|
||||
if (history) {
|
||||
history_map::size_type n = history->prices.erase(date);
|
||||
|
|
@ -1595,15 +1596,15 @@ commodity_t * commodity_t::find(const std::string& symbol)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
amount_t commodity_base_t::value(const std::time_t moment)
|
||||
amount_t commodity_base_t::value(const datetime_t& moment)
|
||||
{
|
||||
std::time_t age = 0;
|
||||
amount_t price;
|
||||
datetime_t age;
|
||||
amount_t price;
|
||||
|
||||
if (history) {
|
||||
assert(history->prices.size() > 0);
|
||||
|
||||
if (moment == 0) {
|
||||
if (! moment) {
|
||||
history_map::reverse_iterator r = history->prices.rbegin();
|
||||
age = (*r).first;
|
||||
price = (*r).second;
|
||||
|
|
@ -1615,7 +1616,7 @@ amount_t commodity_base_t::value(const std::time_t moment)
|
|||
price = (*r).second;
|
||||
} else {
|
||||
age = (*i).first;
|
||||
if (std::difftime(moment, age) != 0) {
|
||||
if (moment != age) {
|
||||
if (i != history->prices.begin()) {
|
||||
--i;
|
||||
age = (*i).first;
|
||||
|
|
@ -1633,7 +1634,7 @@ amount_t commodity_base_t::value(const std::time_t moment)
|
|||
if (updater && ! (flags & COMMODITY_STYLE_NOMARKET))
|
||||
(*updater)(*this, moment, age,
|
||||
(history && history->prices.size() > 0 ?
|
||||
(*history->prices.rbegin()).first : 0), price);
|
||||
(*history->prices.rbegin()).first : datetime_t()), price);
|
||||
|
||||
return price;
|
||||
}
|
||||
|
|
@ -1665,14 +1666,14 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
|
|||
void
|
||||
annotated_commodity_t::write_annotations(std::ostream& out,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag)
|
||||
{
|
||||
if (price)
|
||||
out << " {" << price << '}';
|
||||
|
||||
if (date)
|
||||
out << " [" << datetime_t(date) << ']';
|
||||
out << " [" << date << ']';
|
||||
|
||||
if (! tag.empty())
|
||||
out << " (" << tag << ')';
|
||||
|
|
@ -1681,7 +1682,7 @@ annotated_commodity_t::write_annotations(std::ostream& out,
|
|||
commodity_t *
|
||||
annotated_commodity_t::create(const commodity_t& comm,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag,
|
||||
const std::string& mapping_key)
|
||||
{
|
||||
|
|
@ -1719,7 +1720,7 @@ annotated_commodity_t::create(const commodity_t& comm,
|
|||
namespace {
|
||||
std::string make_qualified_name(const commodity_t& comm,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag)
|
||||
{
|
||||
if (price < 0)
|
||||
|
|
@ -1745,7 +1746,7 @@ namespace {
|
|||
commodity_t *
|
||||
annotated_commodity_t::find_or_create(const commodity_t& comm,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag)
|
||||
{
|
||||
std::string name = make_qualified_name(comm, price, date, tag);
|
||||
|
|
@ -1862,9 +1863,9 @@ struct commodity_updater_wrap : public commodity_base_t::updater_t
|
|||
commodity_updater_wrap(PyObject * self_) : self(self_) {}
|
||||
|
||||
virtual void operator()(commodity_base_t& commodity,
|
||||
const std::time_t moment,
|
||||
const std::time_t date,
|
||||
const std::time_t last,
|
||||
const datetime_t& moment,
|
||||
const datetime_t& date,
|
||||
const datetime_t& last,
|
||||
amount_t& price) {
|
||||
call_method<void>(self, "__call__", commodity, moment, date, last, price);
|
||||
}
|
||||
|
|
|
|||
51
amount.h
51
amount.h
|
|
@ -4,13 +4,13 @@
|
|||
#include <map>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
|
||||
#include "datetime.h"
|
||||
#include "debug.h"
|
||||
#include "error.h"
|
||||
|
||||
|
|
@ -81,8 +81,8 @@ class amount_t
|
|||
void set_commodity(commodity_t& comm) {
|
||||
commodity_ = &comm;
|
||||
}
|
||||
void annotate_commodity(const amount_t& price,
|
||||
const std::time_t date = 0,
|
||||
void annotate_commodity(const amount_t& price,
|
||||
const datetime_t& date = datetime_t(),
|
||||
const std::string& tag = "");
|
||||
amount_t strip_annotations(const bool _keep_price = keep_price,
|
||||
const bool _keep_date = keep_date,
|
||||
|
|
@ -91,7 +91,7 @@ class amount_t
|
|||
commodity_ = NULL;
|
||||
}
|
||||
amount_t price() const;
|
||||
std::time_t date() const;
|
||||
datetime_t date() const;
|
||||
|
||||
bool null() const {
|
||||
return ! quantity && ! commodity_;
|
||||
|
|
@ -253,7 +253,7 @@ class amount_t
|
|||
return ! (*this == num);
|
||||
}
|
||||
|
||||
amount_t value(const std::time_t moment) const;
|
||||
amount_t value(const datetime_t& moment) const;
|
||||
|
||||
void abs() {
|
||||
if (*this < 0)
|
||||
|
|
@ -297,7 +297,7 @@ class amount_t
|
|||
char * item_pool_end);
|
||||
|
||||
friend void parse_annotations(std::istream& in, amount_t& price,
|
||||
std::time_t& date, std::string& tag);
|
||||
datetime_t& date, std::string& tag);
|
||||
};
|
||||
|
||||
unsigned int sizeof_bigint_t();
|
||||
|
|
@ -356,8 +356,8 @@ inline std::istream& operator>>(std::istream& in, amount_t& amt) {
|
|||
#define COMMODITY_STYLE_NOMARKET 0x0010
|
||||
#define COMMODITY_STYLE_BUILTIN 0x0020
|
||||
|
||||
typedef std::map<const std::time_t, amount_t> history_map;
|
||||
typedef std::pair<const std::time_t, amount_t> history_pair;
|
||||
typedef std::map<const datetime_t, amount_t> history_map;
|
||||
typedef std::pair<const datetime_t, amount_t> history_pair;
|
||||
|
||||
class commodity_base_t;
|
||||
|
||||
|
|
@ -403,24 +403,24 @@ class commodity_base_t
|
|||
|
||||
struct history_t {
|
||||
history_map prices;
|
||||
std::time_t last_lookup;
|
||||
std::time_t bogus_time;
|
||||
datetime_t last_lookup;
|
||||
datetime_t bogus_time;
|
||||
history_t() : last_lookup(0), bogus_time(0) {}
|
||||
};
|
||||
history_t * history;
|
||||
|
||||
void add_price(const std::time_t date, const amount_t& price);
|
||||
bool remove_price(const std::time_t date);
|
||||
amount_t value(const std::time_t moment = std::time(NULL));
|
||||
void add_price(const datetime_t& date, const amount_t& price);
|
||||
bool remove_price(const datetime_t& date);
|
||||
amount_t value(const datetime_t& moment = datetime_t::now);
|
||||
|
||||
class updater_t {
|
||||
public:
|
||||
virtual ~updater_t() {}
|
||||
virtual void operator()(commodity_base_t& commodity,
|
||||
const std::time_t moment,
|
||||
const std::time_t date,
|
||||
const std::time_t last,
|
||||
amount_t& price) = 0;
|
||||
const datetime_t& moment,
|
||||
const datetime_t& date,
|
||||
const datetime_t& last,
|
||||
amount_t& price) = 0;
|
||||
};
|
||||
friend class updater_t;
|
||||
|
||||
|
|
@ -543,13 +543,13 @@ class commodity_t
|
|||
return base->history;
|
||||
}
|
||||
|
||||
void add_price(const std::time_t date, const amount_t& price) {
|
||||
void add_price(const datetime_t& date, const amount_t& price) {
|
||||
return base->add_price(date, price);
|
||||
}
|
||||
bool remove_price(const std::time_t date) {
|
||||
bool remove_price(const datetime_t& date) {
|
||||
return base->remove_price(date);
|
||||
}
|
||||
amount_t value(const std::time_t moment = std::time(NULL)) const {
|
||||
amount_t value(const datetime_t& moment = datetime_t::now) const {
|
||||
return base->value(moment);
|
||||
}
|
||||
|
||||
|
|
@ -562,7 +562,7 @@ class annotated_commodity_t : public commodity_t
|
|||
const commodity_t * ptr;
|
||||
|
||||
amount_t price;
|
||||
std::time_t date;
|
||||
datetime_t date;
|
||||
std::string tag;
|
||||
|
||||
explicit annotated_commodity_t() {
|
||||
|
|
@ -577,25 +577,26 @@ class annotated_commodity_t : public commodity_t
|
|||
|
||||
static void write_annotations(std::ostream& out,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag);
|
||||
|
||||
private:
|
||||
static commodity_t * create(const commodity_t& comm,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag,
|
||||
const std::string& mapping_key);
|
||||
|
||||
static commodity_t * find_or_create(const commodity_t& comm,
|
||||
const amount_t& price,
|
||||
const std::time_t date,
|
||||
const datetime_t& date,
|
||||
const std::string& tag);
|
||||
|
||||
friend class amount_t;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const commodity_t& comm) {
|
||||
out << comm.symbol();
|
||||
return out;
|
||||
}
|
||||
|
|
|
|||
12
balance.cc
12
balance.cc
|
|
@ -33,7 +33,7 @@ amount_t balance_t::amount(const commodity_t& commodity) const
|
|||
return amount_t();
|
||||
}
|
||||
|
||||
balance_t balance_t::value(const std::time_t moment) const
|
||||
balance_t balance_t::value(const datetime_t& moment) const
|
||||
{
|
||||
balance_t temp;
|
||||
|
||||
|
|
@ -57,18 +57,18 @@ balance_t balance_t::price() const
|
|||
return temp;
|
||||
}
|
||||
|
||||
std::time_t balance_t::date() const
|
||||
datetime_t balance_t::date() const
|
||||
{
|
||||
std::time_t temp = 0;
|
||||
datetime_t temp;
|
||||
|
||||
for (amounts_map::const_iterator i = amounts.begin();
|
||||
i != amounts.end();
|
||||
i++) {
|
||||
std::time_t date = (*i).second.date();
|
||||
if (temp == 0 && date != 0)
|
||||
datetime_t date = (*i).second.date();
|
||||
if (! temp && date)
|
||||
temp = date;
|
||||
else if (temp != date)
|
||||
return 0;
|
||||
return datetime_t();
|
||||
}
|
||||
|
||||
return temp;
|
||||
|
|
|
|||
16
balance.h
16
balance.h
|
|
@ -2,10 +2,8 @@
|
|||
#define _BALANCE_H
|
||||
|
||||
#include "amount.h"
|
||||
#include "datetime.h"
|
||||
|
||||
#include <map>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace ledger {
|
||||
|
|
@ -428,11 +426,11 @@ class balance_t
|
|||
return true;
|
||||
}
|
||||
|
||||
amount_t amount(const commodity_t& commodity =
|
||||
*commodity_t::null_commodity) const;
|
||||
balance_t value(const std::time_t moment = now) const;
|
||||
balance_t price() const;
|
||||
std::time_t date() const;
|
||||
amount_t amount(const commodity_t& commodity =
|
||||
*commodity_t::null_commodity) const;
|
||||
balance_t value(const datetime_t& moment = datetime_t::now) const;
|
||||
balance_t price() const;
|
||||
datetime_t date() const;
|
||||
|
||||
balance_t
|
||||
strip_annotations(const bool keep_price = amount_t::keep_price,
|
||||
|
|
@ -870,13 +868,13 @@ class balance_pair_t
|
|||
*commodity_t::null_commodity) const {
|
||||
return quantity.amount(commodity);
|
||||
}
|
||||
balance_t value(const std::time_t moment = now) const {
|
||||
balance_t value(const datetime_t& moment = datetime_t::now) const {
|
||||
return quantity.value(moment);
|
||||
}
|
||||
balance_t price() const {
|
||||
return quantity.price();
|
||||
}
|
||||
std::time_t date() const {
|
||||
datetime_t date() const {
|
||||
return quantity.date();
|
||||
}
|
||||
|
||||
|
|
|
|||
321
binary.cc
321
binary.cc
|
|
@ -3,7 +3,6 @@
|
|||
#include "binary.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define TIMELOG_SUPPORT 1
|
||||
|
|
@ -12,9 +11,9 @@ namespace ledger {
|
|||
|
||||
static unsigned long binary_magic_number = 0xFFEED765;
|
||||
#ifdef DEBUG_ENABLED
|
||||
static unsigned long format_version = 0x00020609;
|
||||
static unsigned long format_version = 0x0002060b;
|
||||
#else
|
||||
static unsigned long format_version = 0x00020608;
|
||||
static unsigned long format_version = 0x0002060a;
|
||||
#endif
|
||||
|
||||
static account_t ** accounts;
|
||||
|
|
@ -34,43 +33,83 @@ extern char * bigints_next;
|
|||
extern unsigned int bigints_index;
|
||||
extern unsigned int bigints_count;
|
||||
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
#define read_binary_guard(in, id) { \
|
||||
unsigned short guard; \
|
||||
in.read((char *)&guard, sizeof(guard)); \
|
||||
assert(guard == id); \
|
||||
template <typename T>
|
||||
inline void read_binary_number_nocheck(std::istream& in, T& num) {
|
||||
in.read((char *)&num, sizeof(num));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T read_binary_number_nocheck(std::istream& in) {
|
||||
T num;
|
||||
read_binary_number_nocheck(in, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void read_binary_number_nocheck(char *& data, T& num) {
|
||||
num = *((T *) data);
|
||||
data += sizeof(T);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T read_binary_number_nocheck(char *& data) {
|
||||
T num;
|
||||
read_binary_number_nocheck(data, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
static void assert_failed() {
|
||||
assert(0);
|
||||
}
|
||||
#define read_binary_guard(in, id) \
|
||||
if (read_binary_number_nocheck<unsigned short>(in) != id) \
|
||||
assert_failed();
|
||||
#else
|
||||
#define read_binary_guard(in, id)
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline void read_binary_number(std::istream& in, T& num) {
|
||||
read_binary_guard(in, 0x2003);
|
||||
in.read((char *)&num, sizeof(num));
|
||||
read_binary_guard(in, 0x2004);
|
||||
}
|
||||
|
||||
inline void read_binary_bool(std::istream& in, bool& num) {
|
||||
read_binary_guard(in, 0x2005);
|
||||
unsigned char val;
|
||||
in.read((char *)&val, sizeof(val));
|
||||
num = val == 1;
|
||||
read_binary_guard(in, 0x2006);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void read_binary_long(std::istream& in, T& num) {
|
||||
read_binary_guard(in, 0x2001);
|
||||
|
||||
unsigned char len;
|
||||
in.read((char *)&len, sizeof(unsigned char));
|
||||
read_binary_number_nocheck(in, len);
|
||||
|
||||
num = 0;
|
||||
unsigned char temp;
|
||||
if (len > 3) {
|
||||
in.read((char *)&temp, sizeof(unsigned char));
|
||||
read_binary_number_nocheck(in, temp);
|
||||
num |= ((unsigned long)temp) << 24;
|
||||
}
|
||||
if (len > 2) {
|
||||
in.read((char *)&temp, sizeof(unsigned char));
|
||||
read_binary_number_nocheck(in, temp);
|
||||
num |= ((unsigned long)temp) << 16;
|
||||
}
|
||||
if (len > 1) {
|
||||
in.read((char *)&temp, sizeof(unsigned char));
|
||||
read_binary_number_nocheck(in, temp);
|
||||
num |= ((unsigned long)temp) << 8;
|
||||
}
|
||||
|
||||
in.read((char *)&temp, sizeof(unsigned char));
|
||||
read_binary_number_nocheck(in, temp);
|
||||
num |= ((unsigned long)temp);
|
||||
|
||||
read_binary_guard(in, 0x2002);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -80,6 +119,12 @@ inline T read_binary_number(std::istream& in) {
|
|||
return num;
|
||||
}
|
||||
|
||||
inline bool read_binary_bool(std::istream& in) {
|
||||
bool num;
|
||||
read_binary_bool(in, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T read_binary_long(std::istream& in) {
|
||||
T num;
|
||||
|
|
@ -92,10 +137,10 @@ inline void read_binary_string(std::istream& in, std::string& str)
|
|||
read_binary_guard(in, 0x3001);
|
||||
|
||||
unsigned char len;
|
||||
read_binary_number(in, len);
|
||||
read_binary_number_nocheck(in, len);
|
||||
if (len == 0xff) {
|
||||
unsigned short slen;
|
||||
read_binary_number(in, slen);
|
||||
read_binary_number_nocheck(in, slen);
|
||||
char * buf = new char[slen + 1];
|
||||
in.read(buf, slen);
|
||||
buf[slen] = '\0';
|
||||
|
|
@ -114,8 +159,7 @@ inline void read_binary_string(std::istream& in, std::string& str)
|
|||
read_binary_guard(in, 0x3002);
|
||||
}
|
||||
|
||||
inline std::string read_binary_string(std::istream& in)
|
||||
{
|
||||
inline std::string read_binary_string(std::istream& in) {
|
||||
std::string temp;
|
||||
read_binary_string(in, temp);
|
||||
return temp;
|
||||
|
|
@ -123,31 +167,46 @@ inline std::string read_binary_string(std::istream& in)
|
|||
|
||||
template <typename T>
|
||||
inline void read_binary_number(char *& data, T& num) {
|
||||
read_binary_guard(data, 0x2003);
|
||||
num = *((T *) data);
|
||||
data += sizeof(T);
|
||||
read_binary_guard(data, 0x2004);
|
||||
}
|
||||
|
||||
inline void read_binary_bool(char *& data, bool& num) {
|
||||
read_binary_guard(data, 0x2005);
|
||||
unsigned char val = *((unsigned char *) data);
|
||||
data += sizeof(unsigned char);
|
||||
num = val == 1;
|
||||
read_binary_guard(data, 0x2006);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void read_binary_long(char *& data, T& num) {
|
||||
unsigned char len = *((unsigned char *)data++);
|
||||
read_binary_guard(data, 0x2001);
|
||||
|
||||
unsigned char len;
|
||||
read_binary_number_nocheck(data, len);
|
||||
|
||||
num = 0;
|
||||
unsigned char temp;
|
||||
if (len > 3) {
|
||||
temp = *((unsigned char *)data++);
|
||||
read_binary_number_nocheck(data, temp);
|
||||
num |= ((unsigned long)temp) << 24;
|
||||
}
|
||||
if (len > 2) {
|
||||
temp = *((unsigned char *)data++);
|
||||
read_binary_number_nocheck(data, temp);
|
||||
num |= ((unsigned long)temp) << 16;
|
||||
}
|
||||
if (len > 1) {
|
||||
temp = *((unsigned char *)data++);
|
||||
read_binary_number_nocheck(data, temp);
|
||||
num |= ((unsigned long)temp) << 8;
|
||||
}
|
||||
|
||||
temp = *((unsigned char *)data++);
|
||||
read_binary_number_nocheck(data, temp);
|
||||
num |= ((unsigned long)temp);
|
||||
|
||||
read_binary_guard(data, 0x2002);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -157,6 +216,12 @@ inline T read_binary_number(char *& data) {
|
|||
return num;
|
||||
}
|
||||
|
||||
inline bool read_binary_bool(char *& data) {
|
||||
bool num;
|
||||
read_binary_bool(data, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T read_binary_long(char *& data) {
|
||||
T num;
|
||||
|
|
@ -166,18 +231,15 @@ inline T read_binary_long(char *& data) {
|
|||
|
||||
inline void read_binary_string(char *& data, std::string& str)
|
||||
{
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
unsigned short guard;
|
||||
guard = *((unsigned short *) data);
|
||||
data += sizeof(unsigned short);
|
||||
assert(guard == 0x3001);
|
||||
#endif
|
||||
read_binary_guard(data, 0x3001);
|
||||
|
||||
unsigned char len = *data++;
|
||||
unsigned char len;
|
||||
read_binary_number_nocheck(data, len);
|
||||
if (len == 0xff) {
|
||||
unsigned short slen = *((unsigned short *) data);
|
||||
str = std::string(data + sizeof(unsigned short), slen);
|
||||
data += sizeof(unsigned short) + slen;
|
||||
unsigned short slen;
|
||||
read_binary_number_nocheck(data, slen);
|
||||
str = std::string(data, slen);
|
||||
data += slen;
|
||||
}
|
||||
else if (len) {
|
||||
str = std::string(data, len);
|
||||
|
|
@ -187,11 +249,7 @@ inline void read_binary_string(char *& data, std::string& str)
|
|||
str = "";
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
guard = *((unsigned short *) data);
|
||||
data += sizeof(unsigned short);
|
||||
assert(guard == 0x3002);
|
||||
#endif
|
||||
read_binary_guard(data, 0x3002);
|
||||
}
|
||||
|
||||
inline std::string read_binary_string(char *& data)
|
||||
|
|
@ -203,18 +261,15 @@ inline std::string read_binary_string(char *& data)
|
|||
|
||||
inline void read_binary_string(char *& data, std::string * str)
|
||||
{
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
unsigned short guard;
|
||||
guard = *((unsigned short *) data);
|
||||
data += sizeof(unsigned short);
|
||||
assert(guard == 0x3001);
|
||||
#endif
|
||||
read_binary_guard(data, 0x3001);
|
||||
|
||||
unsigned char len = *data++;
|
||||
unsigned char len;
|
||||
read_binary_number_nocheck(data, len);
|
||||
if (len == 0xff) {
|
||||
unsigned short slen = *((unsigned short *) data);
|
||||
new(str) std::string(data + sizeof(unsigned short), slen);
|
||||
data += sizeof(unsigned short) + slen;
|
||||
unsigned short slen;
|
||||
read_binary_number_nocheck(data, slen);
|
||||
new(str) std::string(data, slen);
|
||||
data += slen;
|
||||
}
|
||||
else if (len) {
|
||||
new(str) std::string(data, len);
|
||||
|
|
@ -224,11 +279,7 @@ inline void read_binary_string(char *& data, std::string * str)
|
|||
new(str) std::string("");
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
guard = *((unsigned short *) data);
|
||||
data += sizeof(unsigned short);
|
||||
assert(guard == 0x3002);
|
||||
#endif
|
||||
read_binary_guard(data, 0x3002);
|
||||
}
|
||||
|
||||
inline void read_binary_amount(char *& data, amount_t& amt)
|
||||
|
|
@ -251,13 +302,13 @@ inline void read_binary_value(char *& data, value_t& val)
|
|||
|
||||
switch (val.type) {
|
||||
case value_t::BOOLEAN:
|
||||
*((bool *) val.data) = read_binary_number<char>(data) == 1;
|
||||
read_binary_bool(data, *((bool *) val.data));
|
||||
break;
|
||||
case value_t::INTEGER:
|
||||
read_binary_long(data, *((long *) val.data));
|
||||
break;
|
||||
case value_t::DATETIME:
|
||||
read_binary_number(data, ((datetime_t *) val.data)->when);
|
||||
read_binary_number(data, *((datetime_t *) val.data));
|
||||
break;
|
||||
case value_t::AMOUNT:
|
||||
read_binary_amount(data, *((amount_t *) val.data));
|
||||
|
|
@ -283,7 +334,7 @@ inline void read_binary_mask(char *& data, mask_t *& mask)
|
|||
|
||||
inline void read_binary_value_expr(char *& data, value_expr_t *& expr)
|
||||
{
|
||||
if (read_binary_number<unsigned char>(data) == 0) {
|
||||
if (! read_binary_bool(data)) {
|
||||
expr = NULL;
|
||||
return;
|
||||
}
|
||||
|
|
@ -314,7 +365,7 @@ inline void read_binary_value_expr(char *& data, value_expr_t *& expr)
|
|||
case value_expr_t::F_ACCOUNT_MASK:
|
||||
case value_expr_t::F_SHORT_ACCOUNT_MASK:
|
||||
case value_expr_t::F_COMMODITY_MASK:
|
||||
if (read_binary_number<unsigned char>(data) == 1)
|
||||
if (read_binary_bool(data))
|
||||
read_binary_mask(data, expr->mask);
|
||||
break;
|
||||
|
||||
|
|
@ -330,11 +381,11 @@ inline void read_binary_value_expr(char *& data, value_expr_t *& expr)
|
|||
|
||||
inline void read_binary_transaction(char *& data, transaction_t * xact)
|
||||
{
|
||||
read_binary_long(data, xact->_date);
|
||||
read_binary_long(data, xact->_date_eff);
|
||||
read_binary_number(data, xact->_date);
|
||||
read_binary_number(data, xact->_date_eff);
|
||||
xact->account = accounts[read_binary_long<account_t::ident_t>(data) - 1];
|
||||
|
||||
char flag = read_binary_number<char>(data);
|
||||
unsigned char flag = read_binary_number<unsigned char>(data);
|
||||
if (flag == 0) {
|
||||
read_binary_amount(data, xact->amount);
|
||||
}
|
||||
|
|
@ -350,7 +401,7 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
|
|||
read_binary_string(data, xact->amount_expr.expr);
|
||||
}
|
||||
|
||||
if (*data++ == 1) {
|
||||
if (read_binary_bool(data)) {
|
||||
xact->cost = new amount_t;
|
||||
read_binary_amount(data, *xact->cost);
|
||||
read_binary_string(data, xact->cost_expr);
|
||||
|
|
@ -383,7 +434,7 @@ inline void read_binary_entry_base(char *& data, entry_base_t * entry,
|
|||
entry->end_pos = read_binary_long<unsigned long>(data);
|
||||
read_binary_long(data, entry->end_line);
|
||||
|
||||
bool ignore_calculated = read_binary_number<char>(data) == 1;
|
||||
bool ignore_calculated = read_binary_bool(data);
|
||||
|
||||
for (unsigned long i = 0, count = read_binary_long<unsigned long>(data);
|
||||
i < count;
|
||||
|
|
@ -400,8 +451,8 @@ inline void read_binary_entry(char *& data, entry_t * entry,
|
|||
transaction_t *& xact_pool, bool& finalize)
|
||||
{
|
||||
read_binary_entry_base(data, entry, xact_pool, finalize);
|
||||
read_binary_long(data, entry->_date);
|
||||
read_binary_long(data, entry->_date_eff);
|
||||
read_binary_number(data, entry->_date);
|
||||
read_binary_number(data, entry->_date_eff);
|
||||
read_binary_string(data, &entry->code);
|
||||
read_binary_string(data, &entry->payee);
|
||||
}
|
||||
|
|
@ -449,8 +500,8 @@ inline void read_binary_commodity_base_extra(char *& data,
|
|||
for (unsigned long i = 0, count = read_binary_long<unsigned long>(data);
|
||||
i < count;
|
||||
i++) {
|
||||
std::time_t when;
|
||||
read_binary_long(data, when);
|
||||
datetime_t when;
|
||||
read_binary_number(data, when);
|
||||
amount_t amt;
|
||||
read_binary_amount(data, amt);
|
||||
|
||||
|
|
@ -460,22 +511,19 @@ inline void read_binary_commodity_base_extra(char *& data,
|
|||
if (! commodity->history)
|
||||
commodity->history = new commodity_base_t::history_t;
|
||||
commodity->history->prices.insert(history_pair(when, amt));
|
||||
|
||||
read_history = true;
|
||||
}
|
||||
if (read_history)
|
||||
read_binary_long(data, commodity->history->last_lookup);
|
||||
read_binary_number(data, commodity->history->last_lookup);
|
||||
|
||||
unsigned char flag;
|
||||
|
||||
flag = read_binary_number<unsigned char>(data);
|
||||
if (flag) {
|
||||
if (read_binary_bool(data)) {
|
||||
amount_t amt;
|
||||
read_binary_amount(data, amt);
|
||||
commodity->smaller = new amount_t(amt);
|
||||
}
|
||||
|
||||
flag = read_binary_number<unsigned char>(data);
|
||||
if (flag) {
|
||||
if (read_binary_bool(data)) {
|
||||
amount_t amt;
|
||||
read_binary_amount(data, amt);
|
||||
commodity->larger = new amount_t(amt);
|
||||
|
|
@ -517,7 +565,7 @@ inline commodity_t * read_binary_commodity_annotated(char *& data)
|
|||
read_binary_amount(data, amt);
|
||||
commodity->price = amt;
|
||||
|
||||
read_binary_long(data, commodity->date);
|
||||
read_binary_number(data, commodity->date);
|
||||
read_binary_string(data, commodity->tag);
|
||||
|
||||
return commodity;
|
||||
|
|
@ -584,7 +632,7 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
i++) {
|
||||
std::string path = read_binary_string(in);
|
||||
std::time_t old_mtime;
|
||||
read_binary_long(in, old_mtime);
|
||||
read_binary_number(in, old_mtime);
|
||||
struct stat info;
|
||||
stat(path.c_str(), &info);
|
||||
if (std::difftime(info.st_mtime, old_mtime) > 0)
|
||||
|
|
@ -618,7 +666,7 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
delete journal->master;
|
||||
journal->master = read_binary_account(data, journal, master);
|
||||
|
||||
if (read_binary_number<bool>(data))
|
||||
if (read_binary_bool(data))
|
||||
journal->basket = accounts[read_binary_long<account_t::ident_t>(data) - 1];
|
||||
|
||||
// Allocate the memory needed for the entries and transactions in
|
||||
|
|
@ -693,7 +741,7 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
commodity_t * commodity;
|
||||
std::string mapping_key;
|
||||
|
||||
if (read_binary_number<char>(data) == 0) {
|
||||
if (! read_binary_bool(data)) {
|
||||
commodity = read_binary_commodity(data);
|
||||
mapping_key = commodity->base->symbol;
|
||||
} else {
|
||||
|
|
@ -768,8 +816,8 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
|
||||
bool binary_parser_t::test(std::istream& in) const
|
||||
{
|
||||
if (read_binary_number<unsigned long>(in) == binary_magic_number &&
|
||||
read_binary_number<unsigned long>(in) == format_version)
|
||||
if (read_binary_number_nocheck<unsigned long>(in) == binary_magic_number &&
|
||||
read_binary_number_nocheck<unsigned long>(in) == format_version)
|
||||
return true;
|
||||
|
||||
in.clear();
|
||||
|
|
@ -787,22 +835,36 @@ unsigned int binary_parser_t::parse(std::istream& in,
|
|||
journal, master);
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
#define write_binary_guard(in, id) { \
|
||||
unsigned short guard = id; \
|
||||
out.write((char *)&guard, sizeof(guard)); \
|
||||
template <typename T>
|
||||
inline void write_binary_number_nocheck(std::ostream& out, T num) {
|
||||
out.write((char *)&num, sizeof(num));
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL >= ALPHA
|
||||
#define write_binary_guard(out, id) \
|
||||
write_binary_number_nocheck<unsigned short>(out, id)
|
||||
#else
|
||||
#define write_binary_guard(in, id)
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline void write_binary_number(std::ostream& out, T num) {
|
||||
write_binary_guard(out, 0x2003);
|
||||
out.write((char *)&num, sizeof(num));
|
||||
write_binary_guard(out, 0x2004);
|
||||
}
|
||||
|
||||
inline void write_binary_bool(std::ostream& out, bool num) {
|
||||
write_binary_guard(out, 0x2005);
|
||||
unsigned char val = num ? 1 : 0;
|
||||
out.write((char *)&val, sizeof(val));
|
||||
write_binary_guard(out, 0x2006);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void write_binary_long(std::ostream& out, T num) {
|
||||
write_binary_guard(out, 0x2001);
|
||||
|
||||
unsigned char len = 4;
|
||||
if (((unsigned long)num) < 0x00000100UL)
|
||||
len = 1;
|
||||
|
|
@ -810,23 +872,26 @@ inline void write_binary_long(std::ostream& out, T num) {
|
|||
len = 2;
|
||||
else if (((unsigned long)num) < 0x01000000UL)
|
||||
len = 3;
|
||||
out.write((char *)&len, sizeof(unsigned char));
|
||||
write_binary_number_nocheck<unsigned char>(out, len);
|
||||
|
||||
unsigned char temp;
|
||||
if (len > 3) {
|
||||
unsigned char temp = (((unsigned long)num) & 0xFF000000UL) >> 24;
|
||||
out.write((char *)&temp, sizeof(unsigned char));
|
||||
temp = (((unsigned long)num) & 0xFF000000UL) >> 24;
|
||||
write_binary_number_nocheck(out, temp);
|
||||
}
|
||||
if (len > 2) {
|
||||
unsigned char temp = (((unsigned long)num) & 0x00FF0000UL) >> 16;
|
||||
out.write((char *)&temp, sizeof(unsigned char));
|
||||
temp = (((unsigned long)num) & 0x00FF0000UL) >> 16;
|
||||
write_binary_number_nocheck(out, temp);
|
||||
}
|
||||
if (len > 1) {
|
||||
unsigned char temp = (((unsigned long)num) & 0x0000FF00UL) >> 8;
|
||||
out.write((char *)&temp, sizeof(unsigned char));
|
||||
temp = (((unsigned long)num) & 0x0000FF00UL) >> 8;
|
||||
write_binary_number_nocheck(out, temp);
|
||||
}
|
||||
|
||||
unsigned char temp = (((unsigned long)num) & 0x000000FFUL);
|
||||
out.write((char *)&temp, sizeof(unsigned char));
|
||||
temp = (((unsigned long)num) & 0x000000FFUL);
|
||||
write_binary_number_nocheck(out, temp);
|
||||
|
||||
write_binary_guard(out, 0x2002);
|
||||
}
|
||||
|
||||
inline void write_binary_string(std::ostream& out, const std::string& str)
|
||||
|
|
@ -836,10 +901,10 @@ inline void write_binary_string(std::ostream& out, const std::string& str)
|
|||
unsigned long len = str.length();
|
||||
if (len > 255) {
|
||||
assert(len < 65536);
|
||||
write_binary_number<unsigned char>(out, 0xff);
|
||||
write_binary_number<unsigned short>(out, len);
|
||||
write_binary_number_nocheck<unsigned char>(out, 0xff);
|
||||
write_binary_number_nocheck<unsigned short>(out, len);
|
||||
} else {
|
||||
write_binary_number<unsigned char>(out, len);
|
||||
write_binary_number_nocheck<unsigned char>(out, len);
|
||||
}
|
||||
|
||||
if (len)
|
||||
|
|
@ -864,13 +929,13 @@ void write_binary_value(std::ostream& out, const value_t& val)
|
|||
|
||||
switch (val.type) {
|
||||
case value_t::BOOLEAN:
|
||||
write_binary_number<char>(out, *((bool *) val.data) ? 1 : 0);
|
||||
write_binary_bool(out, *((bool *) val.data));
|
||||
break;
|
||||
case value_t::INTEGER:
|
||||
write_binary_long(out, *((long *) val.data));
|
||||
break;
|
||||
case value_t::DATETIME:
|
||||
write_binary_number(out, ((datetime_t *) val.data)->when);
|
||||
write_binary_number(out, *((datetime_t *) val.data));
|
||||
break;
|
||||
case value_t::AMOUNT:
|
||||
write_binary_amount(out, *((amount_t *) val.data));
|
||||
|
|
@ -891,11 +956,10 @@ void write_binary_mask(std::ostream& out, mask_t * mask)
|
|||
void write_binary_value_expr(std::ostream& out, const value_expr_t * expr)
|
||||
{
|
||||
if (! expr) {
|
||||
write_binary_number<unsigned char>(out, 0);
|
||||
write_binary_bool(out, false);
|
||||
return;
|
||||
}
|
||||
write_binary_number<unsigned char>(out, 1);
|
||||
|
||||
write_binary_bool(out, true);
|
||||
write_binary_number(out, expr->kind);
|
||||
|
||||
if (expr->kind > value_expr_t::TERMINALS)
|
||||
|
|
@ -917,10 +981,10 @@ void write_binary_value_expr(std::ostream& out, const value_expr_t * expr)
|
|||
case value_expr_t::F_SHORT_ACCOUNT_MASK:
|
||||
case value_expr_t::F_COMMODITY_MASK:
|
||||
if (expr->mask) {
|
||||
write_binary_number<char>(out, 1);
|
||||
write_binary_bool(out, true);
|
||||
write_binary_mask(out, expr->mask);
|
||||
} else {
|
||||
write_binary_number<char>(out, 0);
|
||||
write_binary_bool(out, false);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -935,36 +999,36 @@ void write_binary_value_expr(std::ostream& out, const value_expr_t * expr)
|
|||
void write_binary_transaction(std::ostream& out, transaction_t * xact,
|
||||
bool ignore_calculated)
|
||||
{
|
||||
write_binary_long(out, xact->_date);
|
||||
write_binary_long(out, xact->_date_eff);
|
||||
write_binary_number(out, xact->_date);
|
||||
write_binary_number(out, xact->_date_eff);
|
||||
write_binary_long(out, xact->account->ident);
|
||||
|
||||
if (ignore_calculated && xact->flags & TRANSACTION_CALCULATED) {
|
||||
write_binary_number<char>(out, 0);
|
||||
write_binary_number<unsigned char>(out, 0);
|
||||
write_binary_amount(out, amount_t());
|
||||
}
|
||||
else if (xact->amount_expr) {
|
||||
write_binary_number<char>(out, 2);
|
||||
write_binary_number<unsigned char>(out, 2);
|
||||
write_binary_value_expr(out, xact->amount_expr.get());
|
||||
write_binary_string(out, xact->amount_expr.expr);
|
||||
}
|
||||
else if (! xact->amount_expr.expr.empty()) {
|
||||
write_binary_number<char>(out, 1);
|
||||
write_binary_number<unsigned char>(out, 1);
|
||||
write_binary_amount(out, xact->amount);
|
||||
write_binary_string(out, xact->amount_expr.expr);
|
||||
}
|
||||
else {
|
||||
write_binary_number<char>(out, 0);
|
||||
write_binary_number<unsigned char>(out, 0);
|
||||
write_binary_amount(out, xact->amount);
|
||||
}
|
||||
|
||||
if (xact->cost &&
|
||||
(! (ignore_calculated && xact->flags & TRANSACTION_CALCULATED))) {
|
||||
write_binary_number<char>(out, 1);
|
||||
write_binary_bool(out, true);
|
||||
write_binary_amount(out, *xact->cost);
|
||||
write_binary_string(out, xact->cost_expr);
|
||||
} else {
|
||||
write_binary_number<char>(out, 0);
|
||||
write_binary_bool(out, false);
|
||||
}
|
||||
|
||||
write_binary_number(out, xact->state);
|
||||
|
|
@ -994,7 +1058,7 @@ void write_binary_entry_base(std::ostream& out, entry_base_t * entry)
|
|||
break;
|
||||
}
|
||||
|
||||
write_binary_number<char>(out, ignore_calculated ? 1 : 0);
|
||||
write_binary_bool(out, ignore_calculated);
|
||||
|
||||
write_binary_long(out, entry->transactions.size());
|
||||
for (transactions_list::const_iterator i = entry->transactions.begin();
|
||||
|
|
@ -1006,8 +1070,8 @@ void write_binary_entry_base(std::ostream& out, entry_base_t * entry)
|
|||
void write_binary_entry(std::ostream& out, entry_t * entry)
|
||||
{
|
||||
write_binary_entry_base(out, entry);
|
||||
write_binary_long(out, entry->_date);
|
||||
write_binary_long(out, entry->_date_eff);
|
||||
write_binary_number(out, entry->_date);
|
||||
write_binary_number(out, entry->_date_eff);
|
||||
write_binary_string(out, entry->code);
|
||||
write_binary_string(out, entry->payee);
|
||||
}
|
||||
|
|
@ -1048,24 +1112,24 @@ void write_binary_commodity_base_extra(std::ostream& out,
|
|||
for (history_map::const_iterator i = commodity->history->prices.begin();
|
||||
i != commodity->history->prices.end();
|
||||
i++) {
|
||||
write_binary_long(out, (*i).first);
|
||||
write_binary_number(out, (*i).first);
|
||||
write_binary_amount(out, (*i).second);
|
||||
}
|
||||
write_binary_long(out, commodity->history->last_lookup);
|
||||
write_binary_number(out, commodity->history->last_lookup);
|
||||
}
|
||||
|
||||
if (commodity->smaller) {
|
||||
write_binary_number<unsigned char>(out, 1);
|
||||
write_binary_bool(out, true);
|
||||
write_binary_amount(out, *commodity->smaller);
|
||||
} else {
|
||||
write_binary_number<unsigned char>(out, 0);
|
||||
write_binary_bool(out, false);
|
||||
}
|
||||
|
||||
if (commodity->larger) {
|
||||
write_binary_number<unsigned char>(out, 1);
|
||||
write_binary_bool(out, true);
|
||||
write_binary_amount(out, *commodity->larger);
|
||||
} else {
|
||||
write_binary_number<unsigned char>(out, 0);
|
||||
write_binary_bool(out, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1090,7 +1154,7 @@ void write_binary_commodity_annotated(std::ostream& out,
|
|||
|
||||
write_binary_long(out, ann_comm->base->ident);
|
||||
write_binary_amount(out, ann_comm->price);
|
||||
write_binary_long(out, ann_comm->date);
|
||||
write_binary_number(out, ann_comm->date);
|
||||
write_binary_string(out, ann_comm->tag);
|
||||
}
|
||||
|
||||
|
|
@ -1132,13 +1196,13 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
base_commodity_index =
|
||||
commodity_index = 0;
|
||||
|
||||
write_binary_number(out, binary_magic_number);
|
||||
write_binary_number(out, format_version);
|
||||
write_binary_number_nocheck(out, binary_magic_number);
|
||||
write_binary_number_nocheck(out, format_version);
|
||||
|
||||
// Write out the files that participated in this journal, so that
|
||||
// they can be checked for changes on reading.
|
||||
|
||||
if (journal->sources.size() == 0) {
|
||||
if (journal->sources.empty()) {
|
||||
write_binary_number<unsigned short>(out, 0);
|
||||
} else {
|
||||
write_binary_number<unsigned short>(out, journal->sources.size());
|
||||
|
|
@ -1148,7 +1212,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
write_binary_string(out, *i);
|
||||
struct stat info;
|
||||
stat((*i).c_str(), &info);
|
||||
write_binary_long(out, std::time_t(info.st_mtime));
|
||||
write_binary_number(out, std::time_t(info.st_mtime));
|
||||
}
|
||||
|
||||
// Write out the price database that relates to this data file, so
|
||||
|
|
@ -1165,10 +1229,10 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
write_binary_account(out, journal->master);
|
||||
|
||||
if (journal->basket) {
|
||||
write_binary_number<bool>(out, true);
|
||||
write_binary_bool(out, true);
|
||||
write_binary_long(out, journal->basket->ident);
|
||||
} else {
|
||||
write_binary_number<bool>(out, false);
|
||||
write_binary_bool(out, false);
|
||||
}
|
||||
|
||||
// Write out the number of entries, transactions, and amounts
|
||||
|
|
@ -1178,10 +1242,11 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
write_binary_long<unsigned long>(out, journal->period_entries.size());
|
||||
|
||||
ostream_pos_type xacts_val = out.tellp();
|
||||
|
||||
write_binary_number<unsigned long>(out, 0);
|
||||
|
||||
ostream_pos_type bigints_val = out.tellp();
|
||||
write_binary_number<unsigned long>(out, 0);
|
||||
|
||||
bigints_count = 0;
|
||||
|
||||
// Write out the commodities
|
||||
|
|
@ -1202,7 +1267,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
i != commodity_t::commodities.end();
|
||||
i++) {
|
||||
if (! (*i).second->annotated) {
|
||||
write_binary_number<char>(out, 0);
|
||||
write_binary_bool(out, false);
|
||||
write_binary_commodity(out, (*i).second);
|
||||
}
|
||||
}
|
||||
|
|
@ -1211,7 +1276,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
i != commodity_t::commodities.end();
|
||||
i++) {
|
||||
if ((*i).second->annotated) {
|
||||
write_binary_number<char>(out, 1);
|
||||
write_binary_bool(out, true);
|
||||
write_binary_string(out, (*i).first); // the mapping key
|
||||
write_binary_commodity_annotated(out, (*i).second);
|
||||
}
|
||||
|
|
|
|||
19
config.cc
19
config.cc
|
|
@ -7,7 +7,6 @@
|
|||
#include "walk.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
|
|
@ -96,12 +95,14 @@ config_t::config_t()
|
|||
prices_format = "%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n";
|
||||
pricesdb_format = "P %[%Y/%m/%d %H:%M:%S] %A %t\n";
|
||||
|
||||
download_quotes = false;
|
||||
use_cache = false;
|
||||
cache_dirty = false;
|
||||
debug_mode = false;
|
||||
verbose_mode = false;
|
||||
trace_mode = false;
|
||||
pricing_leeway = 24 * 3600;
|
||||
|
||||
download_quotes = false;
|
||||
use_cache = false;
|
||||
cache_dirty = false;
|
||||
debug_mode = false;
|
||||
verbose_mode = false;
|
||||
trace_mode = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -109,9 +110,7 @@ config_t::config_t()
|
|||
void trace(const std::string& cat, const std::string& str)
|
||||
{
|
||||
char buf[32];
|
||||
std::time_t now = std::time(NULL);
|
||||
std::strftime(buf, 31, "%H:%M:%S", std::localtime(&now));
|
||||
|
||||
std::strftime(buf, 31, "%H:%M:%S", datetime_t::now.localtime());
|
||||
std::cerr << buf << " " << cat << ": " << str << std::endl;
|
||||
}
|
||||
|
||||
|
|
|
|||
4
config.h
4
config.h
|
|
@ -31,9 +31,13 @@ class config_t
|
|||
std::string prices_format;
|
||||
std::string pricesdb_format;
|
||||
|
||||
std::string date_input_format;
|
||||
|
||||
std::string account;
|
||||
std::string pager;
|
||||
|
||||
unsigned long pricing_leeway;
|
||||
|
||||
bool download_quotes;
|
||||
bool use_cache;
|
||||
bool cache_dirty;
|
||||
|
|
|
|||
408
datetime.cc
408
datetime.cc
|
|
@ -7,19 +7,12 @@
|
|||
#include <ctime>
|
||||
#include <cctype>
|
||||
|
||||
std::time_t now = std::time(NULL);
|
||||
int now_year = std::localtime(&now)->tm_year;
|
||||
date_t date_t::now(std::time(NULL));
|
||||
int date_t::current_year = date_t::now.year();
|
||||
std::string date_t::input_format;
|
||||
std::string date_t::output_format = "%Y/%m/%d";
|
||||
|
||||
static std::time_t base = -1;
|
||||
static int base_year = -1;
|
||||
|
||||
static const int month_days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
char input_format[128];
|
||||
|
||||
const char * formats[] = {
|
||||
const char * date_t::formats[] = {
|
||||
"%Y/%m/%d",
|
||||
"%m/%d",
|
||||
"%Y.%m.%d",
|
||||
|
|
@ -34,29 +27,70 @@ const char * formats[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
std::string datetime_t::date_format = "%Y/%m/%d";
|
||||
datetime_t datetime_t::now(std::time(NULL));
|
||||
|
||||
std::time_t interval_t::first(const std::time_t moment) const
|
||||
namespace {
|
||||
static std::time_t base = -1;
|
||||
static int base_year = -1;
|
||||
|
||||
static const int month_days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
bool parse_date_mask(const char * date_str, struct std::tm * result);
|
||||
bool parse_date(const char * date_str, std::time_t * result,
|
||||
const int year = -1);
|
||||
bool quick_parse_date(const char * date_str, std::time_t * result);
|
||||
}
|
||||
|
||||
date_t::date_t(const std::string& _when)
|
||||
{
|
||||
std::time_t quant = begin;
|
||||
if (! quick_parse_date(_when.c_str(), &when))
|
||||
throw new date_error
|
||||
(std::string("Invalid date string: ") + _when);
|
||||
}
|
||||
|
||||
if (moment && std::difftime(moment, quant) > 0) {
|
||||
datetime_t::datetime_t(const std::string& _when)
|
||||
{
|
||||
if (const char * p = std::strchr(_when.c_str(), ' ')) {
|
||||
date_t date(std::string(_when, 0, p - _when.c_str()));
|
||||
|
||||
struct std::tm moment = *std::localtime(&date.when);
|
||||
if (! strptime(++p, "%H:%M:%S", &moment))
|
||||
throw new datetime_error
|
||||
(std::string("Invalid date/time string: ") + _when);
|
||||
|
||||
when = std::mktime(&moment);
|
||||
} else {
|
||||
when = date_t(_when).when;
|
||||
}
|
||||
}
|
||||
|
||||
datetime_t interval_t::first(const datetime_t& moment) const
|
||||
{
|
||||
datetime_t quant(begin);
|
||||
|
||||
if (moment && moment > quant) {
|
||||
// Find an efficient starting point for the upcoming while loop.
|
||||
// We want a date early enough that the range will be correct, but
|
||||
// late enough that we don't spend hundreds of thousands of loops
|
||||
// skipping through time.
|
||||
|
||||
struct std::tm * desc = std::localtime(&moment);
|
||||
struct std::tm * desc = std::localtime(&moment.when);
|
||||
|
||||
if (years)
|
||||
desc->tm_mon = 0;
|
||||
desc->tm_mday = 1;
|
||||
desc->tm_hour = 0;
|
||||
desc->tm_min = 0;
|
||||
desc->tm_sec = 0;
|
||||
desc->tm_mday = 1;
|
||||
|
||||
desc->tm_hour = 0;
|
||||
desc->tm_min = 0;
|
||||
desc->tm_sec = 0;
|
||||
desc->tm_isdst = -1;
|
||||
|
||||
quant = std::mktime(desc);
|
||||
|
||||
std::time_t temp;
|
||||
while (std::difftime(moment, temp = increment(quant)) >= 0) {
|
||||
datetime_t temp;
|
||||
while (moment >= (temp = increment(quant))) {
|
||||
if (quant == temp)
|
||||
break;
|
||||
quant = temp;
|
||||
|
|
@ -66,145 +100,134 @@ std::time_t interval_t::first(const std::time_t moment) const
|
|||
return quant;
|
||||
}
|
||||
|
||||
std::time_t interval_t::increment(const std::time_t moment) const
|
||||
datetime_t interval_t::increment(const datetime_t& moment) const
|
||||
{
|
||||
std::time_t then = moment;
|
||||
struct std::tm * desc = std::localtime(&moment.when);
|
||||
|
||||
if (years || months) {
|
||||
struct std::tm * desc = std::localtime(&then);
|
||||
if (years)
|
||||
desc->tm_year += years;
|
||||
if (months)
|
||||
desc->tm_mon += months;
|
||||
if (days)
|
||||
desc->tm_mon += days;
|
||||
|
||||
if (years)
|
||||
desc->tm_year += years;
|
||||
desc->tm_hour += hours;
|
||||
desc->tm_min += minutes;
|
||||
desc->tm_sec += seconds;
|
||||
|
||||
if (months) {
|
||||
desc->tm_mon += months;
|
||||
desc->tm_isdst = -1;
|
||||
|
||||
if (desc->tm_mon > 11) {
|
||||
desc->tm_year++;
|
||||
desc->tm_mon -= 12;
|
||||
}
|
||||
else if (desc->tm_mon < 0) {
|
||||
desc->tm_year--;
|
||||
desc->tm_mon += 12;
|
||||
}
|
||||
return std::mktime(desc);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void parse_inclusion_specifier(const std::string& word,
|
||||
datetime_t * begin, datetime_t * end)
|
||||
{
|
||||
struct std::tm when;
|
||||
|
||||
if (! parse_date_mask(word.c_str(), &when))
|
||||
throw new datetime_error(std::string("Could not parse date mask: ") + word);
|
||||
|
||||
when.tm_hour = 0;
|
||||
when.tm_min = 0;
|
||||
when.tm_sec = 0;
|
||||
when.tm_isdst = -1;
|
||||
|
||||
bool saw_year = true;
|
||||
bool saw_mon = true;
|
||||
bool saw_day = true;
|
||||
|
||||
if (when.tm_year == -1) {
|
||||
when.tm_year = date_t::current_year;
|
||||
saw_year = false;
|
||||
}
|
||||
if (when.tm_mon == -1) {
|
||||
when.tm_mon = 0;
|
||||
saw_mon = false;
|
||||
} else {
|
||||
saw_year = false; // don't increment by year if month used
|
||||
}
|
||||
if (when.tm_mday == -1) {
|
||||
when.tm_mday = 1;
|
||||
saw_day = false;
|
||||
} else {
|
||||
saw_mon = false; // don't increment by month if day used
|
||||
saw_year = false; // don't increment by year if day used
|
||||
}
|
||||
|
||||
desc->tm_hour = 0;
|
||||
desc->tm_min = 0;
|
||||
desc->tm_sec = 0;
|
||||
desc->tm_isdst = 0;
|
||||
|
||||
then = std::mktime(desc);
|
||||
}
|
||||
|
||||
return then + seconds;
|
||||
}
|
||||
|
||||
static void parse_inclusion_specifier(const std::string& word,
|
||||
std::time_t * begin,
|
||||
std::time_t * end)
|
||||
{
|
||||
struct std::tm when;
|
||||
|
||||
if (! parse_date_mask(word.c_str(), &when))
|
||||
throw new datetime_error(std::string("Could not parse date mask: ") + word);
|
||||
|
||||
when.tm_hour = 0;
|
||||
when.tm_min = 0;
|
||||
when.tm_sec = 0;
|
||||
|
||||
bool saw_year = true;
|
||||
bool saw_mon = true;
|
||||
bool saw_day = true;
|
||||
|
||||
if (when.tm_year == -1) {
|
||||
when.tm_year = now_year;
|
||||
saw_year = false;
|
||||
}
|
||||
if (when.tm_mon == -1) {
|
||||
when.tm_mon = 0;
|
||||
saw_mon = false;
|
||||
} else {
|
||||
saw_year = false; // don't increment by year if month used
|
||||
}
|
||||
if (when.tm_mday == -1) {
|
||||
when.tm_mday = 1;
|
||||
saw_day = false;
|
||||
} else {
|
||||
saw_mon = false; // don't increment by month if day used
|
||||
saw_year = false; // don't increment by year if day used
|
||||
}
|
||||
|
||||
if (begin) {
|
||||
*begin = std::mktime(&when);
|
||||
if (end)
|
||||
*end = interval_t(saw_day ? 86400 : 0, saw_mon ? 1 : 0,
|
||||
saw_year ? 1 : 0).increment(*begin);
|
||||
}
|
||||
else if (end) {
|
||||
*end = std::mktime(&when);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void read_lower_word(std::istream& in, std::string& word) {
|
||||
in >> word;
|
||||
for (int i = 0, l = word.length(); i < l; i++)
|
||||
word[i] = std::tolower(word[i]);
|
||||
}
|
||||
|
||||
static void parse_date_words(std::istream& in, std::string& word,
|
||||
std::time_t * begin, std::time_t * end)
|
||||
{
|
||||
std::string type;
|
||||
bool mon_spec = false;
|
||||
char buf[32];
|
||||
|
||||
if (word == "this" || word == "last" || word == "next") {
|
||||
type = word;
|
||||
if (! in.eof())
|
||||
read_lower_word(in, word);
|
||||
else
|
||||
word = "month";
|
||||
} else {
|
||||
type = "this";
|
||||
}
|
||||
|
||||
if (word == "month") {
|
||||
std::strftime(buf, 31, "%B", std::localtime(&now));
|
||||
word = buf;
|
||||
mon_spec = true;
|
||||
}
|
||||
else if (word == "year") {
|
||||
std::strftime(buf, 31, "%Y", std::localtime(&now));
|
||||
word = buf;
|
||||
}
|
||||
|
||||
parse_inclusion_specifier(word, begin, end);
|
||||
|
||||
if (type == "last") {
|
||||
if (mon_spec) {
|
||||
if (begin)
|
||||
*begin = interval_t(0, -1, 0).increment(*begin);
|
||||
if (begin) {
|
||||
*begin = std::mktime(&when);
|
||||
if (end)
|
||||
*end = interval_t(0, -1, 0).increment(*end);
|
||||
} else {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 0, -1).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 0, -1).increment(*end);
|
||||
*end = interval_t(saw_day ? 86400 : 0, saw_mon ? 1 : 0,
|
||||
saw_year ? 1 : 0).increment(*begin);
|
||||
}
|
||||
else if (end) {
|
||||
*end = std::mktime(&when);
|
||||
}
|
||||
}
|
||||
else if (type == "next") {
|
||||
if (mon_spec) {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 1, 0).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 1, 0).increment(*end);
|
||||
|
||||
inline void read_lower_word(std::istream& in, std::string& word) {
|
||||
in >> word;
|
||||
for (int i = 0, l = word.length(); i < l; i++)
|
||||
word[i] = std::tolower(word[i]);
|
||||
}
|
||||
|
||||
void parse_date_words(std::istream& in, std::string& word,
|
||||
datetime_t * begin, datetime_t * end)
|
||||
{
|
||||
std::string type;
|
||||
|
||||
bool mon_spec = false;
|
||||
char buf[32];
|
||||
|
||||
if (word == "this" || word == "last" || word == "next") {
|
||||
type = word;
|
||||
if (! in.eof())
|
||||
read_lower_word(in, word);
|
||||
else
|
||||
word = "month";
|
||||
} else {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 0, 1).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 0, 1).increment(*end);
|
||||
type = "this";
|
||||
}
|
||||
|
||||
if (word == "month") {
|
||||
std::strftime(buf, 31, "%B", datetime_t::now.localtime());
|
||||
word = buf;
|
||||
mon_spec = true;
|
||||
}
|
||||
else if (word == "year") {
|
||||
std::strftime(buf, 31, "%Y", datetime_t::now.localtime());
|
||||
word = buf;
|
||||
}
|
||||
|
||||
parse_inclusion_specifier(word, begin, end);
|
||||
|
||||
if (type == "last") {
|
||||
if (mon_spec) {
|
||||
if (begin)
|
||||
*begin = interval_t(0, -1, 0).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, -1, 0).increment(*end);
|
||||
} else {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 0, -1).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 0, -1).increment(*end);
|
||||
}
|
||||
}
|
||||
else if (type == "next") {
|
||||
if (mon_spec) {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 1, 0).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 1, 0).increment(*end);
|
||||
} else {
|
||||
if (begin)
|
||||
*begin = interval_t(0, 0, 1).increment(*begin);
|
||||
if (end)
|
||||
*end = interval_t(0, 0, 1).increment(*end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -221,9 +244,9 @@ void interval_t::parse(std::istream& in)
|
|||
int quantity = std::atol(word.c_str());
|
||||
read_lower_word(in, word);
|
||||
if (word == "days")
|
||||
seconds = 86400 * quantity;
|
||||
days = quantity;
|
||||
else if (word == "weeks")
|
||||
seconds = 7 * 86400 * quantity;
|
||||
days = 7 * quantity;
|
||||
else if (word == "months")
|
||||
months = quantity;
|
||||
else if (word == "quarters")
|
||||
|
|
@ -232,9 +255,9 @@ void interval_t::parse(std::istream& in)
|
|||
years = quantity;
|
||||
}
|
||||
else if (word == "day")
|
||||
seconds = 86400;
|
||||
days = 1;
|
||||
else if (word == "week")
|
||||
seconds = 7 * 86400;
|
||||
days = 7;
|
||||
else if (word == "month")
|
||||
months = 1;
|
||||
else if (word == "quarter")
|
||||
|
|
@ -243,11 +266,11 @@ void interval_t::parse(std::istream& in)
|
|||
years = 1;
|
||||
}
|
||||
else if (word == "daily")
|
||||
seconds = 86400;
|
||||
days = 1;
|
||||
else if (word == "weekly")
|
||||
seconds = 7 * 86400;
|
||||
days = 7;
|
||||
else if (word == "biweekly")
|
||||
seconds = 14 * 86400;
|
||||
days = 14;
|
||||
else if (word == "monthly")
|
||||
months = 1;
|
||||
else if (word == "bimonthly")
|
||||
|
|
@ -277,42 +300,49 @@ void interval_t::parse(std::istream& in)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (! parse_date_mask(date_str, &when))
|
||||
namespace {
|
||||
bool parse_date_mask(const char * date_str, struct std::tm * result)
|
||||
{
|
||||
if (! date_t::input_format.empty()) {
|
||||
std::memset(result, INT_MAX, sizeof(struct std::tm));
|
||||
if (strptime(date_str, date_t::input_format.c_str(), result))
|
||||
return true;
|
||||
}
|
||||
for (const char ** f = date_t::formats; *f; f++) {
|
||||
std::memset(result, INT_MAX, sizeof(struct std::tm));
|
||||
if (strptime(date_str, *f, result))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
when.tm_hour = 0;
|
||||
when.tm_min = 0;
|
||||
when.tm_sec = 0;
|
||||
bool parse_date(const char * date_str, std::time_t * result, const int year)
|
||||
{
|
||||
struct std::tm when;
|
||||
|
||||
if (when.tm_year == -1)
|
||||
when.tm_year = ((year == -1) ? now_year : (year - 1900));
|
||||
if (! parse_date_mask(date_str, &when))
|
||||
return false;
|
||||
|
||||
if (when.tm_mon == -1)
|
||||
when.tm_mon = 0;
|
||||
when.tm_hour = 0;
|
||||
when.tm_min = 0;
|
||||
when.tm_sec = 0;
|
||||
|
||||
if (when.tm_mday == -1)
|
||||
when.tm_mday = 1;
|
||||
if (when.tm_year == -1)
|
||||
when.tm_year = ((year == -1) ? date_t::current_year : (year - 1900));
|
||||
|
||||
*result = std::mktime(&when);
|
||||
if (when.tm_mon == -1)
|
||||
when.tm_mon = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool quick_parse_date(const char * date_str, std::time_t * result)
|
||||
{
|
||||
return parse_date(date_str, result, now_year + 1900);
|
||||
if (when.tm_mday == -1)
|
||||
when.tm_mday = 1;
|
||||
|
||||
*result = std::mktime(&when);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool quick_parse_date(const char * date_str, std::time_t * result)
|
||||
{
|
||||
return parse_date(date_str, result, date_t::current_year + 1900);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
325
datetime.h
325
datetime.h
|
|
@ -6,31 +6,206 @@
|
|||
|
||||
#include "error.h"
|
||||
|
||||
struct interval_t;
|
||||
class date_error : public error {
|
||||
public:
|
||||
date_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~date_error() throw() {}
|
||||
};
|
||||
|
||||
struct datetime_t
|
||||
struct interval_t;
|
||||
class datetime_t;
|
||||
|
||||
class date_t
|
||||
{
|
||||
date_t(const datetime_t& _when);
|
||||
|
||||
protected:
|
||||
std::time_t when;
|
||||
|
||||
static std::string date_format;
|
||||
public:
|
||||
static date_t now;
|
||||
static const char * formats[];
|
||||
static int current_year;
|
||||
static std::string input_format;
|
||||
static std::string output_format;
|
||||
|
||||
datetime_t(const std::time_t _when) : when(_when) {}
|
||||
date_t() : when(0) {}
|
||||
date_t(const date_t& _when) : when(_when.when) {}
|
||||
|
||||
datetime_t& operator+=(const long secs) {
|
||||
date_t(const std::time_t _when) : when(_when) {
|
||||
#if 0
|
||||
struct std::tm * moment = std::localtime(&_when);
|
||||
moment->tm_hour = 0;
|
||||
moment->tm_min = 0;
|
||||
moment->tm_sec = 0;
|
||||
when = std::mktime(moment);
|
||||
#endif
|
||||
}
|
||||
date_t(const interval_t& period);
|
||||
date_t(const std::string& _when);
|
||||
|
||||
virtual ~date_t() {}
|
||||
|
||||
date_t& operator=(const date_t& _when) {
|
||||
when = _when.when;
|
||||
return *this;
|
||||
}
|
||||
date_t& operator=(const std::time_t _when) {
|
||||
return *this = date_t(_when);
|
||||
}
|
||||
date_t& operator=(const datetime_t& _when) {
|
||||
return *this = date_t(_when);
|
||||
}
|
||||
date_t& operator=(const interval_t& period) {
|
||||
return *this = date_t(period);
|
||||
}
|
||||
date_t& operator=(const std::string& _when) {
|
||||
return *this = date_t(_when);
|
||||
}
|
||||
|
||||
date_t& operator+=(const interval_t& period);
|
||||
|
||||
long operator-=(const date_t& date) {
|
||||
return (when - date.when) / 86400;
|
||||
}
|
||||
|
||||
virtual date_t& operator+=(const long days) {
|
||||
// jww (2006-03-26): This is not accurate enough when DST is in effect!
|
||||
assert(0);
|
||||
when += days * 86400;
|
||||
return *this;
|
||||
}
|
||||
virtual date_t& operator-=(const long days) {
|
||||
assert(0);
|
||||
when -= days * 86400;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define DEF_DATE_OP(OP) \
|
||||
bool operator OP(const date_t& other) const { \
|
||||
return when OP other.when; \
|
||||
}
|
||||
|
||||
DEF_DATE_OP(<)
|
||||
DEF_DATE_OP(<=)
|
||||
DEF_DATE_OP(>)
|
||||
DEF_DATE_OP(>=)
|
||||
DEF_DATE_OP(==)
|
||||
DEF_DATE_OP(!=)
|
||||
|
||||
operator bool() const {
|
||||
return when != 0;
|
||||
}
|
||||
operator std::time_t() const {
|
||||
return when;
|
||||
}
|
||||
operator std::string() const {
|
||||
return to_string();
|
||||
}
|
||||
|
||||
std::string to_string(const std::string& format = output_format) const {
|
||||
char buf[64];
|
||||
std::strftime(buf, 63, format.c_str(), localtime());
|
||||
return buf;
|
||||
}
|
||||
|
||||
int year() const {
|
||||
return localtime()->tm_year + 1900;
|
||||
}
|
||||
int month() const {
|
||||
return localtime()->tm_mon + 1;
|
||||
}
|
||||
int day() const {
|
||||
return localtime()->tm_mday;
|
||||
}
|
||||
int wday() const {
|
||||
return localtime()->tm_wday;
|
||||
}
|
||||
|
||||
std::tm * localtime() const {
|
||||
return std::localtime(&when);
|
||||
}
|
||||
|
||||
void write(std::ostream& out,
|
||||
const std::string& format = output_format) const {
|
||||
out << to_string(format);
|
||||
}
|
||||
|
||||
friend class datetime_t;
|
||||
friend struct interval_t;
|
||||
};
|
||||
|
||||
inline long operator-(const date_t& left, const date_t& right) {
|
||||
date_t temp(left);
|
||||
temp -= right;
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline date_t operator+(const date_t& left, const long days) {
|
||||
date_t temp(left);
|
||||
temp += days;
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline date_t operator-(const date_t& left, const long days) {
|
||||
date_t temp(left);
|
||||
temp -= days;
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const date_t& moment) {
|
||||
moment.write(out);
|
||||
}
|
||||
|
||||
class datetime_error : public error {
|
||||
public:
|
||||
datetime_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~datetime_error() throw() {}
|
||||
};
|
||||
|
||||
class datetime_t : public date_t
|
||||
{
|
||||
public:
|
||||
static datetime_t now;
|
||||
|
||||
datetime_t() : date_t() {}
|
||||
datetime_t(const datetime_t& _when) : date_t(_when.when) {}
|
||||
datetime_t(const date_t& _when) : date_t(_when) {}
|
||||
|
||||
datetime_t(const std::time_t _when) : date_t(_when) {}
|
||||
datetime_t(const std::string& _when);
|
||||
|
||||
datetime_t& operator=(const datetime_t& _when) {
|
||||
when = _when.when;
|
||||
return *this;
|
||||
}
|
||||
datetime_t& operator=(const date_t& _when) {
|
||||
when = _when.when;
|
||||
return *this;
|
||||
}
|
||||
datetime_t& operator=(const std::time_t _when) {
|
||||
return *this = datetime_t(_when);
|
||||
}
|
||||
datetime_t& operator=(const std::string& _when) {
|
||||
return *this = datetime_t(_when);
|
||||
}
|
||||
|
||||
long operator-=(const datetime_t& date) {
|
||||
return when - date.when;
|
||||
}
|
||||
|
||||
virtual datetime_t& operator+=(const long secs) {
|
||||
when += secs;
|
||||
return *this;
|
||||
}
|
||||
datetime_t& operator-=(const long secs) {
|
||||
virtual datetime_t& operator-=(const long secs) {
|
||||
when -= secs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
datetime_t& operator=(const interval_t& period);
|
||||
datetime_t& operator+=(const interval_t& period);
|
||||
|
||||
#define DEF_DATETIME_OP(OP) \
|
||||
bool operator OP(const datetime_t& other) { \
|
||||
return when OP other.when; \
|
||||
#define DEF_DATETIME_OP(OP) \
|
||||
bool operator OP(const datetime_t& other) const { \
|
||||
return when OP other.when; \
|
||||
}
|
||||
|
||||
DEF_DATETIME_OP(<)
|
||||
|
|
@ -40,96 +215,98 @@ struct datetime_t
|
|||
DEF_DATETIME_OP(==)
|
||||
DEF_DATETIME_OP(!=)
|
||||
|
||||
operator bool() const {
|
||||
return when != 0;
|
||||
int hour() const {
|
||||
return localtime()->tm_hour;
|
||||
}
|
||||
operator long() const {
|
||||
return (long)when;
|
||||
int min() const {
|
||||
return localtime()->tm_min;
|
||||
}
|
||||
operator double() const {
|
||||
return (double)when;
|
||||
}
|
||||
|
||||
int year() const {
|
||||
struct std::tm * desc = std::localtime(&when);
|
||||
return desc->tm_year + 1900;
|
||||
}
|
||||
int month() const {
|
||||
struct std::tm * desc = std::localtime(&when);
|
||||
return desc->tm_mon + 1;
|
||||
}
|
||||
int day() const {
|
||||
struct std::tm * desc = std::localtime(&when);
|
||||
return desc->tm_mday;
|
||||
int sec() const {
|
||||
return localtime()->tm_sec;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const datetime_t& moment) {
|
||||
char buf[32];
|
||||
std::strftime(buf, 31, datetime_t::date_format.c_str(),
|
||||
std::localtime(&moment.when));
|
||||
out << buf;
|
||||
inline long operator-(const datetime_t& left, const datetime_t& right) {
|
||||
datetime_t temp(left);
|
||||
temp -= right;
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline long operator-(const datetime_t& left, const datetime_t& right) {
|
||||
return (long)left.when - (long)right.when;
|
||||
inline datetime_t operator+(const datetime_t& left, const long seconds) {
|
||||
datetime_t temp(left);
|
||||
temp += seconds;
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline datetime_t operator-(const datetime_t& left, const long seconds) {
|
||||
datetime_t temp(left);
|
||||
temp -= seconds;
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const datetime_t& moment) {
|
||||
char buf[64];
|
||||
std::strftime(buf, 63, (date_t::output_format + " %H:%M:%S").c_str(),
|
||||
moment.localtime());
|
||||
out << buf;
|
||||
}
|
||||
|
||||
struct interval_t
|
||||
{
|
||||
unsigned int years;
|
||||
unsigned int months;
|
||||
unsigned int seconds;
|
||||
std::time_t begin;
|
||||
std::time_t end;
|
||||
unsigned short years;
|
||||
unsigned short months;
|
||||
unsigned short days;
|
||||
unsigned short hours;
|
||||
unsigned short minutes;
|
||||
unsigned short seconds;
|
||||
|
||||
datetime_t begin;
|
||||
datetime_t end;
|
||||
|
||||
interval_t(int _days = 0, int _months = 0, int _years = 0,
|
||||
const date_t& _begin = date_t(),
|
||||
const date_t& _end = date_t())
|
||||
: years(_years), months(_months), days(_days),
|
||||
hours(0), minutes(0), seconds(0),
|
||||
begin(_begin), end(_end) {}
|
||||
|
||||
interval_t(int _seconds = 0, int _months = 0, int _years = 0,
|
||||
std::time_t _begin = 0, std::time_t _end = 0)
|
||||
: years(_years), months(_months), seconds(_seconds),
|
||||
begin(_begin), end(_end) {
|
||||
}
|
||||
interval_t(const std::string& desc)
|
||||
: years(0), months(0), seconds(0), begin(0), end(0) {
|
||||
: years(0), months(0), days(0),
|
||||
hours(0), minutes(0), seconds(0) {
|
||||
std::istringstream stream(desc);
|
||||
parse(stream);
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return seconds > 0 || months > 0 || years > 0;
|
||||
return (years > 0 || months > 0 || days > 0 ||
|
||||
hours > 0 || minutes > 0 || seconds > 0);
|
||||
}
|
||||
|
||||
void start(const std::time_t moment) {
|
||||
void start(const datetime_t& moment) {
|
||||
begin = first(moment);
|
||||
}
|
||||
std::time_t first(const std::time_t moment = 0) const;
|
||||
std::time_t increment(const std::time_t) const;
|
||||
datetime_t first(const datetime_t& moment = datetime_t()) const;
|
||||
datetime_t increment(const datetime_t&) const;
|
||||
|
||||
void parse(std::istream& in);
|
||||
};
|
||||
|
||||
inline datetime_t& datetime_t::operator=(const interval_t& period) {
|
||||
when = period.first();
|
||||
return *this;
|
||||
}
|
||||
inline datetime_t& datetime_t::operator+=(const interval_t& period) {
|
||||
when = period.increment(when);
|
||||
return *this;
|
||||
inline date_t::date_t(const interval_t& period) {
|
||||
when = period.first().when;
|
||||
}
|
||||
|
||||
extern std::time_t now;
|
||||
extern int now_year;
|
||||
extern char input_format[128];
|
||||
extern const char * formats[];
|
||||
inline date_t& date_t::operator+=(const interval_t& period) {
|
||||
return *this = period.increment(*this);
|
||||
}
|
||||
|
||||
bool parse_date_mask(const char * date_str, struct std::tm * result);
|
||||
bool parse_date(const char * date_str, std::time_t * result,
|
||||
const int year = -1);
|
||||
bool quick_parse_date(const char * date_str, std::time_t * result);
|
||||
|
||||
class datetime_error : public error {
|
||||
public:
|
||||
datetime_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~datetime_error() throw() {}
|
||||
};
|
||||
inline date_t::date_t(const datetime_t& _when) {
|
||||
assert(0);
|
||||
struct std::tm * moment = _when.localtime();
|
||||
moment->tm_hour = 0;
|
||||
moment->tm_min = 0;
|
||||
moment->tm_sec = 0;
|
||||
when = std::mktime(moment);
|
||||
}
|
||||
|
||||
#endif // _DATETIME_H
|
||||
|
|
|
|||
9
debug.h
9
debug.h
|
|
@ -62,7 +62,8 @@ void debug_assert(const std::string& reason,
|
|||
#include <new>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#include "datetime.h"
|
||||
|
||||
#define DEBUG_ENABLED
|
||||
|
||||
|
|
@ -85,10 +86,8 @@ bool _debug_active(const char * const cls);
|
|||
}
|
||||
#define DEBUG_PRINT_(x) DEBUG_PRINT(_debug_cls, x)
|
||||
|
||||
#define DEBUG_PRINT_TIME(cls, x) { \
|
||||
char buf[32]; \
|
||||
std::strftime(buf, 31, "%Y/%m/%d:%H", std::localtime(&x)); \
|
||||
DEBUG_PRINT(cls, #x << " is " << buf); \
|
||||
#define DEBUG_PRINT_TIME(cls, x) { \
|
||||
DEBUG_PRINT(cls, #x << " is " << x); \
|
||||
}
|
||||
|
||||
#define DEBUG_PRINT_TIME_(x) DEBUG_PRINT_TIME(_debug_cls, x)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@ entry_t * derive_new_entry(journal_t& journal,
|
|||
|
||||
entry_t * matching = NULL;
|
||||
|
||||
if (! parse_date((*i).c_str(), &added->_date))
|
||||
throw new error("Bad date passed to 'entry'");
|
||||
|
||||
if (++i == end)
|
||||
added->_date = *i++;
|
||||
if (i == end)
|
||||
throw new error("Too few arguments to 'entry'");
|
||||
|
||||
mask_t regexp(*i++);
|
||||
|
|
|
|||
22
format.cc
22
format.cc
|
|
@ -3,7 +3,6 @@
|
|||
#include "util.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -208,11 +207,11 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
|
||||
case 'd':
|
||||
current->type = element_t::COMPLETE_DATE_STRING;
|
||||
current->chars = datetime_t::date_format;
|
||||
current->chars = datetime_t::output_format;
|
||||
break;
|
||||
case 'D':
|
||||
current->type = element_t::DATE_STRING;
|
||||
current->chars = datetime_t::date_format;
|
||||
current->chars = datetime_t::output_format;
|
||||
break;
|
||||
|
||||
case 'S': current->type = element_t::SOURCE; break;
|
||||
|
|
@ -536,21 +535,21 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
break;
|
||||
|
||||
case element_t::DATE_STRING: {
|
||||
std::time_t date = 0;
|
||||
datetime_t date;
|
||||
if (details.xact)
|
||||
date = details.xact->date();
|
||||
else if (details.entry)
|
||||
date = details.entry->date();
|
||||
|
||||
char buf[256];
|
||||
std::strftime(buf, 255, elem->chars.c_str(), std::localtime(&date));
|
||||
std::strftime(buf, 255, elem->chars.c_str(), date.localtime());
|
||||
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
|
||||
break;
|
||||
}
|
||||
|
||||
case element_t::COMPLETE_DATE_STRING: {
|
||||
std::time_t actual_date = 0;
|
||||
std::time_t effective_date = 0;
|
||||
datetime_t actual_date;
|
||||
datetime_t effective_date;
|
||||
if (details.xact) {
|
||||
actual_date = details.xact->actual_date();
|
||||
effective_date = details.xact->effective_date();
|
||||
|
|
@ -561,14 +560,13 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
}
|
||||
|
||||
char abuf[256];
|
||||
std::strftime(abuf, 255, elem->chars.c_str(),
|
||||
std::localtime(&actual_date));
|
||||
std::strftime(abuf, 255, elem->chars.c_str(), actual_date.localtime());
|
||||
|
||||
if (effective_date != 0 && effective_date != actual_date) {
|
||||
if (effective_date && effective_date != actual_date) {
|
||||
char buf[512];
|
||||
char ebuf[256];
|
||||
std::strftime(ebuf, 255, elem->chars.c_str(),
|
||||
std::localtime(&effective_date));
|
||||
effective_date.localtime());
|
||||
|
||||
std::strcpy(buf, abuf);
|
||||
std::strcat(buf, "=");
|
||||
|
|
@ -892,7 +890,7 @@ format_equity::format_equity(std::ostream& _output_stream,
|
|||
|
||||
entry_t header_entry;
|
||||
header_entry.payee = "Opening Balances";
|
||||
header_entry._date = now;
|
||||
header_entry._date = datetime_t::now;
|
||||
first_line_format.format(output_stream, details_t(header_entry));
|
||||
}
|
||||
|
||||
|
|
|
|||
11
gnucash.cc
11
gnucash.cc
|
|
@ -292,12 +292,9 @@ static void dataHandler(void *userData, const char *s, int len)
|
|||
curr_entry->code = std::string(s, len);
|
||||
break;
|
||||
|
||||
case ENTRY_DATE: {
|
||||
struct tm when;
|
||||
strptime(std::string(s, len).c_str(), "%Y-%m-%d %H:%M:%S %z", &when);
|
||||
curr_entry->_date = std::mktime(&when);
|
||||
case ENTRY_DATE:
|
||||
curr_entry->_date = std::string(s, len);
|
||||
break;
|
||||
}
|
||||
|
||||
case ENTRY_DESC:
|
||||
curr_entry->payee = std::string(s, len);
|
||||
|
|
@ -375,6 +372,10 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
|
|||
{
|
||||
char buf[BUFSIZ];
|
||||
|
||||
// This is the date format used by Gnucash, so override whatever the
|
||||
// user specified.
|
||||
date_t::input_format = "%Y-%m-%d %H:%M:%S %z";
|
||||
|
||||
count = 0;
|
||||
action = NO_ACTION;
|
||||
curr_journal = journal;
|
||||
|
|
|
|||
15
journal.cc
15
journal.cc
|
|
@ -19,16 +19,16 @@ transaction_t::~transaction_t()
|
|||
if (cost) delete cost;
|
||||
}
|
||||
|
||||
std::time_t transaction_t::actual_date() const
|
||||
datetime_t transaction_t::actual_date() const
|
||||
{
|
||||
if (_date == 0 && entry)
|
||||
if (! _date && entry)
|
||||
return entry->actual_date();
|
||||
return _date;
|
||||
}
|
||||
|
||||
std::time_t transaction_t::effective_date() const
|
||||
datetime_t transaction_t::effective_date() const
|
||||
{
|
||||
if (_date_eff == 0 && entry)
|
||||
if (! _date_eff && entry)
|
||||
return entry->effective_date();
|
||||
return _date_eff;
|
||||
}
|
||||
|
|
@ -176,9 +176,10 @@ bool entry_base_t::finalize()
|
|||
|
||||
if ((*x)->amount.commodity() &&
|
||||
! (*x)->amount.commodity().annotated)
|
||||
(*x)->amount.annotate_commodity(abs(per_unit_cost),
|
||||
entry ? entry->actual_date() : 0,
|
||||
entry ? entry->code : "");
|
||||
(*x)->amount.annotate_commodity
|
||||
(abs(per_unit_cost),
|
||||
entry ? entry->actual_date() : datetime_t(),
|
||||
entry ? entry->code : "");
|
||||
|
||||
(*x)->cost = new amount_t(- (per_unit_cost * (*x)->amount));
|
||||
balance += *(*x)->cost;
|
||||
|
|
|
|||
37
journal.h
37
journal.h
|
|
@ -4,7 +4,6 @@
|
|||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
#include "amount.h"
|
||||
|
|
@ -34,8 +33,8 @@ class transaction_t
|
|||
enum state_t { UNCLEARED, CLEARED, PENDING };
|
||||
|
||||
entry_t * entry;
|
||||
std::time_t _date;
|
||||
std::time_t _date_eff;
|
||||
datetime_t _date;
|
||||
datetime_t _date_eff;
|
||||
account_t * account;
|
||||
amount_t amount;
|
||||
value_expr amount_expr;
|
||||
|
|
@ -53,8 +52,8 @@ class transaction_t
|
|||
static bool use_effective_date;
|
||||
|
||||
transaction_t(account_t * _account = NULL)
|
||||
: entry(NULL), _date(0), _date_eff(0), account(_account),
|
||||
cost(NULL), state(UNCLEARED), flags(TRANSACTION_NORMAL),
|
||||
: entry(NULL), account(_account), cost(NULL),
|
||||
state(UNCLEARED), flags(TRANSACTION_NORMAL),
|
||||
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
||||
}
|
||||
|
|
@ -62,24 +61,24 @@ class transaction_t
|
|||
const amount_t& _amount,
|
||||
unsigned int _flags = TRANSACTION_NORMAL,
|
||||
const std::string& _note = "")
|
||||
: entry(NULL), _date(0), _date_eff(0), account(_account),
|
||||
amount(_amount), cost(NULL), state(UNCLEARED), flags(_flags),
|
||||
: entry(NULL), account(_account), amount(_amount), cost(NULL),
|
||||
state(UNCLEARED), flags(_flags),
|
||||
note(_note), beg_pos(0), beg_line(0), end_pos(0), end_line(0),
|
||||
data(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
||||
}
|
||||
transaction_t(const transaction_t& xact)
|
||||
: entry(xact.entry), _date(0), _date_eff(0), account(xact.account),
|
||||
amount(xact.amount), cost(xact.cost ? new amount_t(*xact.cost) : NULL),
|
||||
: entry(xact.entry), account(xact.account), amount(xact.amount),
|
||||
cost(xact.cost ? new amount_t(*xact.cost) : NULL),
|
||||
state(xact.state), flags(xact.flags), note(xact.note),
|
||||
beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
||||
}
|
||||
~transaction_t();
|
||||
|
||||
std::time_t actual_date() const;
|
||||
std::time_t effective_date() const;
|
||||
std::time_t date() const {
|
||||
datetime_t actual_date() const;
|
||||
datetime_t effective_date() const;
|
||||
datetime_t date() const {
|
||||
if (use_effective_date)
|
||||
return effective_date();
|
||||
else
|
||||
|
|
@ -162,12 +161,12 @@ class entry_base_t
|
|||
class entry_t : public entry_base_t
|
||||
{
|
||||
public:
|
||||
std::time_t _date;
|
||||
std::time_t _date_eff;
|
||||
datetime_t _date;
|
||||
datetime_t _date_eff;
|
||||
std::string code;
|
||||
std::string payee;
|
||||
|
||||
entry_t() : _date(0), _date_eff(0) {
|
||||
entry_t() {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
|
||||
}
|
||||
entry_t(const entry_t& e);
|
||||
|
|
@ -176,15 +175,15 @@ class entry_t : public entry_base_t
|
|||
DEBUG_PRINT("ledger.memory.dtors", "dtor entry_t");
|
||||
}
|
||||
|
||||
std::time_t actual_date() const {
|
||||
datetime_t actual_date() const {
|
||||
return _date;
|
||||
}
|
||||
std::time_t effective_date() const {
|
||||
if (_date_eff == 0)
|
||||
datetime_t effective_date() const {
|
||||
if (! _date_eff)
|
||||
return _date;
|
||||
return _date_eff;
|
||||
}
|
||||
std::time_t date() const {
|
||||
datetime_t date() const {
|
||||
if (transaction_t::use_effective_date)
|
||||
return effective_date();
|
||||
else
|
||||
|
|
|
|||
16
main.cc
16
main.cc
|
|
@ -8,7 +8,6 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include "acconf.h"
|
||||
|
||||
|
|
@ -28,7 +27,7 @@ int parse_and_report(config_t& config, report_t& report,
|
|||
{
|
||||
// Configure the terminus for value expressions
|
||||
|
||||
ledger::terminus = now;
|
||||
ledger::terminus = datetime_t::now;
|
||||
|
||||
// Parse command-line arguments, and those set in the environment
|
||||
|
||||
|
|
@ -49,7 +48,8 @@ int parse_and_report(config_t& config, report_t& report,
|
|||
|
||||
TRACE(main, "Processing options and environment variables");
|
||||
|
||||
process_environment(ledger::config_options, envp, "LEDGER_");
|
||||
process_environment(ledger::config_options,
|
||||
const_cast<const char **>(envp), "LEDGER_");
|
||||
|
||||
#if 1
|
||||
// These are here for backwards compatability, but are deprecated.
|
||||
|
|
@ -175,11 +175,10 @@ int parse_and_report(config_t& config, report_t& report,
|
|||
|
||||
// If downloading is to be supported, configure the updater
|
||||
|
||||
// jww (2006-03-23): Should the pricing_leeway be in config_t?
|
||||
// Should download_quotes be in report_t?
|
||||
if (! commodity_base_t::updater && config.download_quotes)
|
||||
commodity_base_t::updater =
|
||||
new quotes_by_script(config.price_db, report.pricing_leeway, config.cache_dirty);
|
||||
new quotes_by_script(config.price_db, config.pricing_leeway,
|
||||
config.cache_dirty);
|
||||
|
||||
std::auto_ptr<entry_t> new_entry;
|
||||
if (command == "e") {
|
||||
|
|
@ -325,13 +324,8 @@ appending the output of this command to your Ledger file if you so choose."
|
|||
formatter = new format_entries(*out, *format);
|
||||
else if (command == "x")
|
||||
formatter = new format_emacs_transactions(*out);
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
else if (command == "X")
|
||||
formatter = new format_xml_entries(*out, report.show_totals);
|
||||
#else
|
||||
else if (command == "X")
|
||||
throw new error("XML support was not compiled into this copy of Ledger");
|
||||
#endif
|
||||
else
|
||||
formatter = new format_transactions(*out, *format);
|
||||
|
||||
|
|
|
|||
48
option.cc
48
option.cc
|
|
@ -93,7 +93,7 @@ void process_arguments(option_t * options, int argc, char ** argv,
|
|||
if ((*i)[2] == '\0')
|
||||
break;
|
||||
|
||||
char * name = *i + 2;
|
||||
char * name = *i + 2;
|
||||
if (char * p = std::strchr(name, '=')) {
|
||||
*p++ = '\0';
|
||||
value = p;
|
||||
|
|
@ -132,17 +132,17 @@ void process_arguments(option_t * options, int argc, char ** argv,
|
|||
}
|
||||
}
|
||||
|
||||
void process_environment(option_t * options, char ** envp,
|
||||
void process_environment(option_t * options, const char ** envp,
|
||||
const std::string& tag)
|
||||
{
|
||||
const char * tag_p = tag.c_str();
|
||||
unsigned int tag_len = tag.length();
|
||||
|
||||
for (char ** p = envp; *p; p++)
|
||||
for (const char ** p = envp; *p; p++)
|
||||
if (! tag_p || std::strncmp(*p, tag_p, tag_len) == 0) {
|
||||
char buf[128];
|
||||
char * r = buf;
|
||||
char * q;
|
||||
const char * q;
|
||||
for (q = *p + tag_len;
|
||||
*q && *q != '=' && r - buf < 128;
|
||||
q++)
|
||||
|
|
@ -459,32 +459,28 @@ OPT_BEGIN(effective, "") {
|
|||
OPT_BEGIN(begin, "b:") {
|
||||
char buf[128];
|
||||
interval_t interval(optarg);
|
||||
if (interval.begin)
|
||||
std::strftime(buf, 127, formats[0], std::localtime(&interval.begin));
|
||||
else
|
||||
if (! interval.begin)
|
||||
throw new error(std::string("Could not determine beginning of period '") +
|
||||
optarg + "'");
|
||||
|
||||
if (! report->predicate.empty())
|
||||
report->predicate += "&";
|
||||
report->predicate += "d>=[";
|
||||
report->predicate += buf;
|
||||
report->predicate += interval.begin.to_string();
|
||||
report->predicate += "]";
|
||||
} OPT_END(begin);
|
||||
|
||||
OPT_BEGIN(end, "e:") {
|
||||
char buf[128];
|
||||
interval_t interval(optarg);
|
||||
if (interval.end)
|
||||
std::strftime(buf, 127, formats[0], std::localtime(&interval.end));
|
||||
else
|
||||
if (! interval.end)
|
||||
throw new error(std::string("Could not determine end of period '") +
|
||||
optarg + "'");
|
||||
|
||||
if (! report->predicate.empty())
|
||||
report->predicate += "&";
|
||||
report->predicate += "d<[";
|
||||
report->predicate += buf;
|
||||
report->predicate += interval.end.to_string();
|
||||
report->predicate += "]";
|
||||
|
||||
terminus = interval.end;
|
||||
|
|
@ -547,12 +543,11 @@ OPT_BEGIN(format, "F:") {
|
|||
} OPT_END(format);
|
||||
|
||||
OPT_BEGIN(date_format, "y:") {
|
||||
report->date_format = optarg;
|
||||
report->date_output_format = optarg;
|
||||
} OPT_END(date_format);
|
||||
|
||||
OPT_BEGIN(input_date_format, ":") {
|
||||
std::strcpy(input_format, optarg);
|
||||
formats[0] = input_format;
|
||||
config->date_input_format = optarg;
|
||||
} OPT_END(input_date_format);
|
||||
|
||||
OPT_BEGIN(balance_format, ":") {
|
||||
|
|
@ -684,26 +679,21 @@ OPT_BEGIN(period, "p:") {
|
|||
// modify the calculation predicate (via the --begin and --end
|
||||
// options) to take this into account.
|
||||
|
||||
char buf[128];
|
||||
interval_t interval(report->report_period);
|
||||
|
||||
if (interval.begin) {
|
||||
std::strftime(buf, 127, formats[0], std::localtime(&interval.begin));
|
||||
|
||||
if (! report->predicate.empty())
|
||||
report->predicate += "&";
|
||||
report->predicate += "d>=[";
|
||||
report->predicate += buf;
|
||||
report->predicate += interval.begin.to_string();
|
||||
report->predicate += "]";
|
||||
}
|
||||
|
||||
if (interval.end) {
|
||||
std::strftime(buf, 127, formats[0], std::localtime(&interval.end));
|
||||
|
||||
if (! report->predicate.empty())
|
||||
report->predicate += "&";
|
||||
report->predicate += "d<[";
|
||||
report->predicate += buf;
|
||||
report->predicate += interval.end.to_string();
|
||||
report->predicate += "]";
|
||||
|
||||
terminus = interval.end;
|
||||
|
|
@ -731,6 +721,13 @@ OPT_BEGIN(monthly, "M") {
|
|||
report->report_period = std::string("monthly ") + report->report_period;
|
||||
} OPT_END(monthly);
|
||||
|
||||
OPT_BEGIN(quarterly, "") {
|
||||
if (report->report_period.empty())
|
||||
report->report_period = "quarterly";
|
||||
else
|
||||
report->report_period = std::string("quarterly ") + report->report_period;
|
||||
} OPT_END(quarterly);
|
||||
|
||||
OPT_BEGIN(yearly, "Y") {
|
||||
if (report->report_period.empty())
|
||||
report->report_period = "yearly";
|
||||
|
|
@ -841,7 +838,7 @@ OPT_BEGIN(price_db, ":") {
|
|||
} OPT_END(price_db);
|
||||
|
||||
OPT_BEGIN(price_exp, "Z:") {
|
||||
report->pricing_leeway = std::atol(optarg) * 60;
|
||||
config->pricing_leeway = std::atol(optarg) * 60;
|
||||
} OPT_END(price_exp);
|
||||
|
||||
OPT_BEGIN(download, "Q") {
|
||||
|
|
@ -886,8 +883,8 @@ namespace {
|
|||
amount_t price(equals + 1);
|
||||
|
||||
if (commodity_t * commodity = commodity_t::find_or_create(symbol)) {
|
||||
commodity->add_price(now, price);
|
||||
commodity->history()->bogus_time = now;
|
||||
commodity->add_price(datetime_t::now, price);
|
||||
commodity->history()->bogus_time = datetime_t::now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1012,6 +1009,7 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
|
|||
{ "prices-format", '\0', true, opt_prices_format, false },
|
||||
{ "print-format", '\0', true, opt_print_format, false },
|
||||
{ "quantity", 'O', false, opt_quantity, false },
|
||||
{ "quarterly", '\0', false, opt_quarterly, false },
|
||||
{ "real", 'R', false, opt_real, false },
|
||||
{ "reconcile", '\0', true, opt_reconcile, false },
|
||||
{ "reconcile-date", '\0', true, opt_reconcile_date, false },
|
||||
|
|
|
|||
4
option.h
4
option.h
|
|
@ -27,7 +27,7 @@ bool process_option(option_t * options, const std::string& opt,
|
|||
const char * arg = NULL);
|
||||
void process_arguments(option_t * options, int argc, char ** argv,
|
||||
const bool anywhere, std::list<std::string>& args);
|
||||
void process_environment(option_t * options, char ** envp,
|
||||
void process_environment(option_t * options, const char ** envp,
|
||||
const std::string& tag);
|
||||
|
||||
namespace ledger {
|
||||
|
|
@ -38,7 +38,7 @@ class report_t;
|
|||
extern config_t * config;
|
||||
extern report_t * report;
|
||||
|
||||
#define CONFIG_OPTIONS_SIZE 94
|
||||
#define CONFIG_OPTIONS_SIZE 95
|
||||
extern option_t config_options[CONFIG_OPTIONS_SIZE];
|
||||
|
||||
void option_help(std::ostream& out);
|
||||
|
|
|
|||
3
qif.cc
3
qif.cc
|
|
@ -104,8 +104,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
|
|||
case 'D':
|
||||
SET_BEG_POS_AND_LINE();
|
||||
get_line(in);
|
||||
if (! parse_date(line, &entry->_date))
|
||||
throw new parse_error("Failed to parse date");
|
||||
entry->_date = line;
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
|
|
|
|||
24
quotes.cc
24
quotes.cc
|
|
@ -10,15 +10,15 @@
|
|||
namespace ledger {
|
||||
|
||||
void quotes_by_script::operator()(commodity_base_t& commodity,
|
||||
const std::time_t moment,
|
||||
const std::time_t date,
|
||||
const std::time_t last,
|
||||
const datetime_t& moment,
|
||||
const datetime_t& date,
|
||||
const datetime_t& last,
|
||||
amount_t& price)
|
||||
{
|
||||
DEBUG_CLASS("ledger.quotes.download");
|
||||
|
||||
DEBUG_PRINT_("commodity: " << commodity.symbol);
|
||||
DEBUG_PRINT_TIME_(now);
|
||||
DEBUG_PRINT_TIME_(datetime_t::now);
|
||||
DEBUG_PRINT_TIME_(moment);
|
||||
DEBUG_PRINT_TIME_(date);
|
||||
DEBUG_PRINT_TIME_(last);
|
||||
|
|
@ -27,10 +27,9 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
|
|||
DEBUG_PRINT_("pricing_leeway is " << pricing_leeway);
|
||||
|
||||
if ((commodity.history &&
|
||||
std::difftime(now, commodity.history->last_lookup) < pricing_leeway) ||
|
||||
std::difftime(now, last) < pricing_leeway ||
|
||||
(price && std::difftime(moment, date) > 0 &&
|
||||
std::difftime(moment, date) <= pricing_leeway))
|
||||
(datetime_t::now - commodity.history->last_lookup) < pricing_leeway) ||
|
||||
(datetime_t::now - last) < pricing_leeway ||
|
||||
(price && moment > date && (moment - date) <= pricing_leeway))
|
||||
return;
|
||||
|
||||
using namespace std;
|
||||
|
|
@ -59,20 +58,19 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
|
|||
DEBUG_PRINT_("downloaded quote: " << buf);
|
||||
|
||||
price.parse(buf);
|
||||
commodity.add_price(now, price);
|
||||
commodity.add_price(datetime_t::now, price);
|
||||
|
||||
commodity.history->last_lookup = now;
|
||||
commodity.history->last_lookup = datetime_t::now;
|
||||
cache_dirty = true;
|
||||
|
||||
if (price && ! price_db.empty()) {
|
||||
strftime(buf, 127, "%Y/%m/%d %H:%M:%S", localtime(&now));
|
||||
#if defined(__GNUG__) && __GNUG__ < 3
|
||||
ofstream database(price_db.c_str(), ios::out | ios::app);
|
||||
#else
|
||||
ofstream database(price_db.c_str(), ios_base::out | ios_base::app);
|
||||
#endif
|
||||
database << "P " << buf << " " << commodity.symbol
|
||||
<< " " << price << endl;
|
||||
database << "P " << datetime_t::now.to_string("%Y/%m/%d %H:%M:%S")
|
||||
<< " " << commodity.symbol << " " << price << endl;
|
||||
}
|
||||
} else {
|
||||
throw new error(std::string("Failed to download price for '") +
|
||||
|
|
|
|||
6
quotes.h
6
quotes.h
|
|
@ -19,9 +19,9 @@ class quotes_by_script : public commodity_base_t::updater_t
|
|||
cache_dirty(_cache_dirty) {}
|
||||
|
||||
virtual void operator()(commodity_base_t& commodity,
|
||||
const std::time_t moment,
|
||||
const std::time_t date,
|
||||
const std::time_t last,
|
||||
const datetime_t& moment,
|
||||
const datetime_t& date,
|
||||
const datetime_t& last,
|
||||
amount_t& price);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ void reconcile_transactions::flush()
|
|||
for (transactions_list::iterator x = xacts.begin();
|
||||
x != xacts.end();
|
||||
x++) {
|
||||
if (! cutoff || std::difftime((*x)->date(), cutoff) < 0) {
|
||||
if (! cutoff || (*x)->date() < cutoff) {
|
||||
switch ((*x)->state) {
|
||||
case transaction_t::CLEARED:
|
||||
cleared_balance += (*x)->amount;
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@ namespace ledger {
|
|||
|
||||
class reconcile_transactions : public item_handler<transaction_t>
|
||||
{
|
||||
value_t balance;
|
||||
time_t cutoff;
|
||||
value_t balance;
|
||||
datetime_t cutoff;
|
||||
|
||||
transactions_list xacts;
|
||||
|
||||
public:
|
||||
reconcile_transactions(item_handler<transaction_t> * handler,
|
||||
const value_t& _balance, const time_t _cutoff)
|
||||
const value_t& _balance,
|
||||
const datetime_t& _cutoff)
|
||||
: item_handler<transaction_t>(handler),
|
||||
balance(_balance), cutoff(_cutoff) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ report_t::report_t()
|
|||
display_predicate = "";
|
||||
descend_expr = "";
|
||||
|
||||
pricing_leeway = 24 * 3600;
|
||||
budget_flags = BUDGET_NO_BUDGET;
|
||||
|
||||
head_entries = 0;
|
||||
|
|
@ -204,8 +203,8 @@ void report_t::process_options(const std::string& command,
|
|||
|
||||
// Now setup the various formatting strings
|
||||
|
||||
if (! date_format.empty())
|
||||
datetime_t::date_format = date_format;
|
||||
if (! date_output_format.empty())
|
||||
date_t::output_format = date_output_format;
|
||||
|
||||
amount_t::keep_price = keep_price;
|
||||
amount_t::keep_date = keep_date;
|
||||
|
|
@ -278,9 +277,9 @@ report_t::chain_xact_handlers(const std::string& command,
|
|||
// transactions which can be reconciled to a given balance
|
||||
// (calculated against the transactions which it receives).
|
||||
if (! reconcile_balance.empty()) {
|
||||
std::time_t cutoff = now;
|
||||
datetime_t cutoff = datetime_t::now;
|
||||
if (! reconcile_date.empty())
|
||||
parse_date(reconcile_date.c_str(), &cutoff);
|
||||
cutoff = reconcile_date;
|
||||
ptrs.push_back(formatter =
|
||||
new reconcile_transactions
|
||||
(formatter, value_t(reconcile_balance), cutoff));
|
||||
|
|
|
|||
3
report.h
3
report.h
|
|
@ -27,10 +27,9 @@ class report_t
|
|||
std::string forecast_limit;
|
||||
std::string reconcile_balance;
|
||||
std::string reconcile_date;
|
||||
std::string date_format;
|
||||
std::string date_output_format;
|
||||
|
||||
unsigned long budget_flags;
|
||||
unsigned long pricing_leeway;
|
||||
|
||||
int head_entries;
|
||||
int tail_entries;
|
||||
|
|
|
|||
182
textual.cc
182
textual.cc
|
|
@ -16,7 +16,6 @@
|
|||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
|
@ -36,10 +35,15 @@ static unsigned int linenum;
|
|||
static unsigned int src_idx;
|
||||
static accounts_map account_aliases;
|
||||
|
||||
static std::list<std::pair<std::string, int> > include_stack;
|
||||
|
||||
#ifdef TIMELOG_SUPPORT
|
||||
static std::time_t time_in;
|
||||
static account_t * last_account;
|
||||
static std::string last_desc;
|
||||
struct time_entry_t {
|
||||
datetime_t checkin;
|
||||
account_t * account;
|
||||
std::string desc;
|
||||
};
|
||||
std::list<time_entry_t> time_entries;
|
||||
#endif
|
||||
|
||||
inline char * next_element(char * buf, bool variable = false)
|
||||
|
|
@ -85,7 +89,7 @@ static value_expr parse_amount_expr(std::istream& in, amount_t& amount,
|
|||
|
||||
if (! compute_amount(expr, amount, xact))
|
||||
throw new parse_error("Amount expression failed to compute");
|
||||
|
||||
|
||||
if (expr->kind == value_expr_t::CONSTANT)
|
||||
expr = NULL;
|
||||
|
||||
|
|
@ -285,12 +289,10 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
|
||||
if (char * p = std::strchr(buf, '=')) {
|
||||
*p++ = '\0';
|
||||
if (! quick_parse_date(p, &xact->_date_eff))
|
||||
throw new parse_error("Failed to parse effective date");
|
||||
xact->_date_eff = p;
|
||||
}
|
||||
|
||||
if (buf[0] && ! quick_parse_date(buf, &xact->_date))
|
||||
throw new parse_error("Failed to parse date");
|
||||
if (buf[0])
|
||||
xact->_date = buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -358,12 +360,9 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
|
|||
|
||||
if (char * p = std::strchr(line, '=')) {
|
||||
*p++ = '\0';
|
||||
if (! quick_parse_date(p, &curr->_date_eff))
|
||||
throw new parse_error("Failed to parse effective date");
|
||||
curr->_date_eff = p;
|
||||
}
|
||||
|
||||
if (! quick_parse_date(line, &curr->_date))
|
||||
throw new parse_error("Failed to parse date");
|
||||
curr->_date = line;
|
||||
|
||||
TIMER_STOP(entry_date);
|
||||
|
||||
|
|
@ -492,22 +491,61 @@ bool textual_parser_t::test(std::istream& in) const
|
|||
return true;
|
||||
}
|
||||
|
||||
static void clock_out_from_timelog(const std::time_t when,
|
||||
journal_t * journal)
|
||||
static void clock_out_from_timelog(const datetime_t& when,
|
||||
account_t * account,
|
||||
const char * desc,
|
||||
journal_t * journal)
|
||||
{
|
||||
time_entry_t event;
|
||||
bool found = false;
|
||||
|
||||
if (time_entries.size() == 1) {
|
||||
event = time_entries.back();
|
||||
time_entries.clear();
|
||||
}
|
||||
else if (time_entries.empty()) {
|
||||
throw new parse_error("Timelog check-out event without a check-in");
|
||||
}
|
||||
else if (! account) {
|
||||
throw new parse_error
|
||||
("When multiple check-ins are active, checking out requires an account");
|
||||
}
|
||||
else {
|
||||
for (std::list<time_entry_t>::iterator i = time_entries.begin();
|
||||
i != time_entries.end();
|
||||
i++)
|
||||
if (account == (*i).account) {
|
||||
event = *i;
|
||||
found = true;
|
||||
time_entries.erase(i);
|
||||
break;
|
||||
}
|
||||
if (! found)
|
||||
throw new parse_error
|
||||
("Timelog check-out event does not match any current check-ins");
|
||||
}
|
||||
|
||||
if (desc && event.desc.empty()) {
|
||||
event.desc = desc;
|
||||
desc = NULL;
|
||||
}
|
||||
|
||||
std::auto_ptr<entry_t> curr(new entry_t);
|
||||
curr->_date = when;
|
||||
curr->code = "";
|
||||
curr->payee = last_desc;
|
||||
curr->code = desc ? desc : "";
|
||||
curr->payee = event.desc;
|
||||
|
||||
double diff = std::difftime(curr->_date, time_in);
|
||||
char buf[32];
|
||||
std::sprintf(buf, "%lds", long(diff));
|
||||
if (curr->_date < event.checkin)
|
||||
throw new parse_error
|
||||
("Timelog check-out date less than corresponding check-in");
|
||||
|
||||
char buf[32];
|
||||
std::sprintf(buf, "%lds", curr->_date - event.checkin);
|
||||
amount_t amt;
|
||||
amt.parse(buf);
|
||||
|
||||
transaction_t * xact
|
||||
= new transaction_t(last_account, amt, TRANSACTION_VIRTUAL);
|
||||
= new transaction_t(event.account, amt, TRANSACTION_VIRTUAL);
|
||||
xact->state = transaction_t::CLEARED;
|
||||
curr->add_transaction(xact);
|
||||
|
||||
|
|
@ -517,8 +555,6 @@ static void clock_out_from_timelog(const std::time_t when,
|
|||
curr.release();
|
||||
}
|
||||
|
||||
static std::list<std::pair<std::string, int> > include_stack;
|
||||
|
||||
unsigned int textual_parser_t::parse(std::istream& in,
|
||||
config_t& config,
|
||||
journal_t * journal,
|
||||
|
|
@ -577,37 +613,38 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
|
||||
char * p = skip_ws(line + 22);
|
||||
char * n = next_element(p, true);
|
||||
last_desc = n ? n : "";
|
||||
|
||||
struct std::tm when;
|
||||
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
|
||||
time_in = std::mktime(&when);
|
||||
last_account = account_stack.front()->find_account(p);
|
||||
} else {
|
||||
last_account = NULL;
|
||||
throw new parse_error("Cannot parse timelog entry date");
|
||||
}
|
||||
time_entry_t event;
|
||||
event.desc = n ? n : "";
|
||||
event.checkin = date;
|
||||
event.account = account_stack.front()->find_account(p);
|
||||
|
||||
if (! time_entries.empty())
|
||||
for (std::list<time_entry_t>::iterator i = time_entries.begin();
|
||||
i != time_entries.end();
|
||||
i++)
|
||||
if (event.account == (*i).account)
|
||||
throw new parse_error
|
||||
("Cannot double check-in to the same account");
|
||||
|
||||
time_entries.push_back(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o':
|
||||
case 'O':
|
||||
if (last_account) {
|
||||
if (time_entries.empty()) {
|
||||
throw new parse_error("Timelog check-out event without a check-in");
|
||||
} else {
|
||||
std::string date(line, 2, 19);
|
||||
|
||||
char * p = skip_ws(line + 22);
|
||||
if (last_desc.empty() && *p)
|
||||
last_desc = p;
|
||||
char * n = next_element(p, true);
|
||||
|
||||
struct std::tm when;
|
||||
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
|
||||
clock_out_from_timelog(std::mktime(&when), journal);
|
||||
count++;
|
||||
} else {
|
||||
throw new parse_error("Cannot parse timelog entry date");
|
||||
}
|
||||
|
||||
last_account = NULL;
|
||||
clock_out_from_timelog
|
||||
(date, p ? account_stack.front()->find_account(p) : NULL, n,
|
||||
journal);
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
#endif // TIMELOG_SUPPORT
|
||||
|
|
@ -631,39 +668,21 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
break;
|
||||
|
||||
case 'P': { // a pricing entry
|
||||
char * date_field = skip_ws(line + 1);
|
||||
char * time_field = next_element(date_field);
|
||||
if (! time_field) break;
|
||||
char * date_field_ptr = skip_ws(line + 1);
|
||||
char * time_field_ptr = next_element(date_field_ptr);
|
||||
if (! time_field_ptr) break;
|
||||
std::string date_field = date_field_ptr;
|
||||
|
||||
char * symbol_and_price;
|
||||
std::time_t date;
|
||||
struct std::tm when;
|
||||
char * symbol_and_price;
|
||||
datetime_t datetime;
|
||||
|
||||
if (std::isdigit(time_field[0])) {
|
||||
symbol_and_price = next_element(time_field);
|
||||
if (std::isdigit(time_field_ptr[0])) {
|
||||
symbol_and_price = next_element(time_field_ptr);
|
||||
if (! symbol_and_price) break;
|
||||
|
||||
char date_buffer[64];
|
||||
std::strcpy(date_buffer, date_field);
|
||||
date_buffer[std::strlen(date_field)] = ' ';
|
||||
std::strcpy(&date_buffer[std::strlen(date_field) + 1], time_field);
|
||||
|
||||
if (strptime(date_buffer, "%Y/%m/%d %H:%M:%S", &when)) {
|
||||
date = std::mktime(&when);
|
||||
} else {
|
||||
throw new parse_error("Failed to parse date/time");
|
||||
}
|
||||
datetime = date_field + " " + time_field_ptr;
|
||||
} else {
|
||||
symbol_and_price = time_field;
|
||||
|
||||
if (strptime(date_field, "%Y/%m/%d", &when)) {
|
||||
when.tm_hour = 0;
|
||||
when.tm_min = 0;
|
||||
when.tm_sec = 0;
|
||||
date = std::mktime(&when);
|
||||
} else {
|
||||
throw new parse_error("Failed to parse date");
|
||||
}
|
||||
symbol_and_price = time_field_ptr;
|
||||
datetime = date_t(date_field);
|
||||
}
|
||||
|
||||
std::string symbol;
|
||||
|
|
@ -671,7 +690,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
amount_t price(symbol_and_price);
|
||||
|
||||
if (commodity_t * commodity = commodity_t::find_or_create(symbol))
|
||||
commodity->add_price(date, price);
|
||||
commodity->add_price(datetime, price);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -686,7 +705,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
}
|
||||
|
||||
case 'Y': // set the current year
|
||||
now_year = std::atoi(skip_ws(line + 1)) - 1900;
|
||||
date_t::current_year = std::atoi(skip_ws(line + 1)) - 1900;
|
||||
break;
|
||||
|
||||
#ifdef TIMELOG_SUPPORT
|
||||
|
|
@ -858,9 +877,12 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
}
|
||||
|
||||
done:
|
||||
if (last_account) {
|
||||
clock_out_from_timelog(now, journal);
|
||||
last_account = NULL;
|
||||
if (! time_entries.empty()) {
|
||||
for (std::list<time_entry_t>::iterator i = time_entries.begin();
|
||||
i != time_entries.end();
|
||||
i++)
|
||||
clock_out_from_timelog(datetime_t::now, (*i).account, NULL, journal);
|
||||
time_entries.clear();
|
||||
}
|
||||
|
||||
if (added_auto_entry_hook)
|
||||
|
|
|
|||
43
valexpr.cc
43
valexpr.cc
|
|
@ -11,7 +11,7 @@ value_expr amount_expr;
|
|||
value_expr total_expr;
|
||||
|
||||
std::auto_ptr<scope_t> global_scope;
|
||||
std::time_t terminus;
|
||||
datetime_t terminus;
|
||||
|
||||
details_t::details_t(const transaction_t& _xact)
|
||||
: entry(_xact.entry), xact(&_xact), account(xact_account(_xact))
|
||||
|
|
@ -150,7 +150,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
break;
|
||||
|
||||
case F_NOW:
|
||||
result = datetime_t(terminus);
|
||||
result = terminus;
|
||||
break;
|
||||
|
||||
case AMOUNT:
|
||||
|
|
@ -257,37 +257,37 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
case DATE:
|
||||
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||
transaction_xdata_(*details.xact).date)
|
||||
result = datetime_t(transaction_xdata_(*details.xact).date);
|
||||
result = transaction_xdata_(*details.xact).date;
|
||||
else if (details.xact)
|
||||
result = datetime_t(details.xact->date());
|
||||
result = details.xact->date();
|
||||
else if (details.entry)
|
||||
result = datetime_t(details.entry->date());
|
||||
result = details.entry->date();
|
||||
else
|
||||
result = datetime_t(terminus);
|
||||
result = terminus;
|
||||
break;
|
||||
|
||||
case ACT_DATE:
|
||||
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||
transaction_xdata_(*details.xact).date)
|
||||
result = datetime_t(transaction_xdata_(*details.xact).date);
|
||||
result = transaction_xdata_(*details.xact).date;
|
||||
else if (details.xact)
|
||||
result = datetime_t(details.xact->actual_date());
|
||||
result = details.xact->actual_date();
|
||||
else if (details.entry)
|
||||
result = datetime_t(details.entry->actual_date());
|
||||
result = details.entry->actual_date();
|
||||
else
|
||||
result = datetime_t(terminus);
|
||||
result = terminus;
|
||||
break;
|
||||
|
||||
case EFF_DATE:
|
||||
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||
transaction_xdata_(*details.xact).date)
|
||||
result = datetime_t(transaction_xdata_(*details.xact).date);
|
||||
result = transaction_xdata_(*details.xact).date;
|
||||
else if (details.xact)
|
||||
result = datetime_t(details.xact->effective_date());
|
||||
result = details.xact->effective_date();
|
||||
else if (details.entry)
|
||||
result = datetime_t(details.entry->effective_date());
|
||||
result = details.entry->effective_date();
|
||||
else
|
||||
result = datetime_t(terminus);
|
||||
result = terminus;
|
||||
break;
|
||||
|
||||
case CLEARED:
|
||||
|
|
@ -388,19 +388,20 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
value_expr_t * expr = find_leaf(context, 0, arg_index);
|
||||
expr->compute(result, details, context);
|
||||
|
||||
// jww (2006-03-05): Generate an error if result is not a DATETIME
|
||||
std::time_t moment = (long)result;
|
||||
struct std::tm * desc = std::localtime(&moment);
|
||||
if (result.type != value_t::DATETIME)
|
||||
throw new compute_error("Invalid date passed to year|month|day(date)",
|
||||
new valexpr_context(expr));
|
||||
|
||||
datetime_t& moment(*((datetime_t *)result.data));
|
||||
switch (kind) {
|
||||
case F_YEAR:
|
||||
result = (long)desc->tm_year + 1900L;
|
||||
result = (long)moment.year();
|
||||
break;
|
||||
case F_MONTH:
|
||||
result = (long)desc->tm_mon + 1L;
|
||||
result = (long)moment.month();
|
||||
break;
|
||||
case F_DAY:
|
||||
result = (long)desc->tm_mday;
|
||||
result = (long)moment.day();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1036,7 +1037,7 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope,
|
|||
|
||||
node.reset(new value_expr_t(value_expr_t::CONSTANT));
|
||||
interval_t timespan(buf);
|
||||
node->value = new value_t(datetime_t(timespan.first()));
|
||||
node->value = new value_t(timespan.first());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ struct scope_t
|
|||
|
||||
typedef std::map<const std::string, value_expr_t *> symbol_map;
|
||||
typedef std::pair<const std::string, value_expr_t *> symbol_pair;
|
||||
|
||||
|
||||
symbol_map symbols;
|
||||
|
||||
scope_t(scope_t * _parent = NULL) : parent(_parent) {
|
||||
|
|
@ -267,8 +267,8 @@ struct scope_t
|
|||
|
||||
extern std::auto_ptr<scope_t> global_scope;
|
||||
|
||||
extern std::time_t terminus;
|
||||
extern bool initialized;
|
||||
extern datetime_t terminus;
|
||||
extern bool initialized;
|
||||
|
||||
void init_value_expr();
|
||||
|
||||
|
|
|
|||
12
value.cc
12
value.cc
|
|
@ -836,7 +836,7 @@ value_t::operator double() const
|
|||
case INTEGER:
|
||||
return *((long *) data);
|
||||
case DATETIME:
|
||||
return *((datetime_t *) data);
|
||||
throw new value_error("Cannot convert a date/time to a double");
|
||||
case AMOUNT:
|
||||
return *((amount_t *) data);
|
||||
case BALANCE:
|
||||
|
|
@ -1111,7 +1111,7 @@ void value_t::abs()
|
|||
}
|
||||
}
|
||||
|
||||
value_t value_t::value(const std::time_t moment) const
|
||||
value_t value_t::value(const datetime_t& moment) const
|
||||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
|
|
@ -1225,18 +1225,18 @@ value_t value_t::date() const
|
|||
case BOOLEAN:
|
||||
throw new value_error("Cannot find the date of a boolean");
|
||||
case INTEGER:
|
||||
return 0L;
|
||||
return datetime_t();
|
||||
case DATETIME:
|
||||
return *this;
|
||||
|
||||
case AMOUNT:
|
||||
return ((amount_t *) data)->date();
|
||||
return datetime_t(((amount_t *) data)->date());
|
||||
|
||||
case BALANCE:
|
||||
return (long)((balance_t *) data)->date();
|
||||
return datetime_t(((balance_t *) data)->date());
|
||||
|
||||
case BALANCE_PAIR:
|
||||
return (long)((balance_pair_t *) data)->quantity.date();
|
||||
return datetime_t(((balance_pair_t *) data)->quantity.date());
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
|
|
|
|||
2
value.h
2
value.h
|
|
@ -315,7 +315,7 @@ class value_t
|
|||
const bool keep_tag = amount_t::keep_tag) const;
|
||||
|
||||
value_t& add(const amount_t& amount, const amount_t * cost = NULL);
|
||||
value_t value(const std::time_t moment) const;
|
||||
value_t value(const datetime_t& moment) const;
|
||||
void reduce();
|
||||
|
||||
value_t reduced() const {
|
||||
|
|
|
|||
68
walk.cc
68
walk.cc
|
|
@ -183,7 +183,7 @@ void handle_value(const value_t& value,
|
|||
unsigned int flags,
|
||||
std::list<transaction_t>& temps,
|
||||
item_handler<transaction_t>& handler,
|
||||
const std::time_t date = 0,
|
||||
const datetime_t& date = datetime_t(),
|
||||
transactions_list * component_xacts = NULL)
|
||||
{
|
||||
temps.push_back(transaction_t(account));
|
||||
|
|
@ -312,7 +312,7 @@ void related_transactions::flush()
|
|||
item_handler<transaction_t>::flush();
|
||||
}
|
||||
|
||||
void changed_value_transactions::output_diff(const std::time_t current)
|
||||
void changed_value_transactions::output_diff(const datetime_t& current)
|
||||
{
|
||||
value_t cur_bal;
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ void changed_value_transactions::output_diff(const std::time_t current)
|
|||
void changed_value_transactions::operator()(transaction_t& xact)
|
||||
{
|
||||
if (last_xact) {
|
||||
std::time_t moment = 0;
|
||||
datetime_t moment;
|
||||
if (transaction_has_xdata(*last_xact))
|
||||
moment = transaction_xdata_(*last_xact).date;
|
||||
else
|
||||
|
|
@ -367,19 +367,18 @@ void component_transactions::operator()(transaction_t& xact)
|
|||
|
||||
void subtotal_transactions::report_subtotal(const char * spec_fmt)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
std::ostringstream out_date;
|
||||
if (! spec_fmt) {
|
||||
std::string fmt = "- ";
|
||||
fmt += datetime_t::date_format;
|
||||
std::strftime(buf, 255, fmt.c_str(), std::localtime(&finish));
|
||||
fmt += date_t::output_format;
|
||||
finish.write(out_date, fmt);
|
||||
} else {
|
||||
std::strftime(buf, 255, spec_fmt, std::localtime(&finish));
|
||||
finish.write(out_date, spec_fmt);
|
||||
}
|
||||
|
||||
entry_temps.push_back(entry_t());
|
||||
entry_t& entry = entry_temps.back();
|
||||
entry.payee = buf;
|
||||
entry.payee = out_date.str();
|
||||
entry._date = start;
|
||||
|
||||
for (values_map::iterator i = values.begin();
|
||||
|
|
@ -393,9 +392,9 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
|
|||
|
||||
void subtotal_transactions::operator()(transaction_t& xact)
|
||||
{
|
||||
if (! start || std::difftime(xact.date(), start) < 0)
|
||||
if (! start || xact.date() < start)
|
||||
start = xact.date();
|
||||
if (! finish || std::difftime(xact.date(), finish) > 0)
|
||||
if (! finish || xact.date() > finish)
|
||||
finish = xact.date();
|
||||
|
||||
account_t * acct = xact_account(xact);
|
||||
|
|
@ -429,13 +428,13 @@ void subtotal_transactions::operator()(transaction_t& xact)
|
|||
account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_UNB_VIRTUALS;
|
||||
}
|
||||
|
||||
void interval_transactions::report_subtotal(const std::time_t moment)
|
||||
void interval_transactions::report_subtotal(const datetime_t& moment)
|
||||
{
|
||||
assert(last_xact);
|
||||
|
||||
start = interval.begin;
|
||||
if (moment)
|
||||
finish = moment - 86400;
|
||||
finish = moment - 86400L;
|
||||
else
|
||||
finish = last_xact->date();
|
||||
|
||||
|
|
@ -446,10 +445,10 @@ void interval_transactions::report_subtotal(const std::time_t moment)
|
|||
|
||||
void interval_transactions::operator()(transaction_t& xact)
|
||||
{
|
||||
const std::time_t date = xact.date();
|
||||
const datetime_t date = xact.date();
|
||||
|
||||
if ((interval.begin && std::difftime(date, interval.begin) < 0) ||
|
||||
(interval.end && std::difftime(date, interval.end) >= 0))
|
||||
if ((interval.begin && date < interval.begin) ||
|
||||
(interval.end && date >= interval.end))
|
||||
return;
|
||||
|
||||
if (interval) {
|
||||
|
|
@ -460,13 +459,13 @@ void interval_transactions::operator()(transaction_t& xact)
|
|||
started = true;
|
||||
}
|
||||
|
||||
std::time_t quant = interval.increment(interval.begin);
|
||||
if (std::difftime(date, quant) >= 0) {
|
||||
datetime_t quant = interval.increment(interval.begin);
|
||||
if (date >= quant) {
|
||||
if (last_xact)
|
||||
report_subtotal(quant);
|
||||
|
||||
std::time_t temp;
|
||||
while (std::difftime(date, temp = interval.increment(quant)) >= 0) {
|
||||
datetime_t temp;
|
||||
while (date >= (temp = interval.increment(quant))) {
|
||||
if (quant == temp)
|
||||
break;
|
||||
quant = temp;
|
||||
|
|
@ -518,7 +517,7 @@ void by_payee_transactions::operator()(transaction_t& xact)
|
|||
i = result.first;
|
||||
}
|
||||
|
||||
if (std::difftime(xact.date(), (*i).second->start) > 0)
|
||||
if (xact.date() > (*i).second->start)
|
||||
(*i).second->start = xact.date();
|
||||
|
||||
(*(*i).second)(xact);
|
||||
|
|
@ -602,7 +601,7 @@ void generate_transactions::add_transaction(const interval_t& period,
|
|||
pending_xacts.push_back(pending_xacts_pair(period, &xact));
|
||||
}
|
||||
|
||||
void budget_transactions::report_budget_items(const std::time_t moment)
|
||||
void budget_transactions::report_budget_items(const datetime_t& moment)
|
||||
{
|
||||
if (pending_xacts.size() == 0)
|
||||
return;
|
||||
|
|
@ -613,14 +612,14 @@ void budget_transactions::report_budget_items(const std::time_t moment)
|
|||
for (pending_xacts_list::iterator i = pending_xacts.begin();
|
||||
i != pending_xacts.end();
|
||||
i++) {
|
||||
std::time_t& begin = (*i).first.begin;
|
||||
datetime_t& begin = (*i).first.begin;
|
||||
if (! begin) {
|
||||
(*i).first.start(moment);
|
||||
begin = (*i).first.begin;
|
||||
}
|
||||
|
||||
if (std::difftime(begin, moment) < 0 &&
|
||||
(! (*i).first.end || std::difftime(begin, (*i).first.end) < 0)) {
|
||||
if (begin < moment &&
|
||||
(! (*i).first.end || begin < (*i).first.end)) {
|
||||
transaction_t& xact = *(*i).second;
|
||||
|
||||
DEBUG_PRINT("ledger.walk.budget", "Reporting budget for "
|
||||
|
|
@ -687,10 +686,10 @@ void forecast_transactions::add_transaction(const interval_t& period,
|
|||
|
||||
interval_t& i = pending_xacts.back().first;
|
||||
if (! i.begin) {
|
||||
i.start(now);
|
||||
i.start(datetime_t::now);
|
||||
i.begin = i.increment(i.begin);
|
||||
} else {
|
||||
while (std::difftime(i.begin, now) < 0)
|
||||
while (i.begin < datetime_t::now)
|
||||
i.begin = i.increment(i.begin);
|
||||
}
|
||||
}
|
||||
|
|
@ -698,20 +697,19 @@ void forecast_transactions::add_transaction(const interval_t& period,
|
|||
void forecast_transactions::flush()
|
||||
{
|
||||
transactions_list passed;
|
||||
std::time_t last = 0;
|
||||
datetime_t last;
|
||||
|
||||
while (pending_xacts.size() > 0) {
|
||||
pending_xacts_list::iterator least = pending_xacts.begin();
|
||||
for (pending_xacts_list::iterator i = ++pending_xacts.begin();
|
||||
i != pending_xacts.end();
|
||||
i++)
|
||||
if (std::difftime((*i).first.begin, (*least).first.begin) < 0)
|
||||
if ((*i).first.begin < (*least).first.begin)
|
||||
least = i;
|
||||
|
||||
std::time_t& begin = (*least).first.begin;
|
||||
datetime_t& begin = (*least).first.begin;
|
||||
|
||||
if ((*least).first.end &&
|
||||
std::difftime(begin, (*least).first.end) >= 0) {
|
||||
if ((*least).first.end && begin >= (*least).first.end) {
|
||||
pending_xacts.erase(least);
|
||||
passed.remove((*least).second);
|
||||
continue;
|
||||
|
|
@ -731,9 +729,9 @@ void forecast_transactions::flush()
|
|||
temp.flags |= TRANSACTION_BULK_ALLOC;
|
||||
entry.add_transaction(&temp);
|
||||
|
||||
std::time_t next = (*least).first.increment(begin);
|
||||
if (std::difftime(next, begin) < 0 || // wraparound
|
||||
(last && std::difftime(next, last) > 5 * 365 * 24 * 60 * 60))
|
||||
datetime_t next = (*least).first.increment(begin);
|
||||
if (next < begin || // wraparound
|
||||
(last && (next - last) > 365 * 5 * 24 * 3600))
|
||||
break;
|
||||
begin = next;
|
||||
|
||||
|
|
|
|||
24
walk.h
24
walk.h
|
|
@ -90,15 +90,15 @@ struct transaction_xdata_t
|
|||
value_t value;
|
||||
unsigned int index;
|
||||
unsigned short dflags;
|
||||
std::time_t date;
|
||||
datetime_t date;
|
||||
account_t * account;
|
||||
void * ptr;
|
||||
|
||||
transactions_list * component_xacts;
|
||||
|
||||
transaction_xdata_t()
|
||||
: index(0), dflags(0), date(0), account(NULL), ptr(NULL),
|
||||
component_xacts(NULL) {
|
||||
: index(0), dflags(0),
|
||||
account(NULL), ptr(NULL), component_xacts(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_xdata_t " << this);
|
||||
}
|
||||
|
||||
|
|
@ -445,13 +445,13 @@ class changed_value_transactions : public item_handler<transaction_t>
|
|||
|
||||
virtual void flush() {
|
||||
if (last_xact) {
|
||||
output_diff(now);
|
||||
output_diff(datetime_t::now);
|
||||
last_xact = NULL;
|
||||
}
|
||||
item_handler<transaction_t>::flush();
|
||||
}
|
||||
|
||||
void output_diff(const std::time_t current);
|
||||
void output_diff(const datetime_t& current);
|
||||
|
||||
virtual void operator()(transaction_t& xact);
|
||||
};
|
||||
|
|
@ -481,13 +481,13 @@ class subtotal_transactions : public item_handler<transaction_t>
|
|||
std::list<transaction_t> xact_temps;
|
||||
|
||||
public:
|
||||
std::time_t start;
|
||||
std::time_t finish;
|
||||
datetime_t start;
|
||||
datetime_t finish;
|
||||
|
||||
subtotal_transactions(item_handler<transaction_t> * handler,
|
||||
bool _remember_components = false)
|
||||
: item_handler<transaction_t>(handler),
|
||||
remember_components(_remember_components), start(0), finish(0) {}
|
||||
remember_components(_remember_components) {}
|
||||
#ifdef DEBUG_ENABLED
|
||||
subtotal_transactions(const subtotal_transactions&) {
|
||||
assert(0);
|
||||
|
|
@ -534,7 +534,7 @@ class interval_transactions : public subtotal_transactions
|
|||
: subtotal_transactions(_handler, remember_components),
|
||||
interval(_interval), last_xact(NULL), started(false) {}
|
||||
|
||||
void report_subtotal(const std::time_t moment = 0);
|
||||
void report_subtotal(const datetime_t& moment = datetime_t());
|
||||
|
||||
virtual void flush() {
|
||||
if (last_xact)
|
||||
|
|
@ -606,9 +606,7 @@ class dow_transactions : public subtotal_transactions
|
|||
|
||||
virtual void flush();
|
||||
virtual void operator()(transaction_t& xact) {
|
||||
std::time_t when = xact.date();
|
||||
struct std::tm * desc = std::localtime(&when);
|
||||
days_of_the_week[desc->tm_wday].push_back(&xact);
|
||||
days_of_the_week[xact.date().wday()].push_back(&xact);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -648,7 +646,7 @@ class budget_transactions : public generate_transactions
|
|||
unsigned long _flags = BUDGET_BUDGETED)
|
||||
: generate_transactions(handler), flags(_flags) {}
|
||||
|
||||
void report_budget_items(const std::time_t moment);
|
||||
void report_budget_items(const datetime_t& moment);
|
||||
|
||||
virtual void operator()(transaction_t& xact);
|
||||
};
|
||||
|
|
|
|||
41
xml.cc
41
xml.cc
|
|
@ -12,13 +12,13 @@ extern "C" {
|
|||
#include <expat.h> // expat XML parser
|
||||
#elif defined(HAVE_XMLPARSE)
|
||||
#include <xmlparse.h> // expat XML parser
|
||||
#else
|
||||
#error "No XML parser library defined."
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace ledger {
|
||||
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
|
||||
static XML_Parser current_parser;
|
||||
static unsigned int count;
|
||||
|
||||
|
|
@ -83,10 +83,10 @@ static void endElement(void *userData, const char *name)
|
|||
curr_entry = NULL;
|
||||
}
|
||||
else if (std::strcmp(name, "en:date") == 0) {
|
||||
quick_parse_date(data.c_str(), &curr_entry->_date);
|
||||
curr_entry->_date = data;
|
||||
}
|
||||
else if (std::strcmp(name, "en:date_eff") == 0) {
|
||||
quick_parse_date(data.c_str(), &curr_entry->_date_eff);
|
||||
curr_entry->_date_eff = data;
|
||||
}
|
||||
else if (std::strcmp(name, "en:code") == 0) {
|
||||
curr_entry->code = data;
|
||||
|
|
@ -246,6 +246,8 @@ unsigned int xml_parser_t::parse(std::istream& in,
|
|||
return count;
|
||||
}
|
||||
|
||||
#endif // defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
|
||||
void xml_write_amount(std::ostream& out, const amount_t& amount,
|
||||
const int depth = 0)
|
||||
{
|
||||
|
|
@ -367,16 +369,14 @@ void output_xml_string(std::ostream& out, const std::string& str)
|
|||
|
||||
void format_xml_entries::format_last_entry()
|
||||
{
|
||||
char buf[32];
|
||||
std::strftime(buf, 31, "%Y/%m/%d", std::localtime(&last_entry->_date));
|
||||
|
||||
output_stream << " <entry>\n"
|
||||
<< " <en:date>" << buf << "</en:date>\n";
|
||||
<< " <en:date>" << last_entry->_date.to_string("%Y/%m/%d")
|
||||
<< "</en:date>\n";
|
||||
|
||||
if (last_entry->_date_eff) {
|
||||
std::strftime(buf, 31, "%Y/%m/%d", std::localtime(&last_entry->_date_eff));
|
||||
output_stream << " <en:date_eff>" << buf << "</en:date_eff>\n";
|
||||
}
|
||||
if (last_entry->_date_eff)
|
||||
output_stream << " <en:date_eff>"
|
||||
<< last_entry->_date_eff.to_string("%Y/%m/%d")
|
||||
<< "</en:date_eff>\n";
|
||||
|
||||
if (! last_entry->code.empty()) {
|
||||
output_stream << " <en:code>";
|
||||
|
|
@ -403,14 +403,15 @@ void format_xml_entries::format_last_entry()
|
|||
|
||||
output_stream << " <transaction>\n";
|
||||
|
||||
if ((*i)->_date) {
|
||||
std::strftime(buf, 31, "%Y/%m/%d", std::localtime(&(*i)->_date));
|
||||
output_stream << " <tr:date>" << buf << "</tr:date>\n";
|
||||
}
|
||||
if ((*i)->_date_eff) {
|
||||
std::strftime(buf, 31, "%Y/%m/%d", std::localtime(&(*i)->_date_eff));
|
||||
output_stream << " <tr:date_eff>" << buf << "</tr:date_eff>\n";
|
||||
}
|
||||
if ((*i)->_date)
|
||||
output_stream << " <tr:date>"
|
||||
<< (*i)->_date.to_string("%Y/%m/%d")
|
||||
<< "</tr:date>\n";
|
||||
|
||||
if ((*i)->_date_eff)
|
||||
output_stream << " <tr:date_eff>"
|
||||
<< (*i)->_date_eff.to_string("%Y/%m/%d")
|
||||
<< "</tr:date_eff>\n";
|
||||
|
||||
if ((*i)->state == transaction_t::CLEARED)
|
||||
output_stream << " <tr:cleared/>\n";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue