/** * part of Hydrilla * Routines that perform queries on in-memory scriptbase and return results in * the form of JSON strings. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. */ #include <errno.h> #include "scriptbase.h" #define ADD_COMPONENT(object, key, construct, adder) \ new = cJSON_Create##construct; \ if (!new) \ goto free_json; \ adder(object, key, new) #define ADD_TO_OBJECT(object, key, construct) \ ADD_COMPONENT(object, key, construct, cJSON_AddItemToObject) #define ADD_KEY(key, construct) ADD_TO_OBJECT(json, key, construct) #define ARRAY_ADDER(object, key, var) cJSON_AddItemToArray(object, var) #define ADD_TO_ARRAY(object, construct) \ ADD_COMPONENT(object, dummy, construct, ARRAY_ADDER) char *get_script_json(const char *name, struct scriptbase *base) { const struct script *script; cJSON *json, *new; char *printed = NULL; script = get_script(name, base); if (!script || !script->filled) return NULL; json = cJSON_CreateObject(); if (!json) goto free_json; ADD_KEY("name", String(script->name)); ADD_KEY("location", String(script->location)); ADD_KEY("sha256", String(script->sha256)); printed = cJSON_Print(json); free_json: cJSON_Delete(json); if (!printed) errno = ENOMEM; return printed; } char *get_bag_json(const char *name, struct scriptbase *base) { const struct bag *bag; cJSON *json, *new, *components, *current_component; struct component_ref *ref; char type_prefix[] = "\0"; char *printed = NULL; bag = get_bag(name, base); if (!bag || !bag->filled) return NULL; json = cJSON_CreateObject(); if (!json) goto free_json; ADD_KEY("name", String(bag->name)); ADD_KEY("components", Array()); components = new; for (ref = bag->components; ref; ref = ref->next) { ADD_TO_ARRAY(components, Array()); current_component = new; type_prefix[0] = ref->component_type[0]; ADD_TO_ARRAY(current_component, String(type_prefix)); /* name is at the same offset in struct bag and struct script */ ADD_TO_ARRAY(current_component, String(ref->component.bag->name)); } printed = cJSON_Print(json); free_json: cJSON_Delete(json); if (!printed) errno = ENOMEM; return printed; } cJSON *page_to_cJSON(const struct page *page) { cJSON *json, *new, *payload; char type_prefix[] = "\0"; json = cJSON_CreateObject(); if (!json) goto free_json; ADD_KEY("pattern", String(page->pattern)); if (!page->payload.any) goto skip_payload; ADD_KEY("payload", Array()); payload = new; type_prefix[0] = page->payload_type[0]; ADD_TO_ARRAY(payload, String(type_prefix)); /* name is at the same offset in struct bag and struct script */ ADD_TO_ARRAY(payload, String(page->payload.bag->name)); skip_payload: return json; free_json: cJSON_Delete(json); errno = ENOMEM; return NULL; } char *get_pattern_json(const char *pattern, struct scriptbase *base) { const struct page *page; cJSON *json; char *printed = NULL; page = get_pattern(pattern, base); if (!page) return NULL; json = page_to_cJSON(page); if (!json) return NULL; printed = cJSON_Print(json); cJSON_Delete(json); if (!printed) errno = ENOMEM; return printed; } struct page_array_building { cJSON *page_array; bool OOM_error; }; int lookup_callback(struct page *page, void *data) { struct page_array_building *building = data; cJSON *page_json; page_json = page_to_cJSON(page); if (!page_json) { building->OOM_error = true; return -1; } cJSON_AddItemToArray(building->page_array, page_json); return 0; } #include <stdio.h> char *get_page_query_json(const char *url, struct scriptbase *base) { struct page_array_building building = {NULL, false}; char *printed = NULL; int result = -2; building.page_array = cJSON_CreateArray(); if (!building.page_array) goto free_json; result = lookup_url(url, base, lookup_callback, &building); printf("lookup returned value is %d\n", result); if (building.OOM_error) result = -2; if (result < 0) goto free_json; printed = cJSON_Print(building.page_array); if (!printed) result = -2; free_json: cJSON_Delete(building.page_array); switch (result) { case 0: break; case -1: case -3: errno = EINVAL; break; case -2: errno = ENOMEM; } return printed; }