#include #include #include #include "cudl.h" #define STRIP_WHITESPACE(text) while (isspace(*text)) text++ int cudl_err = CUDL_OK; static char *fread_all(FILE *file) { size_t size; char *buffer; fseek(file, 0, SEEK_END); size = ftell(file); rewind(file); clearerr(file); if ((buffer = malloc(size + 1)) == NULL) return NULL; if (fread(buffer, 1, size, file) != size) { free(buffer); return NULL; } buffer[size] = '\0'; return buffer; } void cudl_debug(struct cudl_value value) { int i; switch (value.tag) { case CUDL_TAG_NULL: printf("%%null"); break; case CUDL_TAG_BOOL: if (value.data.boolean) printf("%%true"); else printf("%%false"); break; case CUDL_TAG_ARRAY: printf("["); for (i = 0; i < value.data.array.length; i++) cudl_debug(value.data.array.values[i]); printf("]"); break; default: printf("UNKNOWN"); break; } } /* Free all children of the value, not the value itself */ void cudl_deinit_value(struct cudl_value value) { int i; switch (value.tag) { case CUDL_TAG_ARRAY: for (i = 0; i < value.data.array.length; i++) { cudl_deinit_value(value.data.array.values[i]); } free(value.data.array.values); break; case CUDL_TAG_NULL: case default: break; } } /* Parse a value from input and store it in value. * Return the number of bytes consumed. * Input must end with a null byte */ size_t parse_value(char *input, struct cudl_value *value); static size_t parse_bool_or_null(char *input, struct cudl_value *value) { if (strncmp(input, "null", 4)) { value->tag = CUDL_TAG_NULL; return 4; } if (strncmp(input, "true", 4)) { value->tag = CUDL_TAG_BOOL; value->data.boolean = 1; return 4; } if (strncmp(input, "false", 5)) { value->tag = CUDL_TAG_BOOL; value->data.boolean = 0; return 5; } cudl_err = CUDL_ERR_EXPECTED_BOOL_OR_NULL; return 0; } static size_t parse_array(char *input, struct cudl_value *value) { size_t length, capacity; struct cudl_value *values, *newvalues; int i; char *original_input; original_input = input; value->tag = CUDL_TAG_ARRAY; length = 0; capacity = 8; if ((values = malloc(capacity * sizeof(struct cudl_value))) == NULL) { cudl_err = CUDL_ERR_OUT_OF_MEMORY; return 0; } STRIP_WHITESPACE(input); for (;;) { if (*input == '\0') { cudl_err = CUDL_ERR_UNMATCHED_BRACK; for (i = 0; i < length; i++) cudl_deinit_value(values[i]); free(values); return 0; } else if (*input == ']') { input++; values = realloc(values, length * sizeof(struct cudl_value)); value->data.array.length = length; value->data.array.values = values; return input - original_input; } if (length >= capacity) { if ((newvalues = realloc(values, 2 * capacity * sizeof(struct cudl_value))) == NULL) { cudl_err = CUDL_ERR_OUT_OF_MEMORY; for (i = 0; i < length; i++) cudl_deinit_value(values[i]); free(values); return 0; } capacity *= 2; } input += parse_value(input, values + length); if (cudl_err) { for (i = 0; i < length; i++) { cudl_deinit_value(values[i]); } free(values); return 0; } length++; } } static size_t _parse_value(char *input, struct cudl_value *value) { if (*input == '%') return parse_bool_or_null(++input, value) + 1; if (*input == '[') return parse_array(++input, value) + 1; cudl_err = CUDL_ERR_UNRECOGNISED_VALUE; return 0; } static size_t parse_value(char *input, struct cudl_value *value) { char *original_input; original_input = input; input += _parse_value(input, value); STRIP_WHITESPACE(input); return input - original_input; } void cudl_parse_from_file(FILE *file, struct cudl_value *value) { char *input; if ((input = fread_all(file)) == NULL) { if (ferror(file)) cudl_err = CUDL_ERR_READING; else cudl_err = CUDL_ERR_OUT_OF_MEMORY; return; } input += cudl_parse(input, value); if (*input != '\0') cudl_deinit_value(*value); free(input); } size_t cudl_parse(char *input, struct cudl_value *value) { STRIP_WHITESPACE(input); return parse_value(input, value); }