Filter option: invert

New filter option: --filter-invert. When present it inverts (negates)
the other filter options combined. This is mostly useful with the -G
option (with -Q the output is limited by the query range (day range)).

The ouput from "calcurse -G <filter options>" is the (set) complement of
"calcurse -G <filter options> --filter-invert". Here <filter options>
may be any combination of filter options.

Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk>
Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
This commit is contained in:
Lars Henriksen 2018-12-06 09:56:45 +01:00 committed by Lukas Fleischer
parent 9300e9154c
commit 42abbf5346
6 changed files with 133 additions and 126 deletions

View File

@ -200,7 +200,8 @@ struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end,
{ {
char buf[BUFSIZ], *newline; char buf[BUFSIZ], *newline;
time_t tstart, tend; time_t tstart, tend;
struct apoint *apt; struct apoint *apt = NULL;
int cond;
EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) || EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) ||
!check_date(end.tm_year, end.tm_mon, end.tm_mday) || !check_date(end.tm_year, end.tm_mon, end.tm_mday) ||
@ -230,31 +231,30 @@ struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end,
/* Filter item. */ /* Filter item. */
if (filter) { if (filter) {
if (!(filter->type_mask & TYPE_MASK_APPT)) cond = (
return NULL; !(filter->type_mask & TYPE_MASK_APPT) ||
if (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) ||
return NULL; (filter->start_from != -1 && tstart < filter->start_from) ||
if (filter->start_from != -1 && tstart < filter->start_from) (filter->start_to != -1 && tstart > filter->start_to) ||
return NULL; (filter->end_from != -1 && tend < filter->end_from) ||
if (filter->start_to != -1 && tstart > filter->start_to) (filter->end_to != -1 && tend > filter->end_to)
return NULL; );
if (filter->end_from != -1 && tend < filter->end_from) if (filter->hash) {
return NULL; apt = apoint_new(
if (filter->end_to != -1 && tend > filter->end_to) buf, note, tstart, tend - tstart, state);
return NULL; char *hash = apoint_hash(apt);
} cond = cond || !hash_matches(filter->hash, hash);
mem_free(hash);
apt = apoint_new(buf, note, tstart, tend - tstart, state); }
/* Filter by hash. */ if ((!filter->invert && cond) || (filter->invert && !cond)) {
if (filter && filter->hash) { if (filter->hash)
char *hash = apoint_hash(apt); apoint_delete(apt);
if (!hash_matches(filter->hash, hash)) { return NULL;
apoint_delete(apt);
apt = NULL;
} }
mem_free(hash);
} }
if (!apt)
apt = apoint_new(buf, note, tstart, tend - tstart, state);
return apt; return apt;
} }

View File

