diff options
Diffstat (limited to 'src/libjson/neoas-json-lexer.h')
-rw-r--r-- | src/libjson/neoas-json-lexer.h | 1036 |
1 files changed, 1036 insertions, 0 deletions
diff --git a/src/libjson/neoas-json-lexer.h b/src/libjson/neoas-json-lexer.h new file mode 100644 index 0000000..d57d3c8 --- /dev/null +++ b/src/libjson/neoas-json-lexer.h @@ -0,0 +1,1036 @@ +#ifndef NEOAS_JSON_LEXER_H_INCLUDED +# define NEOAS_JSON_LEXER_H_INCLUDED + +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <sys/types.h> +# include <math.h> + +struct memory_allocator; + +struct json_lexer; + +static inline int json_lexer_init (const struct memory_allocator *allocator, + struct json_lexer *lexer); + +static inline void json_lexer_deinit (struct json_lexer *lexer); + +static inline void json_lexer_set (struct json_lexer *lexer, + int (*handle_null) (void *), + int (*handle_bool) (void *, bool value), + int (*handle_number) (void *, + double value), + int (*handle_string) (void *, size_t len, + const char *str), + int (*handle_object_start) (void *), + int (*handle_object_assoc) (void *), + int (*handle_object_stop) (void *), + int (*handle_array_start) (void *), + int (*handle_array_stop) (void *), + int (*handle_next) (void *), + int (*handle_syntax_error) (void *), + /* Parsing a number stops when a + foreign character stops the + digit sequence. If the number + handler returns non-zero, the + foreign character is signalled + as a rejected input, so you can + resume parsing by pushing it. */ + int (*handle_rejected_input) (void *, + char c), + void *context); + +static inline int json_lexer_push (struct json_lexer *lexer, char c); + +static inline int json_lexer_terminate (struct json_lexer *lexer); + +static inline int json_lexer_lex (const struct memory_allocator *allocator, + ssize_t (*pull) (void *, size_t request, + void *data), + void *pull_context, + int (*handle_null) (void *), + int (*handle_bool) (void *, bool value), + int (*handle_number) (void *, double value), + int (*handle_string) (void *, size_t len, + const char *str), + int (*handle_object_start) (void *), + int (*handle_object_assoc) (void *), + int (*handle_object_stop) (void *), + int (*handle_array_start) (void *), + int (*handle_array_stop) (void *), + int (*handle_next) (void *), + int (*handle_syntax_error) (void *), + int (*handle_rejected_input) (void *, + char c), + void *context); + +static inline int json_lexer_string (const struct memory_allocator *allocator, + size_t n, + const char *str, + int (*handle_null) (void *), + int (*handle_bool) (void *, bool value), + int (*handle_number) (void *, + double value), + int (*handle_string) (void *, size_t len, + const char *str), + int (*handle_object_start) (void *), + int (*handle_object_assoc) (void *), + int (*handle_object_stop) (void *), + int (*handle_array_start) (void *), + int (*handle_array_stop) (void *), + int (*handle_next) (void *), + int (*handle_syntax_error) (void *), + int (*handle_rejected_input) (void *, + char c), + void *context); + +struct json_lexer_stringbuf; + +static inline int json_lexer_stringbuf_init (const struct memory_allocator + *allocator, + struct json_lexer_stringbuf + *str); + +static inline void json_lexer_stringbuf_deinit (struct json_lexer_stringbuf + *str); + +static inline void json_lexer_stringbuf_set (struct json_lexer_stringbuf *str, + int (*handle_success) (void *, + size_t + size, + const char + *str), + int (*handle_error) (void *), + void *context); + +static inline int json_lexer_stringbuf_push (struct json_lexer_stringbuf *str, + char c); + +# include "../liballoc/allocator.h" + +struct json_lexer_stringbuf +{ + size_t max; + size_t size; + char *str; + uint8_t escape_size; + char escape_sequence[6]; + int (*handle_success) (void *, size_t, const char *); + int (*handle_error) (void *); + void *context; + const struct memory_allocator allocator; +}; + +struct json_lexer_number; + +static inline void json_lexer_number_set (struct json_lexer_number *nb, + int (*handle_success) (void *, + double value, + char + lookahead), + int (*handle_error) (void *), + void *context); + +static inline int json_lexer_number_push (struct json_lexer_number *nb, + char c); + +static inline int json_lexer_number_terminate (struct json_lexer_number *nb); + +enum json_lexer_number_step +{ + LEXER_NUMBER_READ_SIGN, + LEXER_NUMBER_READ_INTEGER, + LEXER_NUMBER_READ_FRACTIONAL, + LEXER_NUMBER_READ_EXPONENT_SIGN, + LEXER_NUMBER_READ_EXPONENT +}; + +struct json_lexer_number +{ + enum json_lexer_number_step step; + double sign; + double digits; + int64_t extra_exponent; + int64_t exponent_sign; + uint64_t exponent; + int (*handle_success) (void *, double, char); + int (*handle_error) (void *); + void *context; +}; + +enum json_lexer_state +{ + JSON_LEXER_READING_WHITESPACE = 0, + JSON_LEXER_READING_STRING, + JSON_LEXER_READING_NUMBER, + JSON_LEXER_READING_NU, + JSON_LEXER_READING_NUL, + JSON_LEXER_READING_NULL, + JSON_LEXER_READING_FA, + JSON_LEXER_READING_FAL, + JSON_LEXER_READING_FALS, + JSON_LEXER_READING_FALSE, + JSON_LEXER_READING_TR, + JSON_LEXER_READING_TRU, + JSON_LEXER_READING_TRUE +}; + +struct json_lexer +{ + const struct memory_allocator allocator; + enum json_lexer_state state; + struct json_lexer_stringbuf str; + struct json_lexer_number nb; + int (*handle_null) (void *); + int (*handle_bool) (void *, bool value); + int (*handle_number) (void *, double value); + int (*handle_string) (void *, size_t len, const char *str); + int (*handle_object_start) (void *); + int (*handle_object_assoc) (void *); + int (*handle_object_stop) (void *); + int (*handle_array_start) (void *); + int (*handle_array_stop) (void *); + int (*handle_next) (void *); + int (*handle_syntax_error) (void *); + int (*handle_rejected_input) (void *, char c); + void *context; +}; + +# include <assert.h> + +static inline int +json_lexer_init (const struct memory_allocator *allocator, + struct json_lexer *lexer) +{ + copy_allocator ((struct memory_allocator *) (&(lexer->allocator)), + allocator); + if (json_lexer_stringbuf_init (allocator, &(lexer->str)) != 0) + { + return -1; + } + assert (lexer->allocator.allocate == lexer->str.allocator.allocate); + assert (lexer->allocator.reallocate == lexer->str.allocator.reallocate); + assert (lexer->allocator.deallocate == lexer->str.allocator.deallocate); + return 0; +} + +static inline void +json_lexer_deinit (struct json_lexer *lexer) +{ + assert (lexer->allocator.allocate == lexer->str.allocator.allocate); + assert (lexer->allocator.reallocate == lexer->str.allocator.reallocate); + assert (lexer->allocator.deallocate == lexer->str.allocator.deallocate); + json_lexer_stringbuf_deinit (&(lexer->str)); +} + +static inline int json_lexer_handle_stringbuf_success (void *ctx, size_t size, + const char *str); +static inline int json_lexer_handle_stringbuf_error (void *ctx); +static inline int json_lexer_handle_number_success (void *ctx, double value, + char lookahead); +static inline int json_lexer_handle_number_error (void *ctx); + +static inline void +json_lexer_set (struct json_lexer *lexer, + int (*handle_null) (void *), + int (*handle_bool) (void *, bool value), + int (*handle_number) (void *, double value), + int (*handle_string) (void *, size_t len, const char *str), + int (*handle_object_start) (void *), + int (*handle_object_assoc) (void *), + int (*handle_object_stop) (void *), + int (*handle_array_start) (void *), + int (*handle_array_stop) (void *), + int (*handle_next) (void *), + int (*handle_syntax_error) (void *), + /* Parsing a number stops when a + foreign character stops the + digit sequence. If the number + handler returns non-zero, the + foreign character is signalled + as a rejected input, so you can + resume parsing by pushing it. */ + int (*handle_rejected_input) (void *, char c), void *context) +{ + lexer->state = JSON_LEXER_READING_WHITESPACE; + json_lexer_stringbuf_set (&(lexer->str), + json_lexer_handle_stringbuf_success, + json_lexer_handle_stringbuf_error, lexer); + json_lexer_number_set (&(lexer->nb), + json_lexer_handle_number_success, + json_lexer_handle_number_error, lexer); + lexer->handle_null = handle_null; + lexer->handle_bool = handle_bool; + lexer->handle_number = handle_number; + lexer->handle_string = handle_string; + lexer->handle_object_start = handle_object_start; + lexer->handle_object_assoc = handle_object_assoc; + lexer->handle_object_stop = handle_object_stop; + lexer->handle_array_start = handle_array_start; + lexer->handle_array_stop = handle_array_stop; + lexer->handle_next = handle_next; + lexer->handle_syntax_error = handle_syntax_error; + lexer->handle_rejected_input = handle_rejected_input; + lexer->context = context; + assert (lexer->allocator.allocate == lexer->str.allocator.allocate); + assert (lexer->allocator.reallocate == lexer->str.allocator.reallocate); + assert (lexer->allocator.deallocate == lexer->str.allocator.deallocate); +} + +static inline int +json_lexer_push (struct json_lexer *lexer, char c) +{ + assert (lexer->allocator.allocate == lexer->str.allocator.allocate); + assert (lexer->allocator.reallocate == lexer->str.allocator.reallocate); + assert (lexer->allocator.deallocate == lexer->str.allocator.deallocate); + switch (lexer->state) + { + case JSON_LEXER_READING_WHITESPACE: + switch (c) + { + case ' ': + case '\t': + case '\r': + case '\n': + /* Stays that way. */ + return 0; + + case '"': + /* Start reading a string. */ + lexer->state = JSON_LEXER_READING_STRING; + return 0; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Start reading a number. */ + lexer->state = JSON_LEXER_READING_NUMBER; + if (json_lexer_number_push (&(lexer->nb), c) != 0) + { + /* Impossible, - or [0-9] always start a number. */ + assert (0); + } + return 0; + + case 'n': + /* Start reading null */ + lexer->state = JSON_LEXER_READING_NU; + return 0; + + case 'f': + /* Start reading false */ + lexer->state = JSON_LEXER_READING_FA; + return 0; + + case 't': + /* Start reading true */ + lexer->state = JSON_LEXER_READING_TR; + return 0; + + case '{': + return lexer->handle_object_start (lexer->context); + + case ':': + return lexer->handle_object_assoc (lexer->context); + + case '}': + return lexer->handle_object_stop (lexer->context); + + case '[': + return lexer->handle_array_start (lexer->context); + + case ']': + return lexer->handle_array_stop (lexer->context); + + case ',': + return lexer->handle_next (lexer->context); + + default: + return lexer->handle_syntax_error (lexer->context); + } + break; + + case JSON_LEXER_READING_STRING: + return json_lexer_stringbuf_push (&(lexer->str), c); + + case JSON_LEXER_READING_NUMBER: + return json_lexer_number_push (&(lexer->nb), c); + + case JSON_LEXER_READING_NU: + if (c == 'u') + { + lexer->state = JSON_LEXER_READING_NUL; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_NUL: + if (c == 'l') + { + lexer->state = JSON_LEXER_READING_NULL; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_NULL: + if (c == 'l') + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_null (lexer->context); + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_FA: + if (c == 'a') + { + lexer->state = JSON_LEXER_READING_FAL; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_FAL: + if (c == 'l') + { + lexer->state = JSON_LEXER_READING_FALS; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_FALS: + if (c == 's') + { + lexer->state = JSON_LEXER_READING_FALSE; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_FALSE: + if (c == 'e') + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_bool (lexer->context, false); + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_TR: + if (c == 'r') + { + lexer->state = JSON_LEXER_READING_TRU; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_TRU: + if (c == 'u') + { + lexer->state = JSON_LEXER_READING_TRUE; + return 0; + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + + case JSON_LEXER_READING_TRUE: + if (c == 'e') + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_bool (lexer->context, true); + } + else + { + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); + } + default: + assert (false); + } +} + +static inline int +json_lexer_terminate (struct json_lexer *lexer) +{ + assert (lexer->allocator.allocate == lexer->str.allocator.allocate); + assert (lexer->allocator.reallocate == lexer->str.allocator.reallocate); + assert (lexer->allocator.deallocate == lexer->str.allocator.deallocate); + switch (lexer->state) + { + case JSON_LEXER_READING_WHITESPACE: + return 0; + case JSON_LEXER_READING_NUMBER: + return json_lexer_number_terminate (&(lexer->nb)); + default: + return lexer->handle_syntax_error (lexer->context); + } +} + +static inline int +json_lexer_handle_stringbuf_success (void *ctx, size_t size, const char *str) +{ + struct json_lexer *lexer = ctx; + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_string (lexer->context, size, str); +} + +static inline int +json_lexer_handle_stringbuf_error (void *ctx) +{ + struct json_lexer *lexer = ctx; + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); +} + +static inline int +json_lexer_handle_number_success (void *ctx, double value, char lookahead) +{ + struct json_lexer *lexer = ctx; + lexer->state = JSON_LEXER_READING_WHITESPACE; + int error = lexer->handle_number (lexer->context, value); + if (error == 0) + { + return json_lexer_push (lexer, lookahead); + } + else + { + return lexer->handle_rejected_input (lexer->context, lookahead); + } +} + +static inline int +json_lexer_handle_number_error (void *ctx) +{ + struct json_lexer *lexer = ctx; + lexer->state = JSON_LEXER_READING_WHITESPACE; + return lexer->handle_syntax_error (lexer->context); +} + +static inline int +json_lexer_stringbuf_init (const struct memory_allocator *allocator, + struct json_lexer_stringbuf *str) +{ + str->max = 8; + copy_allocator ((struct memory_allocator *) (&(str->allocator)), allocator); + if (ALLOCATE (str->str, str->max) < 0) + { + return -1; + } + return 0; +} + +static inline void +json_lexer_stringbuf_deinit (struct json_lexer_stringbuf *str) +{ + if (str != NULL) + { + const struct memory_allocator *allocator = &(str->allocator); + DEALLOCATE (str->str); + } +} + +static inline void +json_lexer_stringbuf_set (struct json_lexer_stringbuf *str, + int (*handle_success) (void *, size_t, + const char *), + int (*handle_error) (void *), void *context) +{ + str->size = 0; + str->escape_size = 0; + str->handle_success = handle_success; + str->handle_error = handle_error; + str->context = context; +} + +static inline int json_lexer_stringbuf_push_char (size_t *max, + size_t *size, + char **str, + const struct + memory_allocator *allocator, + char c); + +static inline int +json_lexer_stringbuf_push (struct json_lexer_stringbuf *str, char c) +{ + if (str->escape_size) + { + assert (str->escape_size < 6); + /* Parsing an escape sequence. */ + str->escape_sequence[str->escape_size++] = c; + /* Try to reduce the escape sequence. */ + switch (str->escape_sequence[1]) + { + case '"': + case '\\': + case '/': + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), + &(str->allocator), + str->escape_sequence[1]); + case 'b': + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), + &(str->allocator), '\b'); + case 'f': + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), + &(str->allocator), '\f'); + case 'n': + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), + &(str->allocator), '\n'); + case 'r': + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), + &(str->allocator), '\r'); + case 't': + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), + &(str->allocator), '\t'); + case 'u': + if (str->escape_size == 6) + { + uint16_t escape_sequence = 0; + static const uint16_t factors[] = { 4096, 256, 16, 0 }; + for (size_t i = 0; i < 4; i++) + { + char c = str->escape_sequence[i + 2]; + if (c >= '0' && c <= '9') + { + escape_sequence += factors[i] * (c - '0'); + } + else if (c >= 'a' && c <= 'f') + { + escape_sequence += factors[i] * (c - 'a' + 10); + } + else if (c >= 'A' && c <= 'F') + { + escape_sequence += factors[i] * (c - 'A' + 10); + } + else + { + str->escape_size = 0; + return str->handle_error (str->context); + } + } + str->escape_size = 0; + return json_lexer_stringbuf_push_char (&(str->max), + &(str->size), + &(str->str), + &(str->allocator), + (uint8_t) + escape_sequence); + } + else + { + return 0; + } + default: + str->escape_size = 0; + return str->handle_error (str->context); + } + } + else if (c == '\\') + { + str->escape_size = 1; + str->escape_sequence[0] = c; + return 0; + } + else if (c == '"') + { + assert (str->escape_size == 0); + int error = str->handle_success (str->context, str->size, str->str); + str->size = 0; + return error; + } + else + { + /* What about control characters? */ + return json_lexer_stringbuf_push_char (&(str->max), &(str->size), + &(str->str), &(str->allocator), + c); + } +} + +static inline void +json_lexer_number_set (struct json_lexer_number *nb, + int (*handle_success) (void *, double, char), + int (*handle_error) (void *), void *context) +{ + nb->step = LEXER_NUMBER_READ_SIGN; + nb->sign = 1; + nb->digits = 0; + nb->extra_exponent = 0; + nb->exponent_sign = 1; + nb->exponent = 0; + nb->handle_success = handle_success; + nb->handle_error = handle_error; + nb->context = context; +} + +static inline int +json_lexer_number_accept (struct json_lexer_number *nb, char lookahead) +{ + const double final_exponent = + (((double) (nb->exponent_sign) * (double) (nb->exponent)) + + (double) (nb->extra_exponent)); + const double factor = pow (10.0, final_exponent); + const double value = nb->sign * nb->digits * factor; + nb->sign = +1; + nb->digits = 0; + nb->extra_exponent = 0; + nb->exponent_sign = 1; + nb->exponent = 0; + nb->step = LEXER_NUMBER_READ_SIGN; + return nb->handle_success (nb->context, value, lookahead); +} + +static inline int +json_lexer_number_push (struct json_lexer_number *nb, char c) +{ + /* FIXME: it accepts 0....123 as 0.123, 0345 as 345, ----4 as -4, + 123eEeeE4 as 123e4, .4 as 0.4 */ + switch (nb->step) + { + case LEXER_NUMBER_READ_SIGN: + switch (c) + { + case '-': + nb->sign = -1; + nb->step = LEXER_NUMBER_READ_INTEGER; + return 0; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + nb->digits *= 10; + nb->digits += (c - '0'); + nb->step = LEXER_NUMBER_READ_INTEGER; + return 0; + default: + nb->step = LEXER_NUMBER_READ_SIGN; + return nb->handle_error (nb->context); + } + break; /* unreachable */ + case LEXER_NUMBER_READ_INTEGER: + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + nb->digits *= 10; + nb->digits += (c - '0'); + return 0; + case '.': + nb->step = LEXER_NUMBER_READ_FRACTIONAL; + return 0; + case 'e': + case 'E': + nb->step = LEXER_NUMBER_READ_EXPONENT_SIGN; + return 0; + default: + return json_lexer_number_accept (nb, c); + } + break; /* unreachable */ + case LEXER_NUMBER_READ_FRACTIONAL: + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + nb->digits *= 10; + nb->digits += (c - '0'); + nb->extra_exponent -= 1; + return 0; + case 'e': + case 'E': + nb->step = LEXER_NUMBER_READ_EXPONENT_SIGN; + return 0; + default: + return json_lexer_number_accept (nb, c); + } + break; /* unreachable */ + case LEXER_NUMBER_READ_EXPONENT_SIGN: + switch (c) + { + case '-': + nb->exponent_sign = -1; + nb->step = LEXER_NUMBER_READ_EXPONENT; + return 0; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + nb->exponent *= 10; + nb->exponent += (c - '0'); + nb->step = LEXER_NUMBER_READ_EXPONENT; + return 0; + default: + return json_lexer_number_accept (nb, c); + } + break; /* unreachable */ + case LEXER_NUMBER_READ_EXPONENT: + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + nb->exponent *= 10; + nb->exponent += (c - '0'); + return 0; + default: + return json_lexer_number_accept (nb, c); + } + break; /* unreachable */ + default: + assert (false); + } +} + +static inline int +json_lexer_number_terminate (struct json_lexer_number *nb) +{ + switch (nb->step) + { + case LEXER_NUMBER_READ_SIGN: + /* No number being parsed. */ + return 0; + default: + /* FIXME: what if it’s "1.0E"? Accept as "1.0" for now */ + return json_lexer_number_push (nb, '\0'); + } +} + +static inline int +json_lexer_lex (const struct memory_allocator *allocator, + ssize_t (*pull) (void *, size_t request, void *data), + void *pull_context, + int (*handle_null) (void *), + int (*handle_bool) (void *, bool value), + int (*handle_number) (void *, double value), + int (*handle_string) (void *, size_t len, const char *str), + int (*handle_object_start) (void *), + int (*handle_object_assoc) (void *), + int (*handle_object_stop) (void *), + int (*handle_array_start) (void *), + int (*handle_array_stop) (void *), + int (*handle_next) (void *), + int (*handle_syntax_error) (void *), + int (*handle_rejected_input) (void *, char c), void *context) +{ + struct json_lexer lexer; + int error = 0; + error = json_lexer_init (allocator, &lexer); + if (error != 0) + { + goto ret; + } + static const size_t buffer_size = 4096; + char *buffer = NULL; + if (ALLOCATE (buffer, buffer_size) < 0) + { + error = -2; + goto cleanup; + } + json_lexer_set (&lexer, handle_null, handle_bool, handle_number, + handle_string, handle_object_start, + handle_object_assoc, handle_object_stop, + handle_array_start, handle_array_stop, + handle_next, handle_syntax_error, + handle_rejected_input, context); + ssize_t n_available; + do + { + assert (lexer.allocator.allocate == lexer.str.allocator.allocate); + assert (lexer.allocator.reallocate == lexer.str.allocator.reallocate); + assert (lexer.allocator.deallocate == lexer.str.allocator.deallocate); + n_available = pull (pull_context, buffer_size, buffer); + if (n_available > 0) + { + assert (n_available >= 0); + assert ((size_t) n_available <= buffer_size); + for (ssize_t i = 0; i < n_available; i++) + { + error = json_lexer_push (&lexer, buffer[i]); + if (error != 0) + { + goto cleanup; + } + } + } + } + while (n_available > 0); + error = json_lexer_terminate (&lexer); + if (error != 0) + { + goto cleanup; + } +cleanup: + assert (lexer.allocator.allocate == lexer.str.allocator.allocate); + assert (lexer.allocator.reallocate == lexer.str.allocator.reallocate); + assert (lexer.allocator.deallocate == lexer.str.allocator.deallocate); + DEALLOCATE (buffer); + json_lexer_deinit (&lexer); +ret: + return error; +} + +struct string_puller +{ + size_t size; + const char *str; +}; + +static inline ssize_t +json_lexer_pull_from_string (void *ctx, size_t request, void *data) +{ + struct string_puller *puller = ctx; + ssize_t ret = 0; + char *output = data; + while (request != 0) + { + if (puller->size == 0) + { + return ret; + } + *output = *puller->str; + (puller->size)--; + (puller->str)++; + request--; + output++; + } + return ret; +} + +static inline int +json_lexer_string (const struct memory_allocator *allocator, + size_t n, + const char *str, + int (*handle_null) (void *), + int (*handle_bool) (void *, bool value), + int (*handle_number) (void *, double value), + int (*handle_string) (void *, size_t len, const char *str), + int (*handle_object_start) (void *), + int (*handle_object_assoc) (void *), + int (*handle_object_stop) (void *), + int (*handle_array_start) (void *), + int (*handle_array_stop) (void *), + int (*handle_next) (void *), + int (*handle_syntax_error) (void *), + int (*handle_rejected_input) (void *, char c), + void *context) +{ + struct string_puller puller = {.size = n,.str = str }; + return json_lexer_lex (allocator, json_lexer_pull_from_string, &puller, + handle_null, handle_bool, handle_number, + handle_string, handle_object_start, + handle_object_assoc, handle_object_stop, + handle_array_start, handle_array_stop, + handle_next, handle_syntax_error, + handle_rejected_input, context); +} + +static inline int +json_lexer_stringbuf_push_char (size_t *max, + size_t *size, + char **str, + const struct memory_allocator *allocator, + char c) +{ + if (*size >= *max) + { + size_t new_max = 2 * *max; + if (new_max == 0) + { + new_max = 1; + } + if (REALLOCATE (*str, new_max) < 0) + { + return -1; + } + *max = new_max; + } + (*str)[(*size)++] = c; + return 0; +} + +#endif /* NEOAS_JSON_LEXER_H_INCLUDED */ |