c
This commit is contained in:
parent
7ebe72c054
commit
854b719f1e
5 changed files with 325 additions and 181 deletions
|
|
@ -49,6 +49,10 @@ class gmp_amount : public amount
|
||||||
return quantity_comm;
|
return quantity_comm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void set_commdty(commodity * comm) {
|
||||||
|
quantity_comm = comm;
|
||||||
|
}
|
||||||
|
|
||||||
virtual amount * copy() const;
|
virtual amount * copy() const;
|
||||||
virtual amount * value(amount *) const;
|
virtual amount * value(amount *) const;
|
||||||
virtual amount * street(bool get_quotes) const;
|
virtual amount * street(bool get_quotes) const;
|
||||||
|
|
|
||||||
194
ledger.cc
194
ledger.cc
|
|
@ -136,6 +136,184 @@ bool entry::validate(bool show_unaccounted) const
|
||||||
return balance.is_zero(); // must balance to 0.0
|
return balance.is_zero(); // must balance to 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool entry::finalize(bool do_compute)
|
||||||
|
{
|
||||||
|
// Scan through and compute the total balance for the entry. This
|
||||||
|
// is used for auto-calculating the value of entries with no cost,
|
||||||
|
// and the per-unit price of unpriced commodities.
|
||||||
|
|
||||||
|
totals balance;
|
||||||
|
|
||||||
|
for (std::list<transaction *>::iterator x = xacts.begin();
|
||||||
|
x != xacts.end();
|
||||||
|
x++)
|
||||||
|
if ((*x)->cost && ! (*x)->is_virtual) {
|
||||||
|
amount * value = (*x)->cost->value();
|
||||||
|
balance.credit(value);
|
||||||
|
delete value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one transaction is of a different commodity than the others,
|
||||||
|
// and it has no per-unit price, determine its price by dividing
|
||||||
|
// the unit count into the value of the balance.
|
||||||
|
//
|
||||||
|
// NOTE: We don't do this for prefix-style or joined-symbol
|
||||||
|
// commodities. Also, do it for the last eligible commodity first,
|
||||||
|
// if it meets the criteria.
|
||||||
|
|
||||||
|
if (! balance.amounts.empty() && balance.amounts.size() == 2) {
|
||||||
|
for (std::list<transaction *>::iterator x = xacts.begin();
|
||||||
|
x != xacts.end();
|
||||||
|
x++) {
|
||||||
|
if ((*x)->is_virtual)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (! (*x)->cost->has_price() &&
|
||||||
|
! (*x)->cost->commdty()->prefix &&
|
||||||
|
(*x)->cost->commdty()->separate) {
|
||||||
|
for (totals::iterator i = balance.amounts.begin();
|
||||||
|
i != balance.amounts.end();
|
||||||
|
i++) {
|
||||||
|
if ((*i).second->commdty() != (*x)->cost->commdty()) {
|
||||||
|
(*x)->cost->set_value((*i).second);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through each of the transactions, fixing up any that we
|
||||||
|
// can, and performing any on-the-fly calculations.
|
||||||
|
|
||||||
|
bool empty_allowed = true;
|
||||||
|
|
||||||
|
for (std::list<transaction *>::iterator x = xacts.begin();
|
||||||
|
x != xacts.end();
|
||||||
|
x++) {
|
||||||
|
if ((*x)->is_virtual || (*x)->cost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (! empty_allowed || balance.amounts.empty() ||
|
||||||
|
balance.amounts.size() != 1) {
|
||||||
|
std::cerr << "Error, line " //<< linenum
|
||||||
|
<< ": Transaction entry is lacking an amount."
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
empty_allowed = false;
|
||||||
|
|
||||||
|
// If one transaction gives no value at all -- and all the
|
||||||
|
// rest are of the same commodity -- then its value is the
|
||||||
|
// inverse of the computed value of the others.
|
||||||
|
|
||||||
|
totals::iterator i = balance.amounts.begin();
|
||||||
|
(*x)->cost = (*i).second->value();
|
||||||
|
(*x)->cost->negate();
|
||||||
|
|
||||||
|
if (do_compute)
|
||||||
|
(*x)->acct->balance.credit((*x)->cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If virtual accounts are being supported, walk through the
|
||||||
|
// transactions and create new virtual transactions for all that
|
||||||
|
// apply.
|
||||||
|
|
||||||
|
for (book::virtual_map_iterator m = main_ledger->virtual_mapping.begin();
|
||||||
|
m != main_ledger->virtual_mapping.end();
|
||||||
|
m++) {
|
||||||
|
std::list<transaction *> xacts;
|
||||||
|
|
||||||
|
for (std::list<transaction *>::iterator x = xacts.begin();
|
||||||
|
x != xacts.end();
|
||||||
|
x++) {
|
||||||
|
if ((*x)->is_virtual ||
|
||||||
|
! ledger::matches(*((*m).first), (*x)->acct->as_str()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (std::list<transaction *>::iterator i = (*m).second->begin();
|
||||||
|
i != (*m).second->end();
|
||||||
|
i++) {
|
||||||
|
transaction * t;
|
||||||
|
|
||||||
|
if ((*i)->cost->commdty()) {
|
||||||
|
t = new transaction((*i)->acct, (*i)->cost);
|
||||||
|
} else {
|
||||||
|
amount * temp = (*x)->cost->value();
|
||||||
|
t = new transaction((*i)->acct, temp->value((*i)->cost));
|
||||||
|
delete temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->is_virtual = (*i)->is_virtual;
|
||||||
|
t->must_balance = (*i)->must_balance;
|
||||||
|
|
||||||
|
// If there is already a virtual transaction for the
|
||||||
|
// account under consideration, and it's `must_balance'
|
||||||
|
// flag matches, then simply add this amount to that
|
||||||
|
// transaction.
|
||||||
|
|
||||||
|
bool added = false;
|
||||||
|
|
||||||
|
for (std::list<transaction *>::iterator y = xacts.begin();
|
||||||
|
y != xacts.end();
|
||||||
|
y++) {
|
||||||
|
if ((*y)->is_virtual && (*y)->acct == t->acct &&
|
||||||
|
(*y)->must_balance == t->must_balance) {
|
||||||
|
(*y)->cost->credit(t->cost);
|
||||||
|
delete t;
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! added)
|
||||||
|
for (std::list<transaction *>::iterator y = xacts.begin();
|
||||||
|
y != xacts.end();
|
||||||
|
y++) {
|
||||||
|
if ((*y)->is_virtual && (*y)->acct == t->acct &&
|
||||||
|
(*y)->must_balance == t->must_balance) {
|
||||||
|
(*y)->cost->credit(t->cost);
|
||||||
|
delete t;
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! added)
|
||||||
|
xacts.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to the current entry any virtual transactions which were
|
||||||
|
// created. We have to do this afterward, otherwise the
|
||||||
|
// iteration above is screwed up if we try adding new
|
||||||
|
// transactions during the traversal.
|
||||||
|
|
||||||
|
for (std::list<transaction *>::iterator x = xacts.begin();
|
||||||
|
x != xacts.end();
|
||||||
|
x++) {
|
||||||
|
xacts.push_back(*x);
|
||||||
|
|
||||||
|
if (do_compute)
|
||||||
|
(*x)->acct->balance.credit((*x)->cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the balances again, just to make sure it all comes out
|
||||||
|
// right (i.e., zero for every commodity).
|
||||||
|
|
||||||
|
if (! validate()) {
|
||||||
|
std::cerr << "Error, line " //<< (linenum - 1)
|
||||||
|
<< ": Failed to balance the following transaction:"
|
||||||
|
<< std::endl;
|
||||||
|
validate(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool entry::matches(const regexps_map& regexps) const
|
bool entry::matches(const regexps_map& regexps) const
|
||||||
{
|
{
|
||||||
if (regexps.empty() || (ledger::matches(regexps, code) ||
|
if (regexps.empty() || (ledger::matches(regexps, code) ||
|
||||||
|
|
@ -385,6 +563,22 @@ book::~book()
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
account * book::re_find_account(const std::string& regex)
|
||||||
|
{
|
||||||
|
mask acct_regex(regex);
|
||||||
|
|
||||||
|
for (entries_list_reverse_iterator i = entries.rbegin();
|
||||||
|
i != entries.rend();
|
||||||
|
i++)
|
||||||
|
for (std::list<transaction *>::iterator x = (*i)->xacts.begin();
|
||||||
|
x != (*i)->xacts.end();
|
||||||
|
x++)
|
||||||
|
if (acct_regex.match((*x)->acct->as_str()))
|
||||||
|
return (*x)->acct;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
account * book::find_account(const std::string& name, bool create)
|
account * book::find_account(const std::string& name, bool create)
|
||||||
{
|
{
|
||||||
accounts_map_iterator i = accounts_cache.find(name);
|
accounts_map_iterator i = accounts_cache.find(name);
|
||||||
|
|
|
||||||
7
ledger.h
7
ledger.h
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _LEDGER_H
|
#ifndef _LEDGER_H
|
||||||
#define _LEDGER_H "$Revision: 1.25 $"
|
#define _LEDGER_H "$Revision: 1.26 $"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|
@ -66,6 +66,8 @@ class amount
|
||||||
virtual ~amount() {}
|
virtual ~amount() {}
|
||||||
|
|
||||||
virtual commodity * commdty() const = 0;
|
virtual commodity * commdty() const = 0;
|
||||||
|
virtual void set_commdty(commodity *) = 0;
|
||||||
|
|
||||||
virtual amount * copy() const = 0;
|
virtual amount * copy() const = 0;
|
||||||
virtual amount * value(amount * pr = NULL) const = 0;
|
virtual amount * value(amount * pr = NULL) const = 0;
|
||||||
virtual amount * street(bool get_quotes) const = 0;
|
virtual amount * street(bool get_quotes) const = 0;
|
||||||
|
|
@ -179,6 +181,7 @@ class entry
|
||||||
|
|
||||||
bool matches(const regexps_map& regexps) const;
|
bool matches(const regexps_map& regexps) const;
|
||||||
bool validate(bool show_unaccounted = false) const;
|
bool validate(bool show_unaccounted = false) const;
|
||||||
|
bool finalize(bool do_compute = false);
|
||||||
|
|
||||||
void print(std::ostream& out, bool shortcut = true) const;
|
void print(std::ostream& out, bool shortcut = true) const;
|
||||||
};
|
};
|
||||||
|
|
@ -191,6 +194,7 @@ struct cmp_entry_date {
|
||||||
|
|
||||||
typedef std::vector<entry *> entries_list;
|
typedef std::vector<entry *> entries_list;
|
||||||
typedef entries_list::iterator entries_list_iterator;
|
typedef entries_list::iterator entries_list_iterator;
|
||||||
|
typedef entries_list::reverse_iterator entries_list_reverse_iterator;
|
||||||
typedef entries_list::const_iterator entries_list_const_iterator;
|
typedef entries_list::const_iterator entries_list_const_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -280,6 +284,7 @@ class book
|
||||||
}
|
}
|
||||||
void print(std::ostream& out, regexps_map& regexps, bool shortcut) const;
|
void print(std::ostream& out, regexps_map& regexps, bool shortcut) const;
|
||||||
|
|
||||||
|
account * re_find_account(const std::string& regex);
|
||||||
account * find_account(const std::string& name, bool create = true);
|
account * find_account(const std::string& name, bool create = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
176
parse.cc
176
parse.cc
|
|
@ -232,185 +232,11 @@ entry * parse_entry(std::istream& in, book * ledger)
|
||||||
|
|
||||||
// If there were no transactions, throw away the entry
|
// If there were no transactions, throw away the entry
|
||||||
|
|
||||||
if (curr->xacts.empty()) {
|
if (curr->xacts.empty() || ! curr->finalize(do_compute)) {
|
||||||
delete curr;
|
delete curr;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan through and compute the total balance for the entry. This
|
|
||||||
// is used for auto-calculating the value of entries with no cost,
|
|
||||||
// and the per-unit price of unpriced commodities.
|
|
||||||
|
|
||||||
totals balance;
|
|
||||||
|
|
||||||
for (std::list<transaction *>::iterator x = curr->xacts.begin();
|
|
||||||
x != curr->xacts.end();
|
|
||||||
x++)
|
|
||||||
if ((*x)->cost && ! (*x)->is_virtual) {
|
|
||||||
amount * value = (*x)->cost->value();
|
|
||||||
balance.credit(value);
|
|
||||||
delete value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If one transaction is of a different commodity than the others,
|
|
||||||
// and it has no per-unit price, determine its price by dividing
|
|
||||||
// the unit count into the value of the balance.
|
|
||||||
//
|
|
||||||
// NOTE: We don't do this for prefix-style or joined-symbol
|
|
||||||
// commodities. Also, do it for the last eligible commodity first,
|
|
||||||
// if it meets the criteria.
|
|
||||||
|
|
||||||
if (! balance.amounts.empty() && balance.amounts.size() == 2) {
|
|
||||||
for (std::list<transaction *>::iterator x = curr->xacts.begin();
|
|
||||||
x != curr->xacts.end();
|
|
||||||
x++) {
|
|
||||||
if ((*x)->is_virtual)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (! (*x)->cost->has_price() &&
|
|
||||||
! (*x)->cost->commdty()->prefix &&
|
|
||||||
(*x)->cost->commdty()->separate) {
|
|
||||||
for (totals::iterator i = balance.amounts.begin();
|
|
||||||
i != balance.amounts.end();
|
|
||||||
i++) {
|
|
||||||
if ((*i).second->commdty() != (*x)->cost->commdty()) {
|
|
||||||
(*x)->cost->set_value((*i).second);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk through each of the transactions, fixing up any that we
|
|
||||||
// can, and performing any on-the-fly calculations.
|
|
||||||
|
|
||||||
bool empty_allowed = true;
|
|
||||||
|
|
||||||
for (std::list<transaction *>::iterator x = curr->xacts.begin();
|
|
||||||
x != curr->xacts.end();
|
|
||||||
x++) {
|
|
||||||
if ((*x)->is_virtual || (*x)->cost)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (! empty_allowed || balance.amounts.empty() ||
|
|
||||||
balance.amounts.size() != 1) {
|
|
||||||
std::cerr << "Error, line " << linenum
|
|
||||||
<< ": Transaction entry is lacking an amount."
|
|
||||||
<< std::endl;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
empty_allowed = false;
|
|
||||||
|
|
||||||
// If one transaction gives no value at all -- and all the
|
|
||||||
// rest are of the same commodity -- then its value is the
|
|
||||||
// inverse of the computed value of the others.
|
|
||||||
|
|
||||||
totals::iterator i = balance.amounts.begin();
|
|
||||||
(*x)->cost = (*i).second->value();
|
|
||||||
(*x)->cost->negate();
|
|
||||||
|
|
||||||
if (do_compute)
|
|
||||||
(*x)->acct->balance.credit((*x)->cost);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If virtual accounts are being supported, walk through the
|
|
||||||
// transactions and create new virtual transactions for all that
|
|
||||||
// apply.
|
|
||||||
|
|
||||||
for (book::virtual_map_iterator m = ledger->virtual_mapping.begin();
|
|
||||||
m != ledger->virtual_mapping.end();
|
|
||||||
m++) {
|
|
||||||
std::list<transaction *> xacts;
|
|
||||||
|
|
||||||
for (std::list<transaction *>::iterator x = curr->xacts.begin();
|
|
||||||
x != curr->xacts.end();
|
|
||||||
x++) {
|
|
||||||
if ((*x)->is_virtual ||
|
|
||||||
! ledger::matches(*((*m).first), (*x)->acct->as_str()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (std::list<transaction *>::iterator i = (*m).second->begin();
|
|
||||||
i != (*m).second->end();
|
|
||||||
i++) {
|
|
||||||
transaction * t;
|
|
||||||
|
|
||||||
if ((*i)->cost->commdty()) {
|
|
||||||
t = new transaction((*i)->acct, (*i)->cost);
|
|
||||||
} else {
|
|
||||||
amount * temp = (*x)->cost->value();
|
|
||||||
t = new transaction((*i)->acct, temp->value((*i)->cost));
|
|
||||||
delete temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
t->is_virtual = (*i)->is_virtual;
|
|
||||||
t->must_balance = (*i)->must_balance;
|
|
||||||
|
|
||||||
// If there is already a virtual transaction for the
|
|
||||||
// account under consideration, and it's `must_balance'
|
|
||||||
// flag matches, then simply add this amount to that
|
|
||||||
// transaction.
|
|
||||||
|
|
||||||
bool added = false;
|
|
||||||
|
|
||||||
for (std::list<transaction *>::iterator y = xacts.begin();
|
|
||||||
y != xacts.end();
|
|
||||||
y++) {
|
|
||||||
if ((*y)->is_virtual && (*y)->acct == t->acct &&
|
|
||||||
(*y)->must_balance == t->must_balance) {
|
|
||||||
(*y)->cost->credit(t->cost);
|
|
||||||
delete t;
|
|
||||||
added = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! added)
|
|
||||||
for (std::list<transaction *>::iterator y = curr->xacts.begin();
|
|
||||||
y != curr->xacts.end();
|
|
||||||
y++) {
|
|
||||||
if ((*y)->is_virtual && (*y)->acct == t->acct &&
|
|
||||||
(*y)->must_balance == t->must_balance) {
|
|
||||||
(*y)->cost->credit(t->cost);
|
|
||||||
delete t;
|
|
||||||
added = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! added)
|
|
||||||
xacts.push_back(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to the current entry any virtual transactions which were
|
|
||||||
// created. We have to do this afterward, otherwise the
|
|
||||||
// iteration above is screwed up if we try adding new
|
|
||||||
// transactions during the traversal.
|
|
||||||
|
|
||||||
for (std::list<transaction *>::iterator x = xacts.begin();
|
|
||||||
x != xacts.end();
|
|
||||||
x++) {
|
|
||||||
curr->xacts.push_back(*x);
|
|
||||||
|
|
||||||
if (do_compute)
|
|
||||||
(*x)->acct->balance.credit((*x)->cost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the balances again, just to make sure it all comes out
|
|
||||||
// right (i.e., zero for every commodity).
|
|
||||||
|
|
||||||
if (! curr->validate()) {
|
|
||||||
std::cerr << "Error, line " << (linenum - 1)
|
|
||||||
<< ": Failed to balance the following transaction:"
|
|
||||||
<< std::endl;
|
|
||||||
curr->print(std::cerr);
|
|
||||||
curr->validate(true);
|
|
||||||
delete curr;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
115
reports.cc
115
reports.cc
|
|
@ -535,6 +535,7 @@ int main(int argc, char * argv[])
|
||||||
// Compile the list of specified regular expressions, which can be
|
// Compile the list of specified regular expressions, which can be
|
||||||
// specified after the command, or using the '-i FILE' option
|
// specified after the command, or using the '-i FILE' option
|
||||||
|
|
||||||
|
if (command != "add")
|
||||||
for (; index < argc; index++)
|
for (; index < argc; index++)
|
||||||
regexps.push_back(mask(argv[index]));
|
regexps.push_back(mask(argv[index]));
|
||||||
|
|
||||||
|
|
@ -590,6 +591,120 @@ int main(int argc, char * argv[])
|
||||||
else if (command == "equity") {
|
else if (command == "equity") {
|
||||||
equity_ledger(std::cout, regexps);
|
equity_ledger(std::cout, regexps);
|
||||||
}
|
}
|
||||||
|
else if (command == "add") {
|
||||||
|
entry added, * matching = NULL;
|
||||||
|
|
||||||
|
if (! parse_date(argv[index++], &added.date)) {
|
||||||
|
std::cerr << "Error: Bad add date: " << argv[index - 1]
|
||||||
|
<< std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
added.cleared = show_cleared;
|
||||||
|
|
||||||
|
if (index == argc) {
|
||||||
|
std::cerr << "Error: Too few arguments to 'add'." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
regexps.clear();
|
||||||
|
regexps.push_back(mask(argv[index++]));
|
||||||
|
|
||||||
|
for (entries_list_reverse_iterator i = main_ledger->entries.rbegin();
|
||||||
|
i != main_ledger->entries.rend();
|
||||||
|
i++) {
|
||||||
|
if ((*i)->matches(regexps)) {
|
||||||
|
matching = *i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
added.desc = matching ? matching->desc : regexps.front().pattern;
|
||||||
|
|
||||||
|
if (index == argc) {
|
||||||
|
std::cerr << "Error: Too few arguments to 'add'." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[index][0] == '-' || std::isdigit(argv[index][0])) {
|
||||||
|
if (! matching) {
|
||||||
|
std::cerr << "Error: Missing account name for non-matching entry."
|
||||||
|
<< std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction * m_xact, * xact, * first;
|
||||||
|
|
||||||
|
m_xact = matching->xacts.front();
|
||||||
|
|
||||||
|
first = xact = new transaction();
|
||||||
|
xact->acct = m_xact->acct;
|
||||||
|
xact->cost = create_amount(argv[index++]);
|
||||||
|
xact->cost->set_commdty(m_xact->cost->commdty());
|
||||||
|
|
||||||
|
added.xacts.push_back(xact);
|
||||||
|
|
||||||
|
m_xact = matching->xacts.back();
|
||||||
|
|
||||||
|
xact = new transaction();
|
||||||
|
xact->acct = m_xact->acct;
|
||||||
|
xact->cost = first->cost->copy();
|
||||||
|
xact->cost->negate();
|
||||||
|
|
||||||
|
added.xacts.push_back(xact);
|
||||||
|
|
||||||
|
if ((index + 1) < argc && std::string(argv[index]) == "-from")
|
||||||
|
if (account * acct = main_ledger->re_find_account(argv[++index]))
|
||||||
|
added.xacts.back()->acct = acct;
|
||||||
|
} else {
|
||||||
|
while (index < argc && std::string(argv[index]) != "-from") {
|
||||||
|
transaction * xact = new transaction();
|
||||||
|
|
||||||
|
mask acct_regex(argv[index++]);
|
||||||
|
|
||||||
|
account * acct = NULL;
|
||||||
|
for (std::list<transaction *>::iterator x = matching->xacts.begin();
|
||||||
|
x != matching->xacts.end();
|
||||||
|
x++) {
|
||||||
|
if (acct_regex.match((*x)->acct->as_str())) {
|
||||||
|
acct = (*x)->acct;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acct)
|
||||||
|
xact->acct = acct;
|
||||||
|
else
|
||||||
|
xact->acct = main_ledger->re_find_account(acct_regex.pattern);
|
||||||
|
|
||||||
|
if (! xact->acct) {
|
||||||
|
std::cerr << "Error: Could not find account name '"
|
||||||
|
<< acct_regex.pattern << "'." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == argc) {
|
||||||
|
std::cerr << "Error: Too few arguments to 'add'." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xact->cost = create_amount(argv[index++]);
|
||||||
|
added.xacts.push_back(xact);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((index + 1) < argc && std::string(argv[index]) == "-from")
|
||||||
|
if (account * acct = main_ledger->re_find_account(argv[++index])) {
|
||||||
|
transaction * xact = new transaction();
|
||||||
|
xact->acct = acct;
|
||||||
|
xact->cost = NULL;
|
||||||
|
|
||||||
|
added.xacts.push_back(xact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (added.finalize())
|
||||||
|
added.print(std::cout);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Ordinarily, deleting the main ledger isn't necessary, since the
|
// Ordinarily, deleting the main ledger isn't necessary, since the
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue