Merge branch 'next'
This commit is contained in:
commit
97a9b42b2c
15 changed files with 222 additions and 60 deletions
|
|
@ -13,13 +13,13 @@ BOOST_VERSION = 1_40_0
|
|||
# architecture=combined
|
||||
boost-release:
|
||||
(cd $(BOOST_SOURCE) && \
|
||||
bjam release -j16 --prefix=$(STOW_ROOT)/boost_$(BOOST_VERSION) \
|
||||
bjam release --prefix=$(STOW_ROOT)/boost_$(BOOST_VERSION) \
|
||||
--build-dir=$(HOME)/Products/boost_$(BOOST_VERSION) \
|
||||
--toolset=darwin --build-type=complete --layout=versioned install)
|
||||
|
||||
boost-debug:
|
||||
(cd $(BOOST_SOURCE) && \
|
||||
bjam debug -j16 --prefix=$(STOW_ROOT)/boost_$(BOOST_VERSION) \
|
||||
bjam debug --prefix=$(STOW_ROOT)/boost_$(BOOST_VERSION) \
|
||||
--build-dir=$(HOME)/Products/boost_$(BOOST_VERSION) \
|
||||
--toolset=darwin --build-type=complete --layout=versioned \
|
||||
define=_GLIBCXX_DEBUG=1 install)
|
||||
|
|
|
|||
|
|
@ -209,7 +209,11 @@ post_handler_ptr chain_post_handlers(report_t& report,
|
|||
= new forecast_posts(handler,
|
||||
item_predicate(report.HANDLER(forecast_while_).str(),
|
||||
report.what_to_keep()),
|
||||
report);
|
||||
report,
|
||||
report.HANDLED(forecast_years_) ?
|
||||
static_cast<std::size_t>
|
||||
(report.HANDLER(forecast_years_).value.to_long()) :
|
||||
5UL);
|
||||
forecast_handler->add_period_xacts(report.session.journal->period_xacts);
|
||||
handler.reset(forecast_handler);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ namespace {
|
|||
bool from;
|
||||
optional<mask_t> account_mask;
|
||||
optional<amount_t> amount;
|
||||
optional<string> cost_operator;
|
||||
optional<amount_t> cost;
|
||||
|
||||
post_template_t() : from(false) {}
|
||||
};
|
||||
|
|
@ -111,6 +113,10 @@ namespace {
|
|||
|
||||
if (post.amount)
|
||||
out << _(" Amount: ") << *post.amount << std::endl;
|
||||
|
||||
if (post.cost)
|
||||
out << _(" Cost: ") << *post.cost_operator
|
||||
<< " " << *post.cost << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -148,6 +154,8 @@ namespace {
|
|||
string arg = (*begin).to_string();
|
||||
|
||||
if (arg == "at") {
|
||||
if (begin == end)
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
tmpl.payee_mask = (*++begin).to_string();
|
||||
}
|
||||
else if (arg == "to" || arg == "from") {
|
||||
|
|
@ -155,22 +163,41 @@ namespace {
|
|||
tmpl.posts.push_back(xact_template_t::post_template_t());
|
||||
post = &tmpl.posts.back();
|
||||
}
|
||||
if (begin == end)
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
post->account_mask = mask_t((*++begin).to_string());
|
||||
post->from = arg == "from";
|
||||
}
|
||||
else if (arg == "on") {
|
||||
if (begin == end)
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
tmpl.date = parse_date((*++begin).to_string());
|
||||
check_for_date = false;
|
||||
}
|
||||
else if (arg == "code") {
|
||||
if (begin == end)
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
tmpl.code = (*++begin).to_string();
|
||||
}
|
||||
else if (arg == "note") {
|
||||
if (begin == end)
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
tmpl.note = (*++begin).to_string();
|
||||
}
|
||||
else if (arg == "rest") {
|
||||
; // just ignore this argument
|
||||
}
|
||||
else if (arg == "@" || arg == "@@") {
|
||||
amount_t cost;
|
||||
post->cost_operator = arg;
|
||||
if (begin == end)
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
arg = (*++begin).to_string();
|
||||
if (! cost.parse(arg, amount_t::PARSE_SOFT_FAIL |
|
||||
amount_t::PARSE_NO_MIGRATE))
|
||||
throw std::runtime_error(_("Invalid xact command arguments"));
|
||||
post->cost = cost;
|
||||
}
|
||||
else {
|
||||
// Without a preposition, it is either:
|
||||
//
|
||||
|
|
@ -443,6 +470,25 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
if (post.cost) {
|
||||
if (post.cost->sign() < 0)
|
||||
throw parse_error(_("A posting's cost may not be negative"));
|
||||
|
||||
post.cost->in_place_unround();
|
||||
|
||||
if (*post.cost_operator == "@") {
|
||||
// For the sole case where the cost might be uncommoditized,
|
||||
// guarantee that the commodity of the cost after multiplication
|
||||
// is the same as it was before.
|
||||
commodity_t& cost_commodity(post.cost->commodity());
|
||||
*post.cost *= new_post->amount;
|
||||
post.cost->set_commodity(cost_commodity);
|
||||
}
|
||||
|
||||
new_post->cost = *post.cost;
|
||||
DEBUG("derive.xact", "Copied over posting cost");
|
||||
}
|
||||
|
||||
if (found_commodity &&
|
||||
! new_post->amount.is_null() &&
|
||||
! new_post->amount.has_commodity()) {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace ledger {
|
|||
void format_emacs_posts::write_xact(xact_t& xact)
|
||||
{
|
||||
out << "\"" << xact.pos->pathname << "\" "
|
||||
<< (xact.pos->beg_line + 1) << " ";
|
||||
<< xact.pos->beg_line << " ";
|
||||
|
||||
tm when = gregorian::to_tm(xact.date());
|
||||
std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local?
|
||||
|
|
@ -77,7 +77,7 @@ void format_emacs_posts::operator()(post_t& post)
|
|||
out << "\n";
|
||||
}
|
||||
|
||||
out << " (" << (post.pos->beg_line + 1) << " ";
|
||||
out << " (" << post.pos->beg_line << " ";
|
||||
out << "\"" << post.reported_account()->fullname() << "\" \""
|
||||
<< post.amount << "\"";
|
||||
|
||||
|
|
|
|||
|
|
@ -871,9 +871,11 @@ void forecast_posts::flush()
|
|||
date_t next = *(*least).first.next;
|
||||
assert(next > begin);
|
||||
|
||||
if ((next - last).days() > 365 * 5) {
|
||||
if (static_cast<std::size_t>((next - last).days()) >
|
||||
static_cast<std::size_t>(365U) * forecast_years) {
|
||||
DEBUG("filters.forecast",
|
||||
"Forecast transaction exceeds 5 years beyond today");
|
||||
"Forecast transaction exceeds " << forecast_years
|
||||
<< " years beyond today");
|
||||
pending_posts.erase(least);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -764,16 +764,19 @@ public:
|
|||
*/
|
||||
class forecast_posts : public generate_posts
|
||||
{
|
||||
item_predicate pred;
|
||||
scope_t& context;
|
||||
item_predicate pred;
|
||||
scope_t& context;
|
||||
const std::size_t forecast_years;
|
||||
|
||||
public:
|
||||
forecast_posts(post_handler_ptr handler,
|
||||
const item_predicate& predicate,
|
||||
scope_t& _context)
|
||||
: generate_posts(handler), pred(predicate), context(_context) {
|
||||
scope_t& _context,
|
||||
const std::size_t _forecast_years)
|
||||
: generate_posts(handler), pred(predicate), context(_context),
|
||||
forecast_years(_forecast_years) {
|
||||
TRACE_CTOR(forecast_posts,
|
||||
"post_handler_ptr, const item_predicate&, scope_t&");
|
||||
"post_handler_ptr, item_predicate, scope_t&, std::size_t");
|
||||
}
|
||||
virtual ~forecast_posts() throw() {
|
||||
TRACE_DTOR(forecast_posts);
|
||||
|
|
|
|||
27
src/item.cc
27
src/item.cc
|
|
@ -32,6 +32,7 @@
|
|||
#include <system.hh>
|
||||
|
||||
#include "item.h"
|
||||
#include "interactive.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -210,15 +211,31 @@ namespace {
|
|||
return item.has_tag(args[0].as_string());
|
||||
else if (args[0].is_mask())
|
||||
return item.has_tag(args[0].as_mask());
|
||||
} else {
|
||||
return item.has_tag(args[0].to_mask(), args[1].to_mask());
|
||||
else
|
||||
throw_(std::logic_error,
|
||||
_("Expected string for argument 1, but received %1")
|
||||
<< args[0].label());
|
||||
}
|
||||
else if (args.size() == 2) {
|
||||
if (args[0].is_mask() && args[1].is_mask())
|
||||
return item.has_tag(args[0].to_mask(), args[1].to_mask());
|
||||
else
|
||||
throw_(std::logic_error,
|
||||
_("Expected masks for arguments 1 and 2, but received %1 and %2")
|
||||
<< args[0].label() << args[1].label());
|
||||
}
|
||||
else if (args.size() == 0) {
|
||||
throw_(std::logic_error, _("Too few arguments to function"));
|
||||
}
|
||||
else {
|
||||
throw_(std::logic_error, _("Too many arguments to function"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
value_t get_tag(call_scope_t& args) {
|
||||
item_t& item(find_scope<item_t>(args));
|
||||
if (optional<string> value = item.get_tag(args[0].as_string()))
|
||||
value_t get_tag(call_scope_t& scope) {
|
||||
in_context_t<item_t> env(scope, "s");
|
||||
if (optional<string> value = env->get_tag(env.get<string>(0)))
|
||||
return string_value(*value);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,37 +90,48 @@ void posts_commodities_iterator::reset(journal_t& journal)
|
|||
std::map<string, xact_t *> xacts_by_commodity;
|
||||
|
||||
foreach (commodity_t * comm, commodities) {
|
||||
optional<commodity_t::varied_history_t&> history = comm->varied_history();
|
||||
if (! history)
|
||||
continue;
|
||||
if (optional<commodity_t::varied_history_t&> history =
|
||||
comm->varied_history()) {
|
||||
account_t * account = journal.master->find_account(comm->symbol());
|
||||
|
||||
account_t * account = journal.master->find_account(comm->symbol());
|
||||
foreach (commodity_t::base_t::history_by_commodity_map::value_type pair,
|
||||
history->histories) {
|
||||
foreach (commodity_t::base_t::history_map::value_type hpair,
|
||||
pair.second.prices) {
|
||||
xact_t * xact;
|
||||
string symbol = hpair.second.commodity().symbol();
|
||||
|
||||
foreach (commodity_t::base_t::history_by_commodity_map::value_type pair,
|
||||
history->histories) {
|
||||
foreach (commodity_t::base_t::history_map::value_type hpair,
|
||||
pair.second.prices) {
|
||||
xact_t * xact;
|
||||
string symbol = hpair.second.commodity().symbol();
|
||||
std::map<string, xact_t *>::iterator i =
|
||||
xacts_by_commodity.find(symbol);
|
||||
if (i != xacts_by_commodity.end()) {
|
||||
xact = (*i).second;
|
||||
} else {
|
||||
xact = &temps.create_xact();
|
||||
xact_temps.push_back(xact);
|
||||
xact->payee = symbol;
|
||||
xact->_date = hpair.first.date();
|
||||
xacts_by_commodity.insert
|
||||
(std::pair<string, xact_t *>(symbol, xact));
|
||||
}
|
||||
|
||||
std::map<string, xact_t *>::iterator i =
|
||||
xacts_by_commodity.find(symbol);
|
||||
if (i != xacts_by_commodity.end()) {
|
||||
xact = (*i).second;
|
||||
} else {
|
||||
xact = &temps.create_xact();
|
||||
xact_temps.push_back(xact);
|
||||
xact->payee = symbol;
|
||||
xact->_date = hpair.first.date();
|
||||
xacts_by_commodity.insert
|
||||
(std::pair<string, xact_t *>(symbol, xact));
|
||||
bool post_already_exists = false;
|
||||
|
||||
foreach (post_t * post, xact->posts) {
|
||||
if (post->_date == hpair.first.date() &&
|
||||
post->amount == hpair.second) {
|
||||
post_already_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! post_already_exists) {
|
||||
post_t& temp = temps.create_post(*xact, account);
|
||||
temp._date = hpair.first.date();
|
||||
temp.amount = hpair.second;
|
||||
|
||||
temp.xdata().datetime = hpair.first;
|
||||
}
|
||||
}
|
||||
|
||||
post_t& temp = temps.create_post(*xact, account);
|
||||
temp._date = hpair.first.date();
|
||||
temp.amount = hpair.second;
|
||||
|
||||
temp.xdata().datetime = hpair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
src/main.cc
14
src/main.cc
|
|
@ -76,11 +76,13 @@ int main(int argc, char * argv[], char * envp[])
|
|||
::textdomain("ledger");
|
||||
#endif
|
||||
|
||||
// Create the session object, which maintains nearly all state relating to
|
||||
// this invocation of Ledger; and register all known journal parsers.
|
||||
std::auto_ptr<global_scope_t> global_scope(new global_scope_t(envp));
|
||||
std::auto_ptr<global_scope_t> global_scope;
|
||||
|
||||
try {
|
||||
// Create the session object, which maintains nearly all state relating to
|
||||
// this invocation of Ledger; and register all known journal parsers.
|
||||
global_scope.reset(new global_scope_t(envp));
|
||||
|
||||
global_scope->session().set_flush_on_next_data_file(true);
|
||||
|
||||
// Construct an STL-style argument list from the process command arguments
|
||||
|
|
@ -181,7 +183,11 @@ int main(int argc, char * argv[], char * envp[])
|
|||
}
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
global_scope->report_error(err);
|
||||
if (global_scope.get())
|
||||
global_scope->report_error(err);
|
||||
else
|
||||
std::cerr << "Exception during initialization: " << err.what()
|
||||
<< std::endl;
|
||||
}
|
||||
catch (int _status) {
|
||||
status = _status; // used for a "quick" exit, and is used only
|
||||
|
|
|
|||
|
|
@ -116,13 +116,16 @@ void process_environment(const char ** envp, const string& tag,
|
|||
const char * tag_p = tag.c_str();
|
||||
string::size_type tag_len = tag.length();
|
||||
|
||||
assert(tag_p);
|
||||
assert(tag_len > 0);
|
||||
|
||||
for (const char ** p = envp; *p; p++) {
|
||||
if (! tag_p || std::strncmp(*p, tag_p, tag_len) == 0) {
|
||||
char buf[128];
|
||||
if (std::strlen(*p) >= tag_len && std::strncmp(*p, tag_p, tag_len) == 0) {
|
||||
char buf[8192];
|
||||
char * r = buf;
|
||||
const char * q;
|
||||
for (q = *p + tag_len;
|
||||
*q && *q != '=' && r - buf < 128;
|
||||
*q && *q != '=' && r - buf < 8191;
|
||||
q++)
|
||||
if (*q == '_')
|
||||
*r++ = '-';
|
||||
|
|
|
|||
15
src/option.h
15
src/option.h
|
|
@ -162,10 +162,21 @@ public:
|
|||
|
||||
virtual void handler(call_scope_t& args) {
|
||||
if (wants_arg) {
|
||||
if (args.empty() || args.size() == 1)
|
||||
if (args.size() < 2)
|
||||
throw_(std::runtime_error, _("No argument provided for %1") << desc());
|
||||
else if (args.size() > 2)
|
||||
throw_(std::runtime_error, _("To many arguments provided for %1") << desc());
|
||||
else if (! args[0].is_string())
|
||||
throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
|
||||
on_with(args[0].as_string(), args[1]);
|
||||
} else {
|
||||
}
|
||||
else if (args.size() < 1) {
|
||||
throw_(std::runtime_error, _("No argument provided for %1") << desc());
|
||||
}
|
||||
else if (! args[0].is_string()) {
|
||||
throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
|
||||
}
|
||||
else {
|
||||
on_only(args[0].as_string());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,12 +235,13 @@ value_t report_t::fn_justify(call_scope_t& scope)
|
|||
return string_value(out.str());
|
||||
}
|
||||
|
||||
value_t report_t::fn_quoted(call_scope_t& args)
|
||||
value_t report_t::fn_quoted(call_scope_t& scope)
|
||||
{
|
||||
interactive_t args(scope, "s");
|
||||
std::ostringstream out;
|
||||
|
||||
out << '"';
|
||||
foreach (const char ch, args[0].to_string()) {
|
||||
foreach (const char ch, args.get<string>(0)) {
|
||||
if (ch == '"')
|
||||
out << "\\\"";
|
||||
else
|
||||
|
|
@ -253,8 +254,7 @@ value_t report_t::fn_quoted(call_scope_t& args)
|
|||
|
||||
value_t report_t::fn_join(call_scope_t& scope)
|
||||
{
|
||||
interactive_t args(scope, "s");
|
||||
|
||||
interactive_t args(scope, "s");
|
||||
std::ostringstream out;
|
||||
|
||||
foreach (const char ch, args.get<string>(0)) {
|
||||
|
|
@ -315,6 +315,39 @@ value_t report_t::fn_price(call_scope_t& scope)
|
|||
return args.value_at(0).price();
|
||||
}
|
||||
|
||||
value_t report_t::fn_lot_date(call_scope_t& scope)
|
||||
{
|
||||
interactive_t args(scope, "v");
|
||||
if (args.value_at(0).is_annotated()) {
|
||||
const annotation_t& details(args.value_at(0).annotation());
|
||||
if (details.date)
|
||||
return *details.date;
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t report_t::fn_lot_price(call_scope_t& scope)
|
||||
{
|
||||
interactive_t args(scope, "v");
|
||||
if (args.value_at(0).is_annotated()) {
|
||||
const annotation_t& details(args.value_at(0).annotation());
|
||||
if (details.price)
|
||||
return *details.price;
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t report_t::fn_lot_tag(call_scope_t& scope)
|
||||
{
|
||||
interactive_t args(scope, "v");
|
||||
if (args.value_at(0).is_annotated()) {
|
||||
const annotation_t& details(args.value_at(0).annotation());
|
||||
if (details.tag)
|
||||
return string_value(*details.tag);
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
namespace {
|
||||
value_t fn_black(call_scope_t&) {
|
||||
return string_value("black");
|
||||
|
|
@ -559,6 +592,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
|||
case 'f':
|
||||
OPT(flat);
|
||||
else OPT_ALT(forecast_while_, forecast_);
|
||||
else OPT(forecast_years_);
|
||||
else OPT(format_);
|
||||
else OPT(force_color);
|
||||
else OPT(force_pager);
|
||||
|
|
|
|||
|
|
@ -160,6 +160,9 @@ public:
|
|||
value_t fn_ansify_if(call_scope_t& scope);
|
||||
value_t fn_percent(call_scope_t& scope);
|
||||
value_t fn_price(call_scope_t& scope);
|
||||
value_t fn_lot_date(call_scope_t& scope);
|
||||
value_t fn_lot_price(call_scope_t& scope);
|
||||
value_t fn_lot_tag(call_scope_t& scope);
|
||||
|
||||
value_t fn_now(call_scope_t&) {
|
||||
return terminus;
|
||||
|
|
@ -240,6 +243,7 @@ public:
|
|||
HANDLER(force_color).report(out);
|
||||
HANDLER(force_pager).report(out);
|
||||
HANDLER(forecast_while_).report(out);
|
||||
HANDLER(forecast_years_).report(out);
|
||||
HANDLER(format_).report(out);
|
||||
HANDLER(gain).report(out);
|
||||
HANDLER(head_).report(out);
|
||||
|
|
@ -544,6 +548,7 @@ public:
|
|||
OPTION(report_t, force_color);
|
||||
OPTION(report_t, force_pager);
|
||||
OPTION(report_t, forecast_while_);
|
||||
OPTION(report_t, forecast_years_);
|
||||
OPTION(report_t, format_); // -F
|
||||
|
||||
OPTION_(report_t, gain, DO() { // -G
|
||||
|
|
|
|||
|
|
@ -146,9 +146,11 @@ std::size_t session_t::read_data(const string& master_account)
|
|||
cache->should_load(HANDLER(file_).data_files) &&
|
||||
cache->load(journal))) {
|
||||
if (price_db_path) {
|
||||
if (exists(*price_db_path) && read_journal(*price_db_path) > 0)
|
||||
throw_(parse_error, _("Transactions not allowed in price history file"));
|
||||
journal->sources.push_back(journal_t::fileinfo_t(*price_db_path));
|
||||
if (exists(*price_db_path)) {
|
||||
if (read_journal(*price_db_path) > 0)
|
||||
throw_(parse_error, _("Transactions not allowed in price history file"));
|
||||
journal->sources.push_back(journal_t::fileinfo_t(*price_db_path));
|
||||
}
|
||||
HANDLER(file_).data_files.remove(*price_db_path);
|
||||
}
|
||||
|
||||
|
|
|
|||
18
src/utils.h
18
src/utils.h
|
|
@ -580,6 +580,15 @@ inline char peek_next_nonws(std::istream& in) {
|
|||
str.get(var); \
|
||||
if (in.eof()) \
|
||||
break; \
|
||||
switch (var) { \
|
||||
case 'b': var = '\b'; break; \
|
||||
case 'f': var = '\f'; break; \
|
||||
case 'n': var = '\n'; break; \
|
||||
case 'r': var = '\r'; break; \
|
||||
case 't': var = '\t'; break; \
|
||||
case 'v': var = '\v'; break; \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
*_p++ = var; \
|
||||
var = static_cast<char>(str.peek()); \
|
||||
|
|
@ -600,6 +609,15 @@ inline char peek_next_nonws(std::istream& in) {
|
|||
str.get(var); \
|
||||
if (in.eof()) \
|
||||
break; \
|
||||
switch (var) { \
|
||||
case 'b': var = '\b'; break; \
|
||||
case 'f': var = '\f'; break; \
|
||||
case 'n': var = '\n'; break; \
|
||||
case 'r': var = '\r'; break; \
|
||||
case 't': var = '\t'; break; \
|
||||
case 'v': var = '\v'; break; \
|
||||
default: break; \
|
||||
} \
|
||||
idx++; \
|
||||
} \
|
||||
*_p++ = var; \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue