diff options
author | Daniil Cherednik <[email protected]> | 2023-05-05 11:09:01 +0300 |
---|---|---|
committer | Daniil Cherednik <[email protected]> | 2023-05-05 11:09:01 +0300 |
commit | b5a989b16cafa8a3b3bc076f1097a0eda6f48c06 (patch) | |
tree | 4da744117a5aab37758921fa43b95a3068e5aec1 /contrib/libs/libfyaml/src/lib/fy-input.c | |
parent | fc1cffcfa7f0497a1f97b384a24bcbf23362f3be (diff) |
Ydb stable 23-1-2623.1.26
x-stable-origin-commit: 22184a7e157553d447f17a2dffc4ea2d32dfd74d
Diffstat (limited to 'contrib/libs/libfyaml/src/lib/fy-input.c')
-rw-r--r-- | contrib/libs/libfyaml/src/lib/fy-input.c | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/contrib/libs/libfyaml/src/lib/fy-input.c b/contrib/libs/libfyaml/src/lib/fy-input.c new file mode 100644 index 00000000000..ac021ad534d --- /dev/null +++ b/contrib/libs/libfyaml/src/lib/fy-input.c @@ -0,0 +1,1035 @@ +/* + * fy-input.c - YAML input methods + * + * Copyright (c) 2019 Pantelis Antoniou <[email protected]> + * + * SPDX-License-Identifier: MIT + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <fcntl.h> +#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) +#include <unistd.h> +#include <sys/mman.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) +#include <sys/ioctl.h> +#endif +#include <errno.h> + +#include <libfyaml.h> + +#include "fy-parse.h" +#include "fy-ctype.h" + +#include "fy-input.h" + +/* amount of multiplication of page size for CHOP size + * for a 4K page this is 64K blocks + */ +#ifndef FYI_CHOP_MULT +#define FYI_CHOP_MULT 16 +#endif + +struct fy_input *fy_input_alloc(void) +{ + struct fy_input *fyi; + + fyi = malloc(sizeof(*fyi)); + if (!fyi) + return NULL; + memset(fyi, 0, sizeof(*fyi)); + + fyi->state = FYIS_NONE; + fyi->refs = 1; + + return fyi; +} + +void fy_input_free(struct fy_input *fyi) +{ + if (!fyi) + return; + + assert(fyi->refs == 1); + + switch (fyi->state) { + case FYIS_NONE: + case FYIS_QUEUED: + /* nothing to do */ + break; + case FYIS_PARSE_IN_PROGRESS: + case FYIS_PARSED: + fy_input_close(fyi); + break; + } + + /* always release the memory of the alloc memory */ + switch (fyi->cfg.type) { + case fyit_alloc: + free(fyi->cfg.alloc.data); + break; + + default: + break; + } + if (fyi->name) + free(fyi->name); + + free(fyi); +} + +const char *fy_input_get_filename(struct fy_input *fyi) +{ + if (!fyi) + return NULL; + + return fyi->name; +} + +static void fy_input_from_data_setup(struct fy_input *fyi, + struct fy_atom *handle, bool simple) +{ + const char *data; + size_t size; + unsigned int aflags; + + /* this is an internal method, you'd better to pass garbage */ + data = fy_input_start(fyi); + size = fy_input_size(fyi); + + fyi->buffer = NULL; + fyi->allocated = 0; + fyi->read = 0; + fyi->chunk = 0; + fyi->chop = 0; + fyi->fp = NULL; + + if (!handle) + goto out; + + memset(handle, 0, sizeof(*handle)); + + if (size > 0) + aflags = fy_analyze_scalar_content(data, size, + false, fylb_cr_nl, fyfws_space_tab); /* hardcoded yaml mode */ + else + aflags = FYACF_EMPTY | FYACF_FLOW_PLAIN | FYACF_BLOCK_PLAIN | FYACF_SIZE0; + + handle->start_mark.input_pos = 0; + handle->start_mark.line = 0; + handle->start_mark.column = 0; + handle->end_mark.input_pos = size; + handle->end_mark.line = 0; + handle->end_mark.column = fy_utf8_count(data, size); + /* if it's plain, all is good */ + if (simple || (aflags & FYACF_FLOW_PLAIN)) { + handle->storage_hint = size; /* maximum */ + handle->storage_hint_valid = false; + handle->direct_output = !!(aflags & FYACF_JSON_ESCAPE); + handle->style = FYAS_PLAIN; + } else { + handle->storage_hint = 0; /* just calculate */ + handle->storage_hint_valid = false; + handle->direct_output = false; + handle->style = FYAS_DOUBLE_QUOTED_MANUAL; + } + handle->empty = !!(aflags & FYACF_EMPTY); + handle->has_lb = !!(aflags & FYACF_LB); + handle->has_ws = !!(aflags & FYACF_WS); + handle->starts_with_ws = !!(aflags & FYACF_STARTS_WITH_WS); + handle->starts_with_lb = !!(aflags & FYACF_STARTS_WITH_LB); + handle->ends_with_ws = !!(aflags & FYACF_ENDS_WITH_WS); + handle->ends_with_lb = !!(aflags & FYACF_ENDS_WITH_LB); + handle->trailing_lb = !!(aflags & FYACF_TRAILING_LB); + handle->size0 = !!(aflags & FYACF_SIZE0); + handle->valid_anchor = !!(aflags & FYACF_VALID_ANCHOR); + + handle->chomp = FYAC_STRIP; + handle->increment = 0; + handle->fyi = fyi; + handle->fyi_generation = fyi->generation; + handle->tabsize = 0; + handle->json_mode = false; /* XXX hardcoded */ + handle->lb_mode = fylb_cr_nl; + handle->fws_mode = fyfws_space_tab; +out: + fyi->state = FYIS_PARSED; +} + +struct fy_input *fy_input_from_data(const char *data, size_t size, + struct fy_atom *handle, bool simple) +{ + struct fy_input *fyi; + + if (data && size == (size_t)-1) + size = strlen(data); + + fyi = fy_input_alloc(); + if (!fyi) + return NULL; + + fyi->cfg.type = fyit_memory; + fyi->cfg.userdata = NULL; + fyi->cfg.memory.data = data; + fyi->cfg.memory.size = size; + + fy_input_from_data_setup(fyi, handle, simple); + + return fyi; +} + +struct fy_input *fy_input_from_malloc_data(char *data, size_t size, + struct fy_atom *handle, bool simple) +{ + struct fy_input *fyi; + + if (data && size == (size_t)-1) + size = strlen(data); + + fyi = fy_input_alloc(); + if (!fyi) + return NULL; + + fyi->cfg.type = fyit_alloc; + fyi->cfg.userdata = NULL; + fyi->cfg.alloc.data = data; + fyi->cfg.alloc.size = size; + + fy_input_from_data_setup(fyi, handle, simple); + + return fyi; +} + +void fy_input_close(struct fy_input *fyi) +{ + if (!fyi) + return; + + switch (fyi->cfg.type) { + + case fyit_file: + case fyit_fd: + +#if !defined(_MSC_VER) + if (fyi->addr) { + munmap(fyi->addr, fyi->length); + fyi->addr = NULL; + } +#endif + + if (fyi->fd != -1) { + if (!fyi->cfg.no_close_fd) + close(fyi->fd); + fyi->fd = -1; + } + + if (fyi->buffer) { + free(fyi->buffer); + fyi->buffer = NULL; + } + if (fyi->fp) { + if (!fyi->cfg.no_fclose_fp) + fclose(fyi->fp); + fyi->fp = NULL; + } + break; + + case fyit_stream: + case fyit_callback: + if (fyi->buffer) { + free(fyi->buffer); + fyi->buffer = NULL; + } + break; + + case fyit_memory: + /* nothing */ + break; + + case fyit_alloc: + /* nothing */ + break; + + default: + break; + } +} + +struct fy_diag *fy_reader_get_diag(struct fy_reader *fyr) +{ + if (fyr && fyr->ops && fyr->ops->get_diag) + return fyr->ops->get_diag(fyr); + + return NULL; +} + +int fy_reader_file_open(struct fy_reader *fyr, const char *filename) +{ + if (!fyr || !filename) + return -1; + + if (fyr->ops && fyr->ops->file_open) + return fyr->ops->file_open(fyr, filename); + + return open(filename, O_RDONLY); +} + +void fy_reader_reset(struct fy_reader *fyr) +{ + const struct fy_reader_ops *ops; + struct fy_diag *diag; + + if (!fyr) + return; + + ops = fyr->ops; + diag = fyr->diag; + + fy_input_unref(fyr->current_input); + + memset(fyr, 0, sizeof(*fyr)); + + /* by default we're always in yaml mode */ + fyr->mode = fyrm_yaml; + fyr->ops = ops; + fyr->diag = diag; + fyr->current_c = -1; +} + +void fy_reader_setup(struct fy_reader *fyr, const struct fy_reader_ops *ops) +{ + if (!fyr) + return; + + fyr->ops = ops; + fyr->diag = fy_reader_get_diag(fyr); + fyr->current_input = NULL; + fy_reader_reset(fyr); +} + +void fy_reader_cleanup(struct fy_reader *fyr) +{ + if (!fyr) + return; + + fy_input_unref(fyr->current_input); + fyr->current_input = NULL; + fy_reader_reset(fyr); +} + +void fy_reader_apply_mode(struct fy_reader *fyr) +{ + struct fy_input *fyi; + + assert(fyr); + + /* set input mode from the current reader settings */ + switch (fyr->mode) { + case fyrm_yaml: + fyr->json_mode = false; + fyr->lb_mode = fylb_cr_nl; + fyr->fws_mode = fyfws_space_tab; + break; + case fyrm_json: + fyr->json_mode = true; + fyr->lb_mode = fylb_cr_nl; + fyr->fws_mode = fyfws_space; + break; + case fyrm_yaml_1_1: + fyr->json_mode = false; + fyr->lb_mode = fylb_cr_nl_N_L_P; + fyr->fws_mode = fyfws_space_tab; + break; + } + fyi = fyr->current_input; + if (fyi) { + fyi->json_mode = fyr->json_mode; + fyi->lb_mode = fyr->lb_mode; + fyi->fws_mode = fyr->fws_mode; + } +} + +int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const struct fy_reader_input_cfg *icfg) +{ + struct stat sb; + int rc; + + if (!fyi) + return -1; + + /* unref any previous input */ + fy_input_unref(fyr->current_input); + fyr->current_input = fy_input_ref(fyi); + + fy_reader_apply_mode(fyr); + + if (!icfg) + memset(&fyr->current_input_cfg, 0, sizeof(fyr->current_input_cfg)); + else + fyr->current_input_cfg = *icfg; + + /* reset common data */ + fyi->buffer = NULL; + fyi->allocated = 0; + fyi->read = 0; + fyi->chunk = 0; + fyi->chop = 0; + fyi->fp = NULL; + + switch (fyi->cfg.type) { + + case fyit_file: + case fyit_fd: + + switch (fyi->cfg.type) { + case fyit_file: + fyi->fd = fy_reader_file_open(fyr, fyi->cfg.file.filename); + fyr_error_check(fyr, fyi->fd != -1, err_out, + "failed to open %s", fyi->cfg.file.filename); + break; + + case fyit_fd: + fyi->fd = fyi->cfg.fd.fd; + fyr_error_check(fyr, fyi->fd >= 0, err_out, + "bad file.fd %d", fyi->cfg.fd.fd); + break; + default: + assert(0); // will never happen + } + + rc = fstat(fyi->fd, &sb); + fyr_error_check(fyr, rc != -1, err_out, + "failed to fstat %s", fyi->cfg.file.filename); + + fyi->length = sb.st_size; + + /* only map if not zero (and is not disabled) */ +#if !defined(_MSC_VER) + if (sb.st_size > 0 && !fyr->current_input_cfg.disable_mmap_opt) { + fyi->addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fyi->fd, 0); + + /* convert from MAP_FAILED to NULL */ + if (fyi->addr == MAP_FAILED) { + fyr_debug(fyr, "mmap failed for file %s", + fyi->cfg.file.filename); + fyi->addr = NULL; + } + } +#endif + /* if we've managed to mmap, we' good */ + if (fyi->addr) + break; + + /* if we're not ignoring stdio, open a FILE* using the fd */ + if (!fyi->cfg.ignore_stdio) { + fyi->fp = fdopen(fyi->fd, "r"); + fyr_error_check(fyr, rc != -1, err_out, "failed to fdopen %s", fyi->name); + } else + fyi->fp = NULL; + + break; + + case fyit_stream: + if (!fyi->cfg.ignore_stdio) + fyi->fp = fyi->cfg.stream.fp; + else + fyi->fd = fileno(fyi->cfg.stream.fp); + break; + + case fyit_memory: + /* nothing to do for memory */ + break; + + case fyit_alloc: + /* nothing to do for memory */ + break; + + case fyit_callback: + break; + + default: + assert(0); + break; + } + + switch (fyi->cfg.type) { + + /* those two need no memory */ + case fyit_memory: + case fyit_alloc: + break; + + /* all the rest need it */ + default: + /* if we're not in mmap mode */ +#if !defined(_MSC_VER) + if (fyi->addr && !fyr->current_input_cfg.disable_mmap_opt) + break; +#endif + + fyi->chunk = fyi->cfg.chunk; + if (!fyi->chunk) + fyi->chunk = fy_get_pagesize(); + fyi->chop = fyi->chunk * FYI_CHOP_MULT; + fyi->buffer = malloc(fyi->chunk); + fyr_error_check(fyr, fyi->buffer, err_out, + "fy_alloc() failed"); + fyi->allocated = fyi->chunk; + break; + } + + fyr->this_input_start = 0; + fyr->current_input_pos = 0; + fyr->line = 0; + fyr->column = 0; + fyr->current_c = -1; + fyr->current_ptr = NULL; + fyr->current_w = 0; + fyr->current_left = 0; + + fyi->state = FYIS_PARSE_IN_PROGRESS; + + return 0; + +err_out: + fy_input_close(fyi); + return -1; +} + +int fy_reader_input_done(struct fy_reader *fyr) +{ + struct fy_input *fyi; + void *buf; + + if (!fyr) + return -1; + + fyi = fyr->current_input; + if (!fyi) + return 0; + + switch (fyi->cfg.type) { + case fyit_file: + case fyit_fd: + if (fyi->addr) + break; + + /* fall-through */ + + case fyit_stream: + case fyit_callback: + /* chop extra buffer */ + buf = realloc(fyi->buffer, fyr->current_input_pos); + fyr_error_check(fyr, buf || !fyr->current_input_pos, err_out, + "realloc() failed"); + + fyi->buffer = buf; + fyi->allocated = fyr->current_input_pos; + /* increate input generation; required for direct input to work */ + fyi->generation++; + break; + + default: + break; + + } + + fyi->state = FYIS_PARSED; + fy_input_unref(fyi); + fyr->current_input = NULL; + + return 0; + +err_out: + return -1; +} + +int fy_reader_input_scan_token_mark_slow_path(struct fy_reader *fyr) +{ + struct fy_input *fyi, *fyi_new = NULL; + + assert(fyr); + + if (!fy_reader_input_chop_active(fyr)) + return 0; + + fyi = fyr->current_input; + assert(fyi); + + fyi_new = fy_input_alloc(); + fyr_error_check(fyr, fyi_new, err_out, + "fy_input_alloc() failed\n"); + + /* copy the config over */ + fyi_new->cfg = fyi->cfg; + fyi_new->name = strdup(fyi->name); + fyr_error_check(fyr, fyi_new->name, err_out, + "strdup() failed\n"); + + fyi_new->chunk = fyi->chunk; + fyi_new->chop = fyi->chop; + fyi_new->buffer = malloc(fyi->chunk); + fyr_error_check(fyr, fyi_new->buffer, err_out, + "fy_alloc() failed"); + fyi_new->allocated = fyi->chunk; + fyi_new->fp = fyi->fp; + + fyi->fp = NULL; /* the file pointer now assigned to the new */ + + fyi_new->lb_mode = fyi->lb_mode; + fyi_new->fws_mode = fyi->fws_mode; + + fyi_new->state = FYIS_PARSE_IN_PROGRESS; + + /* adjust and copy the left over reads */ + assert(fyi->read >= fyr->current_input_pos); + fyi_new->read = fyi->read - fyr->current_input_pos; + if (fyi_new->read > 0) + memcpy(fyi_new->buffer, (char *)fyi->buffer + fyr->current_input_pos, fyi_new->read); + + fyr->this_input_start += fyr->current_input_pos; + + /* update the reader to point to the new input */ + fyr->current_input = fyi_new; + fyr->current_input_pos = 0; + fyr->current_ptr = fyi_new->buffer; + + fyr_debug(fyr, "chop at this_input_start=%zu chop=%zu\n", fyr->this_input_start, fyi->chop); + + /* free the old input - while references to it exist it will hang around */ + fyi->state = FYIS_PARSED; + fy_input_unref(fyi); + fyi = NULL; + + return 0; +err_out: + fy_input_unref(fyi_new); + return -1; +} + +const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp) +{ + struct fy_input *fyi; + const void *p; + int left; + + if (fyr->current_ptr) { + if (leftp) + *leftp = fyr->current_left; + return fyr->current_ptr; + } + + fyi = fyr->current_input; + if (!fyi) + return NULL; + + /* tokens cannot cross boundaries */ + switch (fyi->cfg.type) { + case fyit_file: + case fyit_fd: + if (fyi->addr) { + left = fyi->length - (fyr->this_input_start + fyr->current_input_pos); + p = (char *)fyi->addr + fyr->current_input_pos; + break; + } + + /* fall-through */ + + case fyit_stream: + case fyit_callback: + left = fyi->read - (fyr->this_input_start + fyr->current_input_pos); + p = (char *)fyi->buffer + fyr->current_input_pos; + break; + + case fyit_memory: + left = fyi->cfg.memory.size - fyr->current_input_pos; + p = (char *)fyi->cfg.memory.data + fyr->current_input_pos; + break; + + case fyit_alloc: + left = fyi->cfg.alloc.size - fyr->current_input_pos; + p = (char *)fyi->cfg.alloc.data + fyr->current_input_pos; + break; + + + default: + assert(0); /* no streams */ + p = NULL; + left = 0; + break; + } + + if (leftp) + *leftp = left; + + fyr->current_ptr = p; + fyr->current_left = left; + fyr->current_c = fy_utf8_get(p, left, &fyr->current_w); + + return p; +} + +const void *fy_reader_input_try_pull(struct fy_reader *fyr, struct fy_input *fyi, + size_t pull, size_t *leftp) +{ + const void *p; + size_t left, pos, size, nread, nreadreq, missing; + ssize_t snread; + size_t space __FY_DEBUG_UNUSED__; + void *buf; + + if (!fyr || !fyi) { + if (leftp) + *leftp = 0; + return NULL; + } + + p = NULL; + left = 0; + pos = fyr->current_input_pos; + + switch (fyi->cfg.type) { + case fyit_file: + case fyit_fd: + + if (fyi->addr) { + assert(fyi->length >= (fyr->this_input_start + pos)); + + left = fyi->length - (fyr->this_input_start + pos); + if (!left) { + fyr_debug(fyr, "file input exhausted"); + break; + } + p = (char *)fyi->addr + pos; + break; + } + + /* fall-through */ + + case fyit_stream: + case fyit_callback: + + assert(fyi->read >= pos); + + left = fyi->read - pos; + p = (char *)fyi->buffer + pos; + + /* enough to satisfy directly */ + if (left >= pull) + break; + + /* no more */ + if (fyi->eof) { + if (!left) { + fyr_debug(fyr, "input exhausted (EOF)"); + p = NULL; + } + break; + } + + space = fyi->allocated - pos; + + /* if we're missing more than the buffer space */ + missing = pull - left; + + fyr_debug(fyr, "input: allocated=%zu read=%zu pos=%zu pull=%zu left=%zu space=%zu missing=%zu", + fyi->allocated, fyi->read, pos, pull, left, space, missing); + + if (pos + pull > fyi->allocated) { + + /* align size to chunk */ + size = fyi->allocated + missing + fyi->chunk - 1; + size = size - size % fyi->chunk; + + fyr_debug(fyr, "input buffer missing %zu bytes (pull=%zu)", missing, pull); + + buf = realloc(fyi->buffer, size); + if (!buf) { + fyr_error(fyr, "realloc() failed"); + goto err_out; + } + + fyr_debug(fyr, "input read allocated=%zu new-size=%zu", fyi->allocated, size); + + fyi->buffer = buf; + fyi->allocated = size; + fyi->generation++; + + space = fyi->allocated - pos; + p = (char *)fyi->buffer + pos; + } + + /* always try to read up to the allocated space */ + do { + nreadreq = fyi->allocated - fyi->read; + assert(nreadreq > 0); + + if (fyi->cfg.type == fyit_callback) { + + fyr_debug(fyr, "performing callback request of %zu", nreadreq); + + nread = fyi->cfg.callback.input(fyi->cfg.userdata, (char *)fyi->buffer + fyi->read, nreadreq); + + fyr_debug(fyr, "callback returned %zu", nread); + + if (nread <= 0) { + if (!nread) { + fyi->eof = true; + fyr_debug(fyr, "callback got EOF"); + } else { + fyi->err = true; + fyr_debug(fyr, "callback got error"); + } + break; + } + + } else if (fyi->fp) { + + fyr_debug(fyr, "performing fread request of %zu", nreadreq); + + nread = fread((char *)fyi->buffer + fyi->read, 1, nreadreq, fyi->fp); + + fyr_debug(fyr, "fread returned %zu", nread); + + if (nread <= 0) { + fyi->err = ferror(fyi->fp); + if (fyi->err) { + fyi->eof = true; + fyr_debug(fyr, "fread got ERROR"); + goto err_out; + } + + fyi->eof = feof(fyi->fp); + if (fyi->eof) + fyr_debug(fyr, "fread got EOF"); + nread = 0; + break; + } + + } else if (fyi->fd >= 0) { + + fyr_debug(fyr, "performing read request of %zu", nreadreq); + + do { + snread = read(fyi->fd, (char *)fyi->buffer + fyi->read, nreadreq); + } while (snread == -1 && errno == EAGAIN); + + fyr_debug(fyr, "read returned %zd", snread); + + if (snread == -1) { + fyi->err = true; + fyi->eof = true; + fyr_error(fyr, "read() failed: %s", strerror(errno)); + goto err_out; + } + + if (!snread) { + fyi->eof = true; + nread = 0; + break; + } + + nread = snread; + } else { + fyr_error(fyr, "No FILE* nor fd available?"); + fyi->eof = true; + nread = 0; + goto err_out; + } + + assert(nread > 0); + + fyi->read += nread; + left = fyi->read - pos; + + } while (left < pull); + + /* no more, move it to parsed input chunk list */ + if (!left) { + fyr_debug(fyr, "input exhausted"); + p = NULL; + } + break; + + case fyit_memory: + assert(fyi->cfg.memory.size >= pos); + + left = fyi->cfg.memory.size - pos; + if (!left) { + fyr_debug(fyr, "memory input exhausted"); + break; + } + p = (char *)fyi->cfg.memory.data + pos; + break; + + case fyit_alloc: + assert(fyi->cfg.alloc.size >= pos); + + left = fyi->cfg.alloc.size - pos; + if (!left) { + fyr_debug(fyr, "alloc input exhausted"); + break; + } + p = (char *)fyi->cfg.alloc.data + pos; + break; + + + default: + assert(0); + break; + } + + if (leftp) + *leftp = left; + return p; + +err_out: + if (leftp) + *leftp = 0; + return NULL; +} + +void +fy_reader_advance_slow_path(struct fy_reader *fyr, int c) +{ + bool is_line_break = false; + size_t w; + + /* skip this character (optimize case of being the current) */ + w = c == fyr->current_c ? (size_t)fyr->current_w : fy_utf8_width(c); + fy_reader_advance_octets(fyr, w); + + /* first check for CR/LF */ + if (c == '\r' && fy_reader_peek(fyr) == '\n') { + fy_reader_advance_octets(fyr, 1); + is_line_break = true; + } else if (fy_reader_is_lb(fyr, c)) + is_line_break = true; + + if (is_line_break) { + fyr->column = 0; + fyr->line++; + } else if (fyr->tabsize && fy_is_tab(c)) + fyr->column += (fyr->tabsize - (fyr->column % fyr->tabsize)); + else + fyr->column++; +} + +struct fy_input *fy_input_create(const struct fy_input_cfg *fyic) +{ + struct fy_input *fyi = NULL; + int ret; + + fyi = fy_input_alloc(); + if (!fyi) + return NULL; + fyi->cfg = *fyic; + + /* copy filename pointers and switch */ + switch (fyic->type) { + + case fyit_file: + fyi->name = strdup(fyic->file.filename); + break; + + case fyit_fd: + ret = asprintf(&fyi->name, "<fd-%d>", fyic->fd.fd); + if (ret == -1) + fyi->name = NULL; + break; + + case fyit_stream: + if (fyic->stream.name) + fyi->name = strdup(fyic->stream.name); + else if (fyic->stream.fp == stdin) + fyi->name = strdup("<stdin>"); + else { + ret = asprintf(&fyi->name, "<stream-%d>", + fileno(fyic->stream.fp)); + if (ret == -1) + fyi->name = NULL; + } + break; + case fyit_memory: + ret = asprintf(&fyi->name, "<memory-@%p-%p>", + fyic->memory.data, (char *)fyic->memory.data + fyic->memory.size - 1); + if (ret == -1) + fyi->name = NULL; + break; + case fyit_alloc: + ret = asprintf(&fyi->name, "<alloc-@%p-%p>", + fyic->memory.data, (char *)fyic->memory.data + fyic->memory.size - 1); + if (ret == -1) + fyi->name = NULL; + break; + case fyit_callback: + ret = asprintf(&fyi->name, "<callback>"); + if (ret == -1) + fyi->name = NULL; + break; + default: + assert(0); + break; + } + if (!fyi->name) + goto err_out; + + fyi->buffer = NULL; + fyi->allocated = 0; + fyi->read = 0; + fyi->chunk = 0; + fyi->chop = 0; + fyi->fp = NULL; + fyi->fd = -1; + fyi->addr = NULL; + fyi->length = -1; + + /* default modes */ + fyi->lb_mode = fylb_cr_nl; + fyi->fws_mode = fyfws_space_tab; + + return fyi; + +err_out: + fy_input_unref(fyi); + return NULL; +} + +/* ensure that there are at least size octets available */ +const void *fy_reader_ensure_lookahead_slow_path(struct fy_reader *fyr, size_t size, size_t *leftp) +{ + const void *p; + size_t left; + + if (!leftp) + leftp = &left; + + p = fy_reader_ptr(fyr, leftp); + if (!p || *leftp < size) { + + fyr_debug(fyr, "ensure lookahead size=%zd left=%zd (%s - %zu)", + size, *leftp, + fy_input_get_filename(fyr->current_input), + fyr->current_input_pos); + + p = fy_reader_input_try_pull(fyr, fyr->current_input, size, leftp); + if (!p || *leftp < size) + return NULL; + + fyr->current_ptr = p; + fyr->current_left = *leftp; + fyr->current_c = fy_utf8_get(fyr->current_ptr, fyr->current_left, &fyr->current_w); + } + return p; +} + |