diff options
Diffstat (limited to 'cudl.c')
-rw-r--r-- | cudl.c | 167 |
1 files changed, 131 insertions, 36 deletions
@@ -1,36 +1,11 @@ #include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include "cudl.h" -struct cudl_array_value { - struct cudl_value *values; - size_t length; -}; +#define STRIP_WHITESPACE(text) while (isspace(*text)) text++ -struct cudl_map_value { - struct cudl_map_field { - char *key; - struct cudl_value value; - } *fields; - size_t length; -}; - -struct cudl_value { - union { - char *string; - double number; - int boolean; - struct array_value array; - struct map_value map; - } data; - int tag; -}; - -#define CUDL_TAG_NULL 0 -#define CUDL_TAG_ARRAY 1 - -#define CUDL_OK 0 -#define CUDL_ERR_OUT_OF_MEMORY 1 -#define CUDL_ERR_MISSING_VALUE 2 -#define CUDL_ERR_READING 3 +int cudl_err = CUDL_OK; static char *fread_all(FILE *file) { size_t size; @@ -49,7 +24,28 @@ static char *fread_all(FILE *file) { return buffer; } -void cudl_debug(struct cudl_value *value) { +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 */ @@ -68,16 +64,115 @@ void cudl_deinit_value(struct cudl_value value) { } } -int cudl_parse_from_file(FILE *file, struct cudl_value *value) { +/* 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)) - return CUDL_ERR_READING; + cudl_err = CUDL_ERR_READING; else - return CUDL_ERR_OUT_OF_MEMORY; + cudl_err = CUDL_ERR_OUT_OF_MEMORY; + return; } - return cudl_parse(input, value); + input += cudl_parse(input, value); + if (*input != '\0') + cudl_deinit_value(*value); + free(input); } -int cudl_parse(char *input, struct cudl_value *value) { +size_t cudl_parse(char *input, struct cudl_value *value) { + STRIP_WHITESPACE(input); + return parse_value(input, value); } |