Add an option to filter by object hash
Implement a new --filter-hash option to filter by object identifiers. Each object having an identifier that has the specified pattern as a prefix is matched. Patterns starting with an exclamation mark (!) are interpreted as negative patterns. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
This commit is contained in:
parent
dd85a73746
commit
7f8c62bf57
15
src/apoint.c
15
src/apoint.c
@ -190,6 +190,7 @@ 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;
|
||||||
|
|
||||||
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) ||
|
||||||
@ -233,7 +234,19 @@ struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return apoint_new(buf, note, tstart, tend - tstart, state);
|
apt = apoint_new(buf, note, tstart, tend - tstart, state);
|
||||||
|
|
||||||
|
/* Filter by hash. */
|
||||||
|
if (filter && filter->hash) {
|
||||||
|
char *hash = apoint_hash(apt);
|
||||||
|
if (!hash_matches(filter->hash, hash)) {
|
||||||
|
apoint_delete(apt);
|
||||||
|
apt = NULL;
|
||||||
|
}
|
||||||
|
mem_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return apt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apoint_delete(struct apoint *apt)
|
void apoint_delete(struct apoint *apt)
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
/* Long options */
|
/* Long options */
|
||||||
enum {
|
enum {
|
||||||
OPT_FILTER_TYPE = 1000,
|
OPT_FILTER_TYPE = 1000,
|
||||||
|
OPT_FILTER_HASH,
|
||||||
OPT_FILTER_PATTERN,
|
OPT_FILTER_PATTERN,
|
||||||
OPT_FILTER_START_FROM,
|
OPT_FILTER_START_FROM,
|
||||||
OPT_FILTER_START_TO,
|
OPT_FILTER_START_TO,
|
||||||
@ -442,7 +443,7 @@ int parse_args(int argc, char **argv)
|
|||||||
int range = -1;
|
int range = -1;
|
||||||
int limit = INT_MAX;
|
int limit = INT_MAX;
|
||||||
/* Filters */
|
/* Filters */
|
||||||
struct item_filter filter = { 0, NULL, -1, -1, -1, -1, 0, 0, 0 };
|
struct item_filter filter = { 0, NULL, NULL, -1, -1, -1, -1, 0, 0, 0 };
|
||||||
/* Format strings */
|
/* Format strings */
|
||||||
const char *fmt_apt = " - %S -> %E\n\t%m\n";
|
const char *fmt_apt = " - %S -> %E\n\t%m\n";
|
||||||
const char *fmt_rapt = " - %S -> %E\n\t%m\n";
|
const char *fmt_rapt = " - %S -> %E\n\t%m\n";
|
||||||
@ -481,6 +482,7 @@ int parse_args(int argc, char **argv)
|
|||||||
{"query", optional_argument, NULL, 'Q'},
|
{"query", optional_argument, NULL, 'Q'},
|
||||||
|
|
||||||
{"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-pattern", required_argument, NULL, OPT_FILTER_PATTERN},
|
{"filter-pattern", required_argument, NULL, OPT_FILTER_PATTERN},
|
||||||
{"filter-start-from", required_argument, NULL, OPT_FILTER_START_FROM},
|
{"filter-start-from", required_argument, NULL, OPT_FILTER_START_FROM},
|
||||||
{"filter-start-to", required_argument, NULL, OPT_FILTER_START_TO},
|
{"filter-start-to", required_argument, NULL, OPT_FILTER_START_TO},
|
||||||
@ -604,6 +606,9 @@ int parse_args(int argc, char **argv)
|
|||||||
EXIT_IF(filter.type_mask == 0,
|
EXIT_IF(filter.type_mask == 0,
|
||||||
_("invalid filter mask"));
|
_("invalid filter mask"));
|
||||||
break;
|
break;
|
||||||
|
case OPT_FILTER_HASH:
|
||||||
|
filter.hash = mem_strdup(optarg);
|
||||||
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
case OPT_FILTER_PATTERN:
|
case OPT_FILTER_PATTERN:
|
||||||
EXIT_IF(filter.regex,
|
EXIT_IF(filter.regex,
|
||||||
|
@ -407,6 +407,7 @@ enum item_type {
|
|||||||
/* Filter settings. */
|
/* Filter settings. */
|
||||||
struct item_filter {
|
struct item_filter {
|
||||||
int type_mask;
|
int type_mask;
|
||||||
|
char *hash;
|
||||||
regex_t *regex;
|
regex_t *regex;
|
||||||
time_t start_from;
|
time_t start_from;
|
||||||
time_t start_to;
|
time_t start_to;
|
||||||
@ -1120,6 +1121,7 @@ int vasprintf(char **, const char *, va_list);
|
|||||||
int asprintf(char **, const char *, ...);
|
int asprintf(char **, const char *, ...);
|
||||||
int starts_with(const char *, const char *);
|
int starts_with(const char *, const char *);
|
||||||
int starts_with_ci(const char *, const char *);
|
int starts_with_ci(const char *, const char *);
|
||||||
|
int hash_matches(const char *, const char *);
|
||||||
|
|
||||||
/* vars.c */
|
/* vars.c */
|
||||||
extern int col, row;
|
extern int col, row;
|
||||||
|
15
src/event.c
15
src/event.c
@ -147,6 +147,7 @@ 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;
|
||||||
|
|
||||||
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),
|
||||||
@ -187,7 +188,19 @@ struct event *event_scan(FILE * f, struct tm start, int id, char *note,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return event_new(buf, note, tstart, id);
|
ev = event_new(buf, note, tstart, id);
|
||||||
|
|
||||||
|
/* Filter by hash. */
|
||||||
|
if (filter && filter->hash) {
|
||||||
|
char *hash = event_hash(ev);
|
||||||
|
if (!hash_matches(filter->hash, hash)) {
|
||||||
|
event_delete(ev);
|
||||||
|
ev = NULL;
|
||||||
|
}
|
||||||
|
mem_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete an event from the list. */
|
/* Delete an event from the list. */
|
||||||
|
14
src/io.c
14
src/io.c
@ -684,7 +684,19 @@ void io_load_todo(struct item_filter *filter)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
todo_add(e_todo, id, note);
|
struct todo *todo = todo_add(e_todo, id, note);
|
||||||
|
|
||||||
|
/* Filter by hash. */
|
||||||
|
if (filter && filter->hash) {
|
||||||
|
char *hash = todo_hash(todo);
|
||||||
|
if (!hash_matches(filter->hash, hash)) {
|
||||||
|
todo_delete(todo);
|
||||||
|
todo = NULL;
|
||||||
|
}
|
||||||
|
mem_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (todo)
|
||||||
++nb_tod;
|
++nb_tod;
|
||||||
}
|
}
|
||||||
file_close(data_file, __FILE_POS__);
|
file_close(data_file, __FILE_POS__);
|
||||||
|
30
src/recur.c
30
src/recur.c
@ -336,6 +336,7 @@ 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;
|
||||||
|
|
||||||
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,8 +394,20 @@ struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return recur_apoint_new(buf, note, tstart, tend - tstart, state,
|
rapt = recur_apoint_new(buf, note, tstart, tend - tstart, state,
|
||||||
recur_char2def(type), freq, tuntil, exc);
|
recur_char2def(type), freq, tuntil, exc);
|
||||||
|
|
||||||
|
/* Filter by hash. */
|
||||||
|
if (filter && filter->hash) {
|
||||||
|
char *hash = recur_apoint_hash(rapt);
|
||||||
|
if (!hash_matches(filter->hash, hash)) {
|
||||||
|
recur_apoint_erase(rapt);
|
||||||
|
rapt = NULL;
|
||||||
|
}
|
||||||
|
mem_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rapt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the recursive events from file */
|
/* Load the recursive events from file */
|
||||||
@ -405,6 +418,7 @@ 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;
|
||||||
|
|
||||||
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) ||
|
||||||
@ -453,8 +467,20 @@ struct recur_event *recur_event_scan(FILE * f, struct tm start, int id,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return recur_event_new(buf, note, tstart, id, recur_char2def(type),
|
rev = recur_event_new(buf, note, tstart, id, recur_char2def(type),
|
||||||
freq, tuntil, exc);
|
freq, tuntil, exc);
|
||||||
|
|
||||||
|
/* Filter by hash. */
|
||||||
|
if (filter && filter->hash) {
|
||||||
|
char *hash = recur_event_hash(rev);
|
||||||
|
if (!hash_matches(filter->hash, hash)) {
|
||||||
|
recur_event_erase(rev);
|
||||||
|
rev = NULL;
|
||||||
|
}
|
||||||
|
mem_free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rev;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *recur_apoint_tostr(struct recur_apoint *o)
|
char *recur_apoint_tostr(struct recur_apoint *o)
|
||||||
|
12
src/utils.c
12
src/utils.c
@ -1641,3 +1641,15 @@ int starts_with_ci(const char *s, const char *p)
|
|||||||
for (; *p && tolower(*p) == tolower(*s); s++, p++);
|
for (; *p && tolower(*p) == tolower(*s); s++, p++);
|
||||||
return (*p == '\0');
|
return (*p == '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hash_matches(const char *pattern, const char *hash)
|
||||||
|
{
|
||||||
|
int invert = 0;
|
||||||
|
|
||||||
|
if (pattern[0] == '!') {
|
||||||
|
invert = 1;
|
||||||
|
pattern++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (starts_with(hash, pattern) != invert);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user