CLI: take input date format from configuration file, do not accept time
Before this patch the input date parsing accepts three formats: yyyy/mm/dd, mm/dd/yyyy, yyyy-mm-dd. They are tried in sequence. It also accepts an additional time (hh:mm), or a time without a date. There are several issues with this: - it is not documented - the date format dd/mm/yyyy is not accepted - print_date() and filter option settings (in parse_args()) can only handle midnight times (which are the result of a date without time) - it is highly uncertain what happens if a time (without a date) is given; at least the -d option treats a time without colon (1215 for 12:15) as a number It seems that acceptance of time input is a by-product and not needed. For these reasons the input date parsing has been changed: - the format is taken from the configuration file (as is the case for the output date format) - only a date, and no time, is accepted Because the input date format is used during parsing of the command line, the configuration file must be loaded first, i.e. the options -D or -C must be parsed before the remaining ones. Loading the configuration file may result in errors (e.g. caused by changes between versions). For this reason config_load() has been made more tolerant and issues warnings instead of exiting. A followup patch will introduce two options to allow the configuration file settings to be overridden for input and output date formats. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
This commit is contained in:
parent
215e90d348
commit
3d7bb89c88
115
src/args.c
115
src/args.c
@ -274,57 +274,19 @@ 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.
|
||||||
|
* The date format is taken from the user configuration.
|
||||||
|
*/
|
||||||
static time_t parse_datearg(const char *str)
|
static time_t parse_datearg(const char *str)
|
||||||
{
|
{
|
||||||
struct date day;
|
struct date day;
|
||||||
|
|
||||||
if (parse_date(str, DATEFMT_YYYYMMDD, (int *)&day.yyyy,
|
if (parse_date(str, conf.input_datefmt,
|
||||||
(int *)&day.mm, (int *)&day.dd, NULL))
|
(int *)&day.yyyy, (int *)&day.mm, (int *)&day.dd, NULL))
|
||||||
return date2sec(day, 0, 0);
|
return date2sec(day, 0, 0);
|
||||||
|
else
|
||||||
if (parse_date(str, DATEFMT_MMDDYYYY, (int *)&day.yyyy,
|
return -1;
|
||||||
(int *)&day.mm, (int *)&day.dd, NULL))
|
|
||||||
return date2sec(day, 0, 0);
|
|
||||||
|
|
||||||
if (parse_date(str, DATEFMT_ISO, (int *)&day.yyyy,
|
|
||||||
(int *)&day.mm, (int *)&day.dd, NULL))
|
|
||||||
return date2sec(day, 0, 0);
|
|
||||||
|
|
||||||
return LONG_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
static time_t parse_datetimearg(const char *str)
|
|
||||||
{
|
|
||||||
char *date = mem_strdup(str);
|
|
||||||
char *time;
|
|
||||||
unsigned hour, min;
|
|
||||||
time_t ret;
|
|
||||||
|
|
||||||
time = strchr(date, ' ');
|
|
||||||
if (time) {
|
|
||||||
/* Date and time. */
|
|
||||||
*time = '\0';
|
|
||||||
time++;
|
|
||||||
|
|
||||||
if (!parse_time(time, &hour, &min))
|
|
||||||
return -1;
|
|
||||||
ret = parse_datearg(date);
|
|
||||||
if (ret == LONG_MAX)
|
|
||||||
return -1;
|
|
||||||
ret += hour * HOURINSEC + min * MININSEC;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = parse_datearg(date);
|
|
||||||
if (ret == LONG_MAX) {
|
|
||||||
/* No date specified, use time only. */
|
|
||||||
if (!parse_time(date, &hour, &min))
|
|
||||||
return -1;
|
|
||||||
return get_today() + hour * HOURINSEC + min * MININSEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_daterange(const char *str, time_t *date_from, time_t *date_to)
|
static int parse_daterange(const char *str, time_t *date_from, time_t *date_to)
|
||||||
@ -340,7 +302,7 @@ static int parse_daterange(const char *str, time_t *date_from, time_t *date_to)
|
|||||||
p++;
|
p++;
|
||||||
|
|
||||||
if (*s != '\0') {
|
if (*s != '\0') {
|
||||||
*date_from = parse_datetimearg(s);
|
*date_from = parse_datearg(s);
|
||||||
if (*date_from == -1)
|
if (*date_from == -1)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
@ -348,7 +310,7 @@ static int parse_daterange(const char *str, time_t *date_from, time_t *date_to)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*p != '\0') {
|
if (*p != '\0') {
|
||||||
*date_to = parse_datetimearg(p);
|
*date_to = parse_datearg(p);
|
||||||
if (*date_to == -1)
|
if (*date_to == -1)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
@ -395,10 +357,11 @@ cleanup:
|
|||||||
/*
|
/*
|
||||||
* Parse the command-line arguments and call the appropriate
|
* Parse the command-line arguments and call the appropriate
|
||||||
* routines to handle those arguments. Also initialize the data paths.
|
* routines to handle those arguments. Also initialize the data paths.
|
||||||
|
* Returns the non-interactive value.
|
||||||
*/
|
*/
|
||||||
int parse_args(int argc, char **argv)
|
int parse_args(int argc, char **argv)
|
||||||
{
|
{
|
||||||
/* Command-line flags */
|
/* Command-line flags - NOTE that read_only is global */
|
||||||
int grep = 0, purge = 0, query = 0, next = 0;
|
int grep = 0, purge = 0, query = 0, next = 0;
|
||||||
int status = 0, gc = 0, import = 0, export = 0, daemon = 0;
|
int status = 0, gc = 0, import = 0, export = 0, daemon = 0;
|
||||||
int filter_opt = 0, format_opt = 0, query_range = 0;
|
int filter_opt = 0, format_opt = 0, query_range = 0;
|
||||||
@ -483,6 +446,28 @@ int parse_args(int argc, char **argv)
|
|||||||
{NULL, no_argument, NULL, 0}
|
{NULL, no_argument, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the configuration file first to get the input date format for
|
||||||
|
* parsing the remaining options.
|
||||||
|
*/
|
||||||
|
while ((ch = getopt_long(argc, argv, optstr, longopts, NULL)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'C':
|
||||||
|
confdir = optarg;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
datadir = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
io_init(cfile, datadir, confdir);
|
||||||
|
vars_init();
|
||||||
|
notify_init_vars();
|
||||||
|
if (io_file_exists(path_conf))
|
||||||
|
config_load();
|
||||||
|
|
||||||
|
/* Parse the remaining options. */
|
||||||
|
optind = 1;
|
||||||
while ((ch = getopt_long(argc, argv, optstr, longopts, NULL)) != -1) {
|
while ((ch = getopt_long(argc, argv, optstr, longopts, NULL)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'a':
|
case 'a':
|
||||||
@ -491,9 +476,9 @@ int parse_args(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
cfile = optarg;
|
cfile = optarg;
|
||||||
|
io_init(cfile, datadir, confdir);
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
confdir = optarg;
|
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if (is_all_digit(optarg) ||
|
if (is_all_digit(optarg) ||
|
||||||
@ -502,7 +487,7 @@ int parse_args(int argc, char **argv)
|
|||||||
EXIT_IF(range == 0, _("invalid range: %s"),
|
EXIT_IF(range == 0, _("invalid range: %s"),
|
||||||
optarg);
|
optarg);
|
||||||
} else {
|
} else {
|
||||||
from = parse_datetimearg(optarg);
|
from = parse_datearg(optarg);
|
||||||
EXIT_IF(from == -1, _("invalid date: %s"),
|
EXIT_IF(from == -1, _("invalid date: %s"),
|
||||||
optarg);
|
optarg);
|
||||||
}
|
}
|
||||||
@ -511,7 +496,6 @@ int parse_args(int argc, char **argv)
|
|||||||
query = 1;
|
query = 1;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
datadir = optarg;
|
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
purge = grep = 1;
|
purge = grep = 1;
|
||||||
@ -550,7 +534,7 @@ int parse_args(int argc, char **argv)
|
|||||||
case 's':
|
case 's':
|
||||||
if (!optarg)
|
if (!optarg)
|
||||||
optarg = "today";
|
optarg = "today";
|
||||||
from = parse_datetimearg(optarg);
|
from = parse_datearg(optarg);
|
||||||
EXIT_IF(from == -1, _("invalid date: %s"), optarg);
|
EXIT_IF(from == -1, _("invalid date: %s"), optarg);
|
||||||
filter.type_mask |= TYPE_MASK_CAL;
|
filter.type_mask |= TYPE_MASK_CAL;
|
||||||
query = 1;
|
query = 1;
|
||||||
@ -613,25 +597,25 @@ int parse_args(int argc, char **argv)
|
|||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_START_FROM:
|
case OPT_FILTER_START_FROM:
|
||||||
filter.start_from = parse_datetimearg(optarg);
|
filter.start_from = parse_datearg(optarg);
|
||||||
EXIT_IF(filter.start_from == -1,
|
EXIT_IF(filter.start_from == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_START_TO:
|
case OPT_FILTER_START_TO:
|
||||||
filter.start_to = parse_datetimearg(optarg);
|
filter.start_to = parse_datearg(optarg);
|
||||||
EXIT_IF(filter.start_to == -1,
|
EXIT_IF(filter.start_to == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_START_AFTER:
|
case OPT_FILTER_START_AFTER:
|
||||||
filter.start_from = parse_datetimearg(optarg) + 1;
|
filter.start_from = parse_datearg(optarg) + 1;
|
||||||
EXIT_IF(filter.start_from == -1,
|
EXIT_IF(filter.start_from == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_START_BEFORE:
|
case OPT_FILTER_START_BEFORE:
|
||||||
filter.start_to = parse_datetimearg(optarg) - 1;
|
filter.start_to = parse_datearg(optarg) - 1;
|
||||||
EXIT_IF(filter.start_to == -1,
|
EXIT_IF(filter.start_to == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
@ -643,25 +627,25 @@ int parse_args(int argc, char **argv)
|
|||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_END_FROM:
|
case OPT_FILTER_END_FROM:
|
||||||
filter.end_from = parse_datetimearg(optarg);
|
filter.end_from = parse_datearg(optarg);
|
||||||
EXIT_IF(filter.end_from == -1,
|
EXIT_IF(filter.end_from == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_END_TO:
|
case OPT_FILTER_END_TO:
|
||||||
filter.end_to = parse_datetimearg(optarg);
|
filter.end_to = parse_datearg(optarg);
|
||||||
EXIT_IF(filter.end_to == -1,
|
EXIT_IF(filter.end_to == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_END_AFTER:
|
case OPT_FILTER_END_AFTER:
|
||||||
filter.end_from = parse_datetimearg(optarg) + 1;
|
filter.end_from = parse_datearg(optarg) + 1;
|
||||||
EXIT_IF(filter.end_from == -1,
|
EXIT_IF(filter.end_from == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FILTER_END_BEFORE:
|
case OPT_FILTER_END_BEFORE:
|
||||||
filter.end_to = parse_datetimearg(optarg) - 1;
|
filter.end_to = parse_datearg(optarg) - 1;
|
||||||
EXIT_IF(filter.end_to == -1,
|
EXIT_IF(filter.end_to == -1,
|
||||||
_("invalid date: %s"), optarg);
|
_("invalid date: %s"), optarg);
|
||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
@ -687,12 +671,12 @@ int parse_args(int argc, char **argv)
|
|||||||
filter_opt = 1;
|
filter_opt = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_FROM:
|
case OPT_FROM:
|
||||||
from = parse_datetimearg(optarg);
|
from = parse_datearg(optarg);
|
||||||
EXIT_IF(from == -1, _("invalid date: %s"), optarg);
|
EXIT_IF(from == -1, _("invalid date: %s"), optarg);
|
||||||
query_range = 1;
|
query_range = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_TO:
|
case OPT_TO:
|
||||||
to = parse_datetimearg(optarg);
|
to = parse_datearg(optarg);
|
||||||
EXIT_IF(to == -1, _("invalid date: %s"), optarg);
|
EXIT_IF(to == -1, _("invalid date: %s"), optarg);
|
||||||
query_range = 1;
|
query_range = 1;
|
||||||
break;
|
break;
|
||||||
@ -768,20 +752,17 @@ int parse_args(int argc, char **argv)
|
|||||||
else if (range < 0)
|
else if (range < 0)
|
||||||
from = date_sec_change(to, 0, range + 1);
|
from = date_sec_change(to, 0, range + 1);
|
||||||
|
|
||||||
io_init(cfile, datadir, confdir);
|
|
||||||
io_check_dir(path_ddir);
|
io_check_dir(path_ddir);
|
||||||
io_check_dir(path_notes);
|
io_check_dir(path_notes);
|
||||||
io_check_dir(path_cdir);
|
io_check_dir(path_cdir);
|
||||||
io_check_dir(path_hooks);
|
io_check_dir(path_hooks);
|
||||||
|
|
||||||
vars_init();
|
|
||||||
if (status) {
|
if (status) {
|
||||||
status_arg();
|
status_arg();
|
||||||
} else if (grep) {
|
} else if (grep) {
|
||||||
io_check_file(path_apts);
|
io_check_file(path_apts);
|
||||||
io_check_file(path_todo);
|
io_check_file(path_todo);
|
||||||
io_check_file(path_conf);
|
io_check_file(path_conf);
|
||||||
config_load(); /* To get output date format. */
|
|
||||||
io_load_data(&filter, FORCE);
|
io_load_data(&filter, FORCE);
|
||||||
if (purge) {
|
if (purge) {
|
||||||
io_save_todo(path_todo);
|
io_save_todo(path_todo);
|
||||||
@ -803,7 +784,6 @@ int parse_args(int argc, char **argv)
|
|||||||
io_check_file(path_apts);
|
io_check_file(path_apts);
|
||||||
io_check_file(path_todo);
|
io_check_file(path_todo);
|
||||||
io_check_file(path_conf);
|
io_check_file(path_conf);
|
||||||
config_load(); /* To get output date format. */
|
|
||||||
io_load_data(&filter, FORCE);
|
io_load_data(&filter, FORCE);
|
||||||
|
|
||||||
/* Use default values for non-specified format strings. */
|
/* Use default values for non-specified format strings. */
|
||||||
@ -855,7 +835,6 @@ int parse_args(int argc, char **argv)
|
|||||||
io_load_data(&filter, FORCE);
|
io_load_data(&filter, FORCE);
|
||||||
io_export_data(xfmt, export_uid);
|
io_export_data(xfmt, export_uid);
|
||||||
} else if (daemon) {
|
} else if (daemon) {
|
||||||
notify_init_vars();
|
|
||||||
dmon_stop();
|
dmon_stop();
|
||||||
dmon_start(0);
|
dmon_start(0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -629,12 +629,9 @@ static int config_load_cb(const char *key, const char *value, void *dummy)
|
|||||||
int result = config_set_conf(key, value);
|
int result = config_set_conf(key, value);
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
EXIT(_("configuration variable unknown: \"%s\""), key);
|
WARN_MSG(_("unknown user option: \"%s\""), key);
|
||||||
/* NOTREACHED */
|
|
||||||
} else if (result == 0) {
|
} else if (result == 0) {
|
||||||
EXIT(_("wrong configuration variable format for \"%s\""),
|
WARN_MSG(_("invalid option format: \"%s\""), key);
|
||||||
key);
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user