Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ src_files = \
src/context.c \
src/error.c \
src/event.c \
src/file.c \
src/info.c \
src/log.c \
src/parse.c \
Expand All @@ -16,6 +17,7 @@ src_headers = \
src/context.h \
src/error.h \
src/event.h \
src/file.h \
src/info.h \
src/log.h \
src/parse.h \
Expand All @@ -34,7 +36,9 @@ ACLOCAL_AMFLAGS = -Im4

include_HEADERS = $(include_dir)/asdf.h
nobase_include_HEADERS = \
$(include_dir)/asdf.h \
$(include_dir)/asdf/event.h \
$(include_dir)/asdf/file.h \
$(include_dir)/asdf/log.h \
$(include_dir)/asdf/parse.h \
$(include_dir)/asdf/util.h \
Expand Down
1 change: 1 addition & 0 deletions include/asdf.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef ASDF_H
#define ASDF_H

#include <asdf/file.h>
#include <asdf/parse.h>

#endif
17 changes: 17 additions & 0 deletions include/asdf/file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef ASDF_FILE_H
#define ASDF_FILE_H

#include <stddef.h>
#include <stdio.h>

#include <asdf/util.h>

/* Forward declaration */
typedef struct asdf_file asdf_file_t;

ASDF_EXPORT asdf_file_t *asdf_open_file(const char *filename, const char* mode);
ASDF_EXPORT asdf_file_t *asdf_open_fp(FILE *fp, const char *filename);
ASDF_EXPORT asdf_file_t *asdf_open_mem(const void *buf, size_t size);
ASDF_EXPORT void asdf_close(asdf_file_t *file);

