diff options
Diffstat (limited to 'web/server/h2o/libh2o/deps/yoml')
-rw-r--r-- | web/server/h2o/libh2o/deps/yoml/.gitmodules | 3 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/yoml/Makefile | 3 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/yoml/README.md | 66 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/yoml/test-yoml.c | 278 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/yoml/yoml-parser.h | 391 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/yoml/yoml.h | 148 |
6 files changed, 889 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/yoml/.gitmodules b/web/server/h2o/libh2o/deps/yoml/.gitmodules new file mode 100644 index 00000000..37df0c6d --- /dev/null +++ b/web/server/h2o/libh2o/deps/yoml/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/picotest"] + path = deps/picotest + url = https://github.com/h2o/picotest.git diff --git a/web/server/h2o/libh2o/deps/yoml/Makefile b/web/server/h2o/libh2o/deps/yoml/Makefile new file mode 100644 index 00000000..6f485902 --- /dev/null +++ b/web/server/h2o/libh2o/deps/yoml/Makefile @@ -0,0 +1,3 @@ +test: + $(CC) -Wall -g -I deps/picotest deps/picotest/picotest.c test-yoml.c -lyaml -o test-yoml + ./test-yoml diff --git a/web/server/h2o/libh2o/deps/yoml/README.md b/web/server/h2o/libh2o/deps/yoml/README.md new file mode 100644 index 00000000..f5867892 --- /dev/null +++ b/web/server/h2o/libh2o/deps/yoml/README.md @@ -0,0 +1,66 @@ +YOML - a DOM-like interface to YAML +==== + +YOML is a DOM-like interface to YAML, implemented as a wrapper around [libyaml](http://pyyaml.org/wiki/LibYAML). + +It is a header-only library. Just include the .h files to use the library. + +``` +#include "yoml.h" /* defines the structures */ +#include "yoml-parser.h" /* defines the parser */ + +static yoml_t *parse_file(FILE *fp) +{ + yaml_parser_t parser; + yoml_t *doc; + + yaml_parser_initialize(&parser); + yaml_parser_set_input_file(&parser, fp); + + doc = yoml_parse_document(&parser, NULL); + + yaml_parser_delete(&parser); + + return doc; +} + +static void dump_node(yoml_t *node, int indent) +{ + size_t i; + + switch (node->type) { + case YOML_TYPE_SCALAR: + printf("%*s[SCALAR] %s\n", indent, "", node->data.scalar); + break; + case YOML_TYPE_SEQUENCE: + printf("%*s[SEQUENCE] (size:%zu)\n", indent, "", node->data.sequence.size); + for (i = 0; i != node.data.sequence.size; ++i) + dump_node(node->data.sequence.elements[i], indent + 2); + break; + case YOML_TYPE_MAPPING: + printf("%*s[MAPPING] (size:%zu)\n", indent, "", node->data.mapping.size); + indent += 2; + for (i = 0; i != node.data.mapping.size; ++i) { + printf(%*s[KEY]\n", indent, ""); + dump_node(node->data.mapping.elements[i].key, indent + 2); + printf(%*s[VALUE]\n", indent, ""); + dump_node(node->data.mapping.elements[i].value, indent + 2); + } + indent -= 2; + break; + } +} + +static void dump_file(FILE *fp) +{ + yoml_t *doc = parse_file(fp); + + if (doc == NULL) { + fprintf(stderr, "parse error!\n"); /* error info can be obtained from yaml_parser_t */ + return; + } + + dump_node(doc, 0); + yoml_free(doc); +} +``` diff --git a/web/server/h2o/libh2o/deps/yoml/test-yoml.c b/web/server/h2o/libh2o/deps/yoml/test-yoml.c new file mode 100644 index 00000000..d154138c --- /dev/null +++ b/web/server/h2o/libh2o/deps/yoml/test-yoml.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <stdio.h> +#include "yoml.h" +#include "yoml-parser.h" + +#include "picotest.h" + +static yoml_t *parse(const char *fn, const char *s) +{ + yaml_parser_t parser; + yoml_t *doc; + + yaml_parser_initialize(&parser); + yaml_parser_set_input_string(&parser, (yaml_char_t*)s, strlen(s)); + doc = yoml_parse_document(&parser, NULL, NULL, fn); + yaml_parser_delete(&parser); + + return doc; +} + +static yoml_t *get_value(yoml_t *mapping, const char *key) +{ + size_t i; + for (i = 0; i != mapping->data.mapping.size; ++i) + if (mapping->data.mapping.elements[i].key->type == YOML_TYPE_SCALAR && + strcmp(mapping->data.mapping.elements[i].key->data.scalar, key) == 0) + return mapping->data.mapping.elements[i].value; + return NULL; +} + +int main(int argc, char **argv) +{ + yoml_t *doc, *t; + size_t i; + + doc = parse("foo.yaml", "abc"); + ok(doc != NULL); + ok(strcmp(doc->filename, "foo.yaml") == 0); + ok(doc->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.scalar, "abc") == 0); + yoml_free(doc, NULL); + + doc = parse( + "foo.yaml", + "---\n" + "a: b\n" + "c: d\n" + "---\n" + "e: f\n"); + ok(doc != NULL); + ok(strcmp(doc->filename, "foo.yaml") == 0); + ok(doc->type == YOML_TYPE_MAPPING); + ok(doc->data.mapping.size == 2); + t = doc->data.mapping.elements[0].key; + ok(strcmp(t->filename, "foo.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "a") == 0); + t = doc->data.mapping.elements[0].value; + ok(strcmp(t->filename, "foo.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "b") == 0); + t = doc->data.mapping.elements[1].key; + ok(strcmp(t->filename, "foo.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "c") == 0); + t = doc->data.mapping.elements[1].value; + ok(strcmp(t->filename, "foo.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "d") == 0); + yoml_free(doc, NULL); + + doc = parse( + "bar.yaml", + "- a: b\n" + " c: d\n" + "- e\n"); + ok(doc != NULL); + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(doc->type == YOML_TYPE_SEQUENCE); + ok(doc->data.sequence.size == 2); + t = doc->data.sequence.elements[0]; + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(t->type == YOML_TYPE_MAPPING); + ok(t->data.mapping.size == 2); + t = doc->data.sequence.elements[0]->data.mapping.elements[0].key; + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "a") == 0); + t = doc->data.sequence.elements[0]->data.mapping.elements[0].value; + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "b") == 0); + t = doc->data.sequence.elements[0]->data.mapping.elements[1].key; + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "c") == 0); + t = doc->data.sequence.elements[0]->data.mapping.elements[1].value; + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "d") == 0); + t = doc->data.sequence.elements[1]; + ok(strcmp(doc->filename, "bar.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "e") == 0); + yoml_free(doc, NULL); + + doc = parse( + "baz.yaml", + "- &abc\n" + " - 1\n" + " - 2\n" + "- *abc\n"); + ok(doc != NULL); + ok(strcmp(doc->filename, "baz.yaml") == 0); + ok(doc->type == YOML_TYPE_SEQUENCE); + ok(doc->data.sequence.size == 2); + ok(doc->data.sequence.elements[0] == doc->data.sequence.elements[1]); + t = doc->data.sequence.elements[0]; + ok(strcmp(t->filename, "baz.yaml") == 0); + ok(t->_refcnt == 2); + ok(t->type == YOML_TYPE_SEQUENCE); + ok(t->data.sequence.size == 2); + t = doc->data.sequence.elements[0]->data.sequence.elements[0]; + ok(strcmp(t->filename, "baz.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "1") == 0); + t = doc->data.sequence.elements[0]->data.sequence.elements[1]; + ok(strcmp(t->filename, "baz.yaml") == 0); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "2") == 0); + + doc = parse( + "foo.yaml", + "- &link\n" + " x: 1\n" + " y: 2\n" + "- <<: *link\n" + " y: 3\n"); + ok(doc != NULL); + ok(doc->type == YOML_TYPE_SEQUENCE); + ok(doc->data.sequence.size == 2); + ok(doc->data.sequence.elements[0]->type == YOML_TYPE_MAPPING); + ok(doc->data.sequence.elements[0]->data.mapping.size == 2); + ok(doc->data.sequence.elements[0]->data.mapping.elements[0].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[0].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[0]->data.mapping.elements[0].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[0].value->data.scalar, "1") == 0); + ok(doc->data.sequence.elements[0]->data.mapping.elements[1].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[1].key->data.scalar, "y") == 0); + ok(doc->data.sequence.elements[0]->data.mapping.elements[1].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[1].value->data.scalar, "2") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[0].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[0].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[0].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[0].value->data.scalar, "1") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[1].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[1].key->data.scalar, "y") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[1].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[1].value->data.scalar, "3") == 0); + + doc = parse( + "foo.yaml", + "- &CENTER { x: 1, y: 2 }\n" + "- &LEFT { x: 0, y: 2 }\n" + "- &BIG { r: 10 }\n" + "- &SMALL { r: 1 }\n" + "- # Explicit keys\n" + " x: 1\n" + " y: 2\n" + " r: 10\n" + "- # Merge one map\n" + " << : *CENTER\n" + " r: 10\n" + "- # Merge multiple maps\n" + " << : [ *CENTER, *BIG ]\n" + "- # Override\n" + " << : [ *BIG, *LEFT, *SMALL ]\n" + " x: 1\n"); + ok(doc != NULL); + ok(doc->type == YOML_TYPE_SEQUENCE); + for (i = 4; i <= 7; ++i) { + ok(doc->data.sequence.elements[i]->type == YOML_TYPE_MAPPING); + ok(doc->data.sequence.elements[i]->data.mapping.size == 3); + t = get_value(doc->data.sequence.elements[i], "x"); + ok(t != NULL); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "1") == 0); + t = get_value(doc->data.sequence.elements[i], "y"); + ok(t != NULL); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "2") == 0); + t = get_value(doc->data.sequence.elements[i], "r"); + ok(t != NULL); + ok(t->type == YOML_TYPE_SCALAR); + ok(strcmp(t->data.scalar, "10") == 0); + } + + doc = parse( + "foo.yaml", + "- &link\n" + " x: 1\n" + " x: 2\n" + "-\n" + " x: 3\n" + " <<: *link\n"); + ok(doc != NULL); + ok(doc->type == YOML_TYPE_SEQUENCE); + ok(doc->data.sequence.size == 2); + ok(doc->data.sequence.elements[0]->type == YOML_TYPE_MAPPING); + ok(doc->data.sequence.elements[0]->data.mapping.size == 2); + ok(doc->data.sequence.elements[0]->data.mapping.elements[0].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[0].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[0]->data.mapping.elements[0].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[0].value->data.scalar, "1") == 0); + ok(doc->data.sequence.elements[0]->data.mapping.elements[1].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[1].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[0]->data.mapping.elements[1].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[0]->data.mapping.elements[1].value->data.scalar, "2") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.size == 3); + ok(doc->data.sequence.elements[1]->data.mapping.elements[0].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[0].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[0].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[0].value->data.scalar, "3") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[1].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[1].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[1].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[1].value->data.scalar, "1") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[2].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[2].key->data.scalar, "x") == 0); + ok(doc->data.sequence.elements[1]->data.mapping.elements[2].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.sequence.elements[1]->data.mapping.elements[2].value->data.scalar, "2") == 0); + + doc = parse( + "foo.yaml", + "a: &link1\n" + " x: 1\n" + "b: &link2\n" + " <<: *link1\n" + " y: 2\n" + "c:\n" + " <<: *link2\n" + ); + ok(doc != NULL); + ok(doc->type == YOML_TYPE_MAPPING); + ok(doc->data.mapping.size == 3); + ok(doc->data.mapping.elements[2].value->type == YOML_TYPE_MAPPING); + ok(doc->data.mapping.elements[2].value->data.mapping.size == 2); + ok(doc->data.mapping.elements[2].value->data.mapping.elements[0].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.mapping.elements[2].value->data.mapping.elements[0].key->data.scalar, "x") == 0); + ok(doc->data.mapping.elements[2].value->data.mapping.elements[0].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.mapping.elements[2].value->data.mapping.elements[0].value->data.scalar, "1") == 0); + ok(doc->data.mapping.elements[2].value->data.mapping.elements[1].key->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.mapping.elements[2].value->data.mapping.elements[1].key->data.scalar, "y") == 0); + ok(doc->data.mapping.elements[2].value->data.mapping.elements[1].value->type == YOML_TYPE_SCALAR); + ok(strcmp(doc->data.mapping.elements[2].value->data.mapping.elements[1].value->data.scalar, "2") == 0); + + return done_testing(); +} diff --git a/web/server/h2o/libh2o/deps/yoml/yoml-parser.h b/web/server/h2o/libh2o/deps/yoml/yoml-parser.h new file mode 100644 index 00000000..78cdd446 --- /dev/null +++ b/web/server/h2o/libh2o/deps/yoml/yoml-parser.h @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef yoml_parser_h +#define yoml_parser_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <yaml.h> +#include "yoml.h" + +typedef struct st_yoml_parse_args_t { + const char *filename; + void *(*mem_set)(void *, int, size_t); + struct { + yoml_t *(*cb)(const char *tag, yoml_t *node, void *cb_arg); + void *cb_arg; + } resolve_tag; +} yoml_parse_args_t; + +static yoml_t *yoml__parse_node(yaml_parser_t *parser, yaml_event_type_t *last_event, yoml_parse_args_t *parse_args); + +static inline char *yoml__strdup(yaml_char_t *s) +{ + return strdup((char *)s); +} + +static inline yoml_t *yoml__new_node(const char *filename, yoml_type_t type, size_t sz, yaml_char_t *anchor, yaml_char_t *tag, yaml_event_t *event) +{ + yoml_t *node = malloc(sz); + node->filename = filename != NULL ? strdup(filename) : NULL; + node->type = type; + node->line = event->start_mark.line; + if (type == YOML_TYPE_SCALAR) { + switch (event->data.scalar.style) { + case YAML_LITERAL_SCALAR_STYLE: + case YAML_FOLDED_SCALAR_STYLE: + ++node->line; + break; + default: + break; + } + } + node->column = event->start_mark.column; + node->anchor = anchor != NULL ? yoml__strdup(anchor) : NULL; + node->tag = tag != NULL ? yoml__strdup(tag) : NULL; + node->_refcnt = 1; + return node; +} + +static inline yoml_t *yoml__parse_sequence(yaml_parser_t *parser, yaml_event_t *event, yoml_parse_args_t *parse_args) +{ + yoml_t *seq = yoml__new_node(parse_args->filename, YOML_TYPE_SEQUENCE, offsetof(yoml_t, data.sequence.elements), + event->data.sequence_start.anchor, event->data.sequence_start.tag, event); + + seq->data.sequence.size = 0; + + while (1) { + yoml_t *new_node; + yaml_event_type_t unhandled; + if ((new_node = yoml__parse_node(parser, &unhandled, parse_args)) == NULL) { + if (unhandled == YAML_SEQUENCE_END_EVENT) { + break; + } else { + yoml_free(seq, parse_args->mem_set); + seq = NULL; + break; + } + } + seq = realloc(seq, offsetof(yoml_t, data.sequence.elements) + sizeof(yoml_t *) * (seq->data.sequence.size + 1)); + seq->data.sequence.elements[seq->data.sequence.size++] = new_node; + } + + return seq; +} + +static inline yoml_t *yoml__parse_mapping(yaml_parser_t *parser, yaml_event_t *event, yoml_parse_args_t *parse_args) +{ + yoml_t *map = yoml__new_node(parse_args->filename, YOML_TYPE_MAPPING, offsetof(yoml_t, data.mapping.elements), + event->data.mapping_start.anchor, event->data.mapping_start.tag, event); + + map->data.mapping.size = 0; + + while (1) { + yoml_t *key, *value; + yaml_event_type_t unhandled; + if ((key = yoml__parse_node(parser, &unhandled, parse_args)) == NULL) { + if (unhandled == YAML_MAPPING_END_EVENT) { + break; + } else { + yoml_free(map, parse_args->mem_set); + map = NULL; + break; + } + } + if ((value = yoml__parse_node(parser, NULL, parse_args)) == NULL) { + yoml_free(map, parse_args->mem_set); + map = NULL; + break; + } + map = realloc(map, offsetof(yoml_t, data.mapping.elements) + sizeof(yoml_mapping_element_t) * (map->data.mapping.size + 1)); + map->data.mapping.elements[map->data.mapping.size].key = key; + map->data.mapping.elements[map->data.mapping.size].value = value; + ++map->data.mapping.size; + } + + return map; +} + +static yoml_t *yoml__parse_node(yaml_parser_t *parser, yaml_event_type_t *unhandled, yoml_parse_args_t *parse_args) +{ + yoml_t *node; + yaml_event_t event; + + if (unhandled != NULL) + *unhandled = YAML_NO_EVENT; + + /* wait for a node that is not a stream/doc start event */ + while (1) { + if (!yaml_parser_parse(parser, &event)) + return NULL; + if (!(event.type == YAML_STREAM_START_EVENT || event.type == YAML_DOCUMENT_START_EVENT)) + break; + yaml_event_delete(&event); + } + + switch (event.type) { + case YAML_ALIAS_EVENT: + node = yoml__new_node(parse_args->filename, YOML__TYPE_UNRESOLVED_ALIAS, sizeof(*node), NULL, NULL, &event); + node->data.alias = yoml__strdup(event.data.alias.anchor); + break; + case YAML_SCALAR_EVENT: + node = yoml__new_node(parse_args->filename, YOML_TYPE_SCALAR, sizeof(*node), event.data.scalar.anchor, event.data.scalar.tag, &event); + node->data.scalar = yoml__strdup(event.data.scalar.value); + if (parse_args->mem_set != NULL) + parse_args->mem_set(event.data.scalar.value, 'A', strlen(node->data.scalar)); + break; + case YAML_SEQUENCE_START_EVENT: + node = yoml__parse_sequence(parser, &event, parse_args); + break; + case YAML_MAPPING_START_EVENT: + node = yoml__parse_mapping(parser, &event, parse_args); + break; + default: + node = NULL; + if (unhandled != NULL) + *unhandled = event.type; + break; + } + + yaml_event_delete(&event); + + return node; +} + +static inline int yoml__merge(yoml_t **dest, size_t offset, yoml_t *src) +{ + yoml_t *key, *value; + size_t i, j; + + if (src->type != YOML_TYPE_MAPPING) + return -1; + + for (i = 0; i != src->data.mapping.size; ++i) { + key = src->data.mapping.elements[i].key; + value = src->data.mapping.elements[i].value; + if (key->type == YOML_TYPE_SCALAR) { + for (j = offset; j != (*dest)->data.mapping.size; ++j) { + if ((*dest)->data.mapping.elements[j].key->type == YOML_TYPE_SCALAR && + strcmp((*dest)->data.mapping.elements[j].key->data.scalar, key->data.scalar) == 0) + goto Skip; + } + } + *dest = realloc(*dest, offsetof(yoml_t, data.mapping.elements) + + ((*dest)->data.mapping.size + 1) * sizeof((*dest)->data.mapping.elements[0])); + memmove((*dest)->data.mapping.elements + offset + 1, (*dest)->data.mapping.elements + offset, + ((*dest)->data.mapping.size - offset) * sizeof((*dest)->data.mapping.elements[0])); + (*dest)->data.mapping.elements[offset].key = key; + ++key->_refcnt; + (*dest)->data.mapping.elements[offset].value = value; + ++value->_refcnt; + ++(*dest)->data.mapping.size; + ++offset; + Skip: + ; + } + + return 0; +} + +static inline int yoml__resolve_merge(yoml_t **target, yaml_parser_t *parser, yoml_parse_args_t *parse_args) +{ + size_t i, j; + + switch ((*target)->type) { + case YOML_TYPE_SCALAR: + break; + case YOML_TYPE_SEQUENCE: + for (i = 0; i != (*target)->data.sequence.size; ++i) { + if (yoml__resolve_merge((*target)->data.sequence.elements + i, parser, parse_args) != 0) + return -1; + } + break; + case YOML_TYPE_MAPPING: + if ((*target)->data.mapping.size != 0) { + i = (*target)->data.mapping.size; + do { + --i; + if (yoml__resolve_merge(&(*target)->data.mapping.elements[i].key, parser, parse_args) != 0) + return -1; + if (yoml__resolve_merge(&(*target)->data.mapping.elements[i].value, parser, parse_args) != 0) + return -1; + if ((*target)->data.mapping.elements[i].key->type == YOML_TYPE_SCALAR && + strcmp((*target)->data.mapping.elements[i].key->data.scalar, "<<") == 0) { + /* erase the slot (as well as preserving the values) */ + yoml_mapping_element_t src = (*target)->data.mapping.elements[i]; + memmove((*target)->data.mapping.elements + i, (*target)->data.mapping.elements + i + 1, + ((*target)->data.mapping.size - i - 1) * sizeof((*target)->data.mapping.elements[0])); + --(*target)->data.mapping.size; + /* merge */ + if (src.value->type == YOML_TYPE_SEQUENCE) { + for (j = 0; j != src.value->data.sequence.size; ++j) + if (yoml__merge(target, i, src.value->data.sequence.elements[j]) != 0) { + MergeError: + if (parser != NULL) { + parser->problem = "value of the merge key MUST be a mapping or a sequence of mappings"; + parser->problem_mark.line = src.key->line; + parser->problem_mark.column = src.key->column; + } + return -1; + } + } else { + if (yoml__merge(target, i, src.value) != 0) + goto MergeError; + } + /* cleanup */ + yoml_free(src.key, parse_args->mem_set); + yoml_free(src.value, parse_args->mem_set); + } + } while (i != 0); + } + break; + case YOML__TYPE_UNRESOLVED_ALIAS: + assert(!"unreachable"); + break; + } + + return 0; +} + + +static inline int yoml__resolve_alias(yoml_t **target, yoml_t *doc, yaml_parser_t *parser, yoml_parse_args_t *parse_args) +{ + size_t i; + + switch ((*target)->type) { + case YOML_TYPE_SCALAR: + break; + case YOML_TYPE_SEQUENCE: + for (i = 0; i != (*target)->data.sequence.size; ++i) { + if (yoml__resolve_alias((*target)->data.sequence.elements + i, doc, parser, parse_args) != 0) + return -1; + } + break; + case YOML_TYPE_MAPPING: + for (i = 0; i != (*target)->data.mapping.size; ++i) { + if (yoml__resolve_alias(&(*target)->data.mapping.elements[i].key, doc, parser, parse_args) != 0) + return -1; + if (yoml__resolve_alias(&(*target)->data.mapping.elements[i].value, doc, parser, parse_args) != 0) + return -1; + } + break; + case YOML__TYPE_UNRESOLVED_ALIAS: { + yoml_t *node = yoml_find_anchor(doc, (*target)->data.alias); + if (node == NULL) { + if (parser != NULL) { + parser->problem = "could not resolve the alias"; + parser->problem_mark.line = (*target)->line; + parser->problem_mark.column = (*target)->column; + } + return -1; + } + yoml_free(*target, parse_args->mem_set); + *target = node; + ++node->_refcnt; + } break; + } + + return 0; +} + +static inline int yoml__resolve_tag(yoml_t **target, yaml_parser_t *parser, yoml_parse_args_t *parse_args) +{ + size_t i; + + if (parse_args->resolve_tag.cb == NULL) + return 0; + + if ((*target)->tag != NULL) { + yoml_t *resolved = parse_args->resolve_tag.cb((*target)->tag, *target, parse_args->resolve_tag.cb_arg); + if (resolved == NULL) { + if (parser != NULL) { + parser->problem = "tag resolution failed"; + parser->problem_mark.line = (*target)->line; + parser->problem_mark.column = (*target)->column; + } + return -1; + } + yoml_free(*target, parse_args->mem_set); + *target = resolved; + } + + switch ((*target)->type) { + case YOML_TYPE_SCALAR: + break; + case YOML_TYPE_SEQUENCE: + for (i = 0; i != (*target)->data.sequence.size; ++i) { + if (yoml__resolve_tag((*target)->data.sequence.elements + i, parser, parse_args) != 0) + return -1; + } + break; + case YOML_TYPE_MAPPING: + for (i = 0; i != (*target)->data.mapping.size; ++i) { + if (yoml__resolve_tag(&(*target)->data.mapping.elements[i].key, parser, parse_args) != 0) + return -1; + if (yoml__resolve_tag(&(*target)->data.mapping.elements[i].value, parser, parse_args) != 0) + return -1; + } + break; + case YOML__TYPE_UNRESOLVED_ALIAS: + break; + } + + return 0; +} + +static inline yoml_t *yoml_parse_document(yaml_parser_t *parser, yaml_event_type_t *unhandled, yoml_parse_args_t *parse_args) +{ + yoml_t *doc; + + /* parse */ + if ((doc = yoml__parse_node(parser, unhandled, parse_args)) == NULL) { + return NULL; + } + if (unhandled != NULL) + *unhandled = YAML_NO_EVENT; + + /* resolve tags, aliases and merge */ + if (yoml__resolve_tag(&doc, parser, parse_args) != 0) + goto Error; + if (yoml__resolve_alias(&doc, doc, parser, parse_args) != 0) + goto Error; + if (yoml__resolve_merge(&doc, parser, parse_args) != 0) + goto Error; + + return doc; + +Error: + yoml_free(doc, parse_args->mem_set); + return NULL; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/web/server/h2o/libh2o/deps/yoml/yoml.h b/web/server/h2o/libh2o/deps/yoml/yoml.h new file mode 100644 index 00000000..e1e66972 --- /dev/null +++ b/web/server/h2o/libh2o/deps/yoml/yoml.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef yoml_h +#define yoml_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <string.h> + +typedef enum enum_yoml_type_t { YOML_TYPE_SCALAR, YOML_TYPE_SEQUENCE, YOML_TYPE_MAPPING, YOML__TYPE_UNRESOLVED_ALIAS } yoml_type_t; + +typedef struct st_yoml_t yoml_t; + +typedef struct st_yoml_sequence_t { + size_t size; + yoml_t *elements[1]; +} yoml_sequence_t; + +typedef struct st_yoml_mapping_element_t { + yoml_t *key; + yoml_t *value; +} yoml_mapping_element_t; + +typedef struct st_yoml_mapping_t { + size_t size; + yoml_mapping_element_t elements[1]; +} yoml_mapping_t; + +struct st_yoml_t { + yoml_type_t type; + char *filename; + size_t line; + size_t column; + char *anchor; + char *tag; + size_t _refcnt; + union { + char *scalar; + yoml_sequence_t sequence; + yoml_mapping_t mapping; + char *alias; + } data; +}; + +static inline void yoml_free(yoml_t *node, void *(*mem_set)(void *, int, size_t)) +{ + size_t i; + + if (node == NULL) + return; + + if (--node->_refcnt == 0) { + free(node->filename); + free(node->anchor); + free(node->tag); + switch (node->type) { + case YOML_TYPE_SCALAR: + if (mem_set != NULL) + mem_set(node->data.scalar, 0, strlen(node->data.scalar)); + free(node->data.scalar); + break; + case YOML_TYPE_SEQUENCE: + for (i = 0; i != node->data.sequence.size; ++i) { + yoml_free(node->data.sequence.elements[i], mem_set); + } + break; + case YOML_TYPE_MAPPING: + for (i = 0; i != node->data.mapping.size; ++i) { + yoml_free(node->data.mapping.elements[i].key, mem_set); + yoml_free(node->data.mapping.elements[i].value, mem_set); + } + break; + case YOML__TYPE_UNRESOLVED_ALIAS: + free(node->data.alias); + break; + } + free(node); + } +} + +static inline yoml_t *yoml_find_anchor(yoml_t *node, const char *name) +{ + yoml_t *n; + size_t i; + + if (node->anchor != NULL && strcmp(node->anchor, name) == 0) + return node; + + switch (node->type) { + case YOML_TYPE_SEQUENCE: + for (i = 0; i != node->data.sequence.size; ++i) + if ((n = yoml_find_anchor(node->data.sequence.elements[i], name)) != NULL) + return n; + break; + case YOML_TYPE_MAPPING: + for (i = 0; i != node->data.mapping.size; ++i) + if ((n = yoml_find_anchor(node->data.mapping.elements[i].key, name)) != NULL || + (n = yoml_find_anchor(node->data.mapping.elements[i].value, name)) != NULL) + return n; + break; + default: + break; + } + + return NULL; +} + +static inline yoml_t *yoml_get(yoml_t *node, const char *name) +{ + size_t i; + + if (node->type != YOML_TYPE_MAPPING) + return NULL; + for (i = 0; i != node->data.mapping.size; ++i) { + yoml_t *key = node->data.mapping.elements[i].key; + if (key->type == YOML_TYPE_SCALAR && strcmp(key->data.scalar, name) == 0) + return node->data.mapping.elements[i].value; + } + return NULL; +} + +#ifdef __cplusplus +} +#endif + +#endif |