diff options
| author | Björn Linse <bjorn.linse@gmail.com> | 2021-09-04 16:59:26 +0200 | 
|---|---|---|
| committer | Björn Linse <bjorn.linse@gmail.com> | 2021-09-09 16:06:43 +0200 | 
| commit | c8f46480bc0bfd07c8a69d61e365706e3184abc9 (patch) | |
| tree | ed0f91460fc3988bb7efd5aea24c9a037c418f07 /src/mpack/object.c | |
| parent | d8339be6915b3640f12a1827cee652b604b1a0d7 (diff) | |
| download | rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.tar.gz rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.tar.bz2 rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.zip | |
build: vendor libmpack source from libmpack/libmpack 22b1fd90285117c995728511f9525d29520a8c82
Diffstat (limited to 'src/mpack/object.c')
| -rw-r--r-- | src/mpack/object.c | 195 | 
1 files changed, 195 insertions, 0 deletions
| diff --git a/src/mpack/object.c b/src/mpack/object.c new file mode 100644 index 0000000000..0c7759ee51 --- /dev/null +++ b/src/mpack/object.c @@ -0,0 +1,195 @@ +#include <string.h> + +#include "object.h" + +static int mpack_parser_full(mpack_parser_t *w); +static mpack_node_t *mpack_parser_push(mpack_parser_t *w); +static mpack_node_t *mpack_parser_pop(mpack_parser_t *w); + +MPACK_API void mpack_parser_init(mpack_parser_t *parser, +    mpack_uint32_t capacity) +{ +  mpack_tokbuf_init(&parser->tokbuf); +  parser->data.p = NULL; +  parser->capacity = capacity ? capacity : MPACK_MAX_OBJECT_DEPTH; +  parser->size = 0; +  parser->exiting = 0; +  memset(parser->items, 0, sizeof(mpack_node_t) * (parser->capacity + 1)); +  parser->items[0].pos = (size_t)-1; +  parser->status = 0; +} + +#define MPACK_EXCEPTION_CHECK(parser)                                           \ +  do {                                                                      \ +    if (parser->status == MPACK_EXCEPTION) {                                    \ +      return MPACK_EXCEPTION;                                                   \ +    }                                                                       \ +  } while (0) + +#define MPACK_WALK(action)                                                  \ +  do {                                                                      \ +    mpack_node_t *n;                                                        \ +                                                                            \ +    if (parser->exiting) goto exit;                                         \ +    if (mpack_parser_full(parser)) return MPACK_NOMEM;                      \ +    n = mpack_parser_push(parser);                                          \ +    action;                                                                 \ +    MPACK_EXCEPTION_CHECK(parser);                                              \ +    parser->exiting = 1;                                                    \ +    return MPACK_EOF;                                                       \ +                                                                            \ +exit:                                                                       \ +    parser->exiting = 0;                                                    \ +    while ((n = mpack_parser_pop(parser))) {                                \ +      exit_cb(parser, n);                                                   \ +      MPACK_EXCEPTION_CHECK(parser);                                            \ +      if (!parser->size) return MPACK_OK;                                   \ +    }                                                                       \ +                                                                            \ +    return MPACK_EOF;                                                       \ +  } while (0) + +MPACK_API int mpack_parse_tok(mpack_parser_t *parser, mpack_token_t tok, +    mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) +{ +  MPACK_EXCEPTION_CHECK(parser); +  MPACK_WALK({n->tok = tok; enter_cb(parser, n);}); +} + +MPACK_API int mpack_unparse_tok(mpack_parser_t *parser, mpack_token_t *tok, +    mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) +{ +  MPACK_EXCEPTION_CHECK(parser); +  MPACK_WALK({enter_cb(parser, n); *tok = n->tok;}); +} + +MPACK_API int mpack_parse(mpack_parser_t *parser, const char **buf, +    size_t *buflen, mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) +{ +  int status = MPACK_EOF; +  MPACK_EXCEPTION_CHECK(parser); + +  while (*buflen && status) { +    mpack_token_t tok; +    mpack_tokbuf_t *tb = &parser->tokbuf; +    const char *buf_save = *buf; +    size_t buflen_save = *buflen; + +    if ((status = mpack_read(tb, buf, buflen, &tok)) == MPACK_EOF) continue; +    else if (status == MPACK_ERROR) goto rollback; + +    do { +      status = mpack_parse_tok(parser, tok, enter_cb, exit_cb); +      MPACK_EXCEPTION_CHECK(parser); +    } while (parser->exiting); + +    if (status != MPACK_NOMEM) continue; + +rollback: +    /* restore buf/buflen so the next call will try to read the same token */ +    *buf = buf_save; +    *buflen = buflen_save; +    break; +  } + +  return status; +} + +MPACK_API int mpack_unparse(mpack_parser_t *parser, char **buf, size_t *buflen, +    mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) +{ +  int status = MPACK_EOF; +  MPACK_EXCEPTION_CHECK(parser); + +  while (*buflen && status) { +    int write_status; +    mpack_token_t tok; +    mpack_tokbuf_t *tb = &parser->tokbuf; + +    if (!tb->plen) +      parser->status = mpack_unparse_tok(parser, &tok, enter_cb, exit_cb); + +    MPACK_EXCEPTION_CHECK(parser); + +    status = parser->status; + +    if (status == MPACK_NOMEM) +      break; + +    if (parser->exiting) { +      write_status = mpack_write(tb, buf, buflen, &tok); +      status = write_status ? write_status : status; +    } +  } + +  return status; +} + +MPACK_API void mpack_parser_copy(mpack_parser_t *dst, mpack_parser_t *src) +{ +  mpack_uint32_t i; +  mpack_uint32_t dst_capacity = dst->capacity;  +  assert(src->capacity <= dst_capacity); +  /* copy all fields except the stack */ +  memcpy(dst, src, sizeof(mpack_one_parser_t) - sizeof(mpack_node_t)); +  /* reset capacity */ +  dst->capacity = dst_capacity; +  /* copy the stack */ +  for (i = 0; i <= src->capacity; i++) { +    dst->items[i] = src->items[i]; +  } +} + +static int mpack_parser_full(mpack_parser_t *parser) +{ +  return parser->size == parser->capacity; +} + +static mpack_node_t *mpack_parser_push(mpack_parser_t *parser) +{ +  mpack_node_t *top; +  assert(parser->size < parser->capacity); +  top = parser->items + parser->size + 1; +  top->data[0].p = NULL; +  top->data[1].p = NULL; +  top->pos = 0; +  top->key_visited = 0; +  /* increase size and invoke callback, passing parent node if any */ +  parser->size++; +  return top; +} + +static mpack_node_t *mpack_parser_pop(mpack_parser_t *parser) +{ +  mpack_node_t *top, *parent; +  assert(parser->size); +  top = parser->items + parser->size; + +  if (top->tok.type > MPACK_TOKEN_CHUNK && top->pos < top->tok.length) { +    /* continue processing children */ +    return NULL; +  } + +  parent = MPACK_PARENT_NODE(top); +  if (parent) { +    /* we use parent->tok.length to keep track of how many children remain. +     * update it to reflect the processed node. */ +    if (top->tok.type == MPACK_TOKEN_CHUNK) { +      parent->pos += top->tok.length; +    } else if (parent->tok.type == MPACK_TOKEN_MAP) { +      /* maps allow up to 2^32 - 1 pairs, so to allow this many items in a +       * 32-bit length variable we use an additional flag to determine if the +       * key of a certain position was visited */ +      if (parent->key_visited) { +        parent->pos++; +      } +      parent->key_visited = !parent->key_visited; +    } else { +      parent->pos++; +    } +  } + +  parser->size--; +  return top; +} + | 
