From bfe73d0e5d66c43006a8a0dd8d58e311432bcb57 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 6 Aug 2014 08:53:51 +0200 Subject: Add item filters This adds the following filter options that allow for restricting the set of items that are read from the appointments file: * --filter-type * --filter-start-from * --filter-start-to * --filter-start-after * --filter-start-before * --filter-end-from * --filter-end-to * --filter-end-after * --filter-end-before Signed-off-by: Lukas Fleischer --- src/apoint.c | 17 +++++++- src/args.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/calcurse.c | 4 +- src/calcurse.h | 29 ++++++++++--- src/dmon.c | 2 +- src/event.c | 13 +++++- src/io.c | 11 ++--- src/recur.c | 30 +++++++++++++- 8 files changed, 207 insertions(+), 24 deletions(-) diff --git a/src/apoint.c b/src/apoint.c index f00dd1e..9bdd575 100644 --- a/src/apoint.c +++ b/src/apoint.c @@ -163,7 +163,7 @@ void apoint_write(struct apoint *o, FILE * f) } struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end, - char state, char *note) + char state, char *note, struct item_filter *filter) { char buf[BUFSIZ], *newline; time_t tstart, tend; @@ -193,6 +193,21 @@ struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end, tend = mktime(&end); EXIT_IF(tstart == -1 || tend == -1 || tstart > tend, _("date error in appointment")); + + /* Filter item. */ + if (filter) { + if (!(filter->type_mask & TYPE_MASK_APPT)) + return NULL; + if (filter->start_from >= 0 && tstart < filter->start_from) + return NULL; + if (filter->start_to >= 0 && tstart > filter->start_to) + return NULL; + if (filter->end_from >= 0 && tend < filter->end_from) + return NULL; + if (filter->end_to >= 0 && tend > filter->end_to) + return NULL; + } + return apoint_new(buf, note, tstart, tend - tstart, state); } diff --git a/src/args.c b/src/args.c index 8a9aa49..e9c9ac2 100644 --- a/src/args.c +++ b/src/args.c @@ -46,7 +46,16 @@ /* Long options */ enum { - OPT_FMT_APT = 1000, + OPT_FILTER_TYPE = 1000, + OPT_FILTER_START_FROM, + OPT_FILTER_START_TO, + OPT_FILTER_START_AFTER, + OPT_FILTER_START_BEFORE, + OPT_FILTER_END_FROM, + OPT_FILTER_END_TO, + OPT_FILTER_END_AFTER, + OPT_FILTER_END_BEFORE, + OPT_FMT_APT, OPT_FMT_RAPT, OPT_FMT_EV, OPT_FMT_REV, @@ -448,6 +457,52 @@ date_arg_extended(const char *startday, const char *range, int add_line, } } +static int parse_datearg(const char *str) +{ + struct date day; + + if (parse_date(str, DATEFMT_YYYYMMDD, (int *)&day.yyyy, + (int *)&day.mm, (int *)&day.dd, NULL)) + return date2sec(day, 0, 0); + + if (parse_date(str, DATEFMT_MMDDYYYY, (int *)&day.yyyy, + (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 -1; +} + +static int parse_type_mask(const char *str) +{ + char *buf = mem_strdup(str), *p; + int mask = 0; + + for (p = strtok(buf, ","); p; p = strtok(NULL, ",")) { + if (!strcmp(p, "event")) { + mask |= TYPE_MASK_EVNT; + } else if (!strcmp(p, "apt")) { + mask |= TYPE_MASK_APPT; + } else if (!strcmp(p, "recur-event")) { + mask |= TYPE_MASK_RECUR_EVNT; + } else if (!strcmp(p, "recur-apt")) { + mask |= TYPE_MASK_RECUR_APPT; + } else if (!strcmp(p, "recur")) { + mask |= TYPE_MASK_RECUR; + } else { + mask = 0; + goto cleanup; + } + } + +cleanup: + mem_free(buf); + return mask; +} + /* * Parse the command-line arguments and call the appropriate * routines to handle those arguments. Also initialize the data paths. @@ -469,6 +524,8 @@ int parse_args(int argc, char **argv) int tflag = 0; /* -t: print todo list */ int vflag = 0; /* -v: print version number */ int xflag = 0; /* -x: export data */ + /* Filters */ + struct item_filter filter = { TYPE_MASK_ALL, -1, -1, -1, -1 }; /* Format strings */ const char *fmt_apt = " - %S -> %E\n\t%m\n"; const char *fmt_rapt = " - %S -> %E\n\t%m\n"; @@ -511,6 +568,15 @@ int parse_args(int argc, char **argv) {"version", no_argument, NULL, 'v'}, {"export", optional_argument, NULL, 'x'}, + {"filter-type", required_argument, NULL, OPT_FILTER_TYPE}, + {"filter-start-from", required_argument, NULL, OPT_FILTER_START_FROM}, + {"filter-start-to", required_argument, NULL, OPT_FILTER_START_TO}, + {"filter-start-after", required_argument, NULL, OPT_FILTER_START_AFTER}, + {"filter-start-before", required_argument, NULL, OPT_FILTER_START_BEFORE}, + {"filter-end-from", required_argument, NULL, OPT_FILTER_END_FROM}, + {"filter-end-to", required_argument, NULL, OPT_FILTER_END_TO}, + {"filter-end-after", required_argument, NULL, OPT_FILTER_END_AFTER}, + {"filter-end-before", required_argument, NULL, OPT_FILTER_END_BEFORE}, {"format-apt", required_argument, NULL, OPT_FMT_APT}, {"format-recur-apt", required_argument, NULL, OPT_FMT_RAPT}, {"format-event", required_argument, NULL, OPT_FMT_EV}, @@ -625,6 +691,51 @@ int parse_args(int argc, char **argv) xfmt = IO_EXPORT_ICAL; } break; + case OPT_FILTER_TYPE: + filter.type_mask = parse_type_mask(optarg); + EXIT_IF(filter.type_mask == 0, + _("invalid filter mask")); + break; + case OPT_FILTER_START_FROM: + filter.start_from = parse_datearg(optarg); + EXIT_IF(filter.start_from == -1, + _("invalid filter start date")); + break; + case OPT_FILTER_START_TO: + filter.start_to = parse_datearg(optarg); + EXIT_IF(filter.start_to == -1, + _("invalid filter end date")); + break; + case OPT_FILTER_START_AFTER: + filter.start_from = parse_datearg(optarg) + 1; + EXIT_IF(filter.start_from == -1, + _("invalid filter start date")); + break; + case OPT_FILTER_START_BEFORE: + filter.start_to = parse_datearg(optarg) - 1; + EXIT_IF(filter.start_to == -1, + _("invalid filter end date")); + break; + case OPT_FILTER_END_FROM: + filter.end_from = parse_datearg(optarg); + EXIT_IF(filter.end_from == -1, + _("invalid filter start date")); + break; + case OPT_FILTER_END_TO: + filter.end_to = parse_datearg(optarg); + EXIT_IF(filter.end_to == -1, + _("invalid filter end date")); + break; + case OPT_FILTER_END_AFTER: + filter.end_from = parse_datearg(optarg) + 1; + EXIT_IF(filter.end_from == -1, + _("invalid filter start date")); + break; + case OPT_FILTER_END_BEFORE: + filter.end_to = parse_datearg(optarg) - 1; + EXIT_IF(filter.end_to == -1, + _("invalid filter end date")); + break; case OPT_FMT_APT: fmt_apt = optarg; break; @@ -689,7 +800,7 @@ int parse_args(int argc, char **argv) io_check_dir(path_notes); io_check_file(path_apts); io_check_file(path_todo); - io_load_app(); + io_load_app(&filter); io_load_todo(); note_gc(); non_interactive = 1; @@ -704,7 +815,7 @@ int parse_args(int argc, char **argv) io_check_file(path_todo); /* Get default pager in case we need to show a log file. */ vars_init(); - io_load_app(); + io_load_app(&filter); io_load_todo(); io_import_data(IO_IMPORT_ICAL, ifile); io_save_apts(path_apts); @@ -714,7 +825,7 @@ int parse_args(int argc, char **argv) if (xflag) { io_check_file(path_apts); io_check_file(path_todo); - io_load_app(); + io_load_app(&filter); io_load_todo(); io_export_data(xfmt); non_interactive = 1; @@ -728,14 +839,14 @@ int parse_args(int argc, char **argv) } if (nflag) { io_check_file(path_apts); - io_load_app(); + io_load_app(&filter); next_arg(); non_interactive = 1; } if (dflag || rflag || sflag) { io_check_file(path_apts); io_check_file(path_conf); - io_load_app(); + io_load_app(&filter); config_load(); /* To get output date format. */ if (dflag) date_arg(ddate, add_line, fmt_apt, @@ -756,7 +867,7 @@ int parse_args(int argc, char **argv) io_check_file(path_conf); vars_init(); config_load(); /* To get output date format. */ - io_load_app(); + io_load_app(&filter); day.dd = day.mm = day.yyyy = 0; app_arg(add_line, &day, 0, fmt_apt, fmt_rapt, fmt_ev, fmt_rev, preg, &limit); diff --git a/src/calcurse.c b/src/calcurse.c index ffd7020..242a142 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -333,7 +333,7 @@ static inline void key_generic_reload(void) todo_init_list(); io_load_todo(); - io_load_app(); + io_load_app(NULL); io_unset_modified(); ui_todo_load_items(); ui_todo_sel_reset(); @@ -684,7 +684,7 @@ int main(int argc, char **argv) wins_erase_status_bar(); io_load_keys(conf.pager); io_load_todo(); - io_load_app(); + io_load_app(NULL); io_unset_modified(); wins_slctd_set(conf.default_panel); wins_resize(); diff --git a/src/calcurse.h b/src/calcurse.h index 0fc3f62..4ae6c66 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -383,6 +383,23 @@ enum day_item_type { APPT }; +/* Available item type masks. */ +#define TYPE_MASK_EVNT (1 << EVNT) +#define TYPE_MASK_APPT (1 << APPT) +#define TYPE_MASK_RECUR_EVNT (1 << RECUR_EVNT) +#define TYPE_MASK_RECUR_APPT (1 << RECUR_APPT) +#define TYPE_MASK_RECUR (TYPE_MASK_RECUR_EVNT | TYPE_MASK_RECUR_APPT) +#define TYPE_MASK_ALL (TYPE_MASK_EVNT | TYPE_MASK_APPT | TYPE_MASK_RECUR) + +/* Filter settings. */ +struct item_filter { + int type_mask; + long start_from; + long start_to; + long end_from; + long end_to; +}; + /* Generic item description (to hold appointments, events...). */ struct day_item { enum day_item_type type; @@ -643,7 +660,8 @@ struct apoint *apoint_new(char *, char *, long, long, char); unsigned apoint_inday(struct apoint *, long *); void apoint_sec2str(struct apoint *, long, char *, char *); void apoint_write(struct apoint *, FILE *); -struct apoint *apoint_scan(FILE *, struct tm, struct tm, char, char *); +struct apoint *apoint_scan(FILE *, struct tm, struct tm, char, char *, + struct item_filter *); void apoint_delete(struct apoint *); struct notify_app *apoint_check_next(struct notify_app *, long); void apoint_switch_notify(struct apoint *); @@ -735,7 +753,7 @@ void event_llist_free(void); struct event *event_new(char *, char *, long, int); unsigned event_inday(struct event *, long *); void event_write(struct event *, FILE *); -struct event *event_scan(FILE *, struct tm, int, char *); +struct event *event_scan(FILE *, struct tm, int, char *, struct item_filter *); void event_delete(struct event *); void event_paste_item(struct event *, long); @@ -761,7 +779,7 @@ unsigned io_save_apts(const char *); unsigned io_save_todo(const char *); unsigned io_save_keys(void); void io_save_cal(enum save_display); -void io_load_app(void); +void io_load_app(struct item_filter *); void io_load_todo(void); void io_load_keys(const char *); int io_check_dir(const char *); @@ -911,9 +929,10 @@ char recur_def2char(enum recur_type); int recur_char2def(char); struct recur_apoint *recur_apoint_scan(FILE *, struct tm, struct tm, char, int, struct tm, char *, - llist_t *, char); + llist_t *, char, struct item_filter *); struct recur_event *recur_event_scan(FILE *, struct tm, int, char, - int, struct tm, char *, llist_t *); + int, struct tm, char *, llist_t *, + struct item_filter *); void recur_apoint_write(struct recur_apoint *, FILE *); void recur_event_write(struct recur_event *, FILE *); void recur_save_data(FILE *); diff --git a/src/dmon.c b/src/dmon.c index c51ee70..546847f 100644 --- a/src/dmon.c +++ b/src/dmon.c @@ -165,7 +165,7 @@ void dmon_start(int parent_exit_status) event_llist_init(); recur_event_llist_init(); todo_init_list(); - io_load_app(); + io_load_app(NULL); data_loaded = 1; DMON_LOG(_("started at %s\n"), nowstr()); diff --git a/src/event.c b/src/event.c index 38305b8..96ac41d 100644 --- a/src/event.c +++ b/src/event.c @@ -120,7 +120,8 @@ void event_write(struct event *o, FILE * f) } /* Load the events from file */ -struct event *event_scan(FILE * f, struct tm start, int id, char *note) +struct event *event_scan(FILE * f, struct tm start, int id, char *note, + struct item_filter *filter) { char buf[BUFSIZ], *nl; time_t tstart; @@ -147,6 +148,16 @@ struct event *event_scan(FILE * f, struct tm start, int id, char *note) tstart = mktime(&start); EXIT_IF(tstart == -1, _("date error in the event\n")); + /* Filter item. */ + if (filter) { + if (!(filter->type_mask & TYPE_MASK_EVNT)) + return NULL; + if (filter->start_from >= 0 && tstart < filter->start_from) + return NULL; + if (filter->start_to >= 0 && tstart > filter->start_to) + return NULL; + } + return event_new(buf, note, tstart, id); } diff --git a/src/io.c b/src/io.c index a50991f..a6c29ac 100644 --- a/src/io.c +++ b/src/io.c @@ -464,7 +464,7 @@ static void io_load_error(const char *filename, unsigned line, * and then load either: a new appointment, a new event, or a new * recursive item (which can also be either an event or an appointment). */ -void io_load_app(void) +void io_load_app(struct item_filter *filter) { FILE *data_file; int c, is_appointment, is_event, is_recursive; @@ -620,18 +620,19 @@ void io_load_app(void) if (is_recursive) { recur_apoint_scan(data_file, start, end, type, freq, until, notep, - &exc, state); + &exc, state, filter); } else { apoint_scan(data_file, start, end, state, - notep); + notep, filter); } } else if (is_event) { if (is_recursive) { recur_event_scan(data_file, start, id, type, freq, until, notep, - &exc); + &exc, filter); } else { - event_scan(data_file, start, id, notep); + event_scan(data_file, start, id, notep, + filter); } } else { io_load_error(path_apts, line, diff --git a/src/recur.c b/src/recur.c index 69706b0..76585d6 100644 --- a/src/recur.c +++ b/src/recur.c @@ -330,7 +330,8 @@ static void recur_write_exc(llist_t * lexc, FILE * f) struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start, struct tm end, char type, int freq, struct tm until, char *note, - llist_t * exc, char state) + llist_t * exc, char state, + struct item_filter *filter) { char buf[BUFSIZ], *nl; time_t tstart, tend, tuntil; @@ -375,6 +376,20 @@ struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start, EXIT_IF(tstart == -1 || tend == -1 || tstart > tend || tuntil == -1, _("date error in appointment")); + /* Filter item. */ + if (filter) { + if (!(filter->type_mask & TYPE_MASK_RECUR_APPT)) + return NULL; + if (filter->start_from >= 0 && tstart < filter->start_from) + return NULL; + if (filter->start_to >= 0 && tstart > filter->start_to) + return NULL; + if (filter->end_from >= 0 && tend < filter->end_from) + return NULL; + if (filter->end_to >= 0 && tend > filter->end_to) + return NULL; + } + return recur_apoint_new(buf, note, tstart, tend - tstart, state, recur_char2def(type), freq, tuntil, exc); } @@ -382,7 +397,8 @@ struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start, /* Load the recursive events from file */ struct recur_event *recur_event_scan(FILE * f, struct tm start, int id, char type, int freq, struct tm until, - char *note, llist_t * exc) + char *note, llist_t * exc, + struct item_filter *filter) { char buf[BUFSIZ], *nl; time_t tstart, tuntil; @@ -417,6 +433,16 @@ struct recur_event *recur_event_scan(FILE * f, struct tm start, int id, tstart = mktime(&start); EXIT_IF(tstart == -1 || tuntil == -1, _("date error in event")); + /* Filter item. */ + if (filter) { + if (!(filter->type_mask & TYPE_MASK_RECUR_EVNT)) + return NULL; + if (filter->start_from >= 0 && tstart < filter->start_from) + return NULL; + if (filter->start_to >= 0 && tstart > filter->start_to) + return NULL; + } + return recur_event_new(buf, note, tstart, id, recur_char2def(type), freq, tuntil, exc); } -- cgit v1.2.3-54-g00ecf