#endif /* ASDF_FILE_H */
2 changes: 1 addition & 1 deletion include/asdf/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ typedef struct asdf_event asdf_event_t;
/* Public API functions */
ASDF_EXPORT asdf_parser_t *asdf_parser_create(asdf_parser_cfg_t *config);
ASDF_EXPORT int asdf_parser_set_input_file(asdf_parser_t *parser, const char *filename);
ASDF_EXPORT int asdf_parser_set_input_fp(asdf_parser_t *parser, FILE *file, const char *filename);
ASDF_EXPORT int asdf_parser_set_input_fp(asdf_parser_t *parser, FILE *fp, const char *filename);
ASDF_EXPORT int asdf_parser_set_input_mem(asdf_parser_t *parser, const void *buf, size_t size);
ASDF_EXPORT asdf_event_t *asdf_parser_parse(asdf_parser_t *parser);
ASDF_EXPORT void asdf_parser_destroy(asdf_parser_t *parser);
Expand Down
2 changes: 1 addition & 1 deletion src/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ASDF_LOCAL void asdf_context_error_set_errno(asdf_context_t *ctx, int errnum);
#define ASDF_ERROR(obj, fmt, ...) \
do { \
__ASDF_GET_CONTEXT(obj); \
asdf_context_error_set(__ctx, (fmt), ...); \
asdf_context_error_set(__ctx, (fmt), ##__VA_ARGS__); \
} while (0)


Expand Down
147 changes: 147 additions & 0 deletions src/file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libfyaml.h>

#include "context.h"
#include "error.h"
#include "event.h"
#include "file.h"
#include "log.h"
#include "parse.h"
#include "util.h"


/* Internal helper to allocate and set up a new asdf_file_t */
static asdf_file_t *asdf_file_create() {
/* Try to allocate asdf_file_t object, returns NULL on memory allocation failure*/
asdf_file_t *file = calloc(1, sizeof(asdf_file_t));

if (UNLIKELY(!file))
return NULL;

/* Basic parser settings for high-level file interface: ignore individual YAML events and
* just store the tree in memory to parse into a fy_document later */
asdf_parser_cfg_t parser_cfg = {.flags = ASDF_PARSER_OPT_BUFFER_TREE};
asdf_parser_t *parser = asdf_parser_create(&parser_cfg);

if (!parser)
return NULL;

file->base.ctx = parser->base.ctx;
asdf_context_retain(file->base.ctx);
file->parser = parser;
/* Now we can start cooking */
return file;
}


asdf_file_t *asdf_open_file(const char *filename, const char *mode) {
asdf_file_t *file = asdf_file_create();

if (!file)
return NULL;

/* Currently only the mode string "r" is supported */
if ((0 != strcasecmp(mode, "r"))) {
ASDF_ERROR(file, "invalid asdf file mode: %s", mode);
return file;
}

asdf_parser_set_input_file(file->parser, filename);
return file;
}


asdf_file_t *asdf_open_fp(FILE *fp, const char *filename) {
asdf_file_t *file = asdf_file_create();

if (!file)
return NULL;

asdf_parser_set_input_fp(file->parser, fp, filename);
return file;
}


asdf_file_t *asdf_open_mem(const void *buf, size_t size) {
asdf_file_t *file = asdf_file_create();

if (!file)
return NULL;

asdf_parser_set_input_mem(file->parser, buf, size);
return file;
}


void asdf_close(asdf_file_t *file) {
if (!file)
return;

asdf_context_release(file->base.ctx);
asdf_parser_destroy(file->parser);
fy_document_destroy(file->tree);
/* Clean up */
ZERO_MEMORY(file, sizeof(asdf_file_t));
free(file);
}


ASDF_LOCAL struct fy_document *asdf_file_get_tree_document(asdf_file_t *file) {
if (!file)
return NULL;

if (file->tree)
/* Already exists and ready to go */
return file->tree;

asdf_parser_t *parser = file->parser;

if (!parser)
return NULL;

if (UNLIKELY(0 == parser->tree.has_tree))
return NULL;

asdf_event_t *event = NULL;

if (parser->tree.has_tree < 0) {
/* We have to run the parser until the tree is found or we hit a block or eof (no tree) */
while ((event = asdf_event_iterate(parser))) {
asdf_event_type_t event_type = asdf_event_type(event);
switch (event_type) {
case ASDF_TREE_END_EVENT:
goto has_tree;
case ASDF_BLOCK_EVENT:
case ASDF_END_EVENT:
asdf_event_free(parser, event);
return NULL;
default:
break;
}
}

return NULL;
}
has_tree:
asdf_event_free(parser, event);

if (parser->tree.has_tree < 1 || parser->tree.buf == NULL) {
ASDF_LOG(
file,
ASDF_LOG_WARN,
"logic error: there should be a YAML tree in the file at "
"this point but it was not found (tree.has_tree = %d; tree.buf = 0x%zu)",
parser->tree.has_tree,
parser->tree.buf);
return NULL;
}

size_t size = parser->tree.size;
const char *buf = (const char *)parser->tree.buf;
file->tree = fy_document_build_from_string(NULL, buf, size);
return file->tree;
}
20 changes: 20 additions & 0 deletions src/file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <libfyaml.h>

#include <asdf/file.h>

#include "context.h"
#include "parse.h"
#include "util.h"


typedef struct asdf_file {
asdf_base_t base;
asdf_parser_t *parser;
struct fy_document *tree;
} asdf_file_t;


/* Internal helper to get the `struct fy_document` for the tree, if any */
ASDF_LOCAL struct fy_document *asdf_file_get_tree_document(asdf_file_t *file);
34 changes: 30 additions & 4 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,13 @@ static parse_result_t parse_tree_or_block(asdf_parser_t *parser, asdf_event_t *e

// Likeliest case--we encounter a %YAML directive indicating beginning of the YAML tree
if (LIKELY(is_yaml_directive((const char *)r, len))) {
parser->tree.has_tree = 1;
return emit_tree_start_event(parser, event);
}

// Or may encounter an ASDF block magic esp. in case of an exploded ASDF file
if (is_block_magic(r, len)) {
parser->tree.has_tree = 0;
parser->state = ASDF_PARSER_STATE_BLOCK;
return ASDF_PARSE_CONTINUE;
}
Expand All @@ -222,10 +224,12 @@ static parse_result_t parse_tree_or_block(asdf_parser_t *parser, asdf_event_t *e
// TODO: Technically this should be either at the start of the file or begin
// with a newline; should be more careful about that.
if (LIKELY(is_yaml_directive((const char *)r, len))) {
parser->tree.has_tree = 1;
return emit_tree_start_event(parser, event);
}
break;
case ASDF_BLOCK_MAGIC_TOK:
parser->tree.has_tree = 0;
parser->state = ASDF_PARSER_STATE_BLOCK;
return ASDF_PARSE_CONTINUE;
default:
Expand Down Expand Up @@ -376,10 +380,30 @@ static parse_result_t parse_tree(asdf_parser_t *parser, asdf_event_t *event) {
// adding a method to push data back onto the buffered stream. But the
// ASDF_PARSER_OPT_EMIT_YAML_EVENTS option is primarily just for debugging purposes
// so for now we don't do anything too crazy.
buffer_tree |= (emit_yaml_events && !parser->stream->is_seekable);
if (buffer_tree) {
ASDF_LOG(
parser,
ASDF_LOG_DEBUG,
"enabling tree buffering due to "
"ASDF_PARSER_OPT_BUFFER_TREE parser flag");
}

if (emit_yaml_events && !parser->stream->is_seekable) {
ASDF_LOG(
parser,
ASDF_LOG_DEBUG,
"enabling tree buffering due to "
"ASDF_PARSER_OPT_EMIT_YAML_EVENTS parser flag");
buffer_tree |= emit_yaml_events;
}

if (buffer_tree) {
// Initialize the tree buffer and set up the stream to capture to it
ASDF_LOG(
parser,
ASDF_LOG_DEBUG,
"allocating an initial %zu bytes for the tree buffer",
(size_t)ASDF_PARSER_READ_BUFFER_INIT_SIZE);
parser->tree.buf = malloc(ASDF_PARSER_READ_BUFFER_INIT_SIZE);
if (!parser->tree.buf) {
ASDF_ERROR_OOM(parser);
Expand Down Expand Up @@ -936,11 +960,13 @@ asdf_parser_t *asdf_parser_create(asdf_parser_cfg_t *config) {
}

parser->base.ctx = ctx;
parser->config = config ? config : &default_asdf_parser_cfg;
parser->config = config ? *config : default_asdf_parser_cfg;
parser->state = ASDF_PARSER_STATE_INITIAL;
parser->done = false;
parser->tree.has_tree = -1;
ZERO_MEMORY(parser->asdf_version, sizeof(parser->asdf_version));
ZERO_MEMORY(parser->standard_version, sizeof(parser->standard_version));
ASDF_LOG(parser, ASDF_LOG_DEBUG, "parser config flags: 0x%x", parser->config.flags);
return parser;
}

Expand All @@ -960,9 +986,9 @@ int asdf_parser_set_input_file(asdf_parser_t *parser, const char *filename) {
}


int asdf_parser_set_input_fp(asdf_parser_t *parser, FILE *file, const char *filename) {
int asdf_parser_set_input_fp(asdf_parser_t *parser, FILE *fp, const char *filename) {
assert(parser);
parser->stream = asdf_stream_from_fp(parser->base.ctx, file, filename);
parser->stream = asdf_stream_from_fp(parser->base.ctx, fp, filename);

if (!parser->stream) {
// TODO: Better error handling for file opening errors
Expand Down
8 changes: 6 additions & 2 deletions src/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ typedef struct asdf_parser_tree_info {
size_t size;
// Found the full YAML tree
bool found;
// Indicates whether the file even has a YAML tree; rare to be false but possible
// in the case of exploded files. This is a trinary value with a negative indicating
// unknown, 0 false, >= 1 true.
int8_t has_tree;
} asdf_parser_tree_info_t;


Expand All @@ -79,7 +83,7 @@ typedef struct asdf_parser_block_info {

typedef struct asdf_parser {
asdf_base_t base;
const asdf_parser_cfg_t *config;
asdf_parser_cfg_t config;
asdf_parser_state_t state;
asdf_stream_t *stream;
struct asdf_event_p *event_freelist;
Expand All @@ -96,5 +100,5 @@ typedef struct asdf_parser {

static inline bool asdf_parser_has_opt(asdf_parser_t *parser, asdf_parser_opt_t opt) {
assert(parser);
return (parser->config && ((parser->config->flags & opt) == opt));
return ((parser->config.flags & opt) == opt);
}
13 changes: 13 additions & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $(asdf_standard_submodule) $(munit_submodule):

check_PROGRAMS = \
test-event.unit \
test-file.unit \
test-parse.unit \
test-parse-util.unit \
test-stream.unit
Expand Down Expand Up @@ -49,6 +50,18 @@ test_event_unit_CFLAGS = $(unit_test_cflags)
test_event_unit_LDFLAGS = $(unit_test_ldflags)
test_event_unit_LDADD = $(unit_test_ldadd)

# test-file.unit
test_file_unit_SOURCES = \
test-file.c \
$(top_srcdir)/src/context.c \
$(top_srcdir)/src/error.c \
$(top_srcdir)/src/file.c \
$(top_srcdir)/src/log.c
test_file_unit_CPPFLAGS = $(unit_test_cppflags)
test_file_unit_CFLAGS = $(unit_test_cflags)
test_file_unit_LDFLAGS = $(unit_test_ldflags)
test_file_unit_LDADD = $(unit_test_ldadd) $(FYAML_LIBS)

# test-parse.unit
test_parse_unit_SOURCES = test-parse.c
test_parse_unit_CPPFLAGS = $(unit_test_cppflags)
Expand Down
Loading