Add YAML configuration option.

Add new extra functions getdns_yaml2(dict|list|bindata|value)(). These are like their getdns_str2() counterparts, but take YAML input rather than JSON.

YAML introduces a new dependency, on libyaml. YAML can be disabled at configuration time, in which case the dependency is removed.

Modify getdns_query such that if a configuration file name includes ".yaml" it will be processed as a YAML configuration, not a JSON configuration.

Internally, getdns_yaml2*() work by passing the YAML string through a simple translation to JSON. At present, this translation assumes that configuration is the only use case, and so will error if the outer layer of the YAML input is not a map. This in effect means that at present all getdns_yaml2*() functions apart from getdns_yaml2dict() will give an error on the YAML translation to JSON.
This commit is contained in:
Jim Hague 2017-09-12 16:47:57 +01:00
parent 10133a71f3
commit 6c95f4177d
8 changed files with 812 additions and 10 deletions

View File

@ -577,6 +577,17 @@ case "$enable_stub_only" in
;;
esac
my_with_yaml=1
AC_ARG_ENABLE(yaml-config, AC_HELP_STRING([--disable-yaml-config], [Remove support for YAML configuration. Removes the libyaml dependency.]))
case "$enable_yaml_config" in
no)
my_with_yaml=0
;;
yes|*)
AC_DEFINE_UNQUOTED([USE_YAML_CONFIG], [1], [Define this to enable YAML config support.])
;;
esac
if test "$USE_WINSOCK" = 1; then
AC_MSG_NOTICE([ Building on Windows ... YES! ])
AC_DEFINE_UNQUOTED([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.])
@ -618,6 +629,30 @@ else
fi
fi
if test $my_with_yaml = 1
then
AC_ARG_WITH(libyaml, AS_HELP_STRING([--with-libyaml=pathname],
[path to libyaml (default: search /usr/local ..)]),
[], [withval="yes"])
if test x_$withval = x_yes; then
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
if test -f "$dir/include/yaml.h"; then
CFLAGS="$CFLAGS -I$dir/include"
LDFLAGS="$LDFLAGS -L$dir/lib"
AC_MSG_NOTICE([Found libyaml in $dir])
break
fi
done
else
if test x_$withval != x_no; then
CFLAGS="$CFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"
else
my_with_yaml=0
fi
fi
fi
if test $my_with_libunbound = 1
then
# find libunbound
@ -658,6 +693,16 @@ then
])
fi
if test $my_with_yaml = 1
then
AC_MSG_NOTICE([Checking for dependency libyaml])
AC_CHECK_LIB([yaml], [yaml_parser_parse], [], [
MISSING_DEPS="${MISSING_DEPS}${MISSING_SEP}libyaml"
MISSING_SEP=", "
found_all_libs=0
])
fi
AC_ARG_ENABLE(unbound-event-api, AC_HELP_STRING([--disable-unbound-event-api], [Disable usage of libunbounds event API]))
case "$enable_unbound_event_api" in
no)

View File

