88static char*
dupn(
const char* s,
size_t n) {
89 char* out = malloc(n + 1);
99 return c ==
'=' || c ==
'!' || c ==
'~' || c ==
'>' || c ==
'<';
104 size_t nl = strlen(needle);
107 for (; *hay; hay++) {
109 while (i < nl && hay[i] && tolower((
unsigned char)hay[i]) == tolower((
unsigned char)needle[i]))
119 const char* s = P->
p;
124 while (*s ==
' ' || *s ==
'\t' || *s ==
'\r' || *s ==
'\n')
142 if (s[0] ==
'>' && s[1] ==
'=') {
148 if (s[0] ==
'<' && s[1] ==
'=') {
154 if (s[0] ==
'=' && s[1] ==
'~') {
160 if (s[0] ==
'!' && s[1] ==
'=') {
166 if (s[0] ==
'!' && s[1] ==
'~') {
197 const char* start = s + 1;
198 const char* e = start;
199 while (*e && *e !=
'"')
201 P->
tval =
dupn(start, (
size_t)(e - start));
203 P->
p = (*e ==
'"') ? e + 1 : e;
208 const char* start = s;
209 while (*s && !isspace((
unsigned char)*s) && *s !=
'(' && *s !=
')' && *s !=
'"' && !
is_op_char(*s))
211 P->
tval =
dupn(start, (
size_t)(s - start));
213 if (P->
tval && strcasecmp(P->
tval,
"and") == 0)
215 else if (P->
tval && strcasecmp(P->
tval,
"or") == 0)
217 else if (P->
tval && strcasecmp(P->
tval,
"not") == 0)
253 snprintf(P->
err,
sizeof(P->
err),
"expected ')'");
261 snprintf(P->
err,
sizeof(P->
err),
"expected a field name");
271 snprintf(P->
err,
sizeof(P->
err),
"expected an operator after field '%s'", field ? field :
"");
278 snprintf(P->
err,
sizeof(P->
err),
"expected a value");
285 if (!n || !field || !val) {
299 for (fi = 0; fi < P->
nfields; fi++) {
300 if (P->
fields[fi] && strcasecmp(P->
fields[fi], field) == 0) {
306 snprintf(P->
err,
sizeof(P->
err),
"unknown field '%s'", field);
319 snprintf(P->
err,
sizeof(P->
err),
"invalid regex '%s'", val);
407 memset(&P, 0,
sizeof(P));
410 P.
p = expr ? expr :
"";
416 q = calloc(1,
sizeof(
N_QUERY));
421 if (errbuf && errlen)
422 snprintf(errbuf, errlen,
"%s", P.
err[0] ? P.
err :
"parse error");
428 if (errbuf && errlen)
429 snprintf(errbuf, errlen,
"unexpected trailing input");
437 q = calloc(1,
sizeof(
N_QUERY));
457 const char* v = get ? get(n->
field, ud) : NULL;
462 return strcasecmp(v, n->
value) == 0;
464 return strcasecmp(v, n->
value) != 0;
477 double a = strtod(v, &e1);
478 double b = strtod(n->
value, &e2);
479 if (e1 == v || e2 == n->
value)
505 if (!query || !*query)
static void right(N_GUI_CTX *gui, float cx, float cy)
right press
int n_query_eval(const N_QUERY *query, N_QUERY_GET get, void *user_data)
Evaluate a compiled query against one record via get.
const char *(* N_QUERY_GET)(const char *field, void *user_data)
Field-value getter: return the value of field for the record being evaluated (NUL-terminated,...
N_QUERY * n_query_compile(const char *expr, char *errbuf, size_t errlen)
Compile an expression into a query.
N_QUERY * n_query_compile_ex(const char *expr, const char *const *fields, size_t nfields, char *errbuf, size_t errlen)
Compile expr, rejecting any field not in fields.
void n_query_free(N_QUERY **query)
Free a compiled query and set the pointer to NULL.
N_PCRE * npcre_new(char *str, int flags)
From pcre doc, the flag bits are: PCRE_ANCHORED Force pattern anchoring PCRE_AUTO_CALLOUT Compile aut...
int npcre_match(char *str, N_PCRE *pcre)
Thread-safe match: returns TRUE/FALSE without modifying the N_PCRE struct.
int npcre_delete(N_PCRE **pcre)
Free a N_PCRE pointer.
PCRE helpers for regex matching.
static char * dupn(const char *s, size_t n)
static int is_op_char(char c)
static QNODE * node_new(int kind)
static void lex_next(PARSER *P)
static int ci_contains(const char *hay, const char *needle)
static int eval_node(const QNODE *n, N_QUERY_GET get, void *ud)
static QNODE * parse_and(PARSER *P)
const char *const * fields
static QNODE * parse_or(PARSER *P)
static QNODE * parse_not(PARSER *P)
static void node_free(QNODE *n)
static QNODE * parse_primary(PARSER *P)
Opaque compiled query (see n_query_compile / n_query_eval / n_query_free).
Small boolean query language over caller-named fields.