From 620c4eeca5cd1dda90a26527aa6d782edb1b5271 Mon Sep 17 00:00:00 2001 From: Lars Henriksen Date: Sat, 1 Dec 2018 19:54:14 +0100 Subject: CLI: Revert to and update of parse_datetimearg() An earlier commit ("CLI: take input date format from configuration file, do not accept time") replaced parse_datetimearg() with parse_datearg() and eliminated time-of-day from command line date arguments. This made the full use of filter options impossible. That earlier commit is reverted and updated. The parse_datearg() function is replaced by an updated parse_datetimearg() function that - takes the date format from the configuration file - accepts date, date-time or time The updated parse_datetimearg() function has been extended to report back the type of the date string received in order to set (filter) options correctly. Input dates for query ranges (--from, --to, --days) are still limited to dates only. Signed-off-by: Lars Henriksen Signed-off-by: Lukas Fleischer --- src/args.c | 147 +++++++++++++++++++++++++++++++++++------------------- src/calcurse.h | 7 ++- src/ui-calendar.c | 6 +++ 3 files changed, 106 insertions(+), 54 deletions(-) diff --git a/src/args.c b/src/args.c index b1bf5ec..d85e099 100644 --- a/src/args.c +++ b/src/args.c @@ -44,6 +44,14 @@ #include "calcurse.h" +/* Input types for parse_datetimearg() */ +enum { + ARG_DATE, + ARG_DATE_TIME, + ARG_TIME, + ARG_ERR +}; + /* Long options */ enum { OPT_FILTER_TYPE = 1000, @@ -277,23 +285,53 @@ date_arg_from_to(long from, long to, int add_line, const char *fmt_apt, } /* - * Convert a string with a date into the Unix time for midnight of that day. + * Convert a string with a (local time) date, date-time or time into + * the Unix time for that point in time as follows: + * - a date only is converted to midnight (beginning) of that day + * - a date-time is converted to that day and time + * - a time only is converted to that time of the current day * The date format is taken from the user configuration. + * The type of the input string is returned in the type argument. */ -static time_t parse_datearg(const char *str) + +static time_t parse_datetimearg(const char *str, int *type) { + char *date = mem_strdup(str); + *type = ARG_ERR; + char *time; struct date day; - - if (parse_date(str, conf.input_datefmt, - (int *)&day.yyyy, (int *)&day.mm, (int *)&day.dd, NULL)) - return date2sec(day, 0, 0); - else + unsigned hour, min; + time_t ret; + + time = strchr(date, ' '); + if (time) { /* Date and time? */ + *time++ = '\0'; + if (!parse_time(time, &hour, &min)) + return -1; + if (!parse_date(date, conf.input_datefmt, + (int *)&day.yyyy, (int *)&day.mm, (int *)&day.dd, NULL)) + return -1; + ret = date2sec(day, hour, min); + *type = ARG_DATE_TIME; + } else /* Date?*/ if (parse_date(date, conf.input_datefmt, + (int *)&day.yyyy, (int *)&day.mm, (int *)&day.dd, NULL)) { + ret = date2sec(day, 0, 0); + *type = ARG_DATE; + } else /* Time? */ if (parse_time(date, &hour, &min)) { + ret = date2sec(*ui_calendar_get_today(), hour, min); + *type = ARG_TIME; + } else return -1; + return ret; } +/* + * Parse a "from,to" date range. + * For an open-end range no change occurs at the open end. + */ static int parse_daterange(const char *str, time_t *date_from, time_t *date_to) { - int ret = 0; + int type, ret = 0; char *s = mem_strdup(str); char *p = strchr(s, ','); @@ -304,21 +342,17 @@ static int parse_daterange(const char *str, time_t *date_from, time_t *date_to) p++; if (*s != '\0') { - *date_from = parse_datearg(s); + *date_from = parse_datetimearg(s, &type); if (*date_from == -1) goto cleanup; - } else { - *date_from = -1; } if (*p != '\0') { - *date_to = parse_datearg(p); + *date_to = parse_datetimearg(p, &type); if (*date_to == -1) goto cleanup; - /* One second before next midnight. */ - *date_to = date_sec_change(*date_to, 0, 1) - 1; - } else { - *date_to = -1; + if (type == ARG_DATE) + *date_to = ENDOFDAY(*date_to); } ret = 1; @@ -390,7 +424,7 @@ int parse_args(int argc, char **argv) const char *cfile = NULL, *ifile = NULL, *confdir = NULL; int non_interactive = 1; - int ch, cpid; + int ch, cpid, type; regex_t reg; char buf[BUFSIZ]; struct tm tm; @@ -497,9 +531,9 @@ int parse_args(int argc, char **argv) EXIT_IF(range == 0, _("invalid range: %s"), optarg); } else { - from = parse_datearg(optarg); - EXIT_IF(from == -1, _("invalid date: %s"), - optarg); + from = parse_datetimearg(optarg, &type); + EXIT_IF(from == -1 || type != ARG_DATE, + _("invalid date: %s"), optarg); } filter.type_mask |= TYPE_MASK_CAL; @@ -544,8 +578,9 @@ int parse_args(int argc, char **argv) case 's': if (!optarg) optarg = "today"; - from = parse_datearg(optarg); - EXIT_IF(from == -1, _("invalid date: %s"), optarg); + from = parse_datetimearg(optarg, &type); + EXIT_IF(from == -1 || type != ARG_DATE, + _("invalid date: %s"), optarg); filter.type_mask |= TYPE_MASK_CAL; query = 1; break; @@ -606,78 +641,84 @@ int parse_args(int argc, char **argv) filter.regex = ® filter_opt = 1; break; - /* Assume that the date argument is midnight of the given day. */ + /* + * A date only is a time span (a day) and interpreted thus: + * "to" means "to end of day" + * "after" means "from start of next day" + */ case OPT_FILTER_START_FROM: - /* Midnight. */ - filter.start_from = parse_datearg(optarg); + filter.start_from = parse_datetimearg(optarg, &type); EXIT_IF(filter.start_from == -1, _("invalid date: %s"), optarg); filter_opt = 1; break; case OPT_FILTER_START_TO: - filter.start_to = parse_datearg(optarg); + filter.start_to = parse_datetimearg(optarg, &type); EXIT_IF(filter.start_to == -1, _("invalid date: %s"), optarg); - /* Next midnight less one second. */ - filter.start_to = date_sec_change(filter.start_to, 0, 1) - 1; + if (type == ARG_DATE) + filter.start_to = ENDOFDAY(filter.start_to); filter_opt = 1; break; case OPT_FILTER_START_AFTER: - filter.start_from = parse_datearg(optarg); + filter.start_from = parse_datetimearg(optarg, &type); EXIT_IF(filter.start_from == -1, _("invalid date: %s"), optarg); - /* Next midnight (belongs to the next day). */ - filter.start_from = date_sec_change(filter.start_from, 0, 1); + if (type == ARG_DATE) + filter.start_from = NEXTDAY(filter.start_from); + else + filter.start_from++; filter_opt = 1; break; case OPT_FILTER_START_BEFORE: - filter.start_to = parse_datearg(optarg); + filter.start_to = parse_datetimearg(optarg, &type); EXIT_IF(filter.start_to == -1, _("invalid date: %s"), optarg); - /* One second before midnight. */ filter.start_to--; filter_opt = 1; break; case OPT_FILTER_START_RANGE: - EXIT_IF(!parse_daterange(optarg, &filter.start_from, - &filter.start_to), + /* Set initialization values in case of open-end range. */ + filter.start_from = filter.start_to = -1; + EXIT_IF(!parse_daterange(optarg, &filter.start_from, &filter.start_to), _("invalid date range: %s"), optarg); filter_opt = 1; break; case OPT_FILTER_END_FROM: - /* Midnight. */ - filter.end_from = parse_datearg(optarg); + filter.end_from = parse_datetimearg(optarg, &type); EXIT_IF(filter.end_from == -1, _("invalid date: %s"), optarg); filter_opt = 1; break; case OPT_FILTER_END_TO: - filter.end_to = parse_datearg(optarg); + filter.end_to = parse_datetimearg(optarg, &type); EXIT_IF(filter.end_to == -1, _("invalid date: %s"), optarg); - /* Next midnight less one second. */ - filter.end_to = date_sec_change(filter.end_to, 0, 1) - 1; + if (type == ARG_DATE) + filter.end_to = ENDOFDAY(filter.end_to); filter_opt = 1; break; case OPT_FILTER_END_AFTER: - filter.end_from = parse_datearg(optarg); + filter.end_from = parse_datetimearg(optarg, &type); EXIT_IF(filter.end_from == -1, _("invalid date: %s"), optarg); - /* Next midnight (belongs to the next day). */ - filter.end_from = date_sec_change(filter.end_from, 0, 1); + if (type == ARG_DATE) + filter.end_from = NEXTDAY(filter.end_from); + else + filter.end_from++; filter_opt = 1; break; case OPT_FILTER_END_BEFORE: - filter.end_to = parse_datearg(optarg); + filter.end_to = parse_datetimearg(optarg, &type); EXIT_IF(filter.end_to == -1, _("invalid date: %s"), optarg); - /* One second before midnight. */ filter.end_to--; filter_opt = 1; break; case OPT_FILTER_END_RANGE: - EXIT_IF(!parse_daterange(optarg, &filter.end_from, - &filter.end_to), + /* Set default values in case of open-ended range. */ + filter.start_from = filter.start_to = -1; + EXIT_IF(!parse_daterange(optarg, &filter.end_from, &filter.end_to), _("invalid date range: %s"), optarg); filter_opt = 1; break; @@ -696,13 +737,15 @@ int parse_args(int argc, char **argv) filter_opt = 1; break; case OPT_FROM: - from = parse_datearg(optarg); - EXIT_IF(from == -1, _("invalid date: %s"), optarg); + from = parse_datetimearg(optarg, &type); + EXIT_IF(from == -1 || type != ARG_DATE, + _("invalid date: %s"), optarg); query_range = 1; break; case OPT_TO: - to = parse_datearg(optarg); - EXIT_IF(to == -1, _("invalid date: %s"), optarg); + to = parse_datetimearg(optarg, &type); + EXIT_IF(to == -1 || type != ARG_DATE, + _("invalid date: %s"), optarg); query_range = 1; break; case OPT_DAYS: @@ -790,7 +833,7 @@ int parse_args(int argc, char **argv) if (from == -1) from = get_today(); if (to == -1) - to = from; + to = ENDOFDAY(from); EXIT_IF(to < from, _("end date cannot come before start date")); if (range > 0) to = date_sec_change(from, 0, range - 1); diff --git a/src/calcurse.h b/src/calcurse.h index 8626393..c6ddc8d 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -137,10 +137,12 @@ /* * Note the difference between the number of seconds in a day and daylength * in seconds. The two may differ when DST is in effect (daylength is either - * 23, 24 or 25 hours. The argument to DAYLEN is of type time_t. + * 23, 24 or 25 hours. The argument "date" is assumed to be of type time_t. */ #define DAYINSEC (DAYINMIN * MININSEC) -#define DAYLEN(date) (date_sec_change((date), 0, 1) - (date)) +#define NEXTDAY(date) date_sec_change((date), 0, 1) +#define DAYLEN(date) (NEXTDAY(date) - (date)) +#define ENDOFDAY(date) (NEXTDAY(date) - 1) #define HOURINSEC (HOURINMIN * MININSEC) #define MAXDAYSPERMONTH 31 @@ -760,6 +762,7 @@ int ui_calendar_get_view(void); void ui_calendar_start_date_thread(void); void ui_calendar_stop_date_thread(void); void ui_calendar_set_current_date(void); +struct date *ui_calendar_get_today(void); void ui_calendar_set_first_day_of_week(enum wday); void ui_calendar_change_first_day_of_week(void); unsigned ui_calendar_week_begins_on_monday(void); diff --git a/src/ui-calendar.c b/src/ui-calendar.c index a668efb..407f294 100644 --- a/src/ui-calendar.c +++ b/src/ui-calendar.c @@ -144,6 +144,12 @@ void ui_calendar_set_current_date(void) pthread_mutex_unlock(&date_thread_mutex); } +/* Return the current date. */ +struct date *ui_calendar_get_today(void) +{ + return &today; +} + /* Needed to display sunday or monday as the first day of week in calendar. */ void ui_calendar_set_first_day_of_week(enum wday first_day) { -- cgit v1.2.3-54-g00ecf