summaryrefslogtreecommitdiff
path: root/constraint.cc
diff options
context:
space:
mode:
Diffstat (limited to 'constraint.cc')
-rw-r--r--constraint.cc219
1 files changed, 219 insertions, 0 deletions
diff --git a/constraint.cc b/constraint.cc
new file mode 100644
index 00000000..1248c2b1
--- /dev/null
+++ b/constraint.cc
@@ -0,0 +1,219 @@
+#include "constraint.h"
+
+#include <pcre.h>
+
+namespace ledger {
+
+mask_t::mask_t(const std::string& pat) : exclude(false)
+{
+ const char * p = pat.c_str();
+ if (*p == '-') {
+ exclude = true;
+ p++;
+ while (std::isspace(*p))
+ p++;
+ }
+ else if (*p == '+') {
+ p++;
+ while (std::isspace(*p))
+ p++;
+ }
+ pattern = p;
+
+ const char *error;
+ int erroffset;
+ regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
+ &error, &erroffset, NULL);
+ if (! regexp)
+ std::cerr << "Warning: Failed to compile regexp: " << pattern
+ << std::endl;
+}
+
+mask_t::mask_t(const mask_t& m) : exclude(m.exclude), pattern(m.pattern)
+{
+ const char *error;
+ int erroffset;
+ regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
+ &error, &erroffset, NULL);
+ assert(regexp);
+}
+
+bool mask_t::match(const std::string& str) const
+{
+ static int ovec[30];
+ int result = pcre_exec((pcre *)regexp, NULL,
+ str.c_str(), str.length(), 0, 0, ovec, 30);
+ return result >= 0 && ! exclude;
+}
+
+mask_t::~mask_t() {
+ pcre_free((pcre *)regexp);
+}
+
+bool matches(const masks_list& regexps, const std::string& str,
+ bool * by_exclusion)
+{
+ if (regexps.empty())
+ return false;
+
+ bool match = false;
+ bool definite = false;
+
+ for (masks_list::const_iterator r = regexps.begin();
+ r != regexps.end();
+ r++) {
+ static int ovec[30];
+ int result = pcre_exec((pcre *)(*r).regexp, NULL,
+ str.c_str(), str.length(), 0, 0, ovec, 30);
+ if (result >= 0) {
+ match = ! (*r).exclude;
+ definite = true;
+ }
+ else if ((*r).exclude) {
+ if (! match)
+ match = ! definite;
+ }
+ else {
+ definite = true;
+ }
+ }
+
+ if (by_exclusion)
+ *by_exclusion = match && ! definite && by_exclusion;
+
+ return match;
+}
+
+bool constraints_t::matches_date_range(const std::time_t date) const
+{
+ if (have_beginning && difftime(date, begin_date) < 0)
+ return false;
+
+ if (have_ending && difftime(date, end_date) >= 0)
+ return false;
+
+ if (have_date_mask) {
+ struct std::tm * then = std::gmtime(&date);
+
+ if (date_mask.tm_mon != -1 &&
+ date_mask.tm_mon != then->tm_mon)
+ return false;
+
+ if (date_mask.tm_mday != -1 &&
+ date_mask.tm_mday != then->tm_mday)
+ return false;
+
+#if 0
+ // jww (2003-10-10): This causes only certain days of the week to
+ // print, even when it was not included in the mask.
+ if (date_mask.tm_wday != -1 &&
+ date_mask.tm_wday != then->tm_wday)
+ return false;
+#endif
+
+ if (date_mask.tm_year != -1 &&
+ date_mask.tm_year != then->tm_year)
+ return false;
+ }
+
+ return true;
+}
+
+bool constraints_t::operator ()(const transaction_t * xact) const
+{
+ if ((cleared_only && xact->entry->state != entry_t::CLEARED) ||
+ (uncleared_only && xact->entry->state == entry_t::CLEARED) ||
+ ! matches_date_range(xact->entry->date))
+ return false;
+
+ if (! payee_masks.empty() &&
+ (! (matches(payee_masks, xact->entry->payee)
+ //|| matches(payee_masks, xact->entry->code))
+ )))
+ return false;
+
+ if (real_only && xact->flags & TRANSACTION_VIRTUAL)
+ return false;
+
+ if (! account_masks.empty() &&
+ ! (matches(account_masks, std::string(*(xact->account)))
+ //|| matches(account_masks, (*i)->note)
+ ))
+ return false;
+
+ return true;
+}
+
+bool constraints_t::operator ()(const entry_t * entry) const
+{
+ if ((cleared_only && entry->state != entry_t::CLEARED) ||
+ (uncleared_only && entry->state == entry_t::CLEARED) ||
+ ! matches_date_range(entry->date))
+ return false;
+
+ if (! payee_masks.empty() &&
+ (! (matches(payee_masks, entry->payee)
+ //|| matches(payee_masks, entry->code)
+ )))
+ return false;
+
+ if (! account_masks.empty()) {
+ bool match = false;
+
+ for (transactions_list::const_iterator i = entry->transactions.begin();
+ i != entry->transactions.end();
+ i++) {
+ if (real_only && (*i)->flags & TRANSACTION_VIRTUAL)
+ continue;
+
+ if (matches(account_masks, std::string(*((*i)->account)))
+ //|| matches(account_masks, (*i)->note)
+ ) {
+ match = true;
+ break;
+ }
+ }
+
+ if (! match)
+ return false;
+ }
+
+ return true;
+}
+
+bool constraints_t::operator ()(const item_t * item) const
+{
+ if (predicate && ! predicate->compute(begin(), end(), item))
+ return false;
+
+ if (! matches_date_range(item->date))
+ return false;
+
+ if (! payee_masks.empty() &&
+ ! (matches(payee_masks, item->payee)))
+ return false;
+
+#if 0
+ if (! account_masks.empty()) {
+ bool match = false;
+
+ for (amounts_map::const_iterator i = item->value.quantity.amounts.begin();
+ i != item->value.quantity.amounts.end();
+ i++) {
+ if (matches(account_masks, std::string(*((*i)->account)))
+ //|| matches(account_masks, (*i)->note)
+ ) {
+ match = true;
+ break;
+ }
+ }
+
+ if (! match)
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+} // namespace ledger