static w_query_expr *suffix_parser(w_query *query, json_t *term) { const char *ignore, *suffix; char *arg; w_string_t *str; int i, l; if (json_unpack(term, "[s,s]", &ignore, &suffix) != 0) { query->errmsg = strdup("must use [\"suffix\", \"suffixstring\"]"); return NULL; } arg = strdup(suffix); if (!arg) { query->errmsg = strdup("out of memory"); return NULL; } l = strlen_uint32(arg); for (i = 0; i < l; i++) { arg[i] = (char)tolower((uint8_t)arg[i]); } str = w_string_new_typed(arg, W_STRING_BYTE); free(arg); if (!str) { query->errmsg = strdup("out of memory"); return NULL; } return w_query_expr_new(eval_suffix, dispose_suffix, str); }
static w_query_expr *match_parser(w_query *query, json_t *term, bool caseless) { const char *ignore, *pattern, *scope = "basename"; const char *which = caseless ? "imatch" : "match"; struct match_data *data; if (json_unpack(term, "[s,s,s]", &ignore, &pattern, &scope) != 0 && json_unpack(term, "[s,s]", &ignore, &pattern) != 0) { asprintf(&query->errmsg, "Expected [\"%s\", \"pattern\", \"scope\"?]", which); return NULL; } if (strcmp(scope, "basename") && strcmp(scope, "wholename")) { asprintf(&query->errmsg, "Invalid scope '%s' for %s expression", scope, which); return NULL; } data = malloc(sizeof(*data)); data->pattern = strdup(pattern); data->caseless = caseless; data->wholename = !strcmp(scope, "wholename"); return w_query_expr_new(eval_match, dispose_match, data); }
static w_query_expr *pcre_parser(w_query *query, json_t *term, bool caseless) { const char *ignore, *pattern, *scope = "basename"; const char *which = caseless ? "ipcre" : "pcre"; struct match_pcre *data; pcre *re; const char *errptr = NULL; int erroff = 0; int errcode = 0; if (json_unpack(term, "[s,s,s]", &ignore, &pattern, &scope) != 0 && json_unpack(term, "[s,s]", &ignore, &pattern) != 0) { asprintf(&query->errmsg, "Expected [\"%s\", \"pattern\", \"scope\"?]", which); return NULL; } if (strcmp(scope, "basename") && strcmp(scope, "wholename")) { asprintf(&query->errmsg, "Invalid scope '%s' for %s expression", scope, which); return NULL; } re = pcre_compile2(pattern, caseless ? PCRE_CASELESS : 0, &errcode, &errptr, &erroff, NULL); if (!re) { asprintf(&query->errmsg, "invalid %s: code %d %s at offset %d in %s", which, errcode, errptr, erroff, pattern); return NULL; } data = malloc(sizeof(*data)); data->re = re; data->extra = pcre_study(re, 0, &errptr); data->wholename = !strcmp(scope, "wholename"); return w_query_expr_new(eval_pcre, dispose_pcre, data); }
static w_query_expr *not_parser(w_query *query, json_t *term) { json_t *other; w_query_expr *other_expr; /* rigidly require ["not", expr] */ if (!json_is_array(term) || json_array_size(term) != 2) { query->errmsg = strdup("must use [\"not\", expr]"); return NULL; } other = json_array_get(term, 1); other_expr = w_query_expr_parse(query, other); if (!other_expr) { // other expr sets errmsg return NULL; } return w_query_expr_new(eval_not, dispose_expr, other_expr); }
static w_query_expr *size_parser(w_query *query, json_t *term) { struct w_query_int_compare *comp; if (!json_is_array(term)) { ignore_result(asprintf(&query->errmsg, "Expected array for 'size' term")); return NULL; } comp = calloc(1, sizeof(*comp)); if (!comp) { ignore_result(asprintf(&query->errmsg, "out of memory")); return NULL; } if (!parse_int_compare(term, comp, &query->errmsg)) { free(comp); return NULL; } return w_query_expr_new(eval_size, free, comp); }
static w_query_expr *type_parser(w_query *query, json_t *term) { const char *ignore, *typestr, *found; intptr_t arg; if (json_unpack(term, "[s,s]", &ignore, &typestr) != 0) { query->errmsg = strdup("must use [\"type\", \"typestr\"]"); return NULL; } found = strpbrk(typestr, "bcdfplsD"); if (!found || strlen(typestr) > 1) { ignore_result(asprintf(&query->errmsg, "invalid type string '%s'", typestr)); return NULL; } arg = *found; return w_query_expr_new(eval_type, dispose_type, (void*)arg); }
static w_query_expr *parse_list(w_query *query, json_t *term, bool allof) { struct w_expr_list *list; size_t i; /* don't allow "allof" on its own */ if (!json_is_array(term) || json_array_size(term) < 2) { query->errmsg = strdup("must use [\"allof\", expr...]"); return NULL; } list = calloc(1, sizeof(*list)); if (!list) { query->errmsg = strdup("out of memory"); return NULL; } list->allof = allof; list->num = json_array_size(term) - 1; list->exprs = calloc(list->num, sizeof(list->exprs[0])); for (i = 0; i < list->num; i++) { w_query_expr *parsed; json_t *exp = json_array_get(term, i + 1); parsed = w_query_expr_parse(query, exp); if (!parsed) { // other expression parser sets errmsg dispose_list(list); return NULL; } list->exprs[i] = parsed; } return w_query_expr_new(eval_list, dispose_list, list); }
// ["dirname", "foo"] -> ["dirname", "foo", ["depth", "ge", 0]] static w_query_expr *dirname_parser_inner(w_query *query, json_t *term, bool caseless) { const char *which = caseless ? "idirname" : "dirname"; struct dirname_data *data; json_t *name; struct w_query_int_compare depth_comp; if (!json_is_array(term)) { ignore_result(asprintf(&query->errmsg, "Expected array for '%s' term", which)); return NULL; } if (json_array_size(term) < 2) { ignore_result(asprintf(&query->errmsg, "Invalid number of arguments for '%s' term", which)); return NULL; } if (json_array_size(term) > 3) { ignore_result(asprintf(&query->errmsg, "Invalid number of arguments for '%s' term", which)); return NULL; } name = json_array_get(term, 1); if (!json_is_string(name)) { ignore_result(asprintf(&query->errmsg, "Argument 2 to '%s' must be a string", which)); return NULL; } if (json_array_size(term) == 3) { json_t *depth; depth = json_array_get(term, 2); if (!json_is_array(depth)) { ignore_result(asprintf(&query->errmsg, "Invalid number of arguments for '%s' term", which)); return NULL; } if (!parse_int_compare(depth, &depth_comp, &query->errmsg)) { return NULL; } if (strcmp("depth", json_string_value(json_array_get(depth, 0)))) { ignore_result(asprintf(&query->errmsg, "Third parameter to '%s' should be a relational depth term", which)); return NULL; } } else { depth_comp.operand = 0; depth_comp.op = W_QUERY_ICMP_GE; } data = calloc(1, sizeof(*data)); if (!data) { ignore_result(asprintf(&query->errmsg, "out of memory")); return NULL; } data->dirname = w_string_new(json_string_value(name)); data->startswith = caseless ? w_string_startswith_caseless : w_string_startswith; data->depth = depth_comp; return w_query_expr_new(eval_dirname, dispose_dirname, data); }
static w_query_expr *false_parser(w_query *query, json_t *term) { unused_parameter(term); unused_parameter(query); return w_query_expr_new(eval_bool, NULL, 0); }
static w_query_expr *true_parser(w_query *query, json_t *term) { unused_parameter(term); unused_parameter(query); return w_query_expr_new(eval_bool, NULL, (void*)1); }
w_query_expr *w_expr_since_parser(w_query *query, json_t *term) { json_t *jval; struct w_clockspec *spec; struct since_term *sterm; int selected_field = SINCE_OCLOCK; const char *fieldname = "oclock"; if (!json_is_array(term)) { query->errmsg = strdup("\"since\" term must be an array"); return NULL; } if (json_array_size(term) < 2 || json_array_size(term) > 3) { query->errmsg = strdup("\"since\" term has invalid number of parameters"); return NULL; } jval = json_array_get(term, 1); spec = w_clockspec_parse(jval); if (!spec) { query->errmsg = strdup("invalid clockspec for \"since\" term"); return NULL; } if (spec->tag == w_cs_named_cursor) { query->errmsg = strdup("named cursors are not allowed in \"since\" terms"); goto fail; } jval = json_array_get(term, 2); if (jval) { int i; bool valid = false; fieldname = json_string_value(jval); if (!fieldname) { query->errmsg = strdup("field name for \"since\" term must be a string"); goto fail; } for (i = 0; allowed_fields[i].label; i++) { if (!strcmp(allowed_fields[i].label, fieldname)) { selected_field = allowed_fields[i].value; valid = true; break; } } if (!valid) { ignore_result(asprintf(&query->errmsg, "invalid field name \"%s\" for \"since\" term", fieldname)); goto fail; } } switch (selected_field) { case SINCE_CTIME: case SINCE_MTIME: if (spec->tag != w_cs_timestamp) { ignore_result(asprintf(&query->errmsg, "field \"%s\" requires a timestamp value " "for comparison in \"since\" term", fieldname)); goto fail; } break; case SINCE_OCLOCK: case SINCE_CCLOCK: /* we'll work with clocks or timestamps */ break; } sterm = calloc(1, sizeof(*sterm)); if (!sterm) { query->errmsg = strdup("out of memory"); goto fail; } sterm->spec = spec; sterm->field = selected_field; return w_query_expr_new(eval_since, dispose_since, sterm); fail: w_clockspec_free(spec); return NULL; }
static w_query_expr *name_parser(w_query *query, json_t *term, bool caseless) { const char *pattern = NULL, *scope = "basename"; const char *which = caseless ? "iname" : "name"; struct name_data *data; json_t *name; w_ht_t *map = NULL; if (!json_is_array(term)) { ignore_result(asprintf(&query->errmsg, "Expected array for '%s' term", which)); return NULL; } if (json_array_size(term) > 3) { ignore_result(asprintf(&query->errmsg, "Invalid number of arguments for '%s' term", which)); return NULL; } if (json_array_size(term) == 3) { json_t *jscope; jscope = json_array_get(term, 2); if (!json_is_string(jscope)) { ignore_result(asprintf(&query->errmsg, "Argument 3 to '%s' must be a string", which)); return NULL; } scope = json_string_value(jscope); if (strcmp(scope, "basename") && strcmp(scope, "wholename")) { ignore_result(asprintf(&query->errmsg, "Invalid scope '%s' for %s expression", scope, which)); return NULL; } } name = json_array_get(term, 1); if (json_is_array(name)) { uint32_t i; for (i = 0; i < json_array_size(name); i++) { if (!json_is_string(json_array_get(name, i))) { ignore_result(asprintf(&query->errmsg, "Argument 2 to '%s' must be either a string or an array of string", which)); return NULL; } } map = w_ht_new(json_array_size(name), &w_ht_string_funcs); for (i = 0; i < json_array_size(name); i++) { w_string_t *element; const char *ele; ele = json_string_value(json_array_get(name, i)); if (caseless) { element = w_string_new_lower(ele); } else { element = w_string_new(ele); } w_ht_set(map, w_ht_ptr_val(element), 1); w_string_delref(element); } } else if (json_is_string(name)) { pattern = json_string_value(name); } else { ignore_result(asprintf(&query->errmsg, "Argument 2 to '%s' must be either a string or an array of string", which)); return NULL; } data = calloc(1, sizeof(*data)); if (pattern) { data->name = w_string_new(pattern); } data->map = map; data->caseless = caseless; data->wholename = !strcmp(scope, "wholename"); return w_query_expr_new(eval_name, dispose_name, data); }