Files
dcfg/programs/dcfgq.c
Slendi 4664ad3bfb
Some checks failed
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=OFF (push) Failing after 11s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=OFF (push) Failing after 12s
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=ON (push) Failing after 11s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=ON (push) Failing after 12s
CMake / ubuntu-latest - shared=OFF, pthread=ON, posix=ON (push) Failing after 10s
CMake / ubuntu-latest - shared=ON, pthread=ON, posix=ON (push) Failing after 10s
Add lazy evaluation, and introduce use-after-free
Signed-off-by: Slendi <slendi@socopon.com>
2025-08-01 08:06:25 +03:00

145 lines
2.9 KiB
C

#include <dcfg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 <query> <file>\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)) {
fputs("no such field\n", stderr);
goto fail;
}
} else {
if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) {
fputs("index out of bounds\n", stderr);
goto fail;
}
}
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;
fail:
dcfg_destroy(evaled);
dcfg_destroy(root);
dcfg_destroy_instance(inst);
return 1;
}