#include #include #include #include typedef enum { T_FIELD, T_INDEX, } TokenType; typedef struct { TokenType type; union { dcfg_StringView field; size_t index; } v; } Token; #define MAX_TOKENS 256 static size_t tokenize(char const *query, Token *out) { size_t count = 0; size_t i = 0; if (query[i] == '.') i++; while (query[i] && count < MAX_TOKENS) { if (query[i] == '.') { i++; size_t start = i; while (query[i] && query[i] != '.' && query[i] != '[') i++; out[count].type = T_FIELD; out[count].v.field.data = query + start; out[count].v.field.size = i - start; count++; } else if (query[i] == '[') { i++; char *end; size_t idx = strtoul(query + i, &end, 10); if (*end != ']') { fprintf(stderr, "invalid index\n"); exit(1); } i = (size_t)(end - query) + 1; out[count].type = T_INDEX; out[count].v.index = idx; count++; } else { size_t start = i; while (query[i] && query[i] != '.' && query[i] != '[') i++; out[count].type = T_FIELD; out[count].v.field.data = query + start; out[count].v.field.size = i - start; count++; } } return count; } static void print_value(dcfg_Value *v) { dcfg_StringView sv; if (dcfg_serialize_value(v, &sv)) { fwrite(sv.data, 1, sv.size, stdout); free((void *)sv.data); putchar('\n'); } else { puts("null"); } } int main(int argc, char **argv) { if (argc < 3) { fprintf(stderr, "usage: %s \n", argv[0]); return 1; } char const *query = argv[1]; char const *file = argv[2]; dcfg_Instance *inst = dcfg_make_instance(&(dcfg_InstanceCreateInfo) { 0 }); if (!inst) { fprintf(stderr, "failed to create instance\n"); return 1; } dcfg_Value *root = dcfg_parse(inst, dcfg_SV(file)); if (!root) { fprintf(stderr, "parse error: %s\n", dcfg_last_error(inst)); dcfg_destroy_instance(inst); return 1; } Token toks[MAX_TOKENS]; size_t n = tokenize(query, toks); dcfg_Value *evaled; if (!dcfg_Value_evaluate_toplevel(root, &evaled, NULL, NULL, 0)) { fprintf(stderr, "evaluation error: %s\n", dcfg_last_error(inst)); dcfg_destroy(root); dcfg_destroy_instance(inst); return 1; } dcfg_Value *cur = evaled; for (size_t i = 0; i < n; i++) { Token *t = &toks[i]; dcfg_Value *next = NULL; if (t->type == T_FIELD) { if (!dcfg_Value_get_object_field_ex(cur, t->v.field, &next, true)) { fprintf(stderr, "no such field\n"); dcfg_destroy(evaled); dcfg_destroy(root); dcfg_destroy_instance(inst); return 1; } } else { if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) { fprintf(stderr, "index out of bounds\n"); dcfg_destroy(evaled); dcfg_destroy(root); dcfg_destroy_instance(inst); return 1; } } if (cur != evaled) dcfg_destroy(cur); cur = next; } print_value(cur); if (cur != evaled) dcfg_destroy(cur); dcfg_destroy(evaled); dcfg_destroy(root); dcfg_destroy_instance(inst); return 0; }