summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/journal.cc78
-rw-r--r--src/journal.h4
-rw-r--r--src/pstream.h5
-rw-r--r--src/session.cc11
-rw-r--r--src/session.h4
-rw-r--r--src/textual.cc5
-rw-r--r--src/wcwidth.cc4
7 files changed, 89 insertions, 22 deletions
diff --git a/src/journal.cc b/src/journal.cc
index a014a964..160abe06 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -96,6 +96,7 @@ void journal_t::initialize()
check_payees = false;
day_break = false;
checking_style = CHECK_PERMISSIVE;
+ recursive_aliases = false;
}
void journal_t::add_account(account_t * acct)
@@ -121,26 +122,9 @@ account_t * journal_t::find_account_re(const string& regexp)
account_t * journal_t::register_account(const string& name, post_t * post,
account_t * master_account)
{
- account_t * result = NULL;
-
- // If there any account aliases, substitute before creating an account
+ // If there are any account aliases, substitute before creating an account
// object.
- if (account_aliases.size() > 0) {
- accounts_map::const_iterator i = account_aliases.find(name);
- if (i != account_aliases.end()) {
- result = (*i).second;
- } else {
- // only check the very first account for alias expansion, in case
- // that can be expanded successfully
- size_t colon = name.find(':');
- if(colon != string::npos) {
- accounts_map::const_iterator j = account_aliases.find(name.substr(0, colon));
- if (j != account_aliases.end()) {
- result = find_account((*j).second->fullname() + name.substr(colon));
- }
- }
- }
- }
+ account_t * result = expand_aliases(name);
// Create the account object and associate it with the journal; this
// is registering the account.
@@ -178,7 +162,63 @@ account_t * journal_t::register_account(const string& name, post_t * post,
}
}
}
+ return result;
+}
+
+account_t * journal_t::expand_aliases(string name) {
+ // Aliases are expanded recursively, so if both alias Foo=Bar:Foo and
+ // alias Bar=Baaz:Bar are in effect, first Foo will be expanded to Bar:Foo,
+ // then Bar:Foo will be expanded to Baaz:Bar:Foo.
+ // The expansion loop keeps a list of already expanded names in order to
+ // prevent infinite excursion. Each alias may only be expanded at most once.
+ account_t * result = NULL;
+ if(no_aliases)
+ return result;
+
+ bool keep_expanding = true;
+ std::list<string> already_seen;
+ // loop until no expansion can be found
+ do {
+ if (account_aliases.size() > 0) {
+ accounts_map::const_iterator i = account_aliases.find(name);
+ if (i != account_aliases.end()) {
+ if(std::find(already_seen.begin(), already_seen.end(), name) != already_seen.end()) {
+ throw_(std::runtime_error,
+ _f("Infinite recursion on alias expansion for %1%")
+ % name);
+ }
+ // there is an alias for the full account name, including colons
+ already_seen.push_back(name);
+ result = (*i).second;
+ name = result->fullname();
+ } else {
+ // only check the very first account for alias expansion, in case
+ // that can be expanded successfully
+ size_t colon = name.find(':');
+ if(colon != string::npos) {
+ string first_account_name = name.substr(0, colon);
+ accounts_map::const_iterator j = account_aliases.find(first_account_name);
+ if (j != account_aliases.end()) {
+ if(std::find(already_seen.begin(), already_seen.end(), first_account_name) != already_seen.end()) {
+ throw_(std::runtime_error,
+ _f("Infinite recursion on alias expansion for %1%")
+ % first_account_name);
+ }
+ already_seen.push_back(first_account_name);
+ result = find_account((*j).second->fullname() + name.substr(colon));
+ name = result->fullname();
+ } else {
+ keep_expanding = false;
+ }
+ } else {
+ keep_expanding = false;
+ }
+ }
+ } else {
+ keep_expanding = false;
+ }
+ } while(keep_expanding && recursive_aliases);
return result;
}
diff --git a/src/journal.h b/src/journal.h
index 0d06e9f0..e4763482 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -131,6 +131,8 @@ public:
bool force_checking;
bool check_payees;
bool day_break;
+ bool recursive_aliases;
+ bool no_aliases;
payee_mappings_t payee_mappings;
account_mappings_t account_mappings;
accounts_map account_aliases;
@@ -167,6 +169,8 @@ public:
account_t * find_account(const string& name, bool auto_create = true);
account_t * find_account_re(const string& regexp);
+ account_t * expand_aliases(string name);
+
account_t * register_account(const string& name, post_t * post,
account_t * master = NULL);
string register_payee(const string& name, xact_t * xact);
diff --git a/src/pstream.h b/src/pstream.h
index bcbf6755..ed314068 100644
--- a/src/pstream.h
+++ b/src/pstream.h
@@ -83,7 +83,10 @@ class ptristream : public std::istream
virtual pos_type seekoff(off_type off, ios_base::seekdir way,
ios_base::openmode)
{
- switch (way) {
+ // cast to avoid gcc '-Wswitch' warning
+ // as ios_base::beg/cur/end are not necesssarily values of 'way' enum type ios_base::seekdir
+ // based on https://svn.boost.org/trac/boost/ticket/7644
+ switch (static_cast<int>(way)) {
case std::ios::cur:
setg(ptr, gptr()+off, ptr+len);
break;
diff --git a/src/session.cc b/src/session.cc
index dbd49a0e..b386607a 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -113,6 +113,11 @@ std::size_t session_t::read_data(const string& master_account)
if (HANDLED(day_break))
journal->day_break = true;
+ if (HANDLED(recursive_aliases))
+ journal->recursive_aliases = true;
+ if (HANDLED(no_aliases))
+ journal->no_aliases = true;
+
if (HANDLED(permissive))
journal->checking_style = journal_t::CHECK_PERMISSIVE;
else if (HANDLED(pedantic))
@@ -344,12 +349,18 @@ option_t<session_t> * session_t::lookup_option(const char * p)
case 'm':
OPT(master_account_);
break;
+ case 'n':
+ OPT(no_aliases);
+ break;
case 'p':
OPT(price_db_);
else OPT(price_exp_);
else OPT(pedantic);
else OPT(permissive);
break;
+ case 'r':
+ OPT(recursive_aliases);
+ break;
case 's':
OPT(strict);
break;
diff --git a/src/session.h b/src/session.h
index 3572b991..d20ba74a 100644
--- a/src/session.h
+++ b/src/session.h
@@ -109,6 +109,8 @@ public:
HANDLER(permissive).report(out);
HANDLER(price_db_).report(out);
HANDLER(price_exp_).report(out);
+ HANDLER(recursive_aliases).report(out);
+ HANDLER(no_aliases).report(out);
HANDLER(strict).report(out);
HANDLER(value_expr_).report(out);
}
@@ -164,6 +166,8 @@ public:
OPTION(session_t, price_db_);
OPTION(session_t, strict);
OPTION(session_t, value_expr_);
+ OPTION(session_t, recursive_aliases);
+ OPTION(session_t, no_aliases);
};
/**
diff --git a/src/textual.cc b/src/textual.cc
index d8648c93..627a1835 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -977,6 +977,11 @@ void instance_t::account_alias_directive(account_t * account, string alias)
// (account), add a reference to the account in the `account_aliases'
// map, which is used by the post parser to resolve alias references.
trim(alias);
+ // Ensure that no alias like "alias Foo=Foo" is registered.
+ if ( alias == account->fullname()) {
+ throw_(parse_error, _f("Illegal alias %1%=%2%")
+ % alias % account->fullname());
+ }
std::pair<accounts_map::iterator, bool> result =
context.journal->account_aliases.insert
(accounts_map::value_type(alias, account));
diff --git a/src/wcwidth.cc b/src/wcwidth.cc
index 71eaf6d6..c23f83d7 100644
--- a/src/wcwidth.cc
+++ b/src/wcwidth.cc
@@ -69,8 +69,8 @@ namespace ledger {
namespace {
struct interval {
- int first;
- int last;
+ boost::uint32_t first;
+ boost::uint32_t last;
};
}