@ -92,6 +92,8 @@ UTIL_OBJ=rbtree.lo val_secalgo.lo lruhash.lo lookup3.lo locks.lo
JSMN_OBJ=jsmn.lo
YAML_OBJ=convert_yaml_to_json.lo
EXTENSION_OBJ=$(DEFAULT_EVENTLOOP_OBJ) libevent.lo libev.lo
NON_C99_OBJS=context.lo libuv.lo
@ -123,6 +125,9 @@ $(UTIL_OBJ):
$(JSMN_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -DJSMN_GETDNS -c $(srcdir)/jsmn/$(@:.lo=.c) -o $@
$(YAML_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/yaml/$(@:.lo=.c) -o $@
$(EXTENSION_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WPEDANTICFLAG) -c $(srcdir)/extension/$(@:.lo=.c) -o $@
@ -173,8 +178,8 @@ libgetdns_ext_ev.la: libgetdns.la libev.lo
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols
libgetdns.la: $(GETDNS_OBJ) version.lo context.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ)
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
libgetdns.la: $(GETDNS_OBJ) version.lo context.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(YAML_OBJ)
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(YAML_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
test: default
cd test && $(MAKE) $@
@ -226,13 +231,14 @@ Makefile: $(srcdir)/Makefile.in ../config.status
depend:
(cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new )
(blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iutil/auxiliary *.c gldns/*.c compat/*.c util/*.c jsmn/*.c extension/*.c| \
(blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iutil/auxiliary *.c gldns/*.c compat/*.c util/*.c jsmn/*.c yaml/*.c extension/*.c| \
sed -e "s? $$blddir/? ?g" \
-e 's? gldns/? $$(srcdir)/gldns/?g' \
-e 's? compat/? $$(srcdir)/compat/?g' \
-e 's? util/auxiliary/util/? $$(srcdir)/util/auxiliary/util/?g' \
-e 's? util/? $$(srcdir)/util/?g' \
-e 's? jsmn/? $$(srcdir)/jsmn/?g' \
-e 's? yaml/? $$(srcdir)/yaml/?g' \
-e 's? extension/? $$(srcdir)/extension/?g' \
-e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \
-e 's? \$$(srcdir)/config\.h? config.h?g' \

View File

@ -54,6 +54,7 @@
#include "dict.h"
#include "list.h"
#include "jsmn/jsmn.h"
#include "yaml/convert_yaml_to_json.h"
#include "convert.h"
#include "debug.h"
@ -1802,3 +1803,99 @@ getdns_str2int(const char *str, uint32_t *value)
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_yaml2dict(const char *str, getdns_dict **dict)
{
#ifdef USE_YAML_CONFIG
char *jsonstr;
if (!str || !dict)
return GETDNS_RETURN_INVALID_PARAMETER;
jsonstr = yaml_string_to_json_string(str);
if (jsonstr) {
getdns_return_t res = getdns_str2dict(jsonstr, dict);
free(jsonstr);
return res;
} else {
return GETDNS_RETURN_GENERIC_ERROR;
}
#else /* USE_YAML_CONFIG */
str = str;
dict = dict;
return GETDNS_RETURN_NOT_IMPLEMENTED;
#endif /* USE_YAML_CONFIG */
}
getdns_return_t
getdns_yaml2list(const char *str, getdns_list **list)
{
#ifdef USE_YAML_CONFIG
char *jsonstr;
if (!str || !list)
return GETDNS_RETURN_INVALID_PARAMETER;
jsonstr = yaml_string_to_json_string(str);
if (jsonstr) {
getdns_return_t res = getdns_str2list(jsonstr, list);
free(jsonstr);
return res;
} else {
return GETDNS_RETURN_GENERIC_ERROR;
}
#else /* USE_YAML_CONFIG */
str = str;
list = list;
return GETDNS_RETURN_NOT_IMPLEMENTED;
#endif /* USE_YAML_CONFIG */
}
getdns_return_t
getdns_yaml2bindata(const char *str, getdns_bindata **bindata)
{
#ifdef USE_YAML_CONFIG
char *jsonstr;
if (!str || !bindata)
return GETDNS_RETURN_INVALID_PARAMETER;
jsonstr = yaml_string_to_json_string(str);
if (jsonstr) {
getdns_return_t res = getdns_str2bindata(jsonstr, bindata);
free(jsonstr);
return res;
} else {
return GETDNS_RETURN_GENERIC_ERROR;
}
#else /* USE_YAML_CONFIG */
str = str;
bindata = bindata;
return GETDNS_RETURN_NOT_IMPLEMENTED;
#endif /* USE_YAML_CONFIG */
}
getdns_return_t
getdns_yaml2int(const char *str, uint32_t *value)
{
#ifdef USE_YAML_CONFIG
char *jsonstr;
if (!str || !value)
return GETDNS_RETURN_INVALID_PARAMETER;
jsonstr = yaml_string_to_json_string(str);
if (jsonstr) {
getdns_return_t res = getdns_str2int(jsonstr, value);
free(jsonstr);
return res;
} else {
return GETDNS_RETURN_GENERIC_ERROR;
}
#else /* USE_YAML_CONFIG */
str = str;
value = value;
return GETDNS_RETURN_NOT_IMPLEMENTED;
#endif /* USE_YAML_CONFIG */
}

View File

@ -1685,6 +1685,54 @@ getdns_str2bindata(const char *str, getdns_bindata **bindata);
getdns_return_t
getdns_str2int(const char *str, uint32_t *value);
/** @}
*/
/**
* \defgroup Uyaml2getdns_data Converting YAML input to getdns data structures
* @{
*/
/**
* Convert YAML text to a getdns_dict.
*
* @param str A textual representation of a getdns_dict.
* @param dict The returned getdns_dict.
* @return GETDNS_RETURN_GOOD on success or an error code on failure.
*/
getdns_return_t
getdns_yaml2dict(const char *str, getdns_dict **dict);
/**
* Convert YAML text to a getdns_list.
*
* @param str A textual representation of a getdns_list.
* @param list The returned getdns_list.
* @return GETDNS_RETURN_GOOD on success or an error code on failure.
*/
getdns_return_t
getdns_yaml2list(const char *str, getdns_list **list);
/**
* Convert string text to a getdns_bindata.
*
* @param str A textual representation of a getdns_bindata
* @param bindata The returned getdns_bindata.
* @return GETDNS_RETURN_GOOD on success or an error code on failure.
*/
getdns_return_t
getdns_yaml2bindata(const char *str, getdns_bindata **bindata);
/**
* Convert string text to a getdns 32 bits unsigned integer.
*
* @param str A textual representation of the integer.
* @param value The returned integer.
* @return GETDNS_RETURN_GOOD on success or an error code on failure.
*/
getdns_return_t
getdns_yaml2int(const char *str, uint32_t *value);
/** @}
*/

View File

@ -159,5 +159,9 @@ getdns_wire2msg_dict_scan
getdns_wire2rr_dict
getdns_wire2rr_dict_buf
getdns_wire2rr_dict_scan
getdns_yaml2bindata
getdns_yaml2dict
getdns_yaml2int
getdns_yaml2list
plain_mem_funcs_user_arg
priv_getdns_context_mf

View File

@ -215,7 +215,7 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-C\t<filename>\n");
fprintf(out, "\t\tRead settings from config file <filename>\n");
fprintf(out, "\t\tThe getdns context will be configured with these settings\n");
fprintf(out, "\t\tThe file must be in json dict format.\n");
fprintf(out, "\t\tThe file must be in JSON or YAML dict format.\n");
if (i_am_stubby) {
fprintf(out, "\t\tBy default, configuration is first read from");
fprintf(out, "\n\t\t\"/etc/stubby.conf\" and then from \"$HOME/.stubby.conf\"\n");
@ -472,16 +472,25 @@ done:
return r;
}
static void parse_config(const char *config_str)
static void parse_config(const char *config_str, int yaml_config)
{
getdns_dict *config_dict;
getdns_list *list;
getdns_return_t r;
if ((r = getdns_str2dict(config_str, &config_dict)))
if (yaml_config) {
#ifdef USE_YAML_CONFIG
r = getdns_yaml2dict(config_str, &config_dict);
#else
fprintf(stderr, "Support for YAML configuration files not available.\n");
return;
#endif
} else {
r = getdns_str2dict(config_str, &config_dict);
}
if (r)
fprintf(stderr, "Could not parse config file: %s\n",
getdns_get_errorstr_by_id(r));
else {
if (!(r = getdns_dict_get_list(
config_dict, "listen_addresses", &list))) {
@ -561,7 +570,7 @@ int parse_config_file(const char *fn, int report_open_failure)
}
config_file[config_file_sz] = 0;
fclose(fh);
parse_config(config_file);
parse_config(config_file, strstr(fn, ".yaml") != NULL);
free(config_file);
return GETDNS_RETURN_GOOD;
}
@ -650,7 +659,7 @@ getdns_return_t parse_args(int argc, char **argv)
}
continue;
} else if (arg[0] == '{') {
parse_config(arg);
parse_config(arg, 0);
continue;
} else if (arg[0] != '-') {
@ -1719,7 +1728,7 @@ main(int argc, char **argv)
, "%s/.stubby.conf"
, getenv("HOME")
);
(void) parse_config(default_stubby_config);
(void) parse_config(default_stubby_config, 0);
(void) parse_config_file("/etc/stubby.conf", 0);
if (n_chars > 0 && n_chars < (int)sizeof(home_stubby_conf_fn)){
(void) parse_config_file(home_stubby_conf_fn, 0);

View File

@ -0,0 +1,542 @@
/*
* Copyright (c) 2017, NLNet Labs, Verisign, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "config.h"
#ifdef USE_YAML_CONFIG
#include <yaml.h>
#include "../gldns/gbuffer.h"
#include "convert_yaml_to_json.h"
static int process_yaml_stream(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
static int process_yaml_document(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
static int process_yaml_mapping(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
static int process_yaml_sequence(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
static int process_yaml_value(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
static int output_scalar(yaml_event_t *, gldns_buffer *);
static void report_parser_error(yaml_parser_t *);
static char* event_type_string(yaml_event_type_t);
/* public functions */
char *
yaml_string_to_json_string(const char *instr)
{
assert(instr);
gldns_buffer *buf;
char* json = NULL;
buf = gldns_buffer_new(8192);
if (!buf) {
fprintf(stderr, "Could not assign buffer for json output");
return NULL;
}
yaml_parser_t parser;
yaml_event_t event;
memset(&parser, 0, sizeof(parser));
memset(&event, 0, sizeof(event));
if (!yaml_parser_initialize(&parser)) {
fprintf(stderr, "Could not initialize the parser object\n");
goto return_error;
}
/* Set the parser parameters. */
yaml_parser_set_input_string(&parser, (const unsigned char *) instr, strlen(instr));
/* Get the first event. */
if (!yaml_parser_parse(&parser, &event)) {
report_parser_error(&parser);
goto return_error;
}
/* First event should be stream start. */
if (event.type != YAML_STREAM_START_EVENT) {
fprintf(stderr, "Event error: wrong type of event: %d\n", event.type);
goto return_error;
}
if (process_yaml_stream(&parser, &event, buf) != 0) {
goto return_error;
}
yaml_event_delete(&event);
yaml_parser_delete(&parser);
/*
* gldns_buffer_export() returns a pointer to the data and
* sets a flag to prevent it from being deleted by
* gldns_buffer_free()
*/
json = (char *) gldns_buffer_export(buf);
gldns_buffer_free(buf);
return json;
return_error:
yaml_event_delete(&event);
yaml_parser_delete(&parser);
gldns_buffer_free(buf);
return NULL;
}
/* local functions */
int
process_yaml_stream(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
{
assert(parser);
assert(event);
assert(buf);
int done = 0;
while (!done)
{
/* Delete the event that brought us here */
yaml_event_delete(event);
/* Get the next event. */
if (!yaml_parser_parse(parser, event)) {
report_parser_error(parser);
return -1;
}
switch (event->type) {
case YAML_STREAM_END_EVENT:
done = 1;
break;
case YAML_DOCUMENT_START_EVENT:
if (process_yaml_document(parser, event, buf) != 0) {
return -1;
}
break;
case YAML_STREAM_START_EVENT:
case YAML_DOCUMENT_END_EVENT:
case YAML_ALIAS_EVENT:
case YAML_SCALAR_EVENT:
case YAML_SEQUENCE_START_EVENT:
case YAML_SEQUENCE_END_EVENT:
case YAML_MAPPING_START_EVENT:
case YAML_MAPPING_END_EVENT:
fprintf(stderr,
"Event error: %s. Expected YAML_DOCUMENT_START_EVENT or YAML_STREAM_END_EVENT.\n",
event_type_string(event->type));
return -1;
default:
/* NOTREACHED */
break;
}
}
return 0;
}
int
process_yaml_document(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
{
assert(parser);
assert(event);
assert(buf);
int done = 0;
while (!done)
{
/* Delete the event that brought us here */
yaml_event_delete(event);
/* Get the next event. */
if (!yaml_parser_parse(parser, event)) {
report_parser_error(parser);
return -1;
}
switch (event->type) {
case YAML_DOCUMENT_END_EVENT:
done = 1;
break;
case YAML_MAPPING_START_EVENT:
/*
* getdns config data is a dictionary (ie yaml mapping)
* so the document must start with a mapping; scalar
* or sequence would be wrong.
*/
if (process_yaml_mapping(parser, event, buf) != 0) {
return -1;
}
break;
case YAML_STREAM_START_EVENT:
case YAML_STREAM_END_EVENT:
case YAML_DOCUMENT_START_EVENT:
case YAML_ALIAS_EVENT:
case YAML_SCALAR_EVENT:
case YAML_SEQUENCE_START_EVENT:
case YAML_SEQUENCE_END_EVENT:
case YAML_MAPPING_END_EVENT:
fprintf(stderr,
"Event error: %s. Expected YAML_MAPPING_START_EVENT or YAML_DOCUMENT_END_EVENT.\n",
event_type_string(event->type));
return -1;
default:
/* NOTREACHED */
break;
}
}
return 0;
}
int
process_yaml_mapping(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
{
assert(parser);
assert(event);
assert(buf);
int done = 0;
int members = 0;
if ( gldns_buffer_printf(buf, "{ ") == -1 )
return -1;
while (!done)
{
/* Delete the event that brought us here */
yaml_event_delete(event);
/* Get the next event. */
if (!yaml_parser_parse(parser, event)) {
report_parser_error(parser);
return -1;
}
if (event->type == YAML_SCALAR_EVENT) {
if (members)
if (gldns_buffer_printf(buf, ", ") == -1)
return -1;
if (output_scalar(event, buf) != 0) {
fprintf(stderr, "Mapping error: Error outputting key\n");
return -1;
}
if (gldns_buffer_printf(buf, ": ") == -1)
return -1;
members = 1;
} else if (event->type == YAML_MAPPING_END_EVENT) {
if (gldns_buffer_printf(buf, " }") == -1)
return -1;
done = 1;
continue;
} else {
fprintf(stderr,
"Event error: %s. Expected YAML_SCALAR_EVENT or YAML_MAPPING_END_EVENT.\n",
event_type_string(event->type));
return -1;
}
/* Delete the event that brought us here */
yaml_event_delete(event);
/* Get the next event. */
if (!yaml_parser_parse(parser, event)) {
report_parser_error(parser);
return -1;
}
switch (event->type) {
case YAML_SCALAR_EVENT:
case YAML_SEQUENCE_START_EVENT:
case YAML_MAPPING_START_EVENT:
if (process_yaml_value(parser, event, buf) != 0) {
return -1;
}
break;
case YAML_STREAM_START_EVENT:
case YAML_STREAM_END_EVENT:
case YAML_DOCUMENT_START_EVENT:
case YAML_DOCUMENT_END_EVENT:
case YAML_ALIAS_EVENT:
case YAML_SEQUENCE_END_EVENT:
case YAML_MAPPING_END_EVENT:
fprintf(stderr,
"Event error: %s. Expected YAML_MAPPING_START_EVENT, YAML_SEQUENCE_START_EVENT or YAML_SCALAR_EVENT.\n",
event_type_string(event->type));
return -1;
default:
/* NOTREACHED */
break;
}
}
return 0;
}
int
process_yaml_sequence(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
{
assert(parser);
assert(event);
assert(buf);
int done = 0;
int elements = 0;
if ( gldns_buffer_printf(buf, "[ ") == -1 )
return -1;
while (!done)
{
/* Delete the event that brought us here */
yaml_event_delete(event);
/* Get the next event. */
if (!yaml_parser_parse(parser, event)) {
report_parser_error(parser);
return -1;
}
switch (event->type) {
case YAML_SCALAR_EVENT:
case YAML_SEQUENCE_START_EVENT:
case YAML_MAPPING_START_EVENT:
if (elements)
if (gldns_buffer_printf(buf, ", ") == -1)
return -1;
if (process_yaml_value(parser, event, buf) != 0)
return -1;
elements = 1;
break;
case YAML_SEQUENCE_END_EVENT:
if (gldns_buffer_printf(buf, " ]") == -1)
return -1;
done = 1;
break;
case YAML_STREAM_START_EVENT:
case YAML_STREAM_END_EVENT:
case YAML_DOCUMENT_START_EVENT:
case YAML_DOCUMENT_END_EVENT:
case YAML_ALIAS_EVENT:
case YAML_MAPPING_END_EVENT:
fprintf(stderr,
"Event error: %s. Expected YAML_MAPPING_START_EVENT, YAML_SEQUENCE_START_EVENT, YAML_SCALAR_EVENT or YAML_SEQUENCE_END_EVENT.\n",
event_type_string(event->type));
return -1;
default:
/* NOTREACHED */
break;
}
}
return 0;
}
int
process_yaml_value(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
{
assert(parser);
assert(event);
assert(buf);
switch (event->type) {
case YAML_SCALAR_EVENT:
if (output_scalar(event, buf) != 0) {
fprintf(stderr, "Value error: Error outputting scalar\n");
return -1;
}
break;
case YAML_SEQUENCE_START_EVENT:
if (process_yaml_sequence(parser, event, buf) != 0) {
return -1;
}
break;
case YAML_MAPPING_START_EVENT:
if (process_yaml_mapping(parser, event, buf) != 0) {
return -1;
}
break;
default:
fprintf(stderr, "Bug: calling process_yaml_value() in the wrong context");
return -1;
}
return 0;
}
int
output_scalar(yaml_event_t *event, gldns_buffer *buf)
{
const char *fmt = "%s";
assert(event);
assert(buf);
assert(event->data.scalar.length > 0);
if (event->data.scalar.style != YAML_PLAIN_SCALAR_STYLE)
fmt = "\"%s\"";
if ( gldns_buffer_printf(buf, fmt, event->data.scalar.value) == -1 )
return -1;
return 0;
}
void report_parser_error(yaml_parser_t *parser)
{
assert(parser);
/* Display a parser error message. */
switch (parser->error) {
case YAML_MEMORY_ERROR:
fprintf(stderr, "Memory error: Not enough memory for parsing\n");
break;
case YAML_READER_ERROR:
if (parser->problem_value != -1) {
fprintf(stderr, "Reader error: %s: #%X at %zu\n", parser->problem,
parser->problem_value, parser->problem_offset);
} else {
fprintf(stderr, "Reader error: %s at %zu\n", parser->problem,
parser->problem_offset);
}
break;
case YAML_SCANNER_ERROR:
if (parser->context) {
fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n"
"%s at line %lu, column %lu\n", parser->context,
parser->context_mark.line+1, parser->context_mark.column+1,
parser->problem, parser->problem_mark.line+1,
parser->problem_mark.column+1);
} else {
fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n",
parser->problem, parser->problem_mark.line+1,
parser->problem_mark.column+1);
}
break;
case YAML_PARSER_ERROR:
if (parser->context) {
fprintf(stderr, "Parser error: %s at line %lu, column %lu\n"
"%s at line %lu, column %lu\n", parser->context,
parser->context_mark.line+1, parser->context_mark.column+1,
parser->problem, parser->problem_mark.line+1,
parser->problem_mark.column+1);
} else {
fprintf(stderr, "Parser error: %s at line %lu, column %lu\n",
parser->problem, parser->problem_mark.line+1,
parser->problem_mark.column+1);
}
break;
default:
/* Couldn't happen. */
fprintf(stderr, "Internal error\n");
break;
}
return;
}
/* TODO - improve this */
char*
event_type_string(yaml_event_type_t type)
{
switch (type) {
case YAML_STREAM_START_EVENT:
return "YAML_STREAM_START_EVENT";
case YAML_STREAM_END_EVENT:
return "YAML_STREAM_END_EVENT";
case YAML_DOCUMENT_START_EVENT:
return "YAML_DOCUMENT_START_EVENT";
case YAML_DOCUMENT_END_EVENT:
return "YAML_DOCUMENT_END_EVENT";
case YAML_ALIAS_EVENT:
return "YAML_ALIAS_EVENT";
case YAML_SCALAR_EVENT:
return "YAML_SCALAR_EVENT";
case YAML_SEQUENCE_START_EVENT:
return "YAML_SEQUENCE_START_EVENT";
case YAML_SEQUENCE_END_EVENT:
return "YAML_SEQUENCE_END_EVENT";
case YAML_MAPPING_START_EVENT:
return "YAML_MAPPING_START_EVENT";
case YAML_MAPPING_END_EVENT:
return "YAML_MAPPING_END_EVENT";
default:
/* NOTREACHED */
return NULL;
}
return NULL;
}
#endif /* USE_YAML_CONFIG */

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2017, NLNet Labs, Verisign, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _CONVERT_YAML_TO_JSON_H
#define _CONVERT_YAML_TO_JSON_H
#include <stdio.h>
/**
* read yaml-syntax data from the string and convert to json-syntax
* yaml syntax resitrictions imposed for getdns:
* the outer-most data structure must be a yaml mapping
* mapping keys must be yaml scalars
* plain scalars are output to the json string unchanged
* non-plain scalars (quoted, double-quoted, wrapped) are output double-quoted
* TODO Test on yaml data containing yaml tags (these are ignored at present)
* The code has only been tested on yaml data using indentation style, so it
* should be tested on other styles as well.
* @param instr the string carrying data in yaml syntax
* @return a string of data in json syntax on success
* @return NULL if there is a yaml syntax violation
* the outer-most structure in not a mapping
* a mapping key is complex (a mapping or sequence)
*/
char * yaml_string_to_json_string(const char *instr);
#endif //_CONVERT_YAML_TO_JSON_H