diff options
-rw-r--r-- | config.cc | 10 | ||||
-rw-r--r-- | datetime.cc | 122 | ||||
-rw-r--r-- | datetime.h | 3 | ||||
-rw-r--r-- | main.cc | 53 |
4 files changed, 129 insertions, 59 deletions
@@ -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); } @@ -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; @@ -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); |