summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2004-08-18 01:20:01 -0400
committerJohn Wiegley <johnw@newartisans.com>2004-08-18 01:20:01 -0400
commit9d1bdd0989996318825a458e01b7b0eb5f48397f (patch)
treef836fccb1548a4891718295ff6e04c94eb697e75
parent5ab3b21396c68aea35b2ab441e9fca9dca3f2370 (diff)
downloadfork-ledger-9d1bdd0989996318825a458e01b7b0eb5f48397f.tar.gz
fork-ledger-9d1bdd0989996318825a458e01b7b0eb5f48397f.tar.bz2
fork-ledger-9d1bdd0989996318825a458e01b7b0eb5f48397f.zip
added inclusion specifiers: -z june, -z 2004, -z "monthly in 2003", etc.
-rw-r--r--config.cc10
-rw-r--r--datetime.cc122
-rw-r--r--datetime.h3
-rw-r--r--main.cc53
4 files changed, 129 insertions, 59 deletions
diff --git a/config.cc b/config.cc
index ddacbc32..7fec3f4d 100644
--- a/config.cc
+++ b/config.cc
@@ -160,23 +160,23 @@ OPT_BEGIN(set_price, "p:") {
OPT_BEGIN(begin_date, "b:") {
if (! config->predicate.empty())
config->predicate += "&";
- config->predicate += "(d>=[";
+ config->predicate += "d>=[";
config->predicate += optarg;
- config->predicate += "])";
+ config->predicate += "]";
} OPT_END(begin_date);
OPT_BEGIN(end_date, "e:") {
if (! config->predicate.empty())
config->predicate += "&";
- config->predicate += "(d<[";
+ config->predicate += "d<[";
config->predicate += optarg;
- config->predicate += "])";
+ config->predicate += "]";
} OPT_END(end_date);
OPT_BEGIN(current, "c") {
if (! config->predicate.empty())
config->predicate += "&";
- config->predicate += "(d<=N)";
+ config->predicate += "d<=N";
} OPT_END(current);
OPT_BEGIN(cleared, "C") {
diff --git a/datetime.cc b/datetime.cc
index 4f6cf0d3..baa0bd2c 100644
--- a/datetime.cc
+++ b/datetime.cc
@@ -1,4 +1,5 @@
#include "datetime.h"
+#include "error.h"
#include <ctime>
@@ -51,56 +52,109 @@ std::time_t interval_t::increment(const std::time_t moment)
return then + seconds;
}
-interval_t * interval_t::parse(std::istream& in)
+static void parse_inclusion_specifier(const std::string& word,
+ std::time_t * begin,
+ std::time_t * end)
+{
+ struct std::tm when;
+
+ if (! parse_date_mask(word.c_str(), &when))
+ throw interval_expr_error("Could not parse 'in' date mask");
+
+ when.tm_hour = 0;
+ when.tm_min = 0;
+ when.tm_sec = 0;
+
+ bool saw_year = true;
+ bool saw_mon = true;
+
+ if (when.tm_year == -1) {
+ when.tm_year = now_tm->tm_year;
+ saw_year = false;
+ }
+ if (when.tm_mon == -1) {
+ when.tm_mon = 0;
+ saw_mon = false;
+ }
+ if (when.tm_mday == -1)
+ when.tm_mday = 1;
+
+ *begin = std::mktime(&when);
+ *end = interval_t(0, saw_mon ? 1 : 0, saw_year ? 1 : 0).increment(*begin);
+}
+
+interval_t * interval_t::parse(std::istream& in,
+ std::time_t * begin,
+ std::time_t * end)
{
unsigned long years = 0;
unsigned long months = 0;
unsigned long seconds = 0;
std::string word;
- in >> word;
- if (word == "every") {
+ while (! in.eof()) {
in >> word;
- if (std::isdigit(word[0])) {
- int quantity = std::atol(word.c_str());
+ if (word == "every") {
in >> word;
- if (word == "days")
- seconds = 86400 * quantity;
- else if (word == "weeks")
- seconds = 7 * 86400 * quantity;
- else if (word == "months")
- months = quantity;
- else if (word == "quarters")
- months = 3 * quantity;
- else if (word == "years")
- years = quantity;
+ if (std::isdigit(word[0])) {
+ int quantity = std::atol(word.c_str());
+ in >> word;
+ if (word == "days")
+ seconds = 86400 * quantity;
+ else if (word == "weeks")
+ seconds = 7 * 86400 * quantity;
+ else if (word == "months")
+ months = quantity;
+ else if (word == "quarters")
+ months = 3 * quantity;
+ else if (word == "years")
+ years = quantity;
+ }
+ else if (word == "day")
+ seconds = 86400;
+ else if (word == "week")
+ seconds = 7 * 86400;
+ else if (word == "monthly")
+ months = 1;
+ else if (word == "quarter")
+ months = 3;
+ else if (word == "year")
+ years = 1;
}
- else if (word == "day")
+ else if (word == "daily")
seconds = 86400;
- else if (word == "week")
+ else if (word == "weekly")
seconds = 7 * 86400;
+ else if (word == "biweekly")
+ seconds = 14 * 86400;
else if (word == "monthly")
months = 1;
- else if (word == "quarter")
+ else if (word == "bimonthly")
+ months = 2;
+ else if (word == "quarterly")
months = 3;
- else if (word == "year")
+ else if (word == "yearly")
years = 1;
+ else if (word == "in") {
+ in >> word;
+ parse_inclusion_specifier(word, begin, end);
+ }
+ else if (word == "from") {
+ in >> word;
+ if (! parse_date(word.c_str(), begin))
+ throw interval_expr_error("Could not parse 'from' date");
+ if (! in.eof())
+ in >> word;
+ }
+ else if (word == "to") {
+ in >> word;
+ if (! parse_date(word.c_str(), end))
+ throw interval_expr_error("Could not parse 'to' date");
+ }
+ else {
+ parse_inclusion_specifier(word, begin, end);
+ }
}
- else if (word == "daily")
- seconds = 86400;
- else if (word == "weekly")
- seconds = 7 * 86400;
- else if (word == "biweekly")
- seconds = 14 * 86400;
- else if (word == "monthly")
- months = 1;
- else if (word == "bimonthly")
- months = 2;
- else if (word == "quarterly")
- months = 3;
- else if (word == "yearly")
- years = 1;
-
return new interval_t(seconds, months, years);
}
diff --git a/datetime.h b/datetime.h
index d546dbaa..bc32032a 100644
--- a/datetime.h
+++ b/datetime.h
@@ -19,7 +19,8 @@ struct interval_t
std::time_t increment(const std::time_t);
- static interval_t * parse(std::istream& in);
+ static interval_t * parse(std::istream& in, std::time_t * begin,
+ std::time_t * end);
};
extern std::time_t now;
diff --git a/main.cc b/main.cc
index d7f71b7f..6e0bb524 100644
--- a/main.cc
+++ b/main.cc
@@ -295,12 +295,6 @@ int main(int argc, char * argv[], char * envp[])
}
}
-#ifdef DEBUG_ENABLED
- DEBUG_PRINT("ledger.main.predicates", "predicate: " << config->predicate);
- DEBUG_PRINT("ledger.main.predicates",
- "disp-pred: " << config->display_predicate);
-#endif
-
// Compile the sorting criteria
std::auto_ptr<value_expr_t> sort_order;
@@ -418,26 +412,47 @@ int main(int argc, char * argv[], char * envp[])
#define OUT() (output_stream.get() ? *output_stream : std::cout)
if (! config->interval_text.empty()) {
- std::istringstream stream(config->interval_text);
- report_interval.reset(interval_t::parse(stream));
- if (! stream.eof()) {
- std::string word;
- stream >> word;
- if (word == "from") {
- stream >> word;
- if (! parse_date(word.c_str(), &interval_begin)) {
- std::cerr << "Error in report interval: "
- << "Could not parse 'from' date"
- << std::endl;
- return 1;
- }
+ try {
+ std::istringstream stream(config->interval_text);
+ std::time_t begin = -1, end = -1;
+ report_interval.reset(interval_t::parse(stream, &begin, &end));
+ if (report_interval->seconds == 0 &&
+ report_interval->months == 0 &&
+ report_interval->years == 0)
+ report_interval.release();
+
+ if (begin != -1) {
+ if (! config->predicate.empty())
+ config->predicate += "&";
+ char buf[32];
+ std::sprintf(buf, "d>=%lu", begin);
+ config->predicate += buf;
+ }
+
+ if (end != -1) {
+ if (! config->predicate.empty())
+ config->predicate += "&";
+ char buf[32];
+ std::sprintf(buf, "d<%lu", end);
+ config->predicate += buf;
}
}
+ catch (const interval_expr_error& err) {
+ std::cerr << "Error in interval (-z) specifier: " << err.what()
+ << std::endl;
+ return 1;
+ }
}
if (! config->date_format.empty())
format_t::date_format = config->date_format;
+#ifdef DEBUG_ENABLED
+ DEBUG_PRINT("ledger.main.predicates", "predicate: " << config->predicate);
+ DEBUG_PRINT("ledger.main.predicates",
+ "disp-pred: " << config->display_predicate);
+#endif
+
// Walk the entries based on the report type and the options
TIMER_START(report_gen);