86static char*
dupn(
const char* s,
size_t n) {
87 char* out = malloc(n + 1);
97 return c ==
'=' || c ==
'!' || c ==
'~' || c ==
'>' || c ==
'<';
102 size_t nl = strlen(needle);
105 for (; *hay; hay++) {
107 while (i < nl && hay[i] && tolower((
unsigned char)hay[i]) == tolower((
unsigned char)needle[i]))
117 const char* s = P->
p;
122 while (*s ==
' ' || *s ==
'\t' || *s ==
'\r' || *s ==
'\n')
140 if (s[0] ==
'>' && s[1] ==
'=') {
146 if (s[0] ==
'<' && s[1] ==
'=') {
152 if (s[0] ==
'=' && s[1] ==
'~') {
158 if (s[0] ==
'!' && s[1] ==
'=') {
164 if (s[0] ==
'!' && s[1] ==
'~') {
195 const char* start = s + 1;
196 const char* e = start;
197 while (*e && *e !=
'"')
199 P->
tval =
dupn(start, (
size_t)(e - start));
201 P->
p = (*e ==
'"') ? e + 1 : e;
206 const char* start = s;
207 while (*s && !isspace((
unsigned char)*s) && *s !=
'(' && *s !=
')' && *s !=
'"' && !
is_op_char(*s))
209 P->
tval =
dupn(start, (
size_t)(s - start));
211 if (P->
tval && strcasecmp(P->
tval,
"and") == 0)
213 else if (P->
tval && strcasecmp(P->
tval,
"or") == 0)
215 else if (P->
tval && strcasecmp(P->
tval,
"not") == 0)
251 snprintf(P->
err,
sizeof(P->
err),
"expected ')'");
259 snprintf(P->
err,
sizeof(P->
err),
"expected a field name");
269 snprintf(P->
err,
sizeof(P->
err),
"expected an operator after field '%s'", field ? field :
"");
276 snprintf(P->
err,
sizeof(P->
err),
"expected a value");
283 if (!n || !field || !val) {
295 snprintf(P->
err,
sizeof(P->
err),
"invalid regex '%s'", val);
379 memset(&P, 0,
sizeof(P));
380 P.
p = expr ? expr :
"";
386 q = calloc(1,
sizeof(
N_QUERY));
391 if (errbuf && errlen)
392 snprintf(errbuf, errlen,
"%s", P.
err[0] ? P.
err :
"parse error");
398 if (errbuf && errlen)
399 snprintf(errbuf, errlen,
"unexpected trailing input");
407 q = calloc(1,
sizeof(
N_QUERY));
427 const char* v = get ? get(n->
field, ud) : NULL;
432 return strcasecmp(v, n->
value) == 0;
434 return strcasecmp(v, n->
value) != 0;
447 double a = strtod(v, &e1);
448 double b = strtod(n->
value, &e2);
449 if (e1 == v || e2 == n->
value)
475 if (!query || !*query)
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.
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)
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.