@ -54,7 +54,8 @@ enum {
/* Long options */ /* Long options */
enum { enum {
OPT_FILTER_TYPE = 1000, OPT_FILTER_INVERT = 1000,
OPT_FILTER_TYPE,
OPT_FILTER_HASH, OPT_FILTER_HASH,
OPT_FILTER_PATTERN, OPT_FILTER_PATTERN,
OPT_FILTER_START_FROM, OPT_FILTER_START_FROM,
@ -410,7 +411,7 @@ int parse_args(int argc, char **argv)
int range = 0; int range = 0;
int limit = INT_MAX; int limit = INT_MAX;
/* Filters */ /* Filters */
struct item_filter filter = { 0, NULL, NULL, -1, -1, -1, -1, 0, 0, 0 }; struct item_filter filter = { 0, 0, NULL, NULL, -1, -1, -1, -1, 0, 0, 0 };
/* Format strings */ /* Format strings */
const char *fmt_apt = NULL; const char *fmt_apt = NULL;
const char *fmt_rapt = NULL; const char *fmt_rapt = NULL;
@ -457,6 +458,7 @@ int parse_args(int argc, char **argv)
{"quiet", no_argument, NULL, 'q'}, {"quiet", no_argument, NULL, 'q'},
{"query", optional_argument, NULL, 'Q'}, {"query", optional_argument, NULL, 'Q'},
{"filter-invert", no_argument, NULL, OPT_FILTER_INVERT},
{"filter-type", required_argument, NULL, OPT_FILTER_TYPE}, {"filter-type", required_argument, NULL, OPT_FILTER_TYPE},
{"filter-hash", required_argument, NULL, OPT_FILTER_HASH}, {"filter-hash", required_argument, NULL, OPT_FILTER_HASH},
{"filter-pattern", required_argument, NULL, OPT_FILTER_PATTERN}, {"filter-pattern", required_argument, NULL, OPT_FILTER_PATTERN},
@ -623,6 +625,10 @@ int parse_args(int argc, char **argv)
case 'Q': case 'Q':
query = 1; query = 1;
break; break;
case OPT_FILTER_INVERT:
filter.invert = !filter.invert;
filter_opt = 1;
break;
case OPT_FILTER_TYPE: case OPT_FILTER_TYPE:
filter.type_mask = parse_type_mask(optarg); filter.type_mask = parse_type_mask(optarg);
EXIT_IF(filter.type_mask == 0, EXIT_IF(filter.type_mask == 0,

View File

@ -427,6 +427,7 @@ enum item_type {
/* Filter settings. */ /* Filter settings. */
struct item_filter { struct item_filter {
int invert;
int type_mask; int type_mask;
char *hash; char *hash;
regex_t *regex; regex_t *regex;

View File

@ -152,7 +152,8 @@ struct event *event_scan(FILE * f, struct tm start, int id, char *note,
{ {
char buf[BUFSIZ], *nl; char buf[BUFSIZ], *nl;
time_t tstart, tend; time_t tstart, tend;
struct event *ev; struct event *ev = NULL;
int cond;
EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) || EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) ||
!check_time(start.tm_hour, start.tm_min), !check_time(start.tm_hour, start.tm_min),
@ -179,31 +180,29 @@ struct event *event_scan(FILE * f, struct tm start, int id, char *note,
/* Filter item. */ /* Filter item. */
if (filter) { if (filter) {
if (!(filter->type_mask & TYPE_MASK_EVNT)) cond = (
return NULL; !(filter->type_mask & TYPE_MASK_EVNT) ||
if (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) ||
return NULL; (filter->start_from != -1 && tstart < filter->start_from) ||
if (filter->start_from != -1 && tstart < filter->start_from) (filter->start_to != -1 && tstart > filter->start_to) ||
return NULL; (filter->end_from != -1 && tend < filter->end_from) ||
if (filter->start_to != -1 && tstart > filter->start_to) (filter->end_to != -1 && tend > filter->end_to)
return NULL; );
if (filter->end_from != -1 && tend < filter->end_from) if (filter->hash) {
return NULL; ev = event_new(buf, note, tstart, id);
if (filter->end_to != -1 && tend > filter->end_to) char *hash = event_hash(ev);
return NULL; cond = cond || !hash_matches(filter->hash, hash);
} mem_free(hash);
}
ev = event_new(buf, note, tstart, id);
if ((!filter->invert && cond) || (filter->invert && !cond)) {
/* Filter by hash. */ if (filter->hash)
if (filter && filter->hash) { event_delete(ev);
char *hash = event_hash(ev); return NULL;
if (!hash_matches(filter->hash, hash)) {
event_delete(ev);
ev = NULL;
} }
mem_free(hash);
} }
if (!ev)
ev = event_new(buf, note, tstart, id);
return ev; return ev;
} }

View File

@ -707,8 +707,7 @@ void io_load_todo(struct item_filter *filter)
{ {
FILE *data_file; FILE *data_file;
char *newline; char *newline;
int nb_tod = 0; int c, id, completed, cond;
int c, id, completed;
char buf[BUFSIZ], e_todo[BUFSIZ], note[MAX_NOTESIZ + 1]; char buf[BUFSIZ], e_todo[BUFSIZ], note[MAX_NOTESIZ + 1];
unsigned line = 0; unsigned line = 0;
@ -760,34 +759,31 @@ void io_load_todo(struct item_filter *filter)
io_extract_data(e_todo, buf, sizeof buf); io_extract_data(e_todo, buf, sizeof buf);
/* Filter item. */ /* Filter item. */
struct todo *todo = NULL;
if (filter) { if (filter) {
if (!(filter->type_mask & TYPE_MASK_TODO)) cond = (
continue; !(filter->type_mask & TYPE_MASK_TODO) ||
if (filter->regex && (filter->regex && regexec(filter->regex, e_todo, 0, 0, 0)) ||
regexec(filter->regex, e_todo, 0, 0, 0)) (filter->priority && id != filter->priority) ||
continue; (filter->completed && !completed) ||
if (filter->priority && id != filter->priority) (filter->uncompleted && completed)
continue; );
if (filter->completed && !completed) if (filter->hash) {
continue; todo = todo_add(e_todo, id, completed, note);
if (filter->uncompleted && completed) char *hash = todo_hash(todo);
continue; cond = cond || !hash_matches(filter->hash, hash);
} mem_free(hash);
}
struct todo *todo = todo_add(e_todo, id, completed, note);
if ((!filter->invert && cond) || (filter->invert && !cond)) {
/* Filter by hash. */ if (filter->hash)
if (filter && filter->hash) { todo_delete(todo);
char *hash = todo_hash(todo); continue;
if (!hash_matches(filter->hash, hash)) {
todo_delete(todo);
todo = NULL;
} }
mem_free(hash);
} }
if (todo) if (!todo)
++nb_tod; todo = todo_add(e_todo, id, completed, note);
} }
file_close(data_file, __FILE_POS__); file_close(data_file, __FILE_POS__);
} }

View File

@ -349,7 +349,8 @@ struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start,
{ {
char buf[BUFSIZ], *nl; char buf[BUFSIZ], *nl;
time_t tstart, tend, tuntil; time_t tstart, tend, tuntil;
struct recur_apoint *rapt; struct recur_apoint *rapt = NULL;
int cond;
EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) || EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) ||
!check_date(end.tm_year, end.tm_mon, end.tm_mday) || !check_date(end.tm_year, end.tm_mon, end.tm_mday) ||
@ -393,32 +394,34 @@ struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start,
/* Filter item. */ /* Filter item. */
if (filter) { if (filter) {
if (!(filter->type_mask & TYPE_MASK_RECUR_APPT)) cond = (
return NULL; !(filter->type_mask & TYPE_MASK_RECUR_APPT) ||
if (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) ||
return NULL; (filter->start_from != -1 && tstart < filter->start_from) ||
if (filter->start_from != -1 && tstart < filter->start_from) (filter->start_to != -1 && tstart > filter->start_to) ||
return NULL; (filter->end_from != -1 && tend < filter->end_from) ||
if (filter->start_to != -1 && tstart > filter->start_to) (filter->end_to != -1 && tend > filter->end_to)
return NULL; );
if (filter->end_from != -1 && tend < filter->end_from) if (filter->hash) {
return NULL; rapt = recur_apoint_new(buf, note, tstart,
if (filter->end_to != -1 && tend > filter->end_to) tend - tstart, state,
return NULL; recur_char2def(type),
} freq, tuntil, exc);
char *hash = recur_apoint_hash(rapt);
rapt = recur_apoint_new(buf, note, tstart, tend - tstart, state, cond = cond || !hash_matches(filter->hash, hash);
recur_char2def(type), freq, tuntil, exc); mem_free(hash);
}
/* Filter by hash. */
if (filter && filter->hash) { if ((!filter->invert && cond) || (filter->invert && !cond)) {
char *hash = recur_apoint_hash(rapt); if (filter->hash)
if (!hash_matches(filter->hash, hash)) { recur_apoint_erase(rapt);
recur_apoint_erase(rapt); return NULL;
rapt = NULL;
} }
mem_free(hash);
} }
if (!rapt)
rapt = recur_apoint_new(buf, note, tstart, tend - tstart,
state, recur_char2def(type), freq,
tuntil, exc);
return rapt; return rapt;
} }
@ -431,7 +434,8 @@ struct recur_event *recur_event_scan(FILE * f, struct tm start, int id,
{ {
char buf[BUFSIZ], *nl; char buf[BUFSIZ], *nl;
time_t tstart, tend, tuntil; time_t tstart, tend, tuntil;
struct recur_event *rev; struct recur_event *rev = NULL;
int cond;
EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) || EXIT_IF(!check_date(start.tm_year, start.tm_mon, start.tm_mday) ||
!check_time(start.tm_hour, start.tm_min) || !check_time(start.tm_hour, start.tm_min) ||
@ -466,32 +470,33 @@ struct recur_event *recur_event_scan(FILE * f, struct tm start, int id,
/* Filter item. */ /* Filter item. */
if (filter) { if (filter) {
if (!(filter->type_mask & TYPE_MASK_RECUR_EVNT)) cond = (
return NULL; !(filter->type_mask & TYPE_MASK_RECUR_EVNT) ||
if (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) (filter->regex && regexec(filter->regex, buf, 0, 0, 0)) ||
return NULL; (filter->start_from != -1 && tstart < filter->start_from) ||
if (filter->start_from != -1 && tstart < filter->start_from) (filter->start_to != -1 && tstart > filter->start_to) ||
return NULL; (filter->end_from != -1 && tend < filter->end_from) ||
if (filter->start_to != -1 && tstart > filter->start_to) (filter->end_to != -1 && tend > filter->end_to)
return NULL; );
if (filter->end_from != -1 && tend < filter->end_from) if (filter->hash) {
return NULL; rev = recur_event_new(buf, note, tstart, id,
if (filter->end_to != -1 && tend > filter->end_to) recur_char2def(type),
return NULL; freq, tuntil, exc);
} char *hash = recur_event_hash(rev);
cond = cond || !hash_matches(filter->hash, hash);
rev = recur_event_new(buf, note, tstart, id, recur_char2def(type), mem_free(hash);
freq, tuntil, exc); }
/* Filter by hash. */ if ((!filter->invert && cond) || (filter->invert && !cond)) {
if (filter && filter->hash) { if (filter->hash)
char *hash = recur_event_hash(rev); recur_event_erase(rev);
if (!hash_matches(filter->hash, hash)) { return NULL;
recur_event_erase(rev);
rev = NULL;
} }
mem_free(hash);
} }
if (!rev)
rev = recur_event_new(buf, note, tstart, id,
recur_char2def(type),
freq, tuntil, exc);
return rev; return rev;
} }