Added a DATETIME value type.
This commit is contained in:
parent
d02f74efea
commit
b737cd8e6d
20 changed files with 994 additions and 392 deletions
|
|
@ -133,4 +133,4 @@ all-clean: maintainer-clean
|
||||||
acconf.h.in aclocal.m4 autom4te config.guess config.sub \
|
acconf.h.in aclocal.m4 autom4te config.guess config.sub \
|
||||||
configure depcomp install-sh libtool ltconfig ltmain.sh \
|
configure depcomp install-sh libtool ltconfig ltmain.sh \
|
||||||
missing stamp texinfo.tex Makefile.in mkinstalldirs \
|
missing stamp texinfo.tex Makefile.in mkinstalldirs \
|
||||||
elisp-comp elc-stamp
|
elisp-comp elc-stamp py-compile
|
||||||
|
|
|
||||||
53
NEWS
53
NEWS
|
|
@ -3,6 +3,59 @@
|
||||||
|
|
||||||
* 2.5
|
* 2.5
|
||||||
|
|
||||||
|
- Add a new --only predicate, which occurs during transaction
|
||||||
|
processing between --limit and --display. Here is a summary of how
|
||||||
|
the three supported predicates are used:
|
||||||
|
|
||||||
|
--limit "a>100"
|
||||||
|
|
||||||
|
This flag limits computation to *only transactions whose amount
|
||||||
|
is greater than 100 of a given commodity*. It means that if you
|
||||||
|
scan your dining expenses, for example, only individual bills
|
||||||
|
greater than $100 would be caculated by the report.
|
||||||
|
|
||||||
|
--only "a>100"
|
||||||
|
|
||||||
|
This flag happens much later than --limit, and corresponding
|
||||||
|
more directly to what one normally expects. If --limit isn't
|
||||||
|
used, then ALL your dining expenses contribute to the report,
|
||||||
|
*but only those calculated transactions whose value is greater
|
||||||
|
than $100 are used*. This becomes important when doing a
|
||||||
|
monthly costs report, for example, because it makes the
|
||||||
|
following command possible:
|
||||||
|
|
||||||
|
ledger -M --only "a>100" reg ^Expenses:Food
|
||||||
|
|
||||||
|
This shows only *months* whose amount is greater than 100. If
|
||||||
|
--limit had been used, it would have been a monthly summary of
|
||||||
|
all individual dinner bills greater than 100 -- which is a very
|
||||||
|
different thing.
|
||||||
|
|
||||||
|
--display "a>100"
|
||||||
|
|
||||||
|
This predicate does not constrain calculation, but only display.
|
||||||
|
Consider the same command as above:
|
||||||
|
|
||||||
|
ledger -M --display "a>100" reg ^Expenses:Food
|
||||||
|
|
||||||
|
This displays only lines whose amount is greater than 100, *yet
|
||||||
|
the running total still includes amounts from all transactions*.
|
||||||
|
This command has more particular application, such as showing
|
||||||
|
the current month's checking register while still giving a
|
||||||
|
correct ending balance:
|
||||||
|
|
||||||
|
ledger --display "d>[this month]" reg Checking
|
||||||
|
|
||||||
|
Note that these predicates can be combined. Here is a report that
|
||||||
|
considers only food bills whose individual cost is greater than
|
||||||
|
$20, but shows the monthly total only if it is greater than $500.
|
||||||
|
Finally, we only display the months of the last year, but we
|
||||||
|
retain an accurate running total with respect to the entire ledger
|
||||||
|
file:
|
||||||
|
|
||||||
|
ledger -M --limit "a>20" --only "a>200" \
|
||||||
|
--display "year == yearof([last year])" reg ^Expenses:Food
|
||||||
|
|
||||||
- There have a few changes to value expression syntax. The most
|
- There have a few changes to value expression syntax. The most
|
||||||
significant incompatibilities being:
|
significant incompatibilities being:
|
||||||
|
|
||||||
|
|
|
||||||
58
amount.cc
58
amount.cc
|
|
@ -10,6 +10,12 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
bool do_cleanup = true;
|
||||||
|
|
||||||
|
bool amount_t::keep_price = false;
|
||||||
|
bool amount_t::keep_date = false;
|
||||||
|
bool amount_t::keep_tag = false;
|
||||||
|
|
||||||
#define BIGINT_BULK_ALLOC 0x0001
|
#define BIGINT_BULK_ALLOC 0x0001
|
||||||
#define BIGINT_KEEP_PREC 0x0002
|
#define BIGINT_KEEP_PREC 0x0002
|
||||||
|
|
||||||
|
|
@ -32,10 +38,7 @@ class amount_t::bigint_t {
|
||||||
ref(1), index(0) {
|
ref(1), index(0) {
|
||||||
mpz_init_set(val, other.val);
|
mpz_init_set(val, other.val);
|
||||||
}
|
}
|
||||||
~bigint_t() {
|
~bigint_t();
|
||||||
assert(ref == 0);
|
|
||||||
mpz_clear(val);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int sizeof_bigint_t() {
|
unsigned int sizeof_bigint_t() {
|
||||||
|
|
@ -44,10 +47,16 @@ unsigned int sizeof_bigint_t() {
|
||||||
|
|
||||||
#define MPZ(x) ((x)->val)
|
#define MPZ(x) ((x)->val)
|
||||||
|
|
||||||
static mpz_t temp;
|
static mpz_t temp; // these are the global temp variables
|
||||||
static mpz_t divisor;
|
static mpz_t divisor;
|
||||||
|
|
||||||
static amount_t::bigint_t true_value;
|
static amount_t::bigint_t true_value;
|
||||||
|
|
||||||
|
inline amount_t::bigint_t::~bigint_t() {
|
||||||
|
assert(ref == 0 || (! do_cleanup && this == &true_value));
|
||||||
|
mpz_clear(val);
|
||||||
|
}
|
||||||
|
|
||||||
base_commodities_map commodity_base_t::commodities;
|
base_commodities_map commodity_base_t::commodities;
|
||||||
|
|
||||||
commodity_base_t::updater_t * commodity_base_t::updater = NULL;
|
commodity_base_t::updater_t * commodity_base_t::updater = NULL;
|
||||||
|
|
@ -93,6 +102,9 @@ static struct _init_amounts {
|
||||||
}
|
}
|
||||||
|
|
||||||
~_init_amounts() {
|
~_init_amounts() {
|
||||||
|
if (! do_cleanup)
|
||||||
|
return;
|
||||||
|
|
||||||
mpz_clear(temp);
|
mpz_clear(temp);
|
||||||
mpz_clear(divisor);
|
mpz_clear(divisor);
|
||||||
|
|
||||||
|
|
@ -1355,19 +1367,19 @@ void amount_t::annotate_commodity(const amount_t& price,
|
||||||
DEBUG_PRINT("amounts.commodities", " Annotated amount is " << *this);
|
DEBUG_PRINT("amounts.commodities", " Annotated amount is " << *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t amount_t::reduce_commodity(const bool keep_price,
|
amount_t amount_t::strip_annotations(const bool _keep_price,
|
||||||
const bool keep_date,
|
const bool _keep_date,
|
||||||
const bool keep_tag) const
|
const bool _keep_tag) const
|
||||||
{
|
{
|
||||||
if (! commodity().annotated ||
|
if (! commodity().annotated ||
|
||||||
(keep_price && keep_date && keep_tag))
|
(_keep_price && _keep_date && _keep_tag))
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
DEBUG_PRINT("amounts.commodities", "Reducing commodity for amount "
|
DEBUG_PRINT("amounts.commodities", "Reducing commodity for amount "
|
||||||
<< *this << std::endl
|
<< *this << std::endl
|
||||||
<< " keep price " << keep_price << " "
|
<< " keep price " << _keep_price << " "
|
||||||
<< " keep date " << keep_date << " "
|
<< " keep date " << _keep_date << " "
|
||||||
<< " keep tag " << keep_tag);
|
<< " keep tag " << _keep_tag);
|
||||||
|
|
||||||
annotated_commodity_t&
|
annotated_commodity_t&
|
||||||
ann_comm(static_cast<annotated_commodity_t&>(commodity()));
|
ann_comm(static_cast<annotated_commodity_t&>(commodity()));
|
||||||
|
|
@ -1375,13 +1387,13 @@ amount_t amount_t::reduce_commodity(const bool keep_price,
|
||||||
|
|
||||||
commodity_t * new_comm;
|
commodity_t * new_comm;
|
||||||
|
|
||||||
if ((keep_price && ann_comm.price) ||
|
if ((_keep_price && ann_comm.price) ||
|
||||||
(keep_date && ann_comm.date) ||
|
(_keep_date && ann_comm.date) ||
|
||||||
(keep_tag && ! ann_comm.tag.empty()))
|
(_keep_tag && ! ann_comm.tag.empty()))
|
||||||
{
|
{
|
||||||
new_comm = annotated_commodity_t::find_or_create
|
new_comm = annotated_commodity_t::find_or_create
|
||||||
(*ann_comm.base, keep_price ? ann_comm.price : amount_t(),
|
(*ann_comm.base, _keep_price ? ann_comm.price : amount_t(),
|
||||||
keep_date ? ann_comm.date : 0, keep_tag ? ann_comm.tag : "");
|
_keep_date ? ann_comm.date : 0, _keep_tag ? ann_comm.tag : "");
|
||||||
} else {
|
} else {
|
||||||
new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
|
new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
|
||||||
}
|
}
|
||||||
|
|
@ -1543,8 +1555,6 @@ amount_t commodity_base_t::value(const std::time_t moment)
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string annotated_commodity_t::date_format = "%Y/%m/%d";
|
|
||||||
|
|
||||||
void
|
void
|
||||||
annotated_commodity_t::write_annotations(std::ostream& out,
|
annotated_commodity_t::write_annotations(std::ostream& out,
|
||||||
const amount_t& price,
|
const amount_t& price,
|
||||||
|
|
@ -1554,12 +1564,8 @@ annotated_commodity_t::write_annotations(std::ostream& out,
|
||||||
if (price)
|
if (price)
|
||||||
out << " {" << price << '}';
|
out << " {" << price << '}';
|
||||||
|
|
||||||
if (date) {
|
if (date)
|
||||||
char buf[128];
|
out << " [" << datetime_t(date) << ']';
|
||||||
std::strftime(buf, 127, annotated_commodity_t::date_format.c_str(),
|
|
||||||
std::localtime(&date));
|
|
||||||
out << " [" << buf << ']';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! tag.empty())
|
if (! tag.empty())
|
||||||
out << " (" << tag << ')';
|
out << " (" << tag << ')';
|
||||||
|
|
|
||||||
14
amount.h
14
amount.h
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
extern bool do_cleanup;
|
||||||
|
|
||||||
class commodity_t;
|
class commodity_t;
|
||||||
|
|
||||||
class amount_t
|
class amount_t
|
||||||
|
|
@ -22,6 +24,10 @@ class amount_t
|
||||||
public:
|
public:
|
||||||
class bigint_t;
|
class bigint_t;
|
||||||
|
|
||||||
|
static bool keep_price;
|
||||||
|
static bool keep_date;
|
||||||
|
static bool keep_tag;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _init();
|
void _init();
|
||||||
void _copy(const amount_t& amt);
|
void _copy(const amount_t& amt);
|
||||||
|
|
@ -76,9 +82,9 @@ class amount_t
|
||||||
void annotate_commodity(const amount_t& price,
|
void annotate_commodity(const amount_t& price,
|
||||||
const std::time_t date = 0,
|
const std::time_t date = 0,
|
||||||
const std::string& tag = "");
|
const std::string& tag = "");
|
||||||
amount_t reduce_commodity(const bool keep_price = false,
|
amount_t strip_annotations(const bool _keep_price = keep_price,
|
||||||
const bool keep_date = false,
|
const bool _keep_date = keep_date,
|
||||||
const bool keep_tag = false) const;
|
const bool _keep_tag = keep_tag) const;
|
||||||
void clear_commodity() {
|
void clear_commodity() {
|
||||||
commodity_ = NULL;
|
commodity_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -543,8 +549,6 @@ class annotated_commodity_t : public commodity_t
|
||||||
std::time_t date;
|
std::time_t date;
|
||||||
std::string tag;
|
std::string tag;
|
||||||
|
|
||||||
static std::string date_format;
|
|
||||||
|
|
||||||
static void write_annotations(std::ostream& out,
|
static void write_annotations(std::ostream& out,
|
||||||
const amount_t& price,
|
const amount_t& price,
|
||||||
const std::time_t date,
|
const std::time_t date,
|
||||||
|
|
|
||||||
209
balance.cc
209
balance.cc
|
|
@ -13,6 +13,17 @@ amount_t balance_t::amount(const commodity_t& commodity) const
|
||||||
amounts_map::const_iterator i = amounts.begin();
|
amounts_map::const_iterator i = amounts.begin();
|
||||||
return (*i).second;
|
return (*i).second;
|
||||||
}
|
}
|
||||||
|
else if (amounts.size() > 1) {
|
||||||
|
// Try stripping annotations before giving an error.
|
||||||
|
balance_t temp(strip_annotations());
|
||||||
|
if (temp.amounts.size() == 1)
|
||||||
|
return temp.amount(commodity);
|
||||||
|
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << "Requested amount of a balance with multiple commodities: "
|
||||||
|
<< *this;
|
||||||
|
throw amount_error(errmsg.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (amounts.size() > 0) {
|
else if (amounts.size() > 0) {
|
||||||
amounts_map::const_iterator i = amounts.find(&commodity);
|
amounts_map::const_iterator i = amounts.find(&commodity);
|
||||||
|
|
@ -63,15 +74,16 @@ std::time_t balance_t::date() const
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
balance_t balance_t::reduce(const bool keep_price, const bool keep_date,
|
balance_t balance_t::strip_annotations(const bool keep_price,
|
||||||
const bool keep_tag) const
|
const bool keep_date,
|
||||||
|
const bool keep_tag) const
|
||||||
{
|
{
|
||||||
balance_t temp;
|
balance_t temp;
|
||||||
|
|
||||||
for (amounts_map::const_iterator i = amounts.begin();
|
for (amounts_map::const_iterator i = amounts.begin();
|
||||||
i != amounts.end();
|
i != amounts.end();
|
||||||
i++)
|
i++)
|
||||||
temp += (*i).second.reduce_commodity(keep_price, keep_date, keep_tag);
|
temp += (*i).second.strip_annotations(keep_price, keep_date, keep_tag);
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
@ -176,44 +188,150 @@ void balance_t::write(std::ostream& out,
|
||||||
|
|
||||||
balance_t& balance_t::operator*=(const balance_t& bal)
|
balance_t& balance_t::operator*=(const balance_t& bal)
|
||||||
{
|
{
|
||||||
if (! *this || ! bal) {
|
if (realzero() || bal.realzero()) {
|
||||||
return (*this = 0L);
|
return *this = 0L;
|
||||||
}
|
}
|
||||||
else if (amounts.size() == 1 && bal.amounts.size() == 1) {
|
else if (bal.amounts.size() == 1) {
|
||||||
return *this *= (*bal.amounts.begin()).second;
|
return *this *= (*bal.amounts.begin()).second;
|
||||||
}
|
}
|
||||||
|
else if (amounts.size() == 1) {
|
||||||
|
return *this = bal * *this;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
|
// Since we would fail with an error at this point otherwise, try
|
||||||
|
// stripping annotations to see if we can come up with a
|
||||||
|
// reasonable result. The user will not notice any annotations
|
||||||
|
// missing (since they are viewing a stripped report anyway), only
|
||||||
|
// that some of their value expression may not see any pricing or
|
||||||
|
// date data because of this operation.
|
||||||
|
|
||||||
|
balance_t temp(bal.strip_annotations());
|
||||||
|
if (temp.amounts.size() == 1)
|
||||||
|
return *this *= temp;
|
||||||
|
temp = strip_annotations();
|
||||||
|
if (temp.amounts.size() == 1)
|
||||||
|
return *this = bal * temp;
|
||||||
|
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << "It makes no sense to multiply two balances: "
|
errmsg << "Cannot multiply two balances: " << *this << " * " << bal;
|
||||||
<< *this << " * " << bal;
|
|
||||||
throw amount_error(errmsg.str());
|
throw amount_error(errmsg.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
balance_t& balance_t::operator*=(const amount_t& amt)
|
||||||
|
{
|
||||||
|
if (realzero() || amt.realzero()) {
|
||||||
|
return *this = 0L;
|
||||||
|
}
|
||||||
|
else if (! amt.commodity()) {
|
||||||
|
// Multiplying by the null commodity causes all amounts to be
|
||||||
|
// increased by the same factor.
|
||||||
|
for (amounts_map::iterator i = amounts.begin();
|
||||||
|
i != amounts.end();
|
||||||
|
i++)
|
||||||
|
(*i).second *= amt;
|
||||||
|
}
|
||||||
|
else if (amounts.size() == 1 &&
|
||||||
|
(*amounts.begin()).first == &amt.commodity()) {
|
||||||
|
(*amounts.begin()).second *= amt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
amounts_map::iterator i = amounts.find(&amt.commodity());
|
||||||
|
if (i != amounts.end()) {
|
||||||
|
(*i).second *= amt;
|
||||||
|
} else {
|
||||||
|
// Try stripping annotations before giving an error.
|
||||||
|
balance_t temp(strip_annotations());
|
||||||
|
if (temp.amounts.size() == 1 &&
|
||||||
|
(*temp.amounts.begin()).first == &amt.commodity()) {
|
||||||
|
return *this = temp * amt;
|
||||||
|
} else {
|
||||||
|
i = temp.amounts.find(&amt.commodity());
|
||||||
|
if (i != temp.amounts.end())
|
||||||
|
return *this = temp * amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << "Attempt to multiply balance by a commodity"
|
||||||
|
<< " not found in that balance: "
|
||||||
|
<< *this << " * " << amt;
|
||||||
|
throw amount_error(errmsg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
balance_t& balance_t::operator/=(const balance_t& bal)
|
balance_t& balance_t::operator/=(const balance_t& bal)
|
||||||
{
|
{
|
||||||
if (! *this) {
|
if (bal.realzero()) {
|
||||||
return (*this = 0L);
|
|
||||||
}
|
|
||||||
else if (! bal) {
|
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
|
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
|
||||||
throw amount_error(errmsg.str());
|
throw amount_error(errmsg.str());
|
||||||
}
|
}
|
||||||
else if (amounts.size() == 1 && bal.amounts.size() == 1) {
|
else if (realzero()) {
|
||||||
|
return *this = 0L;
|
||||||
|
}
|
||||||
|
else if (bal.amounts.size() == 1) {
|
||||||
return *this /= (*bal.amounts.begin()).second;
|
return *this /= (*bal.amounts.begin()).second;
|
||||||
}
|
}
|
||||||
else if (*this == bal) {
|
else if (*this == bal) {
|
||||||
return (*this = 1L);
|
return *this = 1L;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Try stripping annotations before giving an error.
|
||||||
|
balance_t temp(bal.strip_annotations());
|
||||||
|
if (temp.amounts.size() == 1)
|
||||||
|
return *this /= temp;
|
||||||
|
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << "It makes no sense to divide two balances: "
|
errmsg << "Cannot divide between two balances: " << *this << " / " << bal;
|
||||||
<< *this << " / " << bal;
|
|
||||||
throw amount_error(errmsg.str());
|
throw amount_error(errmsg.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
balance_t& balance_t::operator/=(const amount_t& amt)
|
||||||
|
{
|
||||||
|
if (amt.realzero()) {
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << "Attempt to divide by zero: " << *this << " / " << amt;
|
||||||
|
throw amount_error(errmsg.str());
|
||||||
|
}
|
||||||
|
else if (realzero()) {
|
||||||
|
return *this = 0L;
|
||||||
|
}
|
||||||
|
else if (! amt.commodity()) {
|
||||||
|
// Dividing by the null commodity causes all amounts to be
|
||||||
|
// decreased by the same factor.
|
||||||
|
for (amounts_map::iterator i = amounts.begin();
|
||||||
|
i != amounts.end();
|
||||||
|
i++)
|
||||||
|
(*i).second /= amt;
|
||||||
|
}
|
||||||
|
else if (amounts.size() == 1 &&
|
||||||
|
(*amounts.begin()).first == &amt.commodity()) {
|
||||||
|
(*amounts.begin()).second /= amt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
amounts_map::iterator i = amounts.find(&amt.commodity());
|
||||||
|
if (i != amounts.end()) {
|
||||||
|
(*i).second /= amt;
|
||||||
|
} else {
|
||||||
|
// Try stripping annotations before giving an error.
|
||||||
|
balance_t temp(strip_annotations());
|
||||||
|
if (temp.amounts.size() == 1 &&
|
||||||
|
(*temp.amounts.begin()).first == &amt.commodity())
|
||||||
|
return *this = temp / amt;
|
||||||
|
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << "Attempt to divide balance by a commodity"
|
||||||
|
<< " not found in that balance: "
|
||||||
|
<< *this << " * " << amt;
|
||||||
|
throw amount_error(errmsg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
balance_t::operator amount_t() const
|
balance_t::operator amount_t() const
|
||||||
{
|
{
|
||||||
if (amounts.size() == 1) {
|
if (amounts.size() == 1) {
|
||||||
|
|
@ -223,6 +341,11 @@ balance_t::operator amount_t() const
|
||||||
return amount_t();
|
return amount_t();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Try stripping annotations before giving an error.
|
||||||
|
balance_t temp(strip_annotations());
|
||||||
|
if (temp.amounts.size() == 1)
|
||||||
|
return (*temp.amounts.begin()).second;
|
||||||
|
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << "Cannot convert a balance with "
|
errmsg << "Cannot convert a balance with "
|
||||||
<< "multiple commodities to an amount: " << *this;
|
<< "multiple commodities to an amount: " << *this;
|
||||||
|
|
@ -230,27 +353,6 @@ balance_t::operator amount_t() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
balance_pair_t& balance_pair_t::operator/=(const balance_pair_t& bal_pair)
|
|
||||||
{
|
|
||||||
if (bal_pair.cost && ! cost)
|
|
||||||
cost = new balance_t(quantity);
|
|
||||||
quantity /= bal_pair.quantity;
|
|
||||||
if (cost)
|
|
||||||
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
balance_pair_t& balance_pair_t::add(const amount_t& amount,
|
|
||||||
const amount_t * a_cost)
|
|
||||||
{
|
|
||||||
if (a_cost && ! cost)
|
|
||||||
cost = new balance_t(quantity);
|
|
||||||
quantity += amount;
|
|
||||||
if (cost)
|
|
||||||
*cost += a_cost ? *a_cost : amount;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
#ifdef USE_BOOST_PYTHON
|
#ifdef USE_BOOST_PYTHON
|
||||||
|
|
@ -353,13 +455,19 @@ void export_balance()
|
||||||
.def("__len__", balance_len)
|
.def("__len__", balance_len)
|
||||||
.def("__getitem__", balance_getitem)
|
.def("__getitem__", balance_getitem)
|
||||||
|
|
||||||
.def("negate", &balance_t::negate)
|
.def("valid", &balance_t::valid)
|
||||||
|
|
||||||
|
.def("realzero", &balance_t::realzero)
|
||||||
.def("amount", &balance_t::amount)
|
.def("amount", &balance_t::amount)
|
||||||
.def("value", &balance_t::value)
|
.def("value", &balance_t::value)
|
||||||
.def("price", &balance_t::price)
|
.def("price", &balance_t::price)
|
||||||
.def("reduce", &balance_t::reduce)
|
.def("date", &balance_t::date)
|
||||||
|
.def("strip_annotations", &balance_t::strip_annotations)
|
||||||
.def("write", &balance_t::write)
|
.def("write", &balance_t::write)
|
||||||
.def("valid", &balance_t::valid)
|
.def("abs", &balance_t::abs)
|
||||||
|
.def("round", &balance_t::round)
|
||||||
|
.def("negate", &balance_t::negate)
|
||||||
|
.def("negated", &balance_t::negated)
|
||||||
;
|
;
|
||||||
|
|
||||||
class_< balance_pair_t > ("BalancePair")
|
class_< balance_pair_t > ("BalancePair")
|
||||||
|
|
@ -436,16 +544,23 @@ void export_balance()
|
||||||
.def("__len__", balance_pair_len)
|
.def("__len__", balance_pair_len)
|
||||||
.def("__getitem__", balance_pair_getitem)
|
.def("__getitem__", balance_pair_getitem)
|
||||||
|
|
||||||
|
.def("valid", &balance_pair_t::valid)
|
||||||
|
|
||||||
|
.def("realzero", &balance_pair_t::realzero)
|
||||||
|
.def("amount", &balance_pair_t::amount)
|
||||||
|
.def("value", &balance_pair_t::value)
|
||||||
|
.def("price", &balance_pair_t::price)
|
||||||
|
.def("date", &balance_pair_t::date)
|
||||||
|
.def("strip_annotations", &balance_pair_t::strip_annotations)
|
||||||
|
.def("write", &balance_pair_t::write)
|
||||||
|
.def("abs", &balance_pair_t::abs)
|
||||||
|
.def("round", &balance_pair_t::round)
|
||||||
|
.def("negate", &balance_pair_t::negate)
|
||||||
|
.def("negated", &balance_pair_t::negated)
|
||||||
|
|
||||||
.add_property("cost",
|
.add_property("cost",
|
||||||
make_getter(&balance_pair_t::cost,
|
make_getter(&balance_pair_t::cost,
|
||||||
return_value_policy<reference_existing_object>()))
|
return_value_policy<reference_existing_object>()))
|
||||||
|
|
||||||
.def("negate", &balance_pair_t::negate)
|
|
||||||
.def("amount", &balance_pair_t::amount)
|
|
||||||
.def("value", &balance_pair_t::value)
|
|
||||||
.def("write", &balance_pair_t::write)
|
|
||||||
|
|
||||||
.def("valid", &balance_pair_t::valid)
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
139
balance.h
139
balance.h
|
|
@ -2,6 +2,7 @@
|
||||||
#define _BALANCE_H
|
#define _BALANCE_H
|
||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
|
#include "datetime.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
@ -35,13 +36,13 @@ class balance_t
|
||||||
*this += (*i).second;
|
*this += (*i).second;
|
||||||
}
|
}
|
||||||
balance_t(const amount_t& amt) {
|
balance_t(const amount_t& amt) {
|
||||||
if (amt)
|
if (! amt.realzero())
|
||||||
amounts.insert(amounts_pair(&amt.commodity(), amt));
|
amounts.insert(amounts_pair(&amt.commodity(), amt));
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
balance_t(T value) {
|
balance_t(T value) {
|
||||||
amount_t amt(value);
|
amount_t amt(value);
|
||||||
if (amt)
|
if (! amt.realzero())
|
||||||
amounts.insert(amounts_pair(&amt.commodity(), amt));
|
amounts.insert(amounts_pair(&amt.commodity(), amt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +81,7 @@ class balance_t
|
||||||
amounts_map::iterator i = amounts.find(&amt.commodity());
|
amounts_map::iterator i = amounts.find(&amt.commodity());
|
||||||
if (i != amounts.end())
|
if (i != amounts.end())
|
||||||
(*i).second += amt;
|
(*i).second += amt;
|
||||||
else if (amt)
|
else if (! amt.realzero())
|
||||||
amounts.insert(amounts_pair(&amt.commodity(), amt));
|
amounts.insert(amounts_pair(&amt.commodity(), amt));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -148,53 +149,14 @@ class balance_t
|
||||||
|
|
||||||
// multiplication and divide
|
// multiplication and divide
|
||||||
balance_t& operator*=(const balance_t& bal);
|
balance_t& operator*=(const balance_t& bal);
|
||||||
balance_t& operator*=(const amount_t& amt) {
|
balance_t& operator*=(const amount_t& amt);
|
||||||
// Multiplying by the null commodity causes all amounts to be
|
|
||||||
// increased by the same factor.
|
|
||||||
if (amt.realzero()) {
|
|
||||||
amounts.clear();
|
|
||||||
}
|
|
||||||
else if (! amt.commodity()) {
|
|
||||||
for (amounts_map::iterator i = amounts.begin();
|
|
||||||
i != amounts.end();
|
|
||||||
i++)
|
|
||||||
(*i).second *= amt;
|
|
||||||
}
|
|
||||||
else if (amounts.size() == 1) {
|
|
||||||
(*amounts.begin()).second *= amt;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
amounts_map::iterator i = amounts.find(&amt.commodity());
|
|
||||||
if (i != amounts.end())
|
|
||||||
(*i).second *= amt;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
balance_t& operator*=(T val) {
|
balance_t& operator*=(T val) {
|
||||||
return *this *= amount_t(val);
|
return *this *= amount_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
balance_t& operator/=(const balance_t& bal);
|
balance_t& operator/=(const balance_t& bal);
|
||||||
balance_t& operator/=(const amount_t& amt) {
|
balance_t& operator/=(const amount_t& amt);
|
||||||
// Dividing by the null commodity causes all amounts to be
|
|
||||||
// increased by the same factor.
|
|
||||||
if (! amt.commodity()) {
|
|
||||||
for (amounts_map::iterator i = amounts.begin();
|
|
||||||
i != amounts.end();
|
|
||||||
i++)
|
|
||||||
(*i).second /= amt;
|
|
||||||
}
|
|
||||||
else if (amounts.size() == 1) {
|
|
||||||
(*amounts.begin()).second /= amt;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
amounts_map::iterator i = amounts.find(&amt.commodity());
|
|
||||||
if (i != amounts.end())
|
|
||||||
(*i).second /= amt;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
balance_t& operator/=(T val) {
|
balance_t& operator/=(T val) {
|
||||||
return *this /= amount_t(val);
|
return *this /= amount_t(val);
|
||||||
|
|
@ -415,13 +377,27 @@ class balance_t
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t amount(const commodity_t& commodity) const;
|
bool realzero() const {
|
||||||
balance_t value(const std::time_t moment) const;
|
if (amounts.size() == 0)
|
||||||
balance_t price() const;
|
return true;
|
||||||
|
for (amounts_map::const_iterator i = amounts.begin();
|
||||||
|
i != amounts.end();
|
||||||
|
i++)
|
||||||
|
if (! (*i).second.realzero())
|
||||||
|
return false;
|
||||||
|
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;
|
std::time_t date() const;
|
||||||
balance_t reduce(const bool keep_price = false,
|
|
||||||
const bool keep_date = false,
|
balance_t
|
||||||
const bool keep_tag = false) const;
|
strip_annotations(const bool keep_price = amount_t::keep_price,
|
||||||
|
const bool keep_date = amount_t::keep_date,
|
||||||
|
const bool keep_tag = amount_t::keep_tag) const;
|
||||||
|
|
||||||
void write(std::ostream& out, const int first_width,
|
void write(std::ostream& out, const int first_width,
|
||||||
const int latter_width = -1) const;
|
const int latter_width = -1) const;
|
||||||
|
|
@ -440,17 +416,6 @@ class balance_t
|
||||||
if ((*i).second.commodity())
|
if ((*i).second.commodity())
|
||||||
(*i).second = (*i).second.round();
|
(*i).second = (*i).second.round();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool realzero() const {
|
|
||||||
if (amounts.size() == 0)
|
|
||||||
return true;
|
|
||||||
for (amounts_map::const_iterator i = amounts.begin();
|
|
||||||
i != amounts.end();
|
|
||||||
i++)
|
|
||||||
if (! (*i).second.realzero())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline balance_t abs(const balance_t& bal) {
|
inline balance_t abs(const balance_t& bal) {
|
||||||
|
|
@ -496,7 +461,6 @@ class balance_pair_t
|
||||||
delete cost;
|
delete cost;
|
||||||
cost = NULL;
|
cost = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
quantity = bal_pair.quantity;
|
quantity = bal_pair.quantity;
|
||||||
if (bal_pair.cost)
|
if (bal_pair.cost)
|
||||||
cost = new balance_t(*bal_pair.cost);
|
cost = new balance_t(*bal_pair.cost);
|
||||||
|
|
@ -651,7 +615,14 @@ class balance_pair_t
|
||||||
return *this *= amount_t(val);
|
return *this *= amount_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
balance_pair_t& operator/=(const balance_pair_t& bal_pair);
|
balance_pair_t& operator/=(const balance_pair_t& bal_pair) {
|
||||||
|
if (bal_pair.cost && ! cost)
|
||||||
|
cost = new balance_t(quantity);
|
||||||
|
quantity /= bal_pair.quantity;
|
||||||
|
if (cost)
|
||||||
|
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
balance_pair_t& operator/=(const balance_t& bal) {
|
balance_pair_t& operator/=(const balance_t& bal) {
|
||||||
quantity /= bal;
|
quantity /= bal;
|
||||||
if (cost)
|
if (cost)
|
||||||
|
|
@ -813,34 +784,60 @@ class balance_pair_t
|
||||||
}
|
}
|
||||||
|
|
||||||
// test for non-zero (use ! for zero)
|
// test for non-zero (use ! for zero)
|
||||||
operator bool() const {
|
|
||||||
return quantity;
|
|
||||||
}
|
|
||||||
operator balance_t() const {
|
operator balance_t() const {
|
||||||
return quantity;
|
return quantity;
|
||||||
}
|
}
|
||||||
operator amount_t() const {
|
operator amount_t() const {
|
||||||
return quantity;
|
return quantity;
|
||||||
}
|
}
|
||||||
|
operator bool() const {
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool realzero() const {
|
||||||
|
return ((! cost || cost->realzero()) && quantity.realzero());
|
||||||
|
}
|
||||||
|
|
||||||
void abs() {
|
void abs() {
|
||||||
quantity.abs();
|
quantity.abs();
|
||||||
if (cost) cost->abs();
|
if (cost) cost->abs();
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t amount(const commodity_t& commodity) const {
|
amount_t amount(const commodity_t& commodity =
|
||||||
|
*commodity_t::null_commodity) const {
|
||||||
return quantity.amount(commodity);
|
return quantity.amount(commodity);
|
||||||
}
|
}
|
||||||
balance_t value(const std::time_t moment) const {
|
balance_t value(const std::time_t moment = now) const {
|
||||||
return quantity.value(moment);
|
return quantity.value(moment);
|
||||||
}
|
}
|
||||||
|
balance_t price() const {
|
||||||
|
return quantity.price();
|
||||||
|
}
|
||||||
|
std::time_t date() const {
|
||||||
|
return quantity.date();
|
||||||
|
}
|
||||||
|
|
||||||
|
balance_t
|
||||||
|
strip_annotations(const bool keep_price = amount_t::keep_price,
|
||||||
|
const bool keep_date = amount_t::keep_date,
|
||||||
|
const bool keep_tag = amount_t::keep_tag) const {
|
||||||
|
return quantity.strip_annotations(keep_price, keep_date, keep_tag);
|
||||||
|
}
|
||||||
|
|
||||||
void write(std::ostream& out, const int first_width,
|
void write(std::ostream& out, const int first_width,
|
||||||
const int latter_width = -1) const {
|
const int latter_width = -1) const {
|
||||||
quantity.write(out, first_width, latter_width);
|
quantity.write(out, first_width, latter_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
balance_pair_t& add(const amount_t& amount,
|
balance_pair_t& add(const amount_t& amount,
|
||||||
const amount_t * a_cost = NULL);
|
const amount_t * a_cost = NULL) {
|
||||||
|
if (a_cost && ! cost)
|
||||||
|
cost = new balance_t(quantity);
|
||||||
|
quantity += amount;
|
||||||
|
if (cost)
|
||||||
|
*cost += a_cost ? *a_cost : amount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool valid() {
|
bool valid() {
|
||||||
return quantity.valid() && (! cost || cost->valid());
|
return quantity.valid() && (! cost || cost->valid());
|
||||||
|
|
@ -850,10 +847,6 @@ class balance_pair_t
|
||||||
quantity.round();
|
quantity.round();
|
||||||
if (cost) cost->round();
|
if (cost) cost->round();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool realzero() const {
|
|
||||||
return ((! cost || cost->realzero()) && quantity.realzero());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline balance_pair_t abs(const balance_pair_t& bal_pair) {
|
inline balance_pair_t abs(const balance_pair_t& bal_pair) {
|
||||||
|
|
|
||||||
79
config.cc
79
config.cc
|
|
@ -71,8 +71,9 @@ void config_t::reset()
|
||||||
prices_format = "%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n";
|
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";
|
pricesdb_format = "P %[%Y/%m/%d %H:%M:%S] %A %t\n";
|
||||||
|
|
||||||
predicate = "";
|
predicate = "";
|
||||||
display_predicate = "";
|
secondary_predicate = "";
|
||||||
|
display_predicate = "";
|
||||||
|
|
||||||
head_entries = 0;
|
head_entries = 0;
|
||||||
tail_entries = 0;
|
tail_entries = 0;
|
||||||
|
|
@ -91,6 +92,8 @@ void config_t::reset()
|
||||||
show_revalued_only = false;
|
show_revalued_only = false;
|
||||||
download_quotes = false;
|
download_quotes = false;
|
||||||
debug_mode = false;
|
debug_mode = false;
|
||||||
|
verbose_mode = false;
|
||||||
|
trace_mode = false;
|
||||||
keep_price = false;
|
keep_price = false;
|
||||||
keep_date = false;
|
keep_date = false;
|
||||||
keep_tag = false;
|
keep_tag = false;
|
||||||
|
|
@ -301,14 +304,12 @@ void config_t::process_options(const std::string& command,
|
||||||
|
|
||||||
// Now setup the various formatting strings
|
// Now setup the various formatting strings
|
||||||
|
|
||||||
if (! date_format.empty()) {
|
if (! date_format.empty())
|
||||||
format_t::date_format = date_format;
|
datetime_t::date_format = date_format;
|
||||||
annotated_commodity_t::date_format = date_format;
|
|
||||||
}
|
|
||||||
|
|
||||||
format_t::keep_price = keep_price;
|
amount_t::keep_price = keep_price;
|
||||||
format_t::keep_date = keep_date;
|
amount_t::keep_date = keep_date;
|
||||||
format_t::keep_tag = keep_tag;
|
amount_t::keep_tag = keep_tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
item_handler<transaction_t> *
|
item_handler<transaction_t> *
|
||||||
|
|
@ -348,15 +349,21 @@ config_t::chain_xact_handlers(const std::string& command,
|
||||||
// transactions which can be reconciled to a given balance
|
// transactions which can be reconciled to a given balance
|
||||||
// (calculated against the transactions which it receives).
|
// (calculated against the transactions which it receives).
|
||||||
if (! reconcile_balance.empty()) {
|
if (! reconcile_balance.empty()) {
|
||||||
value_t target_balance(reconcile_balance);
|
std::time_t cutoff = now;
|
||||||
time_t cutoff = now;
|
|
||||||
if (! reconcile_date.empty())
|
if (! reconcile_date.empty())
|
||||||
parse_date(reconcile_date.c_str(), &cutoff);
|
parse_date(reconcile_date.c_str(), &cutoff);
|
||||||
ptrs.push_back(formatter =
|
ptrs.push_back(formatter =
|
||||||
new reconcile_transactions(formatter, target_balance,
|
new reconcile_transactions
|
||||||
cutoff));
|
(formatter, value_t(reconcile_balance), cutoff));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter_transactions will only pass through transactions
|
||||||
|
// matching the `secondary_predicate'.
|
||||||
|
if (! secondary_predicate.empty())
|
||||||
|
ptrs.push_back(formatter =
|
||||||
|
new filter_transactions(formatter,
|
||||||
|
secondary_predicate));
|
||||||
|
|
||||||
// sort_transactions will sort all the transactions it sees, based
|
// sort_transactions will sort all the transactions it sees, based
|
||||||
// on the `sort_order' value expression.
|
// on the `sort_order' value expression.
|
||||||
if (! sort_string.empty())
|
if (! sort_string.empty())
|
||||||
|
|
@ -718,6 +725,14 @@ OPT_BEGIN(debug, ":") {
|
||||||
::setenv("DEBUG_CLASS", optarg, 1);
|
::setenv("DEBUG_CLASS", optarg, 1);
|
||||||
} OPT_END(debug);
|
} OPT_END(debug);
|
||||||
|
|
||||||
|
OPT_BEGIN(verbose, "") {
|
||||||
|
config->verbose_mode = true;
|
||||||
|
} OPT_END(verbose);
|
||||||
|
|
||||||
|
OPT_BEGIN(trace, "") {
|
||||||
|
config->trace_mode = true;
|
||||||
|
} OPT_END(trace);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Report filtering
|
// Report filtering
|
||||||
|
|
@ -1016,6 +1031,14 @@ OPT_BEGIN(limit, "l:") {
|
||||||
config->predicate += ")";
|
config->predicate += ")";
|
||||||
} OPT_END(limit);
|
} OPT_END(limit);
|
||||||
|
|
||||||
|
OPT_BEGIN(only, ":") {
|
||||||
|
if (! config->secondary_predicate.empty())
|
||||||
|
config->secondary_predicate += "&";
|
||||||
|
config->secondary_predicate += "(";
|
||||||
|
config->secondary_predicate += optarg;
|
||||||
|
config->secondary_predicate += ")";
|
||||||
|
} OPT_END(only);
|
||||||
|
|
||||||
OPT_BEGIN(display, "d:") {
|
OPT_BEGIN(display, "d:") {
|
||||||
if (! config->display_predicate.empty())
|
if (! config->display_predicate.empty())
|
||||||
config->display_predicate += "&";
|
config->display_predicate += "&";
|
||||||
|
|
@ -1153,6 +1176,7 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
|
||||||
{ "market", 'V', false, opt_market, false },
|
{ "market", 'V', false, opt_market, false },
|
||||||
{ "monthly", 'M', false, opt_monthly, false },
|
{ "monthly", 'M', false, opt_monthly, false },
|
||||||
{ "no-cache", '\0', false, opt_no_cache, false },
|
{ "no-cache", '\0', false, opt_no_cache, false },
|
||||||
|
{ "only", '\0', true, opt_only, false },
|
||||||
{ "output", 'o', true, opt_output, false },
|
{ "output", 'o', true, opt_output, false },
|
||||||
{ "pager", '\0', true, opt_pager, false },
|
{ "pager", '\0', true, opt_pager, false },
|
||||||
{ "percentage", '%', false, opt_percentage, false },
|
{ "percentage", '%', false, opt_percentage, false },
|
||||||
|
|
@ -1178,8 +1202,10 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
|
||||||
{ "total", 'T', true, opt_total, false },
|
{ "total", 'T', true, opt_total, false },
|
||||||
{ "total-data", 'J', false, opt_total_data, false },
|
{ "total-data", 'J', false, opt_total_data, false },
|
||||||
{ "totals", '\0', false, opt_totals, false },
|
{ "totals", '\0', false, opt_totals, false },
|
||||||
|
{ "trace", '\0', false, opt_trace, false },
|
||||||
{ "unbudgeted", '\0', false, opt_unbudgeted, false },
|
{ "unbudgeted", '\0', false, opt_unbudgeted, false },
|
||||||
{ "uncleared", 'U', false, opt_uncleared, false },
|
{ "uncleared", 'U', false, opt_uncleared, false },
|
||||||
|
{ "verbose", '\0', false, opt_verbose, false },
|
||||||
{ "version", 'v', false, opt_version, false },
|
{ "version", 'v', false, opt_version, false },
|
||||||
{ "weekly", 'W', false, opt_weekly, false },
|
{ "weekly", 'W', false, opt_weekly, false },
|
||||||
{ "wide", 'w', false, opt_wide, false },
|
{ "wide", 'w', false, opt_wide, false },
|
||||||
|
|
@ -1189,4 +1215,31 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
|
||||||
{ "yearly", 'Y', false, opt_yearly, false },
|
{ "yearly", 'Y', false, opt_yearly, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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::cerr << buf << " " << cat << ": " << str << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_push(const std::string& cat, const std::string& str,
|
||||||
|
timing_t& timer)
|
||||||
|
{
|
||||||
|
timer.start();
|
||||||
|
trace(cat, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_pop(const std::string& cat, const std::string& str,
|
||||||
|
timing_t& timer)
|
||||||
|
{
|
||||||
|
timer.stop();
|
||||||
|
std::ostringstream out;
|
||||||
|
out << str << ": " << (double(timer.cumulative) / double(CLOCKS_PER_SEC)) << "s";
|
||||||
|
trace(cat, out.str());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
29
config.h
29
config.h
|
|
@ -2,6 +2,7 @@
|
||||||
#define _CONFIG_H
|
#define _CONFIG_H
|
||||||
|
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
|
#include "timing.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -22,6 +23,7 @@ class config_t
|
||||||
std::string output_file;
|
std::string output_file;
|
||||||
std::string account;
|
std::string account;
|
||||||
std::string predicate;
|
std::string predicate;
|
||||||
|
std::string secondary_predicate;
|
||||||
std::string display_predicate;
|
std::string display_predicate;
|
||||||
std::string report_period;
|
std::string report_period;
|
||||||
std::string report_period_sort;
|
std::string report_period_sort;
|
||||||
|
|
@ -66,6 +68,8 @@ class config_t
|
||||||
bool use_cache;
|
bool use_cache;
|
||||||
bool cache_dirty;
|
bool cache_dirty;
|
||||||
bool debug_mode;
|
bool debug_mode;
|
||||||
|
bool verbose_mode;
|
||||||
|
bool trace_mode;
|
||||||
bool keep_price;
|
bool keep_price;
|
||||||
bool keep_date;
|
bool keep_date;
|
||||||
bool keep_tag;
|
bool keep_tag;
|
||||||
|
|
@ -102,7 +106,7 @@ class config_t
|
||||||
std::list<item_handler<transaction_t> *>& ptrs);
|
std::list<item_handler<transaction_t> *>& ptrs);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CONFIG_OPTIONS_SIZE 81
|
#define CONFIG_OPTIONS_SIZE 84
|
||||||
extern option_t config_options[CONFIG_OPTIONS_SIZE];
|
extern option_t config_options[CONFIG_OPTIONS_SIZE];
|
||||||
|
|
||||||
void option_help(std::ostream& out);
|
void option_help(std::ostream& out);
|
||||||
|
|
@ -112,6 +116,29 @@ void option_help(std::ostream& out);
|
||||||
|
|
||||||
#define OPT_END(tag)
|
#define OPT_END(tag)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void trace(const std::string& cat, const std::string& str);
|
||||||
|
void trace_push(const std::string& cat, const std::string& str,
|
||||||
|
timing_t& timer);
|
||||||
|
void trace_pop(const std::string& cat, const std::string& str,
|
||||||
|
timing_t& timer);
|
||||||
|
|
||||||
|
#define TRACE(cat, msg) if (config.trace_mode) trace(#cat, msg)
|
||||||
|
#define TRACE_(cat, msg) if (trace_mode) trace(#cat, msg)
|
||||||
|
|
||||||
|
#define TRACE_PUSH(cat, msg) \
|
||||||
|
timing_t timer_ ## cat(#cat); \
|
||||||
|
if (config.trace_mode) trace_push(#cat, msg, timer_ ## cat)
|
||||||
|
#define TRACE_PUSH_(cat, msg) \
|
||||||
|
timing_t timer_ ## cat(#cat); \
|
||||||
|
if (trace_mode) trace_push(#cat, msg, timer_ ## cat)
|
||||||
|
|
||||||
|
#define TRACE_POP(cat, msg) \
|
||||||
|
if (config.trace_mode) trace_pop(#cat, msg, timer_ ## cat)
|
||||||
|
#define TRACE_POP_(cat, msg) \
|
||||||
|
if (trace_mode) trace_pop(#cat, msg, timer_ ## cat)
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
#endif // _CONFIG_H
|
#endif // _CONFIG_H
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ const char * formats[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string datetime_t::date_format = "%Y/%m/%d";
|
||||||
|
|
||||||
std::time_t interval_t::first(const std::time_t moment) const
|
std::time_t interval_t::first(const std::time_t moment) const
|
||||||
{
|
{
|
||||||
std::time_t quant = begin;
|
std::time_t quant = begin;
|
||||||
|
|
|
||||||
74
datetime.h
74
datetime.h
|
|
@ -4,6 +4,71 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
struct interval_t;
|
||||||
|
|
||||||
|
struct datetime_t
|
||||||
|
{
|
||||||
|
std::time_t when;
|
||||||
|
|
||||||
|
static std::string date_format;
|
||||||
|
|
||||||
|
datetime_t(const std::time_t _when) : when(_when) {}
|
||||||
|
|
||||||
|
datetime_t& operator+=(const long secs) {
|
||||||
|
when += secs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
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; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_DATETIME_OP(<)
|
||||||
|
DEF_DATETIME_OP(<=)
|
||||||
|
DEF_DATETIME_OP(>)
|
||||||
|
DEF_DATETIME_OP(>=)
|
||||||
|
DEF_DATETIME_OP(==)
|
||||||
|
DEF_DATETIME_OP(!=)
|
||||||
|
|
||||||
|
operator bool() const {
|
||||||
|
return when != 0;
|
||||||
|
}
|
||||||
|
operator long() const {
|
||||||
|
return (long)when;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
struct interval_t
|
struct interval_t
|
||||||
{
|
{
|
||||||
unsigned int years;
|
unsigned int years;
|
||||||
|
|
@ -36,6 +101,15 @@ struct interval_t
|
||||||
void parse(std::istream& in);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
extern std::time_t now;
|
extern std::time_t now;
|
||||||
extern int now_year;
|
extern int now_year;
|
||||||
extern char input_format[128];
|
extern char input_format[128];
|
||||||
|
|
|
||||||
32
format.cc
32
format.cc
|
|
@ -7,10 +7,6 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
bool format_t::keep_price = false;
|
|
||||||
bool format_t::keep_date = false;
|
|
||||||
bool format_t::keep_tag = false;
|
|
||||||
|
|
||||||
std::string truncated(const std::string& str, unsigned int width,
|
std::string truncated(const std::string& str, unsigned int width,
|
||||||
const int style)
|
const int style)
|
||||||
{
|
{
|
||||||
|
|
@ -72,8 +68,6 @@ std::string partial_account_name(const account_t& account)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string format_t::date_format = "%Y/%m/%d";
|
|
||||||
|
|
||||||
element_t * format_t::parse_elements(const std::string& fmt)
|
element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
{
|
{
|
||||||
std::auto_ptr<element_t> result;
|
std::auto_ptr<element_t> result;
|
||||||
|
|
@ -204,11 +198,11 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
current->type = element_t::COMPLETE_DATE_STRING;
|
current->type = element_t::COMPLETE_DATE_STRING;
|
||||||
current->chars = format_t::date_format;
|
current->chars = datetime_t::date_format;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
current->type = element_t::DATE_STRING;
|
current->type = element_t::DATE_STRING;
|
||||||
current->chars = format_t::date_format;
|
current->chars = datetime_t::date_format;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': current->type = element_t::SOURCE; break;
|
case 'S': current->type = element_t::SOURCE; break;
|
||||||
|
|
@ -310,15 +304,29 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
||||||
|
|
||||||
calc->compute(value, details);
|
calc->compute(value, details);
|
||||||
|
|
||||||
if (! keep_price || ! keep_date || ! keep_tag)
|
if (! amount_t::keep_price ||
|
||||||
value = value.reduce(keep_price, keep_date, keep_tag);
|
! amount_t::keep_date ||
|
||||||
|
! amount_t::keep_tag) {
|
||||||
|
switch (value.type) {
|
||||||
|
case value_t::AMOUNT:
|
||||||
|
case value_t::BALANCE:
|
||||||
|
case value_t::BALANCE_PAIR:
|
||||||
|
value = value.strip_annotations();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
out << (*((bool *) value.data) ? "1" : "0");
|
out << (*((bool *) value.data) ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
out << *((unsigned int *) value.data);
|
out << *((long *) value.data);
|
||||||
|
break;
|
||||||
|
case value_t::DATETIME:
|
||||||
|
out << *((datetime_t *) value.data);
|
||||||
break;
|
break;
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
out << *((amount_t *) value.data);
|
out << *((amount_t *) value.data);
|
||||||
|
|
|
||||||
6
format.h
6
format.h
|
|
@ -72,12 +72,6 @@ struct format_t
|
||||||
std::string format_string;
|
std::string format_string;
|
||||||
element_t * elements;
|
element_t * elements;
|
||||||
|
|
||||||
static bool keep_price;
|
|
||||||
static bool keep_date;
|
|
||||||
static bool keep_tag;
|
|
||||||
|
|
||||||
static std::string date_format;
|
|
||||||
|
|
||||||
format_t() : elements(NULL) {
|
format_t() : elements(NULL) {
|
||||||
DEBUG_PRINT("ledger.memory.ctors", "ctor format_t");
|
DEBUG_PRINT("ledger.memory.ctors", "ctor format_t");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
123
main.cc
123
main.cc
|
|
@ -10,6 +10,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "acconf.h"
|
||||||
|
|
||||||
#ifdef HAVE_UNIX_PIPES
|
#ifdef HAVE_UNIX_PIPES
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
@ -18,27 +20,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
#include "timing.h"
|
|
||||||
|
|
||||||
using namespace ledger;
|
using namespace ledger;
|
||||||
|
|
||||||
namespace {
|
int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
||||||
TIMER_DEF_(setup);
|
|
||||||
TIMER_DEF_(parse);
|
|
||||||
TIMER_DEF_(process);
|
|
||||||
TIMER_DEF_(walk);
|
|
||||||
TIMER_DEF_(cleanup);
|
|
||||||
TIMER_DEF_(cache_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
int parse_and_report(int argc, char * argv[], char * envp[])
|
|
||||||
{
|
{
|
||||||
TIMER_START(setup);
|
|
||||||
|
|
||||||
config_t config;
|
|
||||||
|
|
||||||
std::auto_ptr<journal_t> journal(new journal_t);
|
|
||||||
|
|
||||||
// Configure the terminus for value expressions
|
// Configure the terminus for value expressions
|
||||||
|
|
||||||
ledger::terminus = now;
|
ledger::terminus = now;
|
||||||
|
|
@ -60,6 +46,8 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
config.use_cache = config.data_file.empty() && config.price_db.empty();
|
config.use_cache = config.data_file.empty() && config.price_db.empty();
|
||||||
DEBUG_PRINT("ledger.config.cache", "1. use_cache = " << config.use_cache);
|
DEBUG_PRINT("ledger.config.cache", "1. use_cache = " << config.use_cache);
|
||||||
|
|
||||||
|
TRACE(main, "Processing options and environment variables");
|
||||||
|
|
||||||
config.process_environment(envp, "LEDGER_");
|
config.process_environment(envp, "LEDGER_");
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
@ -90,6 +78,14 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
config.use_cache = false;
|
config.use_cache = false;
|
||||||
DEBUG_PRINT("ledger.config.cache", "2. use_cache = " << config.use_cache);
|
DEBUG_PRINT("ledger.config.cache", "2. use_cache = " << config.use_cache);
|
||||||
|
|
||||||
|
TRACE(main, std::string("Initialization file is ") + config.init_file);
|
||||||
|
TRACE(main, std::string("Price database is ") + config.price_db);
|
||||||
|
TRACE(main, std::string("Binary cache is ") + config.cache_file);
|
||||||
|
TRACE(main, std::string("Main journal is ") + config.data_file);
|
||||||
|
|
||||||
|
TRACE(main, std::string("Based on option settings, binary cache ") +
|
||||||
|
(config.use_cache ? "WILL " : "will NOT ") + "be used");
|
||||||
|
|
||||||
// Read the command word, canonicalize it to its one letter form,
|
// Read the command word, canonicalize it to its one letter form,
|
||||||
// then configure the system based on the kind of report to be
|
// then configure the system based on the kind of report to be
|
||||||
// generated
|
// generated
|
||||||
|
|
@ -124,15 +120,23 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
}
|
}
|
||||||
else if (command == "parse") {
|
else if (command == "parse") {
|
||||||
value_auto_ptr expr(ledger::parse_value_expr(*arg));
|
value_auto_ptr expr(ledger::parse_value_expr(*arg));
|
||||||
if (config.debug_mode) {
|
if (config.verbose_mode) {
|
||||||
ledger::dump_value_expr(std::cout, expr.get());
|
ledger::dump_value_expr(std::cout, expr.get());
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t result = expr->compute();
|
value_t result = expr->compute();
|
||||||
if (! config.keep_price || ! config.keep_date || ! config.keep_tag)
|
if (! config.keep_price || ! config.keep_date || ! config.keep_tag) {
|
||||||
result = result.reduce(config.keep_price, config.keep_date,
|
switch (result.type) {
|
||||||
config.keep_tag);
|
case value_t::AMOUNT:
|
||||||
|
case value_t::BALANCE:
|
||||||
|
case value_t::BALANCE_PAIR:
|
||||||
|
result = result.strip_annotations();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
std::cout << result << std::endl;
|
std::cout << result << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -142,22 +146,20 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
else
|
else
|
||||||
throw error(std::string("Unrecognized command '") + command + "'");
|
throw error(std::string("Unrecognized command '") + command + "'");
|
||||||
|
|
||||||
TIMER_STOP(setup);
|
|
||||||
|
|
||||||
// Parse initialization files, ledger data, price database, etc.
|
// Parse initialization files, ledger data, price database, etc.
|
||||||
|
|
||||||
TIMER_START(parse);
|
std::auto_ptr<journal_t> journal(new journal_t);
|
||||||
|
|
||||||
if (parse_ledger_data(config, journal.get()) == 0)
|
{ TRACE_PUSH(parser, "Parsing journal file");
|
||||||
throw error("Please specify ledger file using -f"
|
|
||||||
" or LEDGER_FILE environment variable.");
|
|
||||||
|
|
||||||
TIMER_STOP(parse);
|
if (parse_ledger_data(config, journal.get()) == 0)
|
||||||
|
throw error("Please specify ledger file using -f"
|
||||||
|
" or LEDGER_FILE environment variable.");
|
||||||
|
|
||||||
|
TRACE_POP(parser, "Finished parsing"); }
|
||||||
|
|
||||||
// process the command word and its following arguments
|
// process the command word and its following arguments
|
||||||
|
|
||||||
TIMER_START(process);
|
|
||||||
|
|
||||||
std::string first_arg;
|
std::string first_arg;
|
||||||
if (command == "w") {
|
if (command == "w") {
|
||||||
if (arg == args.end())
|
if (arg == args.end())
|
||||||
|
|
@ -165,6 +167,9 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
first_arg = *arg++;
|
first_arg = *arg++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACE(options, std::string("Post-processing options ") +
|
||||||
|
"for command \"" + command + "\"");
|
||||||
|
|
||||||
config.process_options(command, arg, args.end());
|
config.process_options(command, arg, args.end());
|
||||||
|
|
||||||
std::auto_ptr<entry_t> new_entry;
|
std::auto_ptr<entry_t> new_entry;
|
||||||
|
|
@ -232,14 +237,22 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
|
|
||||||
if (command == "expr") {
|
if (command == "expr") {
|
||||||
value_auto_ptr expr(ledger::parse_value_expr(*arg));
|
value_auto_ptr expr(ledger::parse_value_expr(*arg));
|
||||||
if (config.debug_mode) {
|
if (config.verbose_mode) {
|
||||||
ledger::dump_value_expr(std::cout, expr.get());
|
ledger::dump_value_expr(std::cout, expr.get());
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
value_t result = expr->compute();
|
value_t result = expr->compute();
|
||||||
if (! config.keep_price || ! config.keep_date || ! config.keep_tag)
|
if (! config.keep_price || ! config.keep_date || ! config.keep_tag) {
|
||||||
result = result.reduce(config.keep_price, config.keep_date,
|
switch (result.type) {
|
||||||
config.keep_tag);
|
case value_t::AMOUNT:
|
||||||
|
case value_t::BALANCE:
|
||||||
|
case value_t::BALANCE_PAIR:
|
||||||
|
result = result.strip_annotations();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
std::cout << result << std::endl;
|
std::cout << result << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -265,12 +278,8 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
else
|
else
|
||||||
format = &config.print_format;
|
format = &config.print_format;
|
||||||
|
|
||||||
TIMER_STOP(process);
|
|
||||||
|
|
||||||
// Walk the entries based on the report type and the options
|
// Walk the entries based on the report type and the options
|
||||||
|
|
||||||
TIMER_START(walk);
|
|
||||||
|
|
||||||
item_handler<transaction_t> * formatter;
|
item_handler<transaction_t> * formatter;
|
||||||
std::list<item_handler<transaction_t> *> formatter_ptrs;
|
std::list<item_handler<transaction_t> *> formatter_ptrs;
|
||||||
|
|
||||||
|
|
@ -290,9 +299,13 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
formatter = new format_transactions(*out, *format);
|
formatter = new format_transactions(*out, *format);
|
||||||
|
|
||||||
if (command == "w") {
|
if (command == "w") {
|
||||||
|
TRACE_PUSH(text_writer, "Writing journal file");
|
||||||
write_textual_journal(*journal, first_arg, *formatter,
|
write_textual_journal(*journal, first_arg, *formatter,
|
||||||
config.write_hdr_format, *out);
|
config.write_hdr_format, *out);
|
||||||
|
TRACE_POP(text_writer, "Finished writing");
|
||||||
} else {
|
} else {
|
||||||
|
TRACE_PUSH(main, "Walking journal entries");
|
||||||
|
|
||||||
formatter = config.chain_xact_handlers(command, formatter, journal.get(),
|
formatter = config.chain_xact_handlers(command, formatter, journal.get(),
|
||||||
journal->master, formatter_ptrs);
|
journal->master, formatter_ptrs);
|
||||||
if (command == "e")
|
if (command == "e")
|
||||||
|
|
@ -304,11 +317,15 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
|
|
||||||
if (command != "P" && command != "D")
|
if (command != "P" && command != "D")
|
||||||
formatter->flush();
|
formatter->flush();
|
||||||
|
|
||||||
|
TRACE_POP(main, "Finished entry walk");
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the balance and equity reports, output the sum totals.
|
// For the balance and equity reports, output the sum totals.
|
||||||
|
|
||||||
if (command == "b") {
|
if (command == "b") {
|
||||||
|
TRACE_PUSH(main, "Walking journal accounts");
|
||||||
|
|
||||||
format_account acct_formatter(*out, *format, config.display_predicate);
|
format_account acct_formatter(*out, *format, config.display_predicate);
|
||||||
sum_accounts(*journal->master);
|
sum_accounts(*journal->master);
|
||||||
walk_accounts(*journal->master, acct_formatter, config.sort_string);
|
walk_accounts(*journal->master, acct_formatter, config.sort_string);
|
||||||
|
|
@ -322,19 +339,22 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
acct_formatter.format.format(*out, details_t(*journal->master));
|
acct_formatter.format.format(*out, details_t(*journal->master));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TRACE_POP(main, "Finished account walk");
|
||||||
}
|
}
|
||||||
else if (command == "E") {
|
else if (command == "E") {
|
||||||
|
TRACE_PUSH(main, "Walking journal accounts");
|
||||||
|
|
||||||
format_equity acct_formatter(*out, *format, config.display_predicate);
|
format_equity acct_formatter(*out, *format, config.display_predicate);
|
||||||
sum_accounts(*journal->master);
|
sum_accounts(*journal->master);
|
||||||
walk_accounts(*journal->master, acct_formatter, config.sort_string);
|
walk_accounts(*journal->master, acct_formatter, config.sort_string);
|
||||||
acct_formatter.flush();
|
acct_formatter.flush();
|
||||||
|
|
||||||
|
TRACE_POP(main, "Finished account walk");
|
||||||
}
|
}
|
||||||
|
|
||||||
TIMER_STOP(walk);
|
|
||||||
|
|
||||||
TIMER_START(cleanup);
|
|
||||||
|
|
||||||
#if DEBUG_LEVEL >= BETA
|
#if DEBUG_LEVEL >= BETA
|
||||||
|
{ TRACE_PUSH(cleanup, "Cleaning up allocated memory");
|
||||||
|
|
||||||
clear_transaction_xdata xact_cleaner;
|
clear_transaction_xdata xact_cleaner;
|
||||||
walk_entries(journal->entries, xact_cleaner);
|
walk_entries(journal->entries, xact_cleaner);
|
||||||
|
|
||||||
|
|
@ -349,17 +369,19 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
i != formatter_ptrs.end();
|
i != formatter_ptrs.end();
|
||||||
i++)
|
i++)
|
||||||
delete *i;
|
delete *i;
|
||||||
#endif
|
|
||||||
|
|
||||||
TIMER_STOP(cleanup);
|
TRACE_POP(cleanup, "Finished cleaning"); }
|
||||||
|
#endif
|
||||||
|
|
||||||
// Write out the binary cache, if need be
|
// Write out the binary cache, if need be
|
||||||
|
|
||||||
if (config.use_cache && config.cache_dirty && ! config.cache_file.empty()) {
|
if (config.use_cache && config.cache_dirty && ! config.cache_file.empty()) {
|
||||||
TIMER_START(cache_write);
|
TRACE_PUSH(binary_cache, "Writing journal file");
|
||||||
|
|
||||||
std::ofstream stream(config.cache_file.c_str());
|
std::ofstream stream(config.cache_file.c_str());
|
||||||
write_binary_journal(stream, journal.get());
|
write_binary_journal(stream, journal.get());
|
||||||
TIMER_STOP(cache_write);
|
|
||||||
|
TRACE_POP(binary_cache, "Finished writing");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_UNIX_PIPES
|
#ifdef HAVE_UNIX_PIPES
|
||||||
|
|
@ -380,7 +402,14 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
int main(int argc, char * argv[], char * envp[])
|
int main(int argc, char * argv[], char * envp[])
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return parse_and_report(argc, argv, envp);
|
#if DEBUG_LEVEL < BETA
|
||||||
|
ledger::do_cleanup = false;
|
||||||
|
#endif
|
||||||
|
config_t config;
|
||||||
|
TRACE_PUSH(main, "Starting Ledger " PACKAGE_VERSION);
|
||||||
|
int status = parse_and_report(config, argc, argv, envp);
|
||||||
|
TRACE_POP(main, "Ledger done");
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
catch (const std::exception& err) {
|
catch (const std::exception& err) {
|
||||||
std::cerr << "Error: " << err.what() << std::endl;
|
std::cerr << "Error: " << err.what() << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ namespace {
|
||||||
|
|
||||||
startup::~startup()
|
startup::~startup()
|
||||||
{
|
{
|
||||||
|
if (! ledger::do_cleanup)
|
||||||
|
return;
|
||||||
shutdown_parser_support();
|
shutdown_parser_support();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
timing.h
6
timing.h
|
|
@ -20,6 +20,9 @@ class timing_t
|
||||||
timing_t(const std::string& _symbol, const std::string& _category)
|
timing_t(const std::string& _symbol, const std::string& _category)
|
||||||
: begin(0), cumulative(0), symbol(_symbol), category(_category) {}
|
: begin(0), cumulative(0), symbol(_symbol), category(_category) {}
|
||||||
|
|
||||||
|
timing_t(const std::string& _symbol)
|
||||||
|
: begin(0), cumulative(0), symbol(_symbol) {}
|
||||||
|
|
||||||
~timing_t() {
|
~timing_t() {
|
||||||
std::string cls = "timing.results.";
|
std::string cls = "timing.results.";
|
||||||
cls += symbol;
|
cls += symbol;
|
||||||
|
|
@ -33,6 +36,9 @@ class timing_t
|
||||||
line = _line;
|
line = _line;
|
||||||
begin = std::clock();
|
begin = std::clock();
|
||||||
}
|
}
|
||||||
|
void start() {
|
||||||
|
begin = std::clock();
|
||||||
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
cumulative += std::clock() - begin;
|
cumulative += std::clock() - begin;
|
||||||
|
|
|
||||||
115
valexpr.cc
115
valexpr.cc
|
|
@ -35,6 +35,7 @@ bool compute_amount(value_expr_t * expr, amount_t& amt,
|
||||||
amt = *((amount_t *) result.data);
|
amt = *((amount_t *) result.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case value_t::DATETIME:
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
case value_t::BALANCE_PAIR:
|
case value_t::BALANCE_PAIR:
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -68,8 +69,12 @@ value_expr_t::~value_expr_t()
|
||||||
delete constant_a;
|
delete constant_a;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONSTANT_I:
|
|
||||||
case CONSTANT_T:
|
case CONSTANT_T:
|
||||||
|
assert(constant_t);
|
||||||
|
delete constant_t;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTANT_I:
|
||||||
case CONSTANT_V:
|
case CONSTANT_V:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -145,7 +150,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
result = constant_i;
|
result = constant_i;
|
||||||
break;
|
break;
|
||||||
case CONSTANT_T:
|
case CONSTANT_T:
|
||||||
result = long(constant_t);
|
result = *constant_t;
|
||||||
break;
|
break;
|
||||||
case CONSTANT_A:
|
case CONSTANT_A:
|
||||||
result = *constant_a;
|
result = *constant_a;
|
||||||
|
|
@ -155,7 +160,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_NOW:
|
case F_NOW:
|
||||||
result = long(terminus);
|
result = datetime_t(terminus);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
|
|
@ -262,37 +267,37 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
case DATE:
|
case DATE:
|
||||||
if (details.xact && transaction_has_xdata(*details.xact) &&
|
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||||
transaction_xdata_(*details.xact).date)
|
transaction_xdata_(*details.xact).date)
|
||||||
result = long(transaction_xdata_(*details.xact).date);
|
result = datetime_t(transaction_xdata_(*details.xact).date);
|
||||||
else if (details.xact)
|
else if (details.xact)
|
||||||
result = long(details.xact->date());
|
result = datetime_t(details.xact->date());
|
||||||
else if (details.entry)
|
else if (details.entry)
|
||||||
result = long(details.entry->date());
|
result = datetime_t(details.entry->date());
|
||||||
else
|
else
|
||||||
result = long(terminus);
|
result = datetime_t(terminus);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_DATE:
|
case ACT_DATE:
|
||||||
if (details.xact && transaction_has_xdata(*details.xact) &&
|
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||||
transaction_xdata_(*details.xact).date)
|
transaction_xdata_(*details.xact).date)
|
||||||
result = long(transaction_xdata_(*details.xact).date);
|
result = datetime_t(transaction_xdata_(*details.xact).date);
|
||||||
else if (details.xact)
|
else if (details.xact)
|
||||||
result = long(details.xact->actual_date());
|
result = datetime_t(details.xact->actual_date());
|
||||||
else if (details.entry)
|
else if (details.entry)
|
||||||
result = long(details.entry->actual_date());
|
result = datetime_t(details.entry->actual_date());
|
||||||
else
|
else
|
||||||
result = long(terminus);
|
result = datetime_t(terminus);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EFF_DATE:
|
case EFF_DATE:
|
||||||
if (details.xact && transaction_has_xdata(*details.xact) &&
|
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||||
transaction_xdata_(*details.xact).date)
|
transaction_xdata_(*details.xact).date)
|
||||||
result = long(transaction_xdata_(*details.xact).date);
|
result = datetime_t(transaction_xdata_(*details.xact).date);
|
||||||
else if (details.xact)
|
else if (details.xact)
|
||||||
result = long(details.xact->effective_date());
|
result = datetime_t(details.xact->effective_date());
|
||||||
else if (details.entry)
|
else if (details.entry)
|
||||||
result = long(details.entry->effective_date());
|
result = datetime_t(details.entry->effective_date());
|
||||||
else
|
else
|
||||||
result = long(terminus);
|
result = datetime_t(terminus);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLEARED:
|
case CLEARED:
|
||||||
|
|
@ -373,11 +378,40 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
expr = find_leaf(context, 1, index);
|
expr = find_leaf(context, 1, index);
|
||||||
amount_t moment;
|
value_t moment;
|
||||||
if (compute_amount(expr, moment, NULL, context))
|
expr->compute(moment, details, context);
|
||||||
|
if (moment.type == value_t::DATETIME) {
|
||||||
|
result.cast(value_t::INTEGER);
|
||||||
|
moment.cast(value_t::INTEGER);
|
||||||
result -= moment;
|
result -= moment;
|
||||||
else
|
} else {
|
||||||
throw compute_error("Invalid date passed to datecmp(value,date)");
|
throw compute_error("Invalid date passed to datecmp(value,date)");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case F_YEAR:
|
||||||
|
case F_MONTH:
|
||||||
|
case F_DAY: {
|
||||||
|
int index = 0;
|
||||||
|
value_expr_t * expr = find_leaf(context, 0, 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);
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case F_YEAR:
|
||||||
|
result = (long)desc->tm_year + 1900L;
|
||||||
|
break;
|
||||||
|
case F_MONTH:
|
||||||
|
result = (long)desc->tm_mon + 1L;
|
||||||
|
break;
|
||||||
|
case F_DAY:
|
||||||
|
result = (long)desc->tm_mday;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,13 +614,12 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
expr = find_leaf(context, 1, index);
|
expr = find_leaf(context, 1, index);
|
||||||
|
value_t moment;
|
||||||
amount_t moment;
|
expr->compute(moment, details, context);
|
||||||
if (compute_amount(expr, moment, details.xact, context))
|
if (moment.type != value_t::DATETIME)
|
||||||
result = result.value((long)moment);
|
|
||||||
else
|
|
||||||
throw compute_error("Invalid date passed to P(value,date)");
|
throw compute_error("Invalid date passed to P(value,date)");
|
||||||
|
|
||||||
|
result = result.value(*((datetime_t *)moment.data));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -756,14 +789,18 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope)
|
||||||
c = peek_next_nonws(in);
|
c = peek_next_nonws(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool definition = false;
|
||||||
if (c == '=') {
|
if (c == '=') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
if (peek_next_nonws(in) == '=') {
|
if (peek_next_nonws(in) == '=') {
|
||||||
in.unget();
|
in.unget();
|
||||||
c = '\0';
|
c = '\0';
|
||||||
goto parsed; // parse this as == operator
|
} else {
|
||||||
|
definition = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (definition) {
|
||||||
std::auto_ptr<scope_t> params(new scope_t(scope));
|
std::auto_ptr<scope_t> params(new scope_t(scope));
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
@ -970,7 +1007,7 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope)
|
||||||
node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
|
node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
|
||||||
|
|
||||||
interval_t timespan(buf);
|
interval_t timespan(buf);
|
||||||
node->constant_t = timespan.first();
|
node->constant_t = new datetime_t(timespan.first());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1350,6 +1387,28 @@ void init_value_expr()
|
||||||
node->set_right(new value_expr_t(value_expr_t::F_DATECMP));
|
node->set_right(new value_expr_t(value_expr_t::F_DATECMP));
|
||||||
globals->define("datecmp", node);
|
globals->define("datecmp", node);
|
||||||
|
|
||||||
|
node = new value_expr_t(value_expr_t::O_DEF);
|
||||||
|
node->set_left(new value_expr_t(value_expr_t::CONSTANT_I));
|
||||||
|
node->left->constant_i = 1;
|
||||||
|
node->set_right(new value_expr_t(value_expr_t::F_YEAR));
|
||||||
|
globals->define("yearof", node);
|
||||||
|
|
||||||
|
node = new value_expr_t(value_expr_t::O_DEF);
|
||||||
|
node->set_left(new value_expr_t(value_expr_t::CONSTANT_I));
|
||||||
|
node->left->constant_i = 1;
|
||||||
|
node->set_right(new value_expr_t(value_expr_t::F_MONTH));
|
||||||
|
globals->define("monthof", node);
|
||||||
|
|
||||||
|
node = new value_expr_t(value_expr_t::O_DEF);
|
||||||
|
node->set_left(new value_expr_t(value_expr_t::CONSTANT_I));
|
||||||
|
node->left->constant_i = 1;
|
||||||
|
node->set_right(new value_expr_t(value_expr_t::F_DAY));
|
||||||
|
globals->define("dayof", node);
|
||||||
|
|
||||||
|
value_auto_ptr year(parse_boolean_expr("year=yearof(d)", globals));
|
||||||
|
value_auto_ptr month(parse_boolean_expr("month=monthof(d)", globals));
|
||||||
|
value_auto_ptr day(parse_boolean_expr("day=dayof(d)", globals));
|
||||||
|
|
||||||
// Macros
|
// Macros
|
||||||
node = parse_value_expr("P(a,d)");
|
node = parse_value_expr("P(a,d)");
|
||||||
globals->define("v", node);
|
globals->define("v", node);
|
||||||
|
|
@ -1437,7 +1496,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
|
||||||
out << "CONSTANT_I - " << node->constant_i;
|
out << "CONSTANT_I - " << node->constant_i;
|
||||||
break;
|
break;
|
||||||
case value_expr_t::CONSTANT_T:
|
case value_expr_t::CONSTANT_T:
|
||||||
out << "CONSTANT_T - [" << node->constant_t << ']';
|
out << "CONSTANT_T - [" << *(node->constant_t) << ']';
|
||||||
break;
|
break;
|
||||||
case value_expr_t::CONSTANT_A:
|
case value_expr_t::CONSTANT_A:
|
||||||
out << "CONSTANT_A - {" << *(node->constant_a) << '}';
|
out << "CONSTANT_A - {" << *(node->constant_a) << '}';
|
||||||
|
|
@ -1481,6 +1540,10 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
|
||||||
case value_expr_t::F_VALUE: out << "F_VALUE"; break;
|
case value_expr_t::F_VALUE: out << "F_VALUE"; break;
|
||||||
case value_expr_t::F_PRICE: out << "F_PRICE"; break;
|
case value_expr_t::F_PRICE: out << "F_PRICE"; break;
|
||||||
case value_expr_t::F_DATE: out << "F_DATE"; break;
|
case value_expr_t::F_DATE: out << "F_DATE"; break;
|
||||||
|
case value_expr_t::F_DATECMP: out << "F_DATECMP"; break;
|
||||||
|
case value_expr_t::F_YEAR: out << "F_YEAR"; break;
|
||||||
|
case value_expr_t::F_MONTH: out << "F_MONTH"; break;
|
||||||
|
case value_expr_t::F_DAY: out << "F_DAY"; break;
|
||||||
|
|
||||||
case value_expr_t::O_NOT: out << "O_NOT"; break;
|
case value_expr_t::O_NOT: out << "O_NOT"; break;
|
||||||
case value_expr_t::O_ARG: out << "O_ARG"; break;
|
case value_expr_t::O_ARG: out << "O_ARG"; break;
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,9 @@ struct value_expr_t
|
||||||
F_PRICE,
|
F_PRICE,
|
||||||
F_DATE,
|
F_DATE,
|
||||||
F_DATECMP,
|
F_DATECMP,
|
||||||
|
F_YEAR,
|
||||||
|
F_MONTH,
|
||||||
|
F_DAY,
|
||||||
F_CODE_MASK,
|
F_CODE_MASK,
|
||||||
F_PAYEE_MASK,
|
F_PAYEE_MASK,
|
||||||
F_NOTE_MASK,
|
F_NOTE_MASK,
|
||||||
|
|
@ -155,7 +158,7 @@ struct value_expr_t
|
||||||
value_expr_t * left;
|
value_expr_t * left;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
std::time_t constant_t;
|
datetime_t * constant_t;
|
||||||
long constant_i;
|
long constant_i;
|
||||||
amount_t * constant_a;
|
amount_t * constant_a;
|
||||||
value_t * constant_v;
|
value_t * constant_v;
|
||||||
|
|
|
||||||
362
value.cc
362
value.cc
|
|
@ -64,6 +64,10 @@ value_t& value_t::operator=(const value_t& value)
|
||||||
*((long *) data) = *((long *) value.data);
|
*((long *) data) = *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DATETIME:
|
||||||
|
*((datetime_t *) data) = *((datetime_t *) value.data);
|
||||||
|
break;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
new((amount_t *)data) amount_t(*((amount_t *) value.data));
|
new((amount_t *)data) amount_t(*((amount_t *) value.data));
|
||||||
break;
|
break;
|
||||||
|
|
@ -88,14 +92,17 @@ value_t& value_t::operator=(const value_t& value)
|
||||||
|
|
||||||
value_t& value_t::operator+=(const value_t& value)
|
value_t& value_t::operator+=(const value_t& value)
|
||||||
{
|
{
|
||||||
|
if (value.type == BOOLEAN)
|
||||||
|
throw value_error("Cannot add a boolean to a value");
|
||||||
|
else if (value.type == DATETIME)
|
||||||
|
throw value_error("Cannot add a date/time to a value");
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot add a value to a boolean");
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
cast(INTEGER);
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((long *) data) += (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((long *) data) += *((long *) value.data);
|
*((long *) data) += *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -117,17 +124,28 @@ value_t& value_t::operator+=(const value_t& value)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DATETIME:
|
||||||
|
switch (value.type) {
|
||||||
|
case INTEGER:
|
||||||
|
*((datetime_t *) data) += *((long *) value.data);
|
||||||
|
break;
|
||||||
|
case AMOUNT:
|
||||||
|
*((datetime_t *) data) += long(*((amount_t *) value.data));
|
||||||
|
break;
|
||||||
|
case BALANCE:
|
||||||
|
*((datetime_t *) data) += long(*((balance_t *) value.data));
|
||||||
|
break;
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
*((datetime_t *) data) += long(*((balance_pair_t *) value.data));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
if (*((bool *) value.data) &&
|
|
||||||
((amount_t *) data)->commodity()) {
|
|
||||||
cast(BALANCE);
|
|
||||||
return *this += value;
|
|
||||||
}
|
|
||||||
*((amount_t *) data) += (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
if (*((long *) value.data) &&
|
if (*((long *) value.data) &&
|
||||||
((amount_t *) data)->commodity()) {
|
((amount_t *) data)->commodity()) {
|
||||||
|
|
@ -164,9 +182,6 @@ value_t& value_t::operator+=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_t *) data) += (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_t *) data) += *((long *) value.data);
|
*((balance_t *) data) += *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -188,9 +203,6 @@ value_t& value_t::operator+=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_pair_t *) data) += (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_pair_t *) data) += *((long *) value.data);
|
*((balance_pair_t *) data) += *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -218,14 +230,17 @@ value_t& value_t::operator+=(const value_t& value)
|
||||||
|
|
||||||
value_t& value_t::operator-=(const value_t& value)
|
value_t& value_t::operator-=(const value_t& value)
|
||||||
{
|
{
|
||||||
|
if (value.type == BOOLEAN)
|
||||||
|
throw value_error("Cannot subtract a boolean from a value");
|
||||||
|
else if (value.type == DATETIME)
|
||||||
|
throw value_error("Cannot subtract a date/time from a value");
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot subtract a value from a boolean");
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
cast(INTEGER);
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((long *) data) -= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((long *) data) -= *((long *) value.data);
|
*((long *) data) -= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -249,15 +264,6 @@ value_t& value_t::operator-=(const value_t& value)
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
if (*((bool *) value.data) &&
|
|
||||||
((amount_t *) data)->commodity()) {
|
|
||||||
cast(BALANCE);
|
|
||||||
return *this -= value;
|
|
||||||
}
|
|
||||||
*((amount_t *) data) -= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
if (*((long *) value.data) &&
|
if (*((long *) value.data) &&
|
||||||
((amount_t *) data)->commodity()) {
|
((amount_t *) data)->commodity()) {
|
||||||
|
|
@ -294,9 +300,6 @@ value_t& value_t::operator-=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_t *) data) -= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_t *) data) -= *((long *) value.data);
|
*((balance_t *) data) -= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -318,9 +321,6 @@ value_t& value_t::operator-=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_pair_t *) data) -= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_pair_t *) data) -= *((long *) value.data);
|
*((balance_pair_t *) data) -= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -351,6 +351,11 @@ value_t& value_t::operator-=(const value_t& value)
|
||||||
|
|
||||||
value_t& value_t::operator*=(const value_t& value)
|
value_t& value_t::operator*=(const value_t& value)
|
||||||
{
|
{
|
||||||
|
if (value.type == BOOLEAN)
|
||||||
|
throw value_error("Cannot multiply a boolean by a value");
|
||||||
|
else if (value.type == DATETIME)
|
||||||
|
throw value_error("Cannot multiply a date/time by a value");
|
||||||
|
|
||||||
if (value.realzero()) {
|
if (value.realzero()) {
|
||||||
*this = 0L;
|
*this = 0L;
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -358,12 +363,10 @@ value_t& value_t::operator*=(const value_t& value)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot multiply a value by a boolean");
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
cast(INTEGER);
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((long *) data) *= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((long *) data) *= *((long *) value.data);
|
*((long *) data) *= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -387,9 +390,6 @@ value_t& value_t::operator*=(const value_t& value)
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((amount_t *) data) *= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((amount_t *) data) *= *((long *) value.data);
|
*((amount_t *) data) *= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -412,9 +412,6 @@ value_t& value_t::operator*=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_t *) data) *= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_t *) data) *= *((long *) value.data);
|
*((balance_t *) data) *= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -436,9 +433,6 @@ value_t& value_t::operator*=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_pair_t *) data) *= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_pair_t *) data) *= *((long *) value.data);
|
*((balance_pair_t *) data) *= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -466,14 +460,17 @@ value_t& value_t::operator*=(const value_t& value)
|
||||||
|
|
||||||
value_t& value_t::operator/=(const value_t& value)
|
value_t& value_t::operator/=(const value_t& value)
|
||||||
{
|
{
|
||||||
|
if (value.type == BOOLEAN)
|
||||||
|
throw value_error("Cannot divide a boolean by a value");
|
||||||
|
else if (value.type == DATETIME)
|
||||||
|
throw value_error("Cannot divide a date/time by a value");
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot divide a value by a boolean");
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
cast(INTEGER);
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((long *) data) /= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((long *) data) /= *((long *) value.data);
|
*((long *) data) /= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -497,9 +494,6 @@ value_t& value_t::operator/=(const value_t& value)
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((amount_t *) data) /= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((amount_t *) data) /= *((long *) value.data);
|
*((amount_t *) data) /= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -522,9 +516,6 @@ value_t& value_t::operator/=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_t *) data) /= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_t *) data) /= *((long *) value.data);
|
*((balance_t *) data) /= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -546,9 +537,6 @@ value_t& value_t::operator/=(const value_t& value)
|
||||||
|
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case BOOLEAN:
|
|
||||||
*((balance_pair_t *) data) /= (*((bool *) value.data) ? 1L : 0L);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((balance_pair_t *) data) /= *((long *) value.data);
|
*((balance_pair_t *) data) /= *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -586,6 +574,9 @@ bool value_t::operator OP(const value_t& value) \
|
||||||
case INTEGER: \
|
case INTEGER: \
|
||||||
return *((bool *) data) OP bool(*((long *) value.data)); \
|
return *((bool *) data) OP bool(*((long *) value.data)); \
|
||||||
\
|
\
|
||||||
|
case DATETIME: \
|
||||||
|
return *((bool *) data) OP bool(*((datetime_t *) value.data)); \
|
||||||
|
\
|
||||||
case AMOUNT: \
|
case AMOUNT: \
|
||||||
return *((bool *) data) OP bool(*((amount_t *) value.data)); \
|
return *((bool *) data) OP bool(*((amount_t *) value.data)); \
|
||||||
\
|
\
|
||||||
|
|
@ -608,8 +599,11 @@ bool value_t::operator OP(const value_t& value) \
|
||||||
((long) *((bool *) value.data))); \
|
((long) *((bool *) value.data))); \
|
||||||
\
|
\
|
||||||
case INTEGER: \
|
case INTEGER: \
|
||||||
|
return (*((long *) data) OP *((long *) value.data)); \
|
||||||
|
\
|
||||||
|
case DATETIME: \
|
||||||
return (*((long *) data) OP \
|
return (*((long *) data) OP \
|
||||||
*((long *) value.data)); \
|
((long) *((datetime_t *) value.data))); \
|
||||||
\
|
\
|
||||||
case AMOUNT: \
|
case AMOUNT: \
|
||||||
return (amount_t(*((long *) data)) OP \
|
return (amount_t(*((long *) data)) OP \
|
||||||
|
|
@ -629,15 +623,46 @@ bool value_t::operator OP(const value_t& value) \
|
||||||
} \
|
} \
|
||||||
break; \
|
break; \
|
||||||
\
|
\
|
||||||
|
case DATETIME: \
|
||||||
|
switch (value.type) { \
|
||||||
|
case BOOLEAN: \
|
||||||
|
throw value_error("Cannot compare a date/time to a boolean"); \
|
||||||
|
\
|
||||||
|
case INTEGER: \
|
||||||
|
return (*((datetime_t *) data) OP \
|
||||||
|
datetime_t(*((long *) value.data))); \
|
||||||
|
\
|
||||||
|
case DATETIME: \
|
||||||
|
return (*((datetime_t *) data) OP \
|
||||||
|
*((datetime_t *) value.data)); \
|
||||||
|
\
|
||||||
|
case AMOUNT: \
|
||||||
|
throw value_error("Cannot compare a date/time to an amount"); \
|
||||||
|
\
|
||||||
|
case BALANCE: \
|
||||||
|
throw value_error("Cannot compare a date/time to a balance"); \
|
||||||
|
\
|
||||||
|
case BALANCE_PAIR: \
|
||||||
|
throw value_error("Cannot compare a date/time to a balance pair"); \
|
||||||
|
\
|
||||||
|
default: \
|
||||||
|
assert(0); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
\
|
||||||
case AMOUNT: \
|
case AMOUNT: \
|
||||||
switch (value.type) { \
|
switch (value.type) { \
|
||||||
case BOOLEAN: \
|
case BOOLEAN: \
|
||||||
return *((amount_t *) data) OP amount_t(*((bool *) value.data)); \
|
throw value_error("Cannot compare an amount to a boolean"); \
|
||||||
\
|
\
|
||||||
case INTEGER: \
|
case INTEGER: \
|
||||||
return (*((amount_t *) data) OP \
|
return (*((amount_t *) data) OP \
|
||||||
amount_t(*((long *) value.data))); \
|
amount_t(*((long *) value.data))); \
|
||||||
\
|
\
|
||||||
|
case DATETIME: \
|
||||||
|
throw value_error("Cannot compare an amount to a date/time"); \
|
||||||
|
\
|
||||||
case AMOUNT: \
|
case AMOUNT: \
|
||||||
return *((amount_t *) data) OP *((amount_t *) value.data); \
|
return *((amount_t *) data) OP *((amount_t *) value.data); \
|
||||||
\
|
\
|
||||||
|
|
@ -660,11 +685,14 @@ bool value_t::operator OP(const value_t& value) \
|
||||||
case BALANCE: \
|
case BALANCE: \
|
||||||
switch (value.type) { \
|
switch (value.type) { \
|
||||||
case BOOLEAN: \
|
case BOOLEAN: \
|
||||||
return *((balance_t *) data) OP (long)*((bool *) value.data); \
|
throw value_error("Cannot compare a balance to a boolean"); \
|
||||||
\
|
\
|
||||||
case INTEGER: \
|
case INTEGER: \
|
||||||
return *((balance_t *) data) OP *((long *) value.data); \
|
return *((balance_t *) data) OP *((long *) value.data); \
|
||||||
\
|
\
|
||||||
|
case DATETIME: \
|
||||||
|
throw value_error("Cannot compare a balance to a date/time"); \
|
||||||
|
\
|
||||||
case AMOUNT: \
|
case AMOUNT: \
|
||||||
return *((balance_t *) data) OP *((amount_t *) value.data); \
|
return *((balance_t *) data) OP *((amount_t *) value.data); \
|
||||||
\
|
\
|
||||||
|
|
@ -684,13 +712,15 @@ bool value_t::operator OP(const value_t& value) \
|
||||||
case BALANCE_PAIR: \
|
case BALANCE_PAIR: \
|
||||||
switch (value.type) { \
|
switch (value.type) { \
|
||||||
case BOOLEAN: \
|
case BOOLEAN: \
|
||||||
return (((balance_pair_t *) data)->quantity OP \
|
throw value_error("Cannot compare a balance pair to a boolean"); \
|
||||||
(long)*((bool *) value.data)); \
|
|
||||||
\
|
\
|
||||||
case INTEGER: \
|
case INTEGER: \
|
||||||
return (((balance_pair_t *) data)->quantity OP \
|
return (((balance_pair_t *) data)->quantity OP \
|
||||||
*((long *) value.data)); \
|
*((long *) value.data)); \
|
||||||
\
|
\
|
||||||
|
case DATETIME: \
|
||||||
|
throw value_error("Cannot compare a balance pair to a date/time"); \
|
||||||
|
\
|
||||||
case AMOUNT: \
|
case AMOUNT: \
|
||||||
return (((balance_pair_t *) data)->quantity OP \
|
return (((balance_pair_t *) data)->quantity OP \
|
||||||
*((amount_t *) value.data)); \
|
*((amount_t *) value.data)); \
|
||||||
|
|
@ -727,15 +757,42 @@ value_t::operator long() const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
return *((bool *) data) ? 1L : 0L;
|
throw value_error("Cannot convert a boolean to an integer");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *((long *) data);
|
return *((long *) data);
|
||||||
|
case DATETIME:
|
||||||
|
return *((datetime_t *) data);
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return *((amount_t *) data);
|
return *((amount_t *) data);
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
throw value_error("Cannot convert a value balance to a long");
|
throw value_error("Cannot convert a balance to an integer");
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
throw value_error("Cannot convert a value balance pair to a long");
|
throw value_error("Cannot convert a balance pair to an integer");
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
value_t::operator datetime_t() const
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot convert a boolean to a date/time");
|
||||||
|
case INTEGER:
|
||||||
|
return *((long *) data);
|
||||||
|
case DATETIME:
|
||||||
|
return *((datetime_t *) data);
|
||||||
|
case AMOUNT:
|
||||||
|
throw value_error("Cannot convert an amount to a date/time");
|
||||||
|
case BALANCE:
|
||||||
|
throw value_error("Cannot convert a balance to a date/time");
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
throw value_error("Cannot convert a balance pair to a date/time");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
@ -750,15 +807,17 @@ value_t::operator double() const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
return *((bool *) data) ? 1.0 : 0.0;
|
throw value_error("Cannot convert a boolean to a double");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *((long *) data);
|
return *((long *) data);
|
||||||
|
case DATETIME:
|
||||||
|
return *((datetime_t *) data);
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return *((amount_t *) data);
|
return *((amount_t *) data);
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
throw value_error("Cannot convert a value balance to a double");
|
throw value_error("Cannot convert a balance to a double");
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
throw value_error("Cannot convert a value balance pair to a double");
|
throw value_error("Cannot convert a balance pair to a double");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
@ -776,17 +835,15 @@ void value_t::cast(type_t cast_type)
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
break;
|
break;
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((long *) data) = *((bool *) data);
|
throw value_error("Cannot convert a boolean to an integer");
|
||||||
break;
|
case DATETIME:
|
||||||
|
throw value_error("Cannot convert a boolean to a date/time");
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
new((amount_t *)data) amount_t(*((bool *) data));
|
throw value_error("Cannot convert a boolean to an amount");
|
||||||
break;
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
new((balance_t *)data) balance_t(*((bool *) data));
|
throw value_error("Cannot convert a boolean to a balance");
|
||||||
break;
|
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
new((balance_pair_t *)data) balance_pair_t(*((bool *) data));
|
throw value_error("Cannot convert a boolean to a balance pair");
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
@ -801,6 +858,9 @@ void value_t::cast(type_t cast_type)
|
||||||
break;
|
break;
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
break;
|
break;
|
||||||
|
case DATETIME:
|
||||||
|
*((datetime_t *) data) = datetime_t(*((long *) data));
|
||||||
|
break;
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
new((amount_t *)data) amount_t(*((long *) data));
|
new((amount_t *)data) amount_t(*((long *) data));
|
||||||
break;
|
break;
|
||||||
|
|
@ -817,6 +877,29 @@ void value_t::cast(type_t cast_type)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DATETIME:
|
||||||
|
switch (cast_type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
*((bool *) data) = *((datetime_t *) data);
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
*((long *) data) = *((datetime_t *) data);
|
||||||
|
break;
|
||||||
|
case DATETIME:
|
||||||
|
break;
|
||||||
|
case AMOUNT:
|
||||||
|
throw value_error("Cannot convert a date/time to an amount");
|
||||||
|
case BALANCE:
|
||||||
|
throw value_error("Cannot convert a date/time to a balance");
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
throw value_error("Cannot convert a date/time to a balance pair");
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
switch (cast_type) {
|
switch (cast_type) {
|
||||||
case BOOLEAN: {
|
case BOOLEAN: {
|
||||||
|
|
@ -831,6 +914,8 @@ void value_t::cast(type_t cast_type)
|
||||||
*((long *)data) = temp;
|
*((long *)data) = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot convert an amount to a date/time");
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
break;
|
break;
|
||||||
case BALANCE: {
|
case BALANCE: {
|
||||||
|
|
@ -862,6 +947,9 @@ void value_t::cast(type_t cast_type)
|
||||||
}
|
}
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
throw value_error("Cannot convert a balance to an integer");
|
throw value_error("Cannot convert a balance to an integer");
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot convert a balance to a date/time");
|
||||||
|
|
||||||
case AMOUNT: {
|
case AMOUNT: {
|
||||||
balance_t * temp = (balance_t *) data;
|
balance_t * temp = (balance_t *) data;
|
||||||
if (temp->amounts.size() == 1) {
|
if (temp->amounts.size() == 1) {
|
||||||
|
|
@ -903,6 +991,8 @@ void value_t::cast(type_t cast_type)
|
||||||
}
|
}
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
throw value_error("Cannot convert a balance pair to an integer");
|
throw value_error("Cannot convert a balance pair to an integer");
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot convert a balance pair to a date/time");
|
||||||
|
|
||||||
case AMOUNT: {
|
case AMOUNT: {
|
||||||
balance_t * temp = &((balance_pair_t *) data)->quantity;
|
balance_t * temp = &((balance_pair_t *) data)->quantity;
|
||||||
|
|
@ -951,6 +1041,8 @@ void value_t::negate()
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
*((long *) data) = - *((long *) data);
|
*((long *) data) = - *((long *) data);
|
||||||
break;
|
break;
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot negate a date/time");
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
((amount_t *) data)->negate();
|
((amount_t *) data)->negate();
|
||||||
break;
|
break;
|
||||||
|
|
@ -976,6 +1068,8 @@ void value_t::abs()
|
||||||
if (*((long *) data) < 0)
|
if (*((long *) data) < 0)
|
||||||
*((long *) data) = - *((long *) data);
|
*((long *) data) = - *((long *) data);
|
||||||
break;
|
break;
|
||||||
|
case DATETIME:
|
||||||
|
break;
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
((amount_t *) data)->abs();
|
((amount_t *) data)->abs();
|
||||||
break;
|
break;
|
||||||
|
|
@ -992,12 +1086,54 @@ void value_t::abs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_t value_t::value(const std::time_t moment) const
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot find the value of a boolean");
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot find the value of a date/time");
|
||||||
|
case INTEGER:
|
||||||
|
return *this;
|
||||||
|
case AMOUNT:
|
||||||
|
return ((amount_t *) data)->value(moment);
|
||||||
|
case BALANCE:
|
||||||
|
return ((balance_t *) data)->value(moment);
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
return ((balance_pair_t *) data)->quantity.value(moment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void value_t::round()
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot round a boolean");
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot round a date/time");
|
||||||
|
case INTEGER:
|
||||||
|
break;
|
||||||
|
case AMOUNT:
|
||||||
|
*((amount_t *) data) = ((amount_t *) data)->round();
|
||||||
|
break;
|
||||||
|
case BALANCE:
|
||||||
|
((balance_t *) data)->round();
|
||||||
|
break;
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
((balance_pair_t *) data)->round();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
value_t value_t::price() const
|
value_t value_t::price() const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot find the price of a boolean");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *this;
|
return *this;
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot find the price of a date/time");
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return ((amount_t *) data)->price();
|
return ((amount_t *) data)->price();
|
||||||
|
|
@ -1020,7 +1156,10 @@ value_t value_t::date() const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot find the date of a boolean");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
|
return 0L;
|
||||||
|
case DATETIME:
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
|
|
@ -1040,23 +1179,28 @@ value_t value_t::date() const
|
||||||
return value_t();
|
return value_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t value_t::reduce(const bool keep_price, const bool keep_date,
|
value_t value_t::strip_annotations(const bool keep_price,
|
||||||
const bool keep_tag) const
|
const bool keep_date,
|
||||||
|
const bool keep_tag) const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot strip commodity annotations from a boolean");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *this;
|
return *this;
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot strip commodity annotations from a date/time");
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return ((amount_t *) data)->reduce_commodity(keep_price, keep_date,
|
return ((amount_t *) data)->strip_annotations
|
||||||
keep_tag);
|
(keep_price, keep_date, keep_tag);
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
return ((balance_t *) data)->reduce(keep_price, keep_date, keep_tag);
|
return ((balance_t *) data)->strip_annotations
|
||||||
|
(keep_price, keep_date, keep_tag);
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
return ((balance_pair_t *) data)->quantity.reduce(keep_price, keep_date,
|
return ((balance_pair_t *) data)->quantity.strip_annotations
|
||||||
keep_tag);
|
(keep_price, keep_date, keep_tag);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1069,10 +1213,13 @@ value_t value_t::cost() const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot find the cost of a boolean");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
return *this;
|
return *this;
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot find the cost of a date/time");
|
||||||
|
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
assert(((balance_pair_t *) data)->cost);
|
assert(((balance_pair_t *) data)->cost);
|
||||||
|
|
@ -1093,6 +1240,9 @@ value_t& value_t::add(const amount_t& amount, const amount_t * cost)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
throw value_error("Cannot add an amount to a boolean");
|
||||||
|
case DATETIME:
|
||||||
|
throw value_error("Cannot add an amount to a date/time");
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
if (cost) {
|
if (cost) {
|
||||||
|
|
@ -1150,6 +1300,7 @@ long value_len(value_t& value)
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
|
case value_t::DATETIME:
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
@ -1178,9 +1329,14 @@ amount_t value_getitem(value_t& value, int i)
|
||||||
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
|
throw value_error("Cannot cast a boolean to an amount");
|
||||||
|
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
return long(value);
|
return long(value);
|
||||||
|
|
||||||
|
case value_t::DATETIME:
|
||||||
|
throw value_error("Cannot cast a date/time to an amount");
|
||||||
|
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
return *((amount_t *) value.data);
|
return *((amount_t *) value.data);
|
||||||
|
|
||||||
|
|
@ -1213,6 +1369,7 @@ void export_value()
|
||||||
.def(init<std::string>())
|
.def(init<std::string>())
|
||||||
.def(init<double>())
|
.def(init<double>())
|
||||||
.def(init<long>())
|
.def(init<long>())
|
||||||
|
.def(init<datetime_t>())
|
||||||
|
|
||||||
.def(self + self)
|
.def(self + self)
|
||||||
.def(self + other<balance_pair_t>())
|
.def(self + other<balance_pair_t>())
|
||||||
|
|
@ -1301,12 +1458,14 @@ void export_value()
|
||||||
.def(self < other<balance_t>())
|
.def(self < other<balance_t>())
|
||||||
.def(self < other<amount_t>())
|
.def(self < other<amount_t>())
|
||||||
.def(self < long())
|
.def(self < long())
|
||||||
|
.def(self < other<datetime_t>())
|
||||||
.def(self < double())
|
.def(self < double())
|
||||||
|
|
||||||
.def(other<balance_pair_t>() < self)
|
.def(other<balance_pair_t>() < self)
|
||||||
.def(other<balance_t>() < self)
|
.def(other<balance_t>() < self)
|
||||||
.def(other<amount_t>() < self)
|
.def(other<amount_t>() < self)
|
||||||
.def(long() < self)
|
.def(long() < self)
|
||||||
|
.def(other<datetime_t>() < self)
|
||||||
.def(double() < self)
|
.def(double() < self)
|
||||||
|
|
||||||
.def(self <= self)
|
.def(self <= self)
|
||||||
|
|
@ -1314,12 +1473,14 @@ void export_value()
|
||||||
.def(self <= other<balance_t>())
|
.def(self <= other<balance_t>())
|
||||||
.def(self <= other<amount_t>())
|
.def(self <= other<amount_t>())
|
||||||
.def(self <= long())
|
.def(self <= long())
|
||||||
|
.def(self <= other<datetime_t>())
|
||||||
.def(self <= double())
|
.def(self <= double())
|
||||||
|
|
||||||
.def(other<balance_pair_t>() <= self)
|
.def(other<balance_pair_t>() <= self)
|
||||||
.def(other<balance_t>() <= self)
|
.def(other<balance_t>() <= self)
|
||||||
.def(other<amount_t>() <= self)
|
.def(other<amount_t>() <= self)
|
||||||
.def(long() <= self)
|
.def(long() <= self)
|
||||||
|
.def(other<datetime_t>() <= self)
|
||||||
.def(double() <= self)
|
.def(double() <= self)
|
||||||
|
|
||||||
.def(self > self)
|
.def(self > self)
|
||||||
|
|
@ -1327,12 +1488,14 @@ void export_value()
|
||||||
.def(self > other<balance_t>())
|
.def(self > other<balance_t>())
|
||||||
.def(self > other<amount_t>())
|
.def(self > other<amount_t>())
|
||||||
.def(self > long())
|
.def(self > long())
|
||||||
|
.def(self > other<datetime_t>())
|
||||||
.def(self > double())
|
.def(self > double())
|
||||||
|
|
||||||
.def(other<balance_pair_t>() > self)
|
.def(other<balance_pair_t>() > self)
|
||||||
.def(other<balance_t>() > self)
|
.def(other<balance_t>() > self)
|
||||||
.def(other<amount_t>() > self)
|
.def(other<amount_t>() > self)
|
||||||
.def(long() > self)
|
.def(long() > self)
|
||||||
|
.def(other<datetime_t>() > self)
|
||||||
.def(double() > self)
|
.def(double() > self)
|
||||||
|
|
||||||
.def(self >= self)
|
.def(self >= self)
|
||||||
|
|
@ -1340,12 +1503,14 @@ void export_value()
|
||||||
.def(self >= other<balance_t>())
|
.def(self >= other<balance_t>())
|
||||||
.def(self >= other<amount_t>())
|
.def(self >= other<amount_t>())
|
||||||
.def(self >= long())
|
.def(self >= long())
|
||||||
|
.def(self >= other<datetime_t>())
|
||||||
.def(self >= double())
|
.def(self >= double())
|
||||||
|
|
||||||
.def(other<balance_pair_t>() >= self)
|
.def(other<balance_pair_t>() >= self)
|
||||||
.def(other<balance_t>() >= self)
|
.def(other<balance_t>() >= self)
|
||||||
.def(other<amount_t>() >= self)
|
.def(other<amount_t>() >= self)
|
||||||
.def(long() >= self)
|
.def(long() >= self)
|
||||||
|
.def(other<datetime_t>() >= self)
|
||||||
.def(double() >= self)
|
.def(double() >= self)
|
||||||
|
|
||||||
.def(self == self)
|
.def(self == self)
|
||||||
|
|
@ -1353,12 +1518,14 @@ void export_value()
|
||||||
.def(self == other<balance_t>())
|
.def(self == other<balance_t>())
|
||||||
.def(self == other<amount_t>())
|
.def(self == other<amount_t>())
|
||||||
.def(self == long())
|
.def(self == long())
|
||||||
|
.def(self == other<datetime_t>())
|
||||||
.def(self == double())
|
.def(self == double())
|
||||||
|
|
||||||
.def(other<balance_pair_t>() == self)
|
.def(other<balance_pair_t>() == self)
|
||||||
.def(other<balance_t>() == self)
|
.def(other<balance_t>() == self)
|
||||||
.def(other<amount_t>() == self)
|
.def(other<amount_t>() == self)
|
||||||
.def(long() == self)
|
.def(long() == self)
|
||||||
|
.def(other<datetime_t>() == self)
|
||||||
.def(double() == self)
|
.def(double() == self)
|
||||||
|
|
||||||
.def(self != self)
|
.def(self != self)
|
||||||
|
|
@ -1366,12 +1533,14 @@ void export_value()
|
||||||
.def(self != other<balance_t>())
|
.def(self != other<balance_t>())
|
||||||
.def(self != other<amount_t>())
|
.def(self != other<amount_t>())
|
||||||
.def(self != long())
|
.def(self != long())
|
||||||
|
.def(self != other<datetime_t>())
|
||||||
.def(self != double())
|
.def(self != double())
|
||||||
|
|
||||||
.def(other<balance_pair_t>() != self)
|
.def(other<balance_pair_t>() != self)
|
||||||
.def(other<balance_t>() != self)
|
.def(other<balance_t>() != self)
|
||||||
.def(other<amount_t>() != self)
|
.def(other<amount_t>() != self)
|
||||||
.def(long() != self)
|
.def(long() != self)
|
||||||
|
.def(other<datetime_t>() != self)
|
||||||
.def(double() != self)
|
.def(double() != self)
|
||||||
|
|
||||||
.def(! self)
|
.def(! self)
|
||||||
|
|
@ -1386,16 +1555,23 @@ void export_value()
|
||||||
.def("__len__", value_len)
|
.def("__len__", value_len)
|
||||||
.def("__getitem__", value_getitem)
|
.def("__getitem__", value_getitem)
|
||||||
|
|
||||||
|
.def("abs", &value_t::abs)
|
||||||
.def("cast", &value_t::cast)
|
.def("cast", &value_t::cast)
|
||||||
.def("negate", &value_t::negate)
|
|
||||||
.def("price", &value_t::price)
|
|
||||||
.def("cost", &value_t::cost)
|
.def("cost", &value_t::cost)
|
||||||
|
.def("price", &value_t::price)
|
||||||
|
.def("date", &value_t::date)
|
||||||
|
.def("strip_annotations", &value_t::strip_annotations)
|
||||||
.def("add", &value_t::add, return_internal_reference<>())
|
.def("add", &value_t::add, return_internal_reference<>())
|
||||||
|
.def("value", &value_t::value)
|
||||||
|
.def("round", &value_t::round)
|
||||||
|
.def("negate", &value_t::negate)
|
||||||
|
.def("negated", &value_t::negated)
|
||||||
;
|
;
|
||||||
|
|
||||||
enum_< value_t::type_t > ("ValueType")
|
enum_< value_t::type_t > ("ValueType")
|
||||||
.value("BOOLEAN", value_t::BOOLEAN)
|
.value("BOOLEAN", value_t::BOOLEAN)
|
||||||
.value("INTEGER", value_t::INTEGER)
|
.value("INTEGER", value_t::INTEGER)
|
||||||
|
.value("DATETIME", value_t::DATETIME)
|
||||||
.value("AMOUNT", value_t::AMOUNT)
|
.value("AMOUNT", value_t::AMOUNT)
|
||||||
.value("BALANCE", value_t::BALANCE)
|
.value("BALANCE", value_t::BALANCE)
|
||||||
.value("BALANCE_PAIR", value_t::BALANCE_PAIR)
|
.value("BALANCE_PAIR", value_t::BALANCE_PAIR)
|
||||||
|
|
|
||||||
74
value.h
74
value.h
|
|
@ -36,6 +36,7 @@ class value_t
|
||||||
enum type_t {
|
enum type_t {
|
||||||
BOOLEAN,
|
BOOLEAN,
|
||||||
INTEGER,
|
INTEGER,
|
||||||
|
DATETIME,
|
||||||
AMOUNT,
|
AMOUNT,
|
||||||
BALANCE,
|
BALANCE,
|
||||||
BALANCE_PAIR
|
BALANCE_PAIR
|
||||||
|
|
@ -57,6 +58,10 @@ class value_t
|
||||||
*((long *) data) = value;
|
*((long *) data) = value;
|
||||||
type = INTEGER;
|
type = INTEGER;
|
||||||
}
|
}
|
||||||
|
value_t(const datetime_t value) {
|
||||||
|
*((datetime_t *) data) = value;
|
||||||
|
type = DATETIME;
|
||||||
|
}
|
||||||
value_t(const unsigned long value) {
|
value_t(const unsigned long value) {
|
||||||
new((amount_t *) data) amount_t(value);
|
new((amount_t *) data) amount_t(value);
|
||||||
type = AMOUNT;
|
type = AMOUNT;
|
||||||
|
|
@ -108,6 +113,14 @@ class value_t
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
value_t& operator=(const datetime_t value) {
|
||||||
|
if ((datetime_t *) data != &value) {
|
||||||
|
destroy();
|
||||||
|
*((datetime_t *) data) = value;
|
||||||
|
type = DATETIME;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
value_t& operator=(const unsigned long value) {
|
value_t& operator=(const unsigned long value) {
|
||||||
return *this = amount_t(value);
|
return *this = amount_t(value);
|
||||||
}
|
}
|
||||||
|
|
@ -284,6 +297,8 @@ class value_t
|
||||||
return ! *((bool *) data);
|
return ! *((bool *) data);
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *((long *) data) == 0;
|
return *((long *) data) == 0;
|
||||||
|
case DATETIME:
|
||||||
|
return ! *((datetime_t *) data);
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return ((amount_t *) data)->realzero();
|
return ((amount_t *) data)->realzero();
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
|
|
@ -299,46 +314,19 @@ class value_t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void abs();
|
void abs();
|
||||||
void cast(type_t cast_type);
|
void cast(type_t cast_type);
|
||||||
value_t cost() const;
|
value_t cost() const;
|
||||||
value_t price() const;
|
value_t price() const;
|
||||||
value_t date() const;
|
value_t date() const;
|
||||||
value_t reduce(const bool keep_price = false,
|
|
||||||
const bool keep_date = false,
|
value_t strip_annotations(const bool keep_price = amount_t::keep_price,
|
||||||
const bool keep_tag = false) const;
|
const bool keep_date = amount_t::keep_date,
|
||||||
|
const bool keep_tag = amount_t::keep_tag) const;
|
||||||
|
|
||||||
value_t& add(const amount_t& amount, const amount_t * cost = NULL);
|
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 std::time_t moment) const {
|
void round();
|
||||||
switch (type) {
|
|
||||||
case BOOLEAN:
|
|
||||||
case INTEGER:
|
|
||||||
return *this;
|
|
||||||
case AMOUNT:
|
|
||||||
return ((amount_t *) data)->value(moment);
|
|
||||||
case BALANCE:
|
|
||||||
return ((balance_t *) data)->value(moment);
|
|
||||||
case BALANCE_PAIR:
|
|
||||||
return ((balance_pair_t *) data)->quantity.value(moment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void round() {
|
|
||||||
switch (type) {
|
|
||||||
case BOOLEAN:
|
|
||||||
case INTEGER:
|
|
||||||
break;
|
|
||||||
case AMOUNT:
|
|
||||||
*((amount_t *) data) = ((amount_t *) data)->round();
|
|
||||||
break;
|
|
||||||
case BALANCE:
|
|
||||||
((balance_t *) data)->round();
|
|
||||||
break;
|
|
||||||
case BALANCE_PAIR:
|
|
||||||
((balance_pair_t *) data)->round();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEF_VALUE_AUX_OP(OP) \
|
#define DEF_VALUE_AUX_OP(OP) \
|
||||||
|
|
@ -379,6 +367,8 @@ value_t::operator T() const
|
||||||
return *((bool *) data);
|
return *((bool *) data);
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *((long *) data);
|
return *((long *) data);
|
||||||
|
case DATETIME:
|
||||||
|
return *((datetime_t *) data);
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return *((amount_t *) data);
|
return *((amount_t *) data);
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
|
|
@ -395,6 +385,7 @@ value_t::operator T() const
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> value_t::operator long() const;
|
template <> value_t::operator long() const;
|
||||||
|
template <> value_t::operator datetime_t() const;
|
||||||
template <> value_t::operator double() const;
|
template <> value_t::operator double() const;
|
||||||
|
|
||||||
inline value_t abs(const value_t& value) {
|
inline value_t abs(const value_t& value) {
|
||||||
|
|
@ -406,11 +397,14 @@ inline value_t abs(const value_t& value) {
|
||||||
inline std::ostream& operator<<(std::ostream& out, const value_t& value) {
|
inline std::ostream& operator<<(std::ostream& out, const value_t& value) {
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
out << *((bool *) value.data);
|
out << *((bool *) value.data) ? "true" : "false";
|
||||||
break;
|
break;
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
out << *((long *) value.data);
|
out << *((long *) value.data);
|
||||||
break;
|
break;
|
||||||
|
case value_t::DATETIME:
|
||||||
|
out << *((datetime_t *) value.data);
|
||||||
|
break;
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
out << *((amount_t *) value.data);
|
out << *((amount_t *) value.data);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
2
walk.cc
2
walk.cc
|
|
@ -340,7 +340,7 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
|
||||||
|
|
||||||
if (! spec_fmt) {
|
if (! spec_fmt) {
|
||||||
std::string fmt = "- ";
|
std::string fmt = "- ";
|
||||||
fmt += format_t::date_format;
|
fmt += datetime_t::date_format;
|
||||||
std::strftime(buf, 255, fmt.c_str(), std::localtime(&finish));
|
std::strftime(buf, 255, fmt.c_str(), std::localtime(&finish));
|
||||||
} else {
|
} else {
|
||||||
std::strftime(buf, 255, spec_fmt, std::localtime(&finish));
|
std::strftime(buf, 255, spec_fmt, std::localtime(&finish));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue