diff options
Diffstat (limited to 'src/json-lexer.c')
-rw-r--r-- | src/json-lexer.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/json-lexer.c b/src/json-lexer.c new file mode 100644 index 0000000..4357d1a --- /dev/null +++ b/src/json-lexer.c @@ -0,0 +1,282 @@ +#include <config.h> +#include "libjson/neoas-json-lexer-and-parser.h" + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <stdbool.h> + +static inline void *checked_alloc (void *, size_t n, size_t type); +static inline void *checked_realloc (void *, void *allocated, size_t n, + size_t type); +static inline void checked_free (void *, void *memory); +static inline void assert_everything_freed (void *); + +#define MAX_ALLOCS 64 +struct alloc_registry +{ + size_t n_allocated; + void *addresses[MAX_ALLOCS]; + size_t sizes[MAX_ALLOCS]; +}; + +static inline void * +checked_alloc (void *ctx, size_t n, size_t type) +{ + struct alloc_registry *registry = ctx; + if (registry->n_allocated >= MAX_ALLOCS) + { + return NULL; + } + if (n * type >= 8192) + { + return NULL; + } + void *mem = calloc (n, type); + if (mem == NULL) + { + return NULL; + } + registry->addresses[registry->n_allocated] = mem; + registry->sizes[registry->n_allocated] = n * type; + registry->n_allocated++; + return mem; +} + +static inline void * +checked_realloc (void *ctx, void *mem, size_t n, size_t type) +{ + struct alloc_registry *registry = ctx; + for (size_t i = 0; i < registry->n_allocated; i++) + { + if (registry->addresses[i] == mem) + { + void *newmem = realloc (mem, n * type); + if (newmem == NULL) + { + return NULL; + } + registry->addresses[i] = newmem; + registry->sizes[i] = n * type; + return newmem; + } + } + assert (false); +} + +static inline void +checked_free (void *ctx, void *mem) +{ + struct alloc_registry *registry = ctx; + if (mem == NULL) + { + return; + } + for (size_t i = 0; i < registry->n_allocated; i++) + { + if (registry->addresses[i] == mem) + { + free (registry->addresses[i]); + registry->n_allocated--; + registry->addresses[i] = registry->addresses[registry->n_allocated]; + registry->sizes[i] = registry->sizes[registry->n_allocated]; + return; + } + } + assert (false); +} + +static inline void +assert_everything_freed (void *ctx) +{ + struct alloc_registry *registry = ctx; + assert (registry->n_allocated == 0); +} + +static inline int +handle_null (void *ctx) +{ + assert (ctx == NULL); + printf ("Null\n"); + return 0; +} + +static inline int +handle_bool (void *ctx, bool value) +{ + assert (ctx == NULL); + printf ("Boolean: %c\n", value ? 'T' : 'F'); + return 0; +} + +static inline int +handle_number (void *ctx, double value) +{ + assert (ctx == NULL); + printf ("Number: %g\n", value); + return 0; +} + +static inline int +handle_string (void *ctx, size_t len, const char *str) +{ + assert (ctx == NULL); + printf ("String (%lu): ", len); + for (size_t i = 0; i < len; i++) + { + if (str[i] < 32 || str[i] == '\r' || str[i] == '\n') + { + printf ("\\%d", (int) ((uint8_t) str[i])); + } + else + { + printf ("%c", str[i]); + } + } + printf ("\n"); + return 0; +} + +static inline int +handle_object_start (void *ctx, void **user_data) +{ + assert (ctx == NULL); + *user_data = NULL; + printf ("Open object\n"); + return 0; +} + +static inline int +object_next_key (void *ctx, void *user_data, size_t len, const char *key) +{ + assert (ctx == NULL); + assert (user_data == NULL); + printf ("Switch to key (%lu): ", len); + for (size_t i = 0; i < len; i++) + { + if (key[i] < 32 || key[i] == '\r' || key[i] == '\n') + { + printf ("\\%d", (int) ((uint8_t) key[i])); + } + else + { + printf ("%c", key[i]); + } + } + printf ("\n"); + return 0; +} + +static inline int +handle_object_stop (void *ctx, void *user_data) +{ + assert (ctx == NULL); + assert (user_data == NULL); + printf ("Close object\n"); + return 0; +} + +static inline int +handle_array_start (void *ctx, void **user_data) +{ + assert (ctx == NULL); + *user_data = NULL; + printf ("Open array\n"); + return 0; +} + +static inline int +array_next_key (void *ctx, void *user_data, size_t index) +{ + assert (ctx == NULL); + assert (user_data == NULL); + printf ("Switch to array key (%lu)\n", index); + return 0; +} + +static inline int +handle_array_stop (void *ctx, void *user_data) +{ + assert (ctx == NULL); + assert (user_data == NULL); + printf ("Close array\n"); + return 0; +} + +static inline int +handle_next (void *ctx) +{ + assert (ctx == NULL); + printf ("Next\n"); + return 0; +} + +static inline int +handle_syntax_error (void *ctx) +{ + assert (ctx == NULL); + printf ("Syntax error\n"); + return 0; +} + +static inline int +handle_grammar_error (void *ctx) +{ + assert (ctx == NULL); + printf ("Grammar error\n"); + return 0; +} + +static inline int +handle_rejected_input (void *ctx, char c) +{ + assert (ctx == NULL); + printf ("Rejected input: %c\n", c); + return 0; +} + +static inline ssize_t +do_pull (void *ctx, size_t request, void *data) +{ + assert (ctx == NULL); + assert (request >= 1); + int c = getchar (); + if (c >= 0) + { + uint8_t b = c; + uint8_t *dst = data; + *dst = b; + return 1; + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + /* This does not call bindtextdomain(...) because it is not a + user-facing program. */ + (void) argc; + (void) argv; + struct alloc_registry registry = { + .n_allocated = 0 + }; + struct memory_allocator allocator = { + .allocate = checked_alloc, + .reallocate = checked_realloc, + .deallocate = checked_free, + .context = ®istry + }; + int error = json_lexer_and_parser_lex (&allocator, do_pull, NULL, + handle_null, handle_bool, + handle_number, handle_string, + handle_object_start, object_next_key, + handle_object_stop, + handle_array_start, array_next_key, + handle_array_stop, + handle_syntax_error, + handle_grammar_error, + handle_rejected_input, NULL); + assert_everything_freed (®istry); + return error; +} |