{"id":1596,"date":"2024-10-23T21:11:23","date_gmt":"2024-10-23T13:11:23","guid":{"rendered":"https:\/\/www.madbull.site\/?p=1596"},"modified":"2025-07-24T10:13:21","modified_gmt":"2025-07-24T02:13:21","slug":"%e6%9e%84%e9%80%a0c%e8%af%ad%e8%a8%80%e8%a7%a3%e6%9e%90yaml%e6%96%87%e4%bb%b6%e7%9a%84%e5%ba%93","status":"publish","type":"post","link":"https:\/\/www.madbull.site\/?p=1596","title":{"rendered":"\u6784\u9020C\u8bed\u8a00\u89e3\u6790yaml\u6587\u4ef6\u7684\u5e93"},"content":{"rendered":"\n<p>yaml\u5b98\u65b9\u63d0\u4f9b\u4e86\u4e00\u5957\u6587\u4ef6\u89e3\u6790\u7684\u65b9\u6cd5\uff0c\u52a8\u6001\u5e93\u662flibyaml.so\u3002\u5b98\u65b9\u5730\u5740\uff1a<a href=\"https:\/\/yaml.org\/spec\/1.1\/\">https:\/\/yaml.org\/spec\/1.1\/<\/a><\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u4f46\u662f\u8fd9\u4e2a\u5e93\u7684\u89e3\u6790\u65b9\u5f0f\u8fd8\u662f\u592a\u539f\u59cb\uff0c\u4e0d\u597d\u7528\u3002\u6211\u4eec\u60f3\u4e00\u4e2a\u6bd4\u8f83\u597d\u7528\u7684\u65b9\u5f0f\u83b7\u53d6\u6570\u636e\u3002\u60f3\u5230suricata\uff08\u5e93\u5728github\u4e0a\uff0c\u5730\u5740\uff1a<a href=\"https:\/\/github.com\/OISF\/suricata\">https:\/\/github.com\/OISF\/suricata<\/a>\uff09\u6709\u4e00\u5957yaml\u7684\u89e3\u6790\u65b9\u6cd5\u3002\u4e8e\u662f\u628asuricata\u7684\u4ee3\u7801\u62ff\u8fc7\u6765\uff0c\u5c01\u88c5\u4e00\u4e0b\uff0c\u6539\u6210\u4e86lib\u5e93\uff0c\u65b9\u4fbf\u4ee5\u540e\u4f7f\u7528\u3002<\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u4e0d\u8fc7suricata\u7684\u89e3\u6790\u65b9\u6cd5<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-accent-3-color\"><strong>\u4e0d\u652f\u6301<\/strong><\/mark><strong><mark style=\"background-color:rgba(0, 0, 0, 0);color:#ff0000\" class=\"has-inline-color\"> \u951a\u70b9<\/mark><\/strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-accent-3-color\"><strong> \u548c<\/strong><\/mark><strong><mark style=\"background-color:rgba(0, 0, 0, 0);color:#ff0000\" class=\"has-inline-color\"> \u5f15\u7528<\/mark><\/strong>\uff0c\u4f7f\u7528\u65f6\u8981<strong>\u6ce8\u610f\u914d\u7f6e\u6587\u4ef6\u7684\u7f16\u5199<\/strong>\u3002<\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-file\"><a id=\"wp-block-file--media-916ef692-8a7e-4d3f-90e4-5aeab2e2612d\" href=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/tyaml.tar.gz\">tyaml.tar<\/a><a href=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/tyaml.tar.gz\" class=\"wp-block-file__button wp-element-button\" download aria-describedby=\"wp-block-file--media-916ef692-8a7e-4d3f-90e4-5aeab2e2612d\">\u4e0b\u8f7d<\/a><\/div>\n\n\n\n<p>\u53ef\u4ee5\u4e0b\u8f7d\u76f4\u63a5\u4f7f\u7528\uff0c\u4ee3\u7801\u4e5f\u5728\u4e0b\u8fb9\u5217\u51fa\u6765\u4e86\uff0c\u65b9\u4fbf\u968f\u65f6\u5206\u6790\u5b66\u4e60\u3002<\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u30102025-01-07\u3011\u6700\u8fd1\u6574\u7406\u4e00\u4e0b\uff0c\u628a\u4ee3\u7801\u653e\u5728\u4e86 gitee \u4e0a\uff1a<a href=\"https:\/\/gitee.com\/madbullsite\/libparseyaml\">https:\/\/gitee.com\/madbullsite\/libparseyaml<\/a><\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-large-font-size\"><strong>\u76ee\u5f55\u7ed3\u6784<\/strong><\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--10);margin-bottom:var(--wp--preset--spacing--10);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"226\" height=\"215\" src=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-18.png\" alt=\"\" class=\"wp-image-1621\"\/><\/figure>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u4ee3\u7801 Makefile<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>libs=libmyyaml.so\n\nLIBS = -lyaml -lbsd -g -Wall\nDLFLAGS = -shared -fPIC\n\n%.o: %.c\n        gcc -fPIC -o $@ -c $^ -g\n\n\nall: cmptest\n\nlibmyyaml.so: conf-yaml.o conf-yaml-loader.o\n        gcc $(DLFLAGS) -o $@ $^ $(LIBS)\n\ninstall: $(libs)\n        mv $(libs)      \/usr\/local\/lib\/\n        cp conf-yaml.h conf-yaml-loader.h queue.h \/usr\/local\/include\/\n        ldconfig\n\ncmptest: install test\n\ntest: test.o\n        gcc -o $@ $^ -lmyyaml $(LIBS)\n\nclean:\n        rm -f \/usr\/local\/lib\/$(libs) *.o test $(libs)\n\n<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u4ee3\u7801 conf-yaml-loader.c<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;yaml.h&gt;\n#include &lt;limits.h&gt;\n#include &lt;sys\/stat.h&gt;\n#include &lt;fcntl.h&gt;\n#include &lt;errno.h&gt;\n#include &lt;string.h&gt;\n#include &lt;bsd\/string.h&gt;\n\n#include \"conf-yaml.h\"\n#include \"conf-yaml-loader.h\"\n\n\/\/ \u652f\u6301\u7684\u7248\u672c\u53f7\n#define YAML_VERSION_MAJOR 1\n#define YAML_VERSION_MINOR 1\n\n\/* The maximum level of recursion allowed while parsing the YAML\n * file. *\/\n#define RECURSION_LIMIT 128\n\/* Sometimes we'll have to create a node name on the fly (integer\n * conversion, etc), so this is a default length to allocate that will\n * work most of the time. *\/\n#define DEFAULT_NAME_LEN 16\n\n#define MANGLE_ERRORS_MAX 10\nstatic int mangle_errors = 0;\n\n\/\/ yaml \u914d\u7f6e\u6587\u4ef6\u8def\u5f84\nstatic char *conf_dirname = NULL;\n\nstatic int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int rlevel, int state);\n\n\/* Configuration processing states. *\/\nenum conf_state {\n    CONF_KEY = 0,\n    CONF_VAL,\n    CONF_INCLUDE,\n};\n\n\/**\n * \u8f6c\u6362\u4e0d\u652f\u6301\u7684\u5b57\u7b26 _ \u8f6c\u6362\u6210 -\n *\/\nstatic void\nMangle(char *string)\n{\n    char *c;\n\n    while ((c = strchr(string, '_')))\n        *c = '-';\n\n    return;\n}\n\n\/**\n * \u8bbe\u7f6e\u914d\u7f6e\u6587\u4ef6\u7684\u76ee\u5f55\uff0cinclude\u5f15\u5165\u7684\u65f6\u5019\uff0c\u5982\u679c\u662f\u76f8\u5bf9\u8def\u5f84\uff0c\u5219\u6839\u636e\u8bbe\u7f6e\u7684\u8def\u5f84\u62fc\u63a5\n *      \u5168\u5c40\u53d8\u91cf conf_dirname \u8d4b\u503c\n * \u53c2\u6570   \u914d\u7f6e\u6587\u4ef6\u8def\u5f84\n *\/\nstatic void\nConfYamlSetConfDirname(const char *filename)\n{\n    char *ep;\n\n    ep = strrchr(filename, '\\\\');\n    if (ep == NULL)\n        ep = strrchr(filename, '\/');\n\n    if (ep == NULL) { \/\/ \u6ca1\u627e\u5230\uff0c\u7528 . \u4f5c\u4e3a\u5f53\u524d\u76ee\u5f55\n        conf_dirname = strdup(\".\");\n        if (conf_dirname == NULL) {\n            fprintf(stderr, \"ERROR: Failed to allocate memory while loading configuration.\\n\");\n        }\n    }\n    else { \/\/ \u627e\u5230\uff0ccopy\u51fa\u76ee\u5f55\u526f\u672c\uff0c\u5e76\u62a5\u9519\n        conf_dirname = strdup(filename);\n        if (conf_dirname == NULL) {\n            fprintf(stderr, \"ERROR: Failed to allocate memory while loading configuration.\\n\");\n        }\n        conf_dirname&#91;ep - filename] = '\\0';\n    }\n}\n\n\/**\n * \u5728\u914d\u7f6e\u91cc\u5f15\u5165\u4e00\u4e2a\u6587\u4ef6\n * \u53c2\u6570\n *     parent    \u89e3\u6790\u7684\u6570\u636e\u90fd\u653e\u5728\u6b64\u8282\u70b9\n *     filename  \u5f15\u5165\u7684\u6587\u4ef6\u540d\n * \u8fd4\u56de\u503c   0 - \u89e3\u6790\u6210\u529f\n *         1 - \u89e3\u6790\u5931\u8d25\n *\/\nint ConfYamlHandleInclude(ConfNode *parent, const char *filename)\n{\n    yaml_parser_t parser; \n    char include_filename&#91;PATH_MAX];\n    FILE *file = NULL;\n    int ret = -1;\n\n    \/\/ \u91cd\u65b0\u521d\u59cb\u5316\u65b0\u7684\u89e3\u6790\u53e5\u67c4\n    if (yaml_parser_initialize(&amp;parser) != 1) {\n        fprintf(stderr, \"Failed to initialize YAML parser\\n\");\n        return -1;\n    }\n\n    \/\/ \u5224\u65ad\u662f\u5426\u4e3a\u7edd\u5bf9\u8def\u5f84\n    if (PathIsAbsolute(filename)) {\n        strlcpy(include_filename, filename, sizeof(include_filename));\n    }\n    else {\n        \/\/ \u62fc\u5199\u51fa\u8def\u5f84\n        snprintf(include_filename, sizeof(include_filename), \"%s\/%s\",\n            conf_dirname, filename);\n    }\n\n    file = fopen(include_filename, \"r\");\n    if (file == NULL) {\n        fprintf(stderr, \"Failed to open configuration include file %s: %s\\n\", include_filename,\n                strerror(errno));\n        goto done;\n    }\n\n    \/\/ \u8bbe\u7f6e\u8981\u89e3\u6790\u7684\u6587\u4ef6\u53e5\u67c4\n    yaml_parser_set_input_file(&amp;parser, file);\n\n    \/\/ include\u5f15\u5165\u7684\u6587\u4ef6 \u89e3\u6790\n    if (ConfYamlParse(&amp;parser, parent, 0, 0, 0) != 0) {\n        fprintf(stderr, \"Failed to include configuration file %s\\n\", filename);\n        goto done;\n    }\n\n    ret = 0;\n\ndone:\n    yaml_parser_delete(&amp;parser);\n    if (file != NULL) {\n        fclose(file);\n    }\n\n    return ret;\n}\n\n\/**\n * \u89e3\u6790yaml\n *\n * \u53c2\u6570     parser \u6d3b\u52a8\u7684 yaml_parser_t \u6307\u9488\n *         parent \u7236\u8282\u70b9 node\n *         inseq \u5217\u8868\u7684\u89e3\u6790\n *         rlevel \n *         state \u5f53\u524d \u89e3\u6790\u72b6\u6001\n *\n * \u8fd4\u56de\u503c\uff1a0 - success, -1 - failure.\n *\n * \u8c03\u7528\u7684\u5730\u65b9\uff1a \n *        1\u3001 \u9996\u6b21\u6587\u6863\u89e3\u6790\n *        2\u3001 include\u5f15\u5165\u7684\u6587\u4ef6 \u89e3\u6790\n *        3\u3001 \u5217\u8868\u7684\u89e3\u6790\n *        4\u3001 mapping\u7684\u89e3\u6790\n *\/\nstatic int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int rlevel, int state)\n{\n    ConfNode *node = parent;\n    yaml_event_t event;\n    memset(&amp;event, 0, sizeof(event));\n    int done = 0;\n    int seq_idx = 0;   \/\/ \u5217\u8868\u7684\u7d22\u5f15, \u4ece 0 \u5f00\u59cb\n    int retval = 0;\n    int was_empty = -1;\n    int include_count = 0;\n\n    \/\/ rlevel \u7ed9\u9012\u5f52\u5c42\u7ea7\u589e\u52a0\uff0c\u4ece\u65b0\u8c03\u7528\u4e00\u6b21\uff0c\u5c31\u589e\u52a0\u4e00\u6b21\n    if (rlevel++ &gt; RECURSION_LIMIT) {\n        fprintf(stderr, \"Recursion limit reached while parsing \"\n                   \"configuration file, aborting.\\n\");\n        return -1;\n    }\n\n    while (!done) {\n        if (!yaml_parser_parse(parser, &amp;event)) {  \/\/ \u89e3\u6790\u4e0b\u4e00\u4e2a\u4e8b\u4ef6\n            fprintf(stderr, \"Failed to parse configuration file at line %\" PRIuMAX \": %s\\n\",\n                    (uintmax_t)parser-&gt;problem_mark.line, parser-&gt;problem);\n            retval = -1;\n            break;\n        }\n\n        if (event.type == YAML_DOCUMENT_START_EVENT) {   \/\/ \u6587\u6863\u4e8b\u4ef6\n            fprintf(stdout, \"event.type=YAML_DOCUMENT_START_EVENT; state=%d\\n\", state);\n            \/* \u9a8c\u8bc1 YAML \u7248\u672c\u53f7 *\/\n            yaml_version_directive_t *ver =\n                event.data.document_start.version_directive;\n            if (ver == NULL) {\n                fprintf(stderr, \"ERROR: Invalid configuration file.\\n\");\n                fprintf(stderr, \"The configuration file must begin with the following two lines: %%YAML \"\n                           \"1.1 and ---\\n\");\n                goto fail;\n            }\n            int major = ver-&gt;major;\n            int minor = ver-&gt;minor;\n            if (!(major == YAML_VERSION_MAJOR &amp;&amp; minor == YAML_VERSION_MINOR)) {\n                fprintf(stderr, \"ERROR: Invalid YAML version.  Must be 1.1\\n\");\n                goto fail;\n            }\n        }\n        else if (event.type == YAML_SCALAR_EVENT) { \/\/ \u6807\u91cf\n            char *value = (char *)event.data.scalar.value;   \/\/ \u503c\n            char *tag = (char *)event.data.scalar.tag;       \/\/ \u952e\n            fprintf(stdout, \"event.type=YAML_SCALAR_EVENT; state=%d; value=%s; \"\n                \"tag=%s; inseq=%d\\n\", state, value, tag, inseq);\n\n            \/\/ \u8df3\u8fc7\u6ca1\u6709\u503c\u7684\u7a7a\u6807\u91cf\n            if (state == CONF_KEY &amp;&amp; strlen(value) == 0) {\n                goto next;\n            }\n\n            \/* If the value is unquoted, certain strings in YAML represent NULL. *\/\n            \/\/ \u5982\u679c\u503c\u6ca1\u6709\u5f15\u7528\uff0cYAML\u4e2d\u6709\u4e9b\u5b57\u7b26\u4e32\u8868\u793aNULL\n            if ((inseq || state == CONF_VAL) &amp;&amp;\n                    event.data.scalar.style == YAML_PLAIN_SCALAR_STYLE) { \n                \/\/ \u8868\u793aNULL\u7684\u4e00\u4e9b\u503c\n                if (strlen(value) == 0 || strcmp(value, \"~\") == 0 || strcmp(value, \"null\") == 0 ||\n                        strcmp(value, \"Null\") == 0 || strcmp(value, \"NULL\") == 0) {\n                    value = NULL;\n                }\n            }\n            \/\/ \u5217\u8868\u7684\u5904\u7406\n            if (inseq) {\n                \/\/ \u5f15\u5165\u6587\u4ef6\u72b6\u6001\u7684\u5904\u7406\n                if (state == CONF_INCLUDE) {\n                    if (value != NULL) {\n                        fprintf(stdout, \"Including configuration file %s.\\n\", value);\n                        if (ConfYamlHandleInclude(parent, value) != 0) {\n                            goto fail;\n                        }\n                    }\n                    goto next;\n                }\n                \/\/ \u628a \u7d22\u5f15\u4f5c\u4e3a \u8def\u5f84\u8282\u70b9\u540d\u5b57\uff0c \u4ece 0 \u5f00\u59cb\n                char sequence_node_name&#91;DEFAULT_NAME_LEN];\n                snprintf(sequence_node_name, DEFAULT_NAME_LEN, \"%d\", seq_idx++);\n                ConfNode *seq_node = NULL;\n                if (was_empty &lt; 0) {\n                    \/\/ initialize was_empty\n                    if (TAILQ_EMPTY(&amp;parent-&gt;head)) {\n                        was_empty = 1;\n                    } else {\n                        was_empty = 0;\n                    }\n                }\n                \/\/ \u5224\u65ad\u8282\u70b9\u662f\u5426\u5df2\u7ecf\u5b58\u5728\n                if (was_empty == 0) {\n                    seq_node = ConfNodeLookupChild(parent, sequence_node_name);\n                }\n                if (seq_node != NULL) {\n                    \/\/ \u8fd9\u91cc\u5148\u4ece\u5144\u5f1f\u961f\u5217\u91cc\u5220\u9664\uff0c20\u884c\u4e4b\u540e\u7b49\u4f1a\u8fd8\u4f1a\u52a0\u4e0a\uff0c\u8fd9\u91cc\u4e0d\u4f1a\u6e05\u6570\u636e\n                    TAILQ_REMOVE(&amp;parent-&gt;head, seq_node, next);\n                }\n                else {\n                    \/\/ \u521b\u5efa\u8282\u70b9\uff0c\u5e76\u8d4b\u503c\n                    seq_node = ConfNodeNew();\n                    if (unlikely(seq_node == NULL)) {\n                        goto fail;\n                    }\n                    seq_node-&gt;name = strdup(sequence_node_name);\n                    if (unlikely(seq_node-&gt;name == NULL)) {\n                        free(seq_node);\n                        goto fail;\n                    }\n                    if (value != NULL) { \/\/ \u5982\u679cvalue\u6709\u503c\uff0c\u5219\u8d4b\u503c\n                        seq_node-&gt;val = strdup(value);\n                        if (unlikely(seq_node-&gt;val == NULL)) {\n                            free(seq_node-&gt;name);\n                            goto fail;\n                        }\n                    } else {   \/\/ \u5426\u5219\u4e3a NULL\n                        seq_node-&gt;val = NULL;\n                    }\n                }\n                \/\/ \u628a\u8282\u70b9\u63d2\u5165\u5230\n                TAILQ_INSERT_TAIL(&amp;parent-&gt;head, seq_node, next);\n            }\n            else {\n                if (state == CONF_INCLUDE) {\n                    fprintf(stdout, \"Including configuration file %s.\\n\", value);\n                    \/\/ \u89e3\u6790\u5b50\u6587\u4ef6\uff0cparent\u7528\u6765\u63a5\u6536\u89e3\u6790\u7684\u6570\u636e\uff0c\u628a\u503c\u7ed9\u5230\u5904\u7406\u51fd\u6570\n                    if (ConfYamlHandleInclude(parent, value) != 0) {\n                        goto fail;\n                    }\n                    \/\/ \u89e3\u6790\u5b8c\u4e86\uff0c\u4fee\u6539\u89e3\u6790\u72b6\u6001\u4e3a\uff1a\u9700\u8981\u89e3\u6790KEY\n                    state = CONF_KEY;\n                }\n                else if (state == CONF_KEY) {\n\n                    if (strcmp(value, \"include\") == 0) {\n                        \/\/ \u4fee\u6539\u72b6\u6001\uff1a\u5305\u542b\u5b50\u6587\u4ef6\u72b6\u6001\n                        state = CONF_INCLUDE;\n                        if (++include_count &gt; 1) {\n                            fprintf(stderr, \"Multipline \\\"include\\\" fields at the same level are \"\n                                         \"deprecated and will not work in Suricata 8, please move \"\n                                         \"to an array of include files: line: %zu\\n\",\n                                    parser-&gt;mark.line);\n                        }\n                        goto next;\n                    }\n\n                    if (parent-&gt;is_seq) {\n                        if (parent-&gt;val == NULL) {\n                            parent-&gt;val = strdup(value);\n                            if (parent-&gt;val &amp;&amp; strchr(parent-&gt;val, '_'))\n                                \/\/ _ \u8f6c\u6362\u6210 - \n                                Mangle(parent-&gt;val);\n                        }\n                    }\n\n                    if (strchr(value, '.') != NULL) {\n                        node = ConfNodeGetNodeOrCreate(parent, value, 0);\n                        if (node == NULL) {\n                            \/* Error message already logged. *\/\n                            goto fail;\n                        }\n                    } else {\n                        ConfNode *existing = ConfNodeLookupChild(parent, value);\n                        if (existing != NULL) {\n                            if (!existing-&gt;final) {\n                                fprintf(stdout, \"Configuration node '%s' redefined.\\n\", existing-&gt;name);\n                                ConfNodePrune(existing);\n                            }\n                            node = existing;\n                        } else {\n                            node = ConfNodeNew();\n                            node-&gt;name = strdup(value);\n                            node-&gt;parent = parent;\n                            if (node-&gt;name &amp;&amp; strchr(node-&gt;name, '_')) {\n                                if (!(parent-&gt;name &amp;&amp;\n                                            ((strcmp(parent-&gt;name, \"address-groups\") == 0) ||\n                                                    (strcmp(parent-&gt;name, \"port-groups\") == 0)))) {\n                                    \/\/ _ \u8f6c\u6362\u6210 - \n                                    Mangle(node-&gt;name);\n                                    if (mangle_errors &lt; MANGLE_ERRORS_MAX) {\n                                        fprintf(stderr,\n                                                \"%s is deprecated. Please use %s on line %\" PRIuMAX \n                                                \".\\n\",\n                                                value, node-&gt;name,\n                                                (uintmax_t)parser-&gt;mark.line + 1);\n                                        mangle_errors++;\n                                        if (mangle_errors &gt;= MANGLE_ERRORS_MAX)\n                                            fprintf(stderr,\n                                                    \"not showing more \"\n                                                    \"parameter name warnings.\\n\");\n                                    }\n                                }\n                            }\n                            TAILQ_INSERT_TAIL(&amp;parent-&gt;head, node, next);\n                        }\n                    }\n                    \/\/ \u4fee\u6539\u72b6\u6001\uff0c\u9700\u8981\u83b7\u5f97\u503c\n                    state = CONF_VAL;\n                }\n                else {\n                    if (value != NULL &amp;&amp; (tag != NULL) &amp;&amp; (strcmp(tag, \"!include\") == 0)) {\n                        fprintf(stdout, \"Including configuration file %s at \"\n                            \"parent node %s.\\n\", value, node-&gt;name);\n                        if (ConfYamlHandleInclude(node, value) != 0)\n                            goto fail;\n                    } else if (!node-&gt;final &amp;&amp; value != NULL) {\n                        if (node-&gt;val != NULL)\n                            free(node-&gt;val);\n                        node-&gt;val = strdup(value);\n                    }\n                    \/\/ \u4fee\u6539\u72b6\u6001\uff1a\u9700\u8981\u89e3\u6790KEY\n                    state = CONF_KEY;\n                }\n            }\n        }\n        else if (event.type == YAML_SEQUENCE_START_EVENT) {\n            fprintf(stdout, \"event.type=YAML_SEQUENCE_START_EVENT; state=%d\\n\", state);\n            \/\/ \u5982\u679c\u5904\u7406\u5217\u8868\u662finclude\u5217\u8868\uff0c\u4f7f\u7528 \u5f53\u524d\u8282\u70b9\n            \/\/ \u72b6\u6001\u5982\u679c\u662f CONF_INCLUDE   \u4e0b\u4e00\u7ea7\u89e3\u6790\u4f20\u9012 parent\u8282\u70b9\uff0c\u5426\u5219\u4f20\u9012 \u5f53\u524d\u8282\u70b9\n            \/\/ inseq \u6807\u8bb0\u4e3a 1 \u6b64\u6b21\u5904\u7406\u7684\u662f\u88ab\u522b\u7684\u6587\u4ef6\u5f15\u5165\u7684\n            \/\/ \u5217\u8868 \u89e3\u6790\u8fdb\u5165 \u9012\u5f52\u8c03\u7528\n            if (ConfYamlParse(parser, state == CONF_INCLUDE ? parent : node, 1, rlevel,\n                        state == CONF_INCLUDE ? CONF_INCLUDE : 0) != 0)\n                goto fail;\n            \/\/ \u8bbe\u7f6e\u6b64\u8282\u70b9\u662f \u5217\u8868\n            node-&gt;is_seq = 1;\n            \/\/ \u4fee\u6539\u72b6\u6001\uff1a\u9700\u8981\u89e3\u6790KEY\n            state = CONF_KEY;\n        }\n        else if (event.type == YAML_SEQUENCE_END_EVENT) {      \/\/ \u5217\u8868\u7ed3\u675f\n            fprintf(stderr, \"event.type=YAML_SEQUENCE_END_EVENT; state=%d\\n\", state);\n            done = 1; \/\/ \u7ed3\u675f\uff0c\u51fd\u6570\u9000\u51fa\n        }\n        else if (event.type == YAML_MAPPING_START_EVENT) {      \/\/ MAPPING \u5f00\u59cb\u4e8b\u4ef6\n            fprintf(stdout, \"event.type=YAML_MAPPING_START_EVENT; state=%d\\n\", state);\n            if (state == CONF_INCLUDE) {\n                fprintf(stderr, \"Include fields cannot be a mapping: line %zu\\n\", parser-&gt;mark.line);\n                goto fail;\n            }\n            if (inseq) { \/\/ \u5217\u8868\u91cc mapping \u7684\u5904\u7406\u65b9\u5f0f\n                char sequence_node_name&#91;DEFAULT_NAME_LEN];\n                \/\/ \u628a \u7d22\u5f15\u4f5c\u4e3a \u8def\u5f84\u8282\u70b9\u540d\u5b57\uff0c \u4ece 0 \u5f00\u59cb\n                snprintf(sequence_node_name, DEFAULT_NAME_LEN, \"%d\", seq_idx++);\n                \/\/ \u67e5\u627e\u5bf9\u5e94\u7684 \u8282\u70b9\n                ConfNode *seq_node = ConfNodeLookupChild(node,\n                    sequence_node_name);\n                if (seq_node != NULL) {\n                    \/\/ \u5148\u4ece\u89e3\u6790\u7ed3\u679c\u91cc\u5220\u9664\uff0c\u540e\u9762\u518d\u6dfb\u52a0\n                    TAILQ_REMOVE(&amp;node-&gt;head, seq_node, next);\n                }\n                else {\n                    \/\/ \u6ca1\u6709\u8282\u70b9\uff0c\u5c31\u521b\u5efa\u8282\u70b9\n                    seq_node = ConfNodeNew();\n                    if (unlikely(seq_node == NULL)) {\n                        goto fail;\n                    }\n                    seq_node-&gt;name = strdup(sequence_node_name);\n                    if (unlikely(seq_node-&gt;name == NULL)) {\n                        free(seq_node);\n                        goto fail;\n                    }\n                }\n                seq_node-&gt;is_seq = 1;\n                TAILQ_INSERT_TAIL(&amp;node-&gt;head, seq_node, next);\n                \/\/ mapping\u7684\u89e3\u6790\uff0c\u8fdb\u5165\u9012\u5f52\u8c03\u7528\n                if (ConfYamlParse(parser, seq_node, 0, rlevel, 0) != 0)\n                    goto fail;\n            }\n            else {\n                if (ConfYamlParse(parser, node, inseq, rlevel, 0) != 0)\n                    goto fail;\n            }\n            state = CONF_KEY;\n        }\n        else if (event.type == YAML_MAPPING_END_EVENT) {\n            fprintf(stdout, \"event.type=YAML_MAPPING_END_EVENT; state=%d\\n\", state);\n            done = 1; \/\/ \u7ed3\u675f\uff0c\u51fd\u6570\u9000\u51fa\n        }\n        else if (event.type == YAML_STREAM_END_EVENT) {\n            fprintf(stdout, \"event.type=YAML_STREAM_END_EVENT; state=%d\\n\", state);\n            done = 1; \/\/ \u7ed3\u675f\uff0c\u51fd\u6570\u9000\u51fa\n        }\n\n    next:\n        \/\/ \u6e05\u7406\u672c\u6b21\u4e8b\u4ef6\uff0c\u8fdb\u5165\u4e0b\u4e00\u5faa\u73af\uff0c\u7ee7\u7eed\u5904\u7406\u6570\u636e\n        yaml_event_delete(&amp;event);\n        continue;\n\n    fail:\n        \/\/ \u5931\u8d25\u8df3\u51fa\u5faa\u73af\n        yaml_event_delete(&amp;event);\n        retval = -1;\n        break;\n    }\n\n    rlevel--;\n    return retval;\n}\n\n\/**\n * \u89e3\u6790yaml\u6587\u4ef6\n * \u8fd4\u56de\u503c\uff1a0 - success, -1 - failure.\n *\/\nint\nConfYamlLoadFile(const char *filename)\n{\n    FILE *infile;\n    yaml_parser_t parser; \/\/ yaml\u89e3\u6790\u53e5\u67c4\n    int ret;\n    ConfNode *root = ConfGetRootNode();\n\n    if (yaml_parser_initialize(&amp;parser) != 1) {\n        fprintf(stderr, \"failed to initialize yaml parser.\\n\");\n        return -1;\n    }\n\n    struct stat stat_buf;\n    if (stat(filename, &amp;stat_buf) == 0) {\n        if (stat_buf.st_mode &amp; S_IFDIR) {\n            fprintf(stderr, \"yaml argument is not a file but a directory: %s. \"\n                       \"Please specify the yaml file in your -c option.\\n\",\n                    filename);\n            yaml_parser_delete(&amp;parser);\n            return -1;\n        }\n    }\n\n    \/\/ coverity&#91;toctou : FALSE]\n    infile = fopen(filename, \"r\");\n    if (infile == NULL) {\n        fprintf(stderr, \"failed to open file: %s: %s\\n\", filename, strerror(errno));\n        yaml_parser_delete(&amp;parser);\n        return -1;\n    }\n\n    if (conf_dirname == NULL) {\n        \/\/ \u8bbe\u7f6e\u914d\u7f6e\u6587\u4ef6\u8def\u5f84\n        ConfYamlSetConfDirname(filename);\n    }\n\n    \/\/ \u8bbe\u7f6e\u8981\u89e3\u6790\u7684\u6587\u4ef6\u53e5\u67c4\n    yaml_parser_set_input_file(&amp;parser, infile);\n    ret = ConfYamlParse(&amp;parser, root, 0, 0, 0);\n    yaml_parser_delete(&amp;parser);\n    fclose(infile);\n\n    return ret;\n}\n\n\/**\n * \u52a0\u8f7d\u89e3\u6790 yaml\u6587\u4ef6\u7684 \u5b57\u7b26\u4e32\n *\/\nint\nConfYamlLoadString(const char *string, size_t len)\n{\n    ConfNode *root = ConfGetRootNode();\n    yaml_parser_t parser;\n    int ret;\n\n    if (yaml_parser_initialize(&amp;parser) != 1) {\n        fprintf(stderr, \"Failed to initialize yaml parser.\\n\");\n        exit(EXIT_FAILURE);\n    }\n    yaml_parser_set_input_string(&amp;parser, (const unsigned char *)string, len);\n    ret = ConfYamlParse(&amp;parser, root, 0, 0, 0);\n    yaml_parser_delete(&amp;parser);\n\n    return ret;\n}\n\n\/**\n * \u89e3\u6790\u4e00\u4e2a\u6587\u4ef6 filename\uff0c\u628a\u89e3\u6790\u7684\u6570\u636e\u653e\u5728 prefix \u8282\u70b9\u4e0b\n * \u5982\u679c\u6ca1\u6709\u6b64\u8282\u70b9\uff0c\u5c31\u521b\u5efa\u4e00\u4e2a\u7a7a\u8282\u70b9\uff0c\u5e76\u628a\u89e3\u6790\u7684\u6570\u636e\u6302\u8f7d\u6b64\u8282\u70b9\u4e0b\u3002\n *\n * \u8fd4\u56de\u503c    0 - \u6210\u529f\n *          1 - \u5931\u8d25\n *\/\nint\nConfYamlLoadFileWithPrefix(const char *filename, const char *prefix)\n{\n    FILE *infile;\n    yaml_parser_t parser;\n    int ret;\n    \/\/ \u627e\u5230\u8fd9\u4e2a\u8282\u70b9\n    ConfNode *root = ConfGetNode(prefix);\n\n    if (yaml_parser_initialize(&amp;parser) != 1) {\n        fprintf(stderr, \"failed to initialize yaml parser.\\n\");\n        return -1;\n    }\n\n    \/\/ \u68c0\u6d4b\u6587\u4ef6\n    struct stat stat_buf;\n    if (stat(filename, &amp;stat_buf) == 0) {\n        if (stat_buf.st_mode &amp; S_IFDIR) {\n            fprintf(stderr, \"yaml argument is not a file but a directory: %s. \"\n                       \"Please specify the yaml file in your -c option.\\n\",\n                    filename);\n            return -1;\n        }\n    }\n\n    \/\/ \u6253\u5f00\u6587\u4ef6\n    infile = fopen(filename, \"r\");\n    if (infile == NULL) {\n        fprintf(stderr, \"failed to open file: %s: %s\\n\", filename, strerror(errno));\n        yaml_parser_delete(&amp;parser);\n        return -1;\n    }\n\n    if (conf_dirname == NULL) {\n        ConfYamlSetConfDirname(filename);\n    }\n\n    if (root == NULL) { \n        \/\/ \u6ca1\u627e\u5230\u6b64\u8282\u70b9\uff0c\u6dfb\u52a0\u4e00\u4e2a\u7a7a\u8282\u70b9\uff0c\u503c\u8bbe\u7f6e\u4e3a \"&lt;prefix root node&gt;\"\n        ConfSet(prefix, \"&lt;prefix root node&gt;\");\n        \/\/ \u518d\u6b21\u83b7\u53d6\u6b64\u8282\u70b9\n        root = ConfGetNode(prefix);\n        if (root == NULL) {\n            \/\/ \u83b7\u53d6\u4e0d\u5230\u5c31\u7b97\u4e86\uff0c\u4e0d\u89e3\u6790\u4e86\n            fclose(infile);\n            yaml_parser_delete(&amp;parser);\n            return -1;\n        }\n    }\n    \/\/ \u8bbe\u7f6eyaml\u6587\u4ef6\u63cf\u8ff0\u7b26\n    yaml_parser_set_input_file(&amp;parser, infile);\n    ret = ConfYamlParse(&amp;parser, root, 0, 0, 0);\n    yaml_parser_delete(&amp;parser);\n    fclose(infile);\n\n    return ret;\n}<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u4ee3\u7801 conf-yaml-loader.h<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ifndef __CONF_YAML_LOADER_H__\n#define __CONF_YAML_LOADER_H__\n\n#include \"conf-yaml.h\"\n\nint ConfYamlLoadFile(const char *);\nint ConfYamlLoadString(const char *, size_t);\nint ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix);\nint ConfYamlHandleInclude(ConfNode *parent, const char *filename);\n\nvoid ConfYamlRegisterTests(void);\n\n#endif \/* !__CONF_YAML_LOADER_H__ *\/\n<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u4ee3\u7801 conf-yaml.c<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h>\n#include &lt;stdlib.h>\n#include &lt;yaml.h>\n#include &lt;limits.h>\n#include &lt;sys\/stat.h>\n#include &lt;fcntl.h>\n#include &lt;errno.h>\n#include &lt;ctype.h>\n#include &lt;string.h>\n#include &lt;bsd\/string.h>\n\n#include \"conf-yaml.h\"\n\n\/** \u8282\u70b9\u5168\u540d\u79f0\u6700\u5927\u957f\u5ea6\u3002\u5168\u540d\u79f0\u6307\uff0c\u4ee5 . \u8fde\u63a5\u5404\u8def\u5f84\u7684\u6700\u7ec8\u540d\u79f0 *\/\n#define NODE_NAME_MAX 1024\n\n\n\/\/ \u5168\u5c40\u53d8\u91cf\uff0c\u4fdd\u5b58 \u89e3\u6790\u540e\u7684 yaml\u7ed3\u6784\u6839\u7684\u5730\u5740\nstatic ConfNode *yaml_root = NULL;\n\/\/ \u5730\u5740\u5907\u4efd\u4f7f\u7528\nstatic ConfNode *yaml_root_backup = NULL;\n\n\n\/**\n * \u83b7\u5f97\u8282\u70b9\uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u521b\u5efa\u8282\u70b9\uff0c\u5e76\u52a0\u5165\u5230\u6307\u5b9a\u4f4d\u7f6e\u5e76\u8fd4\u56de\n * \u5728\u5168\u8282\u70b9\u67e5\u627e\n *\n * \u53c2\u6570\uff1a    parent \u7528\u6765\u4f5c\u4e3a\u7236\u8282\u70b9\u7684\u8282\u70b9\n *          name \u60f3\u8981\u83b7\u53d6\u7684\u8282\u70b9\u540d\u79f0\n *          final \u8bbe\u7f6efinal\u6807\u8bb0\n * \u8fd4\u56de\u503c\uff1a  \u6210\u529f\u5219\u8fd4\u56de  \u627e\u5230\u7684\u6216\u8005\u521b\u5efa\u7684node\n *         \u5931\u8d25\u5219\u8fd4\u56de  NULL\n *\/\nConfNode *ConfNodeGetNodeOrCreate(ConfNode *parent, const char *name, int final)\n{\n    ConfNode *node = NULL;\n    char node_name&#91;NODE_NAME_MAX];\n    char *key;\n    char *next;\n\n    if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {\n        fprintf(stderr, \"Configuration name too long: %s\\n\", name);\n        return NULL;\n    }\n\n    key = node_name;\n\n    do {\n        if ((next = strchr(key, '.')) != NULL)\n            *next++ = '\\0';\n        if ((node = ConfNodeLookupChild(parent, key)) == NULL) {\n            \/\/ \u6ca1\u627e\u5230\uff0c\u521b\u5efa\uff0c\u5e76\u8bbe\u7f6ename\n            node = ConfNodeNew(); \n            if (unlikely(node == NULL)) {\n                fprintf(stderr, \"Failed to allocate memory for configuration.\\n\");\n                goto end;\n            }\n            node->name = strdup(key);\n            if (unlikely(node->name == NULL)) {\n                ConfNodeFree(node);\n                node = NULL;\n                fprintf(stderr, \"Failed to allocate memory for configuration.\\n\");\n                goto end;\n            }\n            node->parent = parent;\n            node->final = final;\n            \/\/ \u5728\u7236\u8282\u70b9\u63d2\u5165\u521a\u7533\u8bf7\u7684\u8282\u70b9\n            TAILQ_INSERT_TAIL(&amp;parent->head, node, next);\n        }\n        \/\/ \u63a5\u7eed\u51c6\u5907\u4e0b\u4e00\u7ea7\u67e5\u627e\u6216\u8005\u521b\u5efa\n        key = next;\n        parent = node;\n    } while (next != NULL);\n\nend:\n    \/\/ \u6700\u540e\u8fd4\u56de\u8282\u70b9\n    return node;\n}\n\n\/**\n * \u5c01\u88c5 ConfNodeGetNodeOrCreate\uff0c \u4ece yaml_root \u67e5\u627e\u8282\u70b9\n *\/\nstatic ConfNode *ConfGetNodeOrCreate(const char *name, int final)\n{\n    return ConfNodeGetNodeOrCreate(yaml_root, name, final);\n}\n\n\/**\n * \u521d\u59cb\u5316\u914d\u7f6e\u7cfb\u7edf\uff0c\u7ed9\u5168\u5c40\u53d8\u91cf yaml_root \u7533\u8bf7 ConfNode \u8282\u70b9\n *\/\nvoid ConfInit(void)\n{\n    if (yaml_root != NULL) {\n        fprintf(stdout, \"already initialized\\n\");\n        return;\n    }\n    yaml_root = ConfNodeNew();\n    if (yaml_root == NULL) {\n        fprintf(stderr, \"ERROR: Failed to allocate memory for yaml_root configuration node, \"\n                   \"aborting.\\n\");\n    }\n    fprintf(stdout, \"configuration module initialized\\n\");\n}\n\n\/**\n * \u7533\u8bf7\u4e00\u4e2a ConfNode \u8282\u70b9\n *\n * \u8fd4\u56de\u503c \u6210\u529f - \u8fd4\u56de\u7533\u8bf7\u7684\u914d\u7f6e\u8282\u70b9 node\n *       \u5931\u8d25 - NULL\n *\/\nConfNode *ConfNodeNew(void)\n{\n    ConfNode *new;\n\n    new = calloc(1, sizeof(*new));\n    if (unlikely(new == NULL)) {\n        return NULL;\n    }\n    TAILQ_INIT(&amp;new->head);\n\n    return new;\n}\n\n\/**\n * \u91ca\u653e\u8282\u70b9\uff0c\u5e76\u9012\u5f52\u91ca\u653e\u6240\u6709\u5b50\u8282\u70b9\n *\/\nvoid ConfNodeFree(ConfNode *node)\n{\n    ConfNode *tmp;\n\n    while ((tmp = TAILQ_FIRST(&amp;node->head))) { \/\/ \u6ca1\u6709\u4e86\u5b50\u8282\u70b9\n        \/\/ \u4ece\u5144\u5f1f\u8282\u70b9\u4e0a\u53bb\u6389\n        TAILQ_REMOVE(&amp;node->head, tmp, next);\n        \/\/ \u91ca\u653e\u8282\u70b9\u548c\u5b50\u8282\u70b9\n        ConfNodeFree(tmp);\n    }\n\n    if (node->name != NULL)\n        free(node->name);\n    if (node->val != NULL)\n        free(node->val);\n    free(node);\n}\n\n\/**\n * \u6839\u636e\u8282\u70b9\u540d\u5b57\u8fd4\u56de\u8282\u70b9\n * \u4ece yaml_root \u5f00\u59cb\u67e5\u627e\uff0c\u8f93\u5165 \u8282\u70b9\u7684\u5168\u8def\u5f84\n * \u6df1\u5ea6\u67e5\u627e\n *\n * \u8fd4\u56de\u503c  \u67e5\u8be2\u5230\u8282\u70b9\uff0c\u8fd4\u56de\u6b64\u8282\u70b9\u3002\n *        \u5982\u679c\u8282\u70b9\u6ca1\u627e\u5230\uff0c\u8fd4\u56deNULL\n *\/\nConfNode *ConfGetNode(const char *name)\n{\n    ConfNode *node = yaml_root;\n    char node_name&#91;NODE_NAME_MAX];\n    char *key;\n    char *next;\n\n    if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {\n        fprintf(stderr, \"Configuration name too long: %s\\n\", name);\n        return NULL;\n    }\n\n    key = node_name;\n    do {\n        if ((next = strchr(key, '.')) != NULL)\n            *next++ = '\\0';\n        \/\/ root \u8282\u70b9\u662f\u6ca1\u6709\u6570\u636e\u7684\uff0c\u6240\u6709\u4ece\u5b69\u5b50\u8282\u70b9\u4e2d\u67e5\u627e\n        node = ConfNodeLookupChild(node, key);\n        key = next;\n    } while (next != NULL &amp;&amp; node != NULL);\n\n    return node;\n}\n\n\/**\n * \u8fd4\u56de yaml_root \u503c\n *\/\nConfNode *ConfGetRootNode(void)\n{\n    return yaml_root;\n}\n\n\/**\n * \u8bbe\u7f6e\u914d\u7f6e\u503c\uff0c\n * \u5982\u679c\u8282\u70b9\u627e\u5230\uff0c\u5e76\u4e14\u662ffinal\u5219\u8fd4\u56de\u5931\u8d25\n *\n * \u8fd4\u56de\u503c    1 - \u8bbe\u7f6e\u6210\u529f\n *          0 - \u8bbe\u7f6e\u5931\u8d25\n *\/\nint ConfSet(const char *name, const char *val)\n{\n    \/\/ \u627e\u5230\u8282\u70b9\uff0c\u6ca1\u6709\u5c31\u521b\u5efa\u8282\u70b9\n    ConfNode *node = ConfGetNodeOrCreate(name, 0);\n    if (node == NULL || node->final) {\n        return 0;\n    }\n    if (node->val != NULL)\n        free(node->val);\n    node->val = strdup(val);\n    if (unlikely(node->val == NULL)) {\n        return 0;\n    }\n    return 1;\n}\n\n\/**\n * \u4ece\u5b57\u7b26\u4e32\u89e3\u6790yaml\u8282\u70b9\n * \u4e3e\u4f8b\uff1a  aaa.bbb.ccc = hello world\n * \u4f1a\u88ab\u8bbe\u7f6e\u6210  aaa\u7684\u5b50\u8282\u70b9bbb\u7684\u5b50\u8282\u70b9ccc\u7684val\u503c = \"hello world\"\n *\n * \u8fd4\u56de\u503c    1 - value\u88ab\u8bbe\u7f6e\u4e0a\n *          0 - value\u6ca1\u6709\u88ab\u8bbe\u7f6e\n *\/\nint ConfSetFromString(const char *input, int final)\n{\n    int retval = 0;\n    char *name = strdup(input), *val = NULL;\n    if (unlikely(name == NULL)) {\n        goto done;\n    }\n    val = strchr(name, '=');\n    if (val == NULL) {\n        goto done;\n    }\n    *val++ = '\\0';\n\n    \/\/ \u5904\u7406name\u7684\u6570\u636e\uff0c\u53bb\u6389\u540e\u65b9\u7684\u7a7a\u767d\u5b57\u7b26\n    while (isspace((int)name&#91;strlen(name) - 1])) {\n        name&#91;strlen(name) - 1] = '\\0';\n    }\n\n    \/\/ \u5904\u7406val\u7684\u6570\u636e\uff0c\u53bb\u6389\u524d\u65b9\u7684\u7a7a\u767d\u5b57\u7b26\n    while (isspace((int)*val)) {\n        val++;\n    }\n\n    \/\/ \u6dfb\u52a0 \u8282\u70b9  \u6839\u636e final \u8bbe\u7f6e\n    if (final) {\n        if (!ConfSetFinal(name, val)) {\n            goto done;\n        }\n    }\n    else {\n        if (!ConfSet(name, val)) {\n            goto done;\n        }\n    }\n\n    retval = 1;\ndone:\n    if (name != NULL) {\n        free(name);\n    }\n    return retval;\n}\n\n\/**\n * \u8bbe\u7f6e\u6700\u7ec8\u503c\uff0c\u5e76\u8bbe\u7f6e\u4e3a\u6700\u7ec8\u503c\uff0c\u4e0d\u80fd\u88ab\u8986\u76d6\uff0cfinal\u8bbe\u7f6e\u4e3a1\n *\n * \u8fd4\u56de\u503c     1 - \u8bbe\u7f6e\u6210\u529f\n *           0 - \u8bbe\u7f6e\u5931\u8d25\n *\/\nint ConfSetFinal(const char *name, const char *val)\n{\n    ConfNode *node = ConfGetNodeOrCreate(name, 1);\n    if (node == NULL) {\n        return 0;\n    }\n    if (node->val != NULL)\n        free(node->val);\n    node->val = strdup(val);\n    if (unlikely(node->val == NULL)) {\n        return 0;\n    }\n    node->final = 1;\n    return 1;\n}\n\n\/**\n * \u6839\u636e\u540d\u5b57\u83b7\u53d6\u8282\u70b9\u503c\uff0c\u4eceyaml_root\u7ed3\u70b9\u5f00\u59cb\u67e5\u8be2\n * \u8f93\u5165\u5168\u8def\u5f84 \u548c \u6307\u5411val\u503c\u7684\u6307\u9488\u7684\u5730\u5740\u3002\n * \u7ed9 *vptr \u8d4b\u503c\u7684\u662f\u6570\u636e\u539f\u5730\u5740\uff0c\u4e0d\u662f\u526f\u672c\u3002\n * \u6df1\u5ea6\u67e5\u627e\n *\n * \u8fd4\u56de\u503c  1 - \u8282\u70b9\u627e\u5230   0 - \u6ca1\u627e\u5230\u8282\u70b9\n *\/\nint ConfGet(const char *name, const char **vptr)\n{\n    ConfNode *node = ConfGetNode(name);\n    if (node == NULL) {\n        fprintf(stdout, \"failed to lookup configuration parameter '%s'\\n\", name);\n        return 0;\n    }\n    else {\n        *vptr = node->val;\n        return 1;\n    }\n}\n\n\/**\n * \u6839\u636e name \u67e5\u627e\u6307\u5b9a\u8282\u70b9 base \u7684\u5b50\u8282\u70b9\uff0c\u5e76\u628a\u8282\u70b9\u503c\u7684\u5730\u5740\u7ed9\u5230 *vptr\n * \u53ea\u5728\u5b50\u8282\u70b9\u67e5\u627e\n *\n * \u8fd4\u56de\u503c     1 - \u6210\u529f\n *           0 - \u5931\u8d25\n *\/\nint ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr)\n{\n    ConfNode *node = ConfNodeLookupChild(base, name);\n\n    if (node == NULL) {\n        \/\/ fprintf(stdout, \"failed to lookup configuration parameter '%s'\\n\", name);\n        return 0;\n    }\n    else {\n        if (node->val == NULL)\n            return 0;\n        *vptr = node->val;\n        return 1;\n    }\n}\n\n\/**\n * \u4ecebase\u7684\u5b50\u8282\u70b9\u4e2d\u83b7\u53d6\u540d\u5b57\u662fname\u7684\u8282\u70b9\uff0c\n * \u5982\u679cbase\u8282\u70b9\u7684\u5b50\u8282\u70b9\u627e\u4e0d\u5230\u5219\u4ece\u9ed8\u8ba4\u7684\u8282\u70b9dflt\u7684\u5b50\u8282\u70b9\u67e5\u627ename\u8282\u70b9\n * \u5982\u679c\u4e24\u4e2a\u90fd\u627e\u4e0d\u5230\uff0c\u5219\u8fd4\u56deNULL\n *\n * \u8fd4\u56de\u503c:     \u627e\u5230\uff0c\u8fd4\u56dename\u7684\u8282\u70b9\n *            \u627e\u4e0d\u5230\uff0c\u8fd4\u56deNULL\n *\/\nConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt,\n    const char *name)\n{\n    ConfNode *node = ConfNodeLookupChild(base, name);\n    if (node != NULL)\n        return node;\n\n    \/* Get 'default' value *\/\n    if (dflt) {\n        return ConfNodeLookupChild(dflt, name);\n    }\n    return NULL;\n}\n\nint ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt,\n    const char *name, const char **vptr)\n{\n    int ret = ConfGetChildValue(base, name, vptr);\n    \/* Get 'default' value *\/\n    if (ret == 0 &amp;&amp; dflt) {\n        return ConfGetChildValue(dflt, name, vptr);\n    }\n    return ret;\n}\n\n\/**\n * \u5c1d\u8bd5\u627e\u5230 name \u8282\u70b9\u5e76\u628a\u503c\u8f6c\u6362\u6210 integer \u7c7b\u578b\u7684\u503c\uff0c\u8d4b\u503c\u7ed9 *val\n *\n * \u8fd4\u56de\u503c    1 - \u540d\u5b57\u88ab\u627e\u5230\uff0c\u5e76\u4e14\u4e89\u53d6\u8f6c\u6362\u6210 integer\n *          0 - \u5931\u8d25\n *\/\nint ConfGetInt(const char *name, intmax_t *val)\n{\n    const char *strval = NULL;\n    intmax_t tmpint;\n    char *endptr;\n\n    if (ConfGet(name, &amp;strval) == 0)\n        return 0;\n\n    if (strval == NULL) {\n        fprintf(stderr, \"malformed integer value \"\n                   \"for %s: NULL\\n\",\n                name);\n        return 0;\n    }\n\n    errno = 0;\n    tmpint = strtoimax(strval, &amp;endptr, 0);\n    if (strval&#91;0] == '\\0' || *endptr != '\\0') {\n        fprintf(stderr, \"malformed integer value \"\n                   \"for %s: '%s'\\n\",\n                name, strval);\n        return 0;\n    }\n    if (errno == ERANGE &amp;&amp; (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {\n        fprintf(stderr, \"integer value for %s out \"\n                   \"of range: '%s'\\n\",\n                name, strval);\n        return 0;\n    }\n\n    *val = tmpint;\n    return 1;\n}\n\n\/**\n * \u4ece\u7ed9\u5b9a\u7684\u8282\u70b9 base \u7684\u5b50\u8282\u70b9\u4e2d\uff0c\u67e5\u627e\u540d\u5b57\u4e3a name \u7684\u914d\u7f6e\uff0c\u7136\u540e\u8f6c\u6362\u6210int\u7c7b\u578b\u7ed9 *val \u8d4b\u503c\n *\n * \u8fd4\u56de\u503c    1 - \u540d\u5b57\u88ab\u627e\u5230\uff0c\u5e76\u4e14\u6b63\u786e\u8f6c\u6362\u6210 integer\n *          0 - \u5931\u8d25\n *\/\nint ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)\n{\n    const char *strval = NULL;\n    intmax_t tmpint;\n    char *endptr;\n\n    if (ConfGetChildValue(base, name, &amp;strval) == 0)\n        return 0;\n    errno = 0;\n    tmpint = strtoimax(strval, &amp;endptr, 0);\n    if (strval&#91;0] == '\\0' || *endptr != '\\0') {\n        fprintf(stderr, \"malformed integer value \"\n                   \"for %s with base %s: '%s'\\n\",\n                name, base->name, strval);\n        return 0;\n    }\n    if (errno == ERANGE &amp;&amp; (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {\n        fprintf(stderr, \"integer value for %s with \"\n                   \" base %s out of range: '%s'\\n\",\n                name, base->name, strval);\n        return 0;\n    }\n\n    *val = tmpint;\n    return 1;\n\n}\n\n\n\/**\n * \u7ed9 ConfGetChildValueInt \u52a0\u4e86\u4e2a\u58f3\uff0cbase \u7684\u5b50\u8282\u70b9 \u627e\u4e0d\u5230\u5c31\u4ece dflt \u7684\u5b50\u8282\u70b9\u91cc\u627e\n *\n * \u8fd4\u56de\u503c    1 - \u540d\u5b57\u88ab\u627e\u5230\uff0c\u5e76\u4e14\u6b63\u786e\u8f6c\u6362\u6210 integer\n *          0 - \u5931\u8d25\n *\/\nint ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt,\n    const char *name, intmax_t *val)\n{\n    int ret = ConfGetChildValueInt(base, name, val);\n    \/* Get 'default' value *\/\n    if (ret == 0 &amp;&amp; dflt) {\n        return ConfGetChildValueInt(dflt, name, val);\n    }\n    return ret;\n}\n\n\/**\n * \u6839\u636ename\u7528boolean\u7c7b\u578b\u68c0\u7d22\u4e00\u4e2a\u914d\u7f6e\u503c\n *\n * \u8fd4\u56de\u503c    1 - \u540d\u5b57\u88ab\u627e\u5230\uff0c\u5e76\u4e14\u6b63\u786e\u8f6c\u6362\u6210 Bool \u7c7b\u578b 1 \u6216\u8005 0\n *          0 - \u5931\u8d25\n *\/\nint ConfGetBool(const char *name, int *val)\n{\n    const char *strval = NULL;\n\n    *val = 0;\n    if (ConfGet(name, &amp;strval) != 1)\n        return 0;\n\n    \/\/ \u5224\u65ad\u662f\u5426\u4e3a\u771f\n    *val = ConfValIsTrue(strval);\n\n    return 1;\n}\n\n\/**\n * \u6839\u636ename\u5728 base \u8282\u70b9\u7684\u5b50\u8282\u70b9\u4e2d\u7528boolean\u7c7b\u578b\u68c0\u7d22\u4e00\u4e2a\u914d\u7f6e\u503c\uff0c\u628a\u8f6c\u6362\u7684\u503c\u8d4b\u503c\u7ed9 *val\n *\n * \u8fd4\u56de\u503c    1 - \u540d\u5b57\u88ab\u627e\u5230\uff0c\u5e76\u4e14\u6b63\u786e\u8f6c\u6362\u6210 Bool \u7c7b\u578b 1 \u6216\u8005 0\n *          0 - \u5931\u8d25\n *\/\nint ConfGetChildValueBool(const ConfNode *base, const char *name, int *val)\n{\n    const char *strval = NULL;\n\n    *val = 0;\n    if (ConfGetChildValue(base, name, &amp;strval) == 0)\n        return 0;\n\n    *val = ConfValIsTrue(strval);\n\n    return 1;\n}\n\n\/**\n * ConfGetChildValueBool\u7684\u4e00\u4e2a\u5c01\u88c5\uff0c\u5982\u679cbase\u7684\u5b50\u8282\u70b9\u6ca1\u6709\uff0c\u4ece\u9ed8\u8ba4\u8282\u70b9 dflt\u4e2d\u83b7\u53d6\n *\n * \u8fd4\u56de\u503c    1 - \u540d\u5b57\u88ab\u627e\u5230\uff0c\u5e76\u4e14\u6b63\u786e\u8f6c\u6362\u6210 Bool \u7c7b\u578b 1 \u6216\u8005 0\n *          0 - \u5931\u8d25\n *\/\nint ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt,\n    const char *name, int *val)\n{\n    int ret = ConfGetChildValueBool(base, name, val);\n    \/* Get 'default' value *\/\n    if (ret == 0 &amp;&amp; dflt) {\n        return ConfGetChildValueBool(dflt, name, val);\n    }\n    return ret;\n}\n\n\n\/**\n * \u5224\u65ad\u662f\u5426\u4e3a\u771f\n * \u5224\u65ad\u662f\u5426\u4e3a 1, yes, true or on\n *\n * \u8fd4\u56de\u503c     1 - \u662f\u771f\n *           0 - \u4e0d\u662f\u771f\n *\/\nint ConfValIsTrue(const char *val)\n{\n    const char *trues&#91;] = {\"1\", \"yes\", \"true\", \"on\"};\n    size_t u;\n\n    for (u = 0; u &lt; sizeof(trues) \/ sizeof(trues&#91;0]); u++) {\n        if (strcasecmp(val, trues&#91;u]) == 0) {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\n\/**\n * \u5224\u65ad\u662f\u5426\u4e3a\u5047\uff0c\u4e3a\u5047\u8fd4\u56de 1 \n * \u5224\u65ad\u662f\u5426\u4e3a 0, no, false or off\n *\n * \u8fd4\u56de\u503c     1 - \u662f\u5047\n *           0 - \u4e0d\u662f\u5047\n *\/\nint ConfValIsFalse(const char *val)\n{\n    const char *falses&#91;] = {\"0\", \"no\", \"false\", \"off\"};\n    size_t u;\n\n    for (u = 0; u &lt; sizeof(falses) \/ sizeof(falses&#91;0]); u++) {\n        if (strcasecmp(val, falses&#91;u]) == 0) {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\n\/**\n * \u4f7f\u7528 dobule \u68c0\u7d22\u4e00\u4e2a\u914d\u7f6e\u7684\u503c\u7ed9 *val\n * \n * \u8fd4\u56de\u503c        1 - \u6210\u529f\n *              0 - \u5931\u8d25\n *\/\nint ConfGetDouble(const char *name, double *val)\n{\n    const char *strval = NULL;\n    double tmpdo;\n    char *endptr;\n\n    if (ConfGet(name, &amp;strval) == 0)\n        return 0;\n\n    errno = 0;\n    tmpdo = strtod(strval, &amp;endptr);\n    if (strval&#91;0] == '\\0' || *endptr != '\\0')\n        return 0;\n    if (errno == ERANGE)\n        return 0;\n\n    *val = tmpdo;\n    return 1;\n}\n\n\/**\n * \u4f7f\u7528 float \u68c0\u7d22\u4e00\u4e2a\u914d\u7f6e\u7684\u503c\u7ed9 *val\n * \n * \u8fd4\u56de\u503c        1 - \u6210\u529f\n *              0 - \u5931\u8d25\n *\/\nint ConfGetFloat(const char *name, float *val)\n{\n    const char *strval = NULL;\n    double tmpfl;\n    char *endptr;\n\n    if (ConfGet(name, &amp;strval) == 0)\n        return 0;\n\n    errno = 0;\n    tmpfl = strtof(strval, &amp;endptr);\n    if (strval&#91;0] == '\\0' || *endptr != '\\0')\n        return 0;\n    if (errno == ERANGE)\n        return 0;\n\n    *val = tmpfl;\n    return 1;\n}\n\n\/**\n * \u5220\u9664\u4e00\u4e2a\u7ed9\u5b9a\u7684\u8282\u70b9\n *\/\nvoid ConfNodeRemove(ConfNode *node)\n{\n    if (node->parent != NULL)\n        \/\/ \u4ece\u5144\u5f1f\u8282\u70b9\u4e0a\u53bb\u6389 next \n        TAILQ_REMOVE(&amp;node->parent->head, node, next);\n    ConfNodeFree(node);\n}\n\n\/**\n *\n * \u6839\u636e\u540d\u5b57\u5220\u9664\u8282\u70b9\n *\n * \u8fd4\u56de\u503c  1 - \u6210\u529f\u5220\u9664  0 - \u6ca1\u6709\u53d1\u73b0\u8282\u70b9\n *\/\nint ConfRemove(const char *name)\n{\n    ConfNode *node;\n\n    node = ConfGetNode(name);\n    if (node == NULL)\n        return 0;\n    else {\n        ConfNodeRemove(node);\n        return 1;\n    }\n}\n\n\/**\n * \u5907\u4efd yaml_root \u6307\u5411\u7684\u7ed3\u6784\u7684\u5730\u5740 \u7ed9 yaml_root_backup\n * \u6ca1\u6709\u6570\u636e\u62f7\u8d1d\n *\/\nvoid ConfCreateContextBackup(void)\n{\n    yaml_root_backup = yaml_root;\n    yaml_root = NULL;\n\n    return;\n}\n\n\/**\n * \u8fd8\u539f yaml_root_backup \u6307\u5411\u7684\u7ed3\u6784\u7684\u5730\u5740 \u7ed9 yaml_root\uff0c\n * \u6ca1\u6709\u6570\u636e\u62f7\u8d1d\n *\/\nvoid ConfRestoreContextBackup(void)\n{\n    yaml_root = yaml_root_backup;\n    yaml_root_backup = NULL;\n\n    return;\n}\n\n\/**\n * \u6e05\u7406 yaml_root \u8282\u70b9\n *\/\nvoid ConfDeInit(void)\n{\n    if (yaml_root != NULL) {\n        ConfNodeFree(yaml_root);\n        yaml_root = NULL;\n    }\n\n    fprintf(stdout, \"configuration module de-initialized\\n\");\n}\n\n\n\/**\n * \u6253\u5370 key \u7684\u540d\u79f0\n *\/\nstatic char *ConfPrintNameArray(char **name_arr, int level)\n{\n    static char name&#91;128*128];\n    int i;\n\n    name&#91;0] = '\\0';\n    for (i = 0; i &lt;= level; i++) {\n        strlcat(name, name_arr&#91;i], sizeof(name));\n        if (i &lt; level)\n            strlcat(name, \".\", sizeof(name));\n    }\n\n    return name;\n}\n\n\/**\n * \u6253\u5370\u8282\u70b9\u4e0b\u5b50\u8282\u70b9\u7684\u6570\u636e\u5230\u6807\u51c6\u8f93\u51fa\n * \u6ce8\u610f\uff1a\u4e0d\u6253\u5370\u5f53\u524d\u8282\u70b9\n *\/\nvoid ConfNodeDump(const ConfNode *node, const char *prefix)\n{\n    ConfNode *child;\n\n    \/\/ \u9012\u5f52\u8c03\u7528\u4e0d\u91cd\u590d\u7533\u8bf7\u8fd9\u4e24\u4e2a\u53d8\u91cf\n    static char *name&#91;128]; \/\/ 128\u4e2a\u540d\u5b57\u7684\u6307\u9488\u6570\u7ec4\n    static int level = -1;  \/\/ \u5c42\u7ea7\uff0cyaml_root \u5c5e\u4e8e\u7b2c0\u5c42\n\n    level++;\n    \/\/ \u904d\u5386\u5b50\u8282\u70b9\n    TAILQ_FOREACH(child, &amp;node->head, next) {\n\n        \/\/ \u7533\u8bf7\u65b0\u7684name\u7a7a\u95f4\n        name&#91;level] = strdup(child->name);\n        if (unlikely(name&#91;level] == NULL)) {\n            continue;\n        }\n        if (prefix == NULL) {\n            printf(\"%s = %s\\n\", ConfPrintNameArray(name, level),\n                child->val);\n        }\n        else {\n            printf(\"%s.%s = %s\\n\", prefix,\n                ConfPrintNameArray(name, level), child->val);\n        }\n        ConfNodeDump(child, prefix);\n        free(name&#91;level]);\n    }\n    level--;\n}\n\n\/**\n * \u628a yaml_root \u6253\u5370\u5230\u6807\u51c6\u8f93\u51fa\n *\/\nvoid ConfDump(void)\n{\n    ConfNodeDump(yaml_root, NULL);\n}\n\n\/*\n * \u5224\u65ad\u7ed9\u5b9a\u7684\u8282\u70b9\u6709\u6ca1\u6709\u5b50\u8282\u70b9 \n * \u8fd4\u56de   \u5305\u542b\u8282\u70b9 \u8fd4\u56de true\n *       \u4e0d\u5305\u542b\u8282\u70b9  \u8fd4\u56de false\n *\/\nbool ConfNodeHasChildren(const ConfNode *node)\n{\n    if (TAILQ_EMPTY(&amp;node->head)) {\n        return false;\n    }\n    return true;\n}\n\n\/*\n * \u6839\u636e\u540d\u5b57 \u4ece \u5b50\u7ed3\u70b9\u4e2d \u6839\u636e\u540d\u5b57\u67e5\u627e\uff0c\u4e0d\u8fdb\u884c\u9012\u5f52\u67e5\u627e\n * \u6ca1\u627e\u5230\u8fd4\u56de NULL \n * \u627e\u5230\u8fd4\u56de ConfNode \u8282\u70b9\u5730\u5740\n * \u53ea\u5728\u5b50\u8282\u70b9\u67e5\u627e\n *\/\nConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name)\n{\n    ConfNode *child;\n\n    if (node == NULL || name == NULL) {\n        return NULL;\n    }\n\n    \/\/ \u904d\u5386\u5b50\u8282\u70b9\n    TAILQ_FOREACH(child, &amp;node->head, next) {\n        if (child->name != NULL &amp;&amp; strcmp(child->name, name) == 0)\n            return child;\n    }\n\n    return NULL;\n}\n\n\/**\n * \u4ece\u5b50\u8282\u70b9\u4e2d\uff0c\u6839\u636e\u540d\u5b57\u627e\u5230\u5bf9\u5e94\u7684\u503c\n * \u53ea\u5728\u5b50\u8282\u70b9\u67e5\u627e\n *\n * \u53c2\u6570\uff1a     node  \u7236\u8282\u70b9\n *           name  \u8282\u70b9\u540d\u5b57\uff0c\u7236\u8282\u70b9\u7684\u8def\u5f84\n *\n * \u8fd4\u56de\u503c\uff1a   \u627e\u5230\u8282\u70b9\uff0c\u5219\u8fd4\u56de\u503cval\u7684\u5730\u5740\n *           \u6ca1\u6709\u627e\u5230\u8282\u70b9\uff0c\u8fd4\u56de NULL \n *\/\nconst char *ConfNodeLookupChildValue(const ConfNode *node, const char *name)\n{\n    ConfNode *child;\n\n    child = ConfNodeLookupChild(node, name);\n    if (child != NULL)\n        return child->val;\n\n    return NULL;\n}\n\n\/**\n * \u5728\u6307\u5b9a\u7684\u8282\u70b9\u4e0b\uff0c\u67e5\u627e\u4e00\u4e2akey\u7684\u503c\n * \u53ea\u5728\u5b50\u8282\u70b9\u67e5\u627e\n *\n * \u8fd4\u56de\u503c     \u5339\u914d\u4e0a         \u8fd4\u56de\u5339\u914d\u7684 \u8282\u70b9\n *           \u6ca1\u5339\u914d\u4e0a       \u8fd4\u56deNULL\n *\/\nConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key,\n    const char *value)\n{\n    ConfNode *child;\n\n    TAILQ_FOREACH(child, &amp;base->head, next) {\n        if (!strncmp(child->val, key, strlen(child->val))) {\n            ConfNode *subchild;\n            TAILQ_FOREACH(subchild, &amp;child->head, next) {\n                if ((!strcmp(subchild->name, key)) &amp;&amp; (!strcmp(subchild->val, value))) {\n                    return child;\n                }\n            }\n        }\n    }\n\n    return NULL;\n}\n\n\/**\n * \u6d4b\u8bd5\u4e00\u4e2a\u914d\u7f6e\u8282\u70b9\u662f\u5426\u6709\u503c\n * \u53ea\u5728\u5b50\u8282\u70b9\u67e5\u627e\n *\n * \u8fd4\u56de\u503c            1 - \u6709\u8282\u70b9\uff0c\u4e5f\u6709\u503c\n *                  0 - \u6ca1\u627e\u5230\u8282\u70b9\u6216\u8005\u8282\u70b9\u6ca1\u503c\n *\/\nint ConfNodeChildValueIsTrue(const ConfNode *node, const char *key)\n{\n    const char *val;\n\n    val = ConfNodeLookupChildValue(node, key);\n\n    return val != NULL ? ConfValIsTrue(val) : 0;\n}\n\n\/**\n * \u52a0\u8f7d\u4e00\u4e2ainclude\u5f15\u5165\u7684yaml\u6587\u4ef6\n * \n *  \\retval str Pointer to the string path + sig_file\n *\/\nchar *ConfLoadCompleteIncludePath(const char *file)\n{\n    const char *defaultpath = NULL;\n    char *path = NULL;\n\n    \/\/ \u76f8\u5bf9\u8def\u5f84\u62fc\u5199\u8def\u5f84\n    if (PathIsRelative(file)) {\n        \/\/ \u83b7\u53d6 include-path \u914d\u7f6e\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\n        if (ConfGet(\"include-path\", &amp;defaultpath) == 1) {\n            fprintf(stdout, \"Default path: %s\\n\", defaultpath);\n            size_t path_len = sizeof(char) * (strlen(defaultpath) +\n                          strlen(file) + 2);\n            path = malloc(path_len);\n            if (unlikely(path == NULL))\n                return NULL;\n            strlcpy(path, defaultpath, path_len);\n            if (path&#91;strlen(path) - 1] != '\/')\n                strlcat(path, \"\/\", path_len);\n            strlcat(path, file, path_len);\n       } else {\n            path = strdup(file);\n            if (unlikely(path == NULL))\n                return NULL;\n        }\n    } else {\n        path = strdup(file);\n        if (unlikely(path == NULL))\n            return NULL;\n    }\n    return path;\n}\n\n\/**\n * \u6e05\u7a7a\u8282\u70b9 node \u91cc\u7684value\u503c\uff0c\n * \u5982\u679c node \u91cc\u7684\u5b50\u8282\u70b9\u662f\u53ef\u88ab\u8986\u76d6\u7684\uff0c\u5219\u4e00\u5e76\u5220\u9664\u3002\n * node \u8282\u70b9\u672c\u8eab\u5e76\u4e0d\u88ab\u5220\u9664\uff0cnode->name \u4fdd\u7559\uff0cnode->val \u88ab\u5220\u9664\n *\/\nvoid ConfNodePrune(ConfNode *node)\n{\n    ConfNode *item, *it;\n\n    for (item = TAILQ_FIRST(&amp;node->head); item != NULL; item = it) {    \/\/ \u904d\u5386\u6240\u6709\u5b50\u8282\u70b9\n        it = TAILQ_NEXT(item, next) ;\n        if (!item->final) {          \/\/ \u4e0d\u662f\u6700\u7ec8\u53c2\u6570\uff08\u53ef\u88ab\u8986\u76d6\uff09\n            ConfNodePrune(item) ;    \/\/ \u9012\u5f52\u5220\u9664\u5b50\u8282\u70b9\u4e0b\u7684\u6570\u636e\u548c\u81ea\u5df1\u672c\u8eab\n            if (TAILQ_EMPTY(&amp;item->head)) {              \/\/ \u5b50\u8282\u70b9\u4e3a\u7a7a\n                TAILQ_REMOVE(&amp;node->head, item, next) ;  \/\/ \u8282\u70b9\u4ece\u6570\u636e\u7ed3\u6784\u4e0a\u8131\u79bb\n                if (item->name != NULL)\n                    free(item->name) ;  \/\/ \u91ca\u653e name \n                if (item->val != NULL)\n                    free(item->val) ;   \/\/ \u91ca\u653e val\uff0c\u53ef\u80fd\u8c03\u7528\u4e0d\u5230\uff0cval \u5728 \u9012\u5f52\u8c03\u7528 ConfNodePrune\u662f\u91ca\u653e\u4e86\u3002\u4e14 val \u6307\u5411\u4e86 NULL\n                free(item);             \/\/ \u91ca\u653e\u8282\u70b9\n            }\n        }\n    }\n\n    \/\/ 1\u3001\u6ca1\u6709\u5b50\u8282\u70b9\u7684\u8282\u70b9\uff0cval\u5728\u6b64\u5904\u88ab\u5220\u9664\n    \/\/ 2\u3001\u9012\u5f52\u524d\u7684 node \u8282\u70b9\uff08\u9700\u8981\u88ab\u6e05\u7406\u7684\u8282\u70b9\uff09\uff0cval\u503c\u5728\u8fd9\u91cc\u6e05\u7406\n    \/\/ 3\u3001node->val = NULL \u4e3a\u4e86\u9632\u6b62\u91cd\u590d\u91ca\u653e val\n    if (node->val != NULL) {\n        free(node->val);\n        node->val = NULL;\n    }\n}\n\n\/**\n * \u5224\u65ad\u8282\u70b9\u662f\u4e0d\u662f\u5217\u8868\n *\n * \u8fd4\u56de\u503c     1 - \u662f\u5217\u8868\n *           0 - \u4e0d\u662f\u5217\u8868\n *\/\nint ConfNodeIsSequence(const ConfNode *node)\n{\n    return node->is_seq == 0 ? 0 : 1;\n}\n\n\/**\n * \u5224\u65ad\u8def\u5f84\u662f\u4e0d\u662f\u7edd\u5bf9\u8def\u5f84\n *\n *  \u8fd4\u56de\u503c    1 - \u662f\u7edd\u5bf9\u8def\u5f84\n *           0 - \u4e0d\u662f\u7edd\u5bf9\u8def\u5f84 --\u76f8\u5bf9\u8def\u5f84 \n *\/\nint PathIsAbsolute(const char *path)\n{\n    if (strlen(path) > 1 &amp;&amp; path&#91;0] == '\/') {\n        return 1;\n    }\n    return 0;\n}\n\n\/**\n *  \u5224\u65ad\u8def\u5f84\u662f\u4e0d\u662f\u76f8\u5bf9\u8def\u5f84\n *\n *  \u8fd4\u56de\u503c    1 - \u662f\u76f8\u5bf9\u8def\u5f84\n *           0 - \u4e0d\u662f\u76f8\u5bf9\u8def\u5f84 --\u7edd\u5bf9\u8def\u5f84\n *\/\nint PathIsRelative(const char *path)\n{\n    return PathIsAbsolute(path) ? 0 : 1;\n}\n\n\/**\n * \u5c1d\u8bd5\u627e\u5230 LIST \u7684\u6240\u6709\u6570\u636e\n *\n * \u8fd4\u56de\u503c    >=0 - \u627e\u5230\u7684\u6570\u91cf\n *          -1  - \u5931\u8d25\n *\/\nint ConfGetList(const char *name, const char *(**val)&#91;])\n{\n    int ret = -1 ;\n\n    \/\/ \u83b7\u53d6\u8282\u70b9\n    ConfNode * base = ConfGetNode(name) ;\n    if( base == NULL ) {\n        return -1 ;\n    } \n\n    char idx_str&#91;8] ;\n\n    \/\/ \u67e5\u770b\u6709\u591a\u5c11\u4e2a\u5b50\u8282\u70b9\n    int idx = 0 ;\n    snprintf(idx_str, sizeof(idx_str), \"%d\", idx) ;\n    while(ConfNodeLookupChild(base, idx_str)) {\n        idx++ ;\n        snprintf(idx_str, sizeof(idx_str), \"%d\", idx) ;\n    }\n    \n    const char *(*tmpval)&#91;] = calloc(1, sizeof(void *) * idx) ;\n    const char * vptr ;\n\n    \/\/ \u83b7\u53d6\u6bcf\u4e2a\u5b50\u8282\u70b9\u7684value\n    idx = 0 ;\n    snprintf(idx_str, sizeof(idx_str), \"%d\", idx) ;\n    while( ret = ConfGetChildValue( base, idx_str, &amp;vptr ) ) {\n        (*tmpval)&#91;idx] = vptr ;\n        idx++ ;\n        snprintf(idx_str, sizeof(idx_str), \"%d\", idx) ;\n    }\n    *val = tmpval ;\n    return idx ;    \n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u4ee3\u7801 conf-yaml.h<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ifndef __CONF_YAML_H__\n#define __CONF_YAML_H__\n\n#include &lt;inttypes.h&gt;\n#include &lt;stdbool.h&gt;\n\n#include \"queue.h\"\n\n\/**\n * yaml\u914d\u7f6e\u6587\u4ef6\u89e3\u6790\u7ed3\u6784\n *\/\ntypedef struct ConfNode_ {\n    char *name; \/\/ \u6307\u9488\uff0c\u8d4b\u503c\u9700\u8981\u7533\u8bf7\u7a7a\u95f4\n    char *val;  \/\/ \u8d4b\u503c\u9700\u8981\u7533\u8bf7\u7a7a\u95f4\n\n    int is_seq;   \/\/ \u6807\u8bb0\u6b64\u8282\u70b9\u662f\u5217\u8868\u7684\u4e00\u4e2a\u8282\u70b9\n\n    int final;    \/\/ \u6700\u7ec8\u6807\u8bb0\uff0c\u8bbe\u7f6e\u4e3a final \u4e4b\u540e\uff0c\u503c\u4e0d\u80fd\u88ab\u8986\u76d6\n\n    struct ConfNode_ *parent;         \/\/ \u7236\u8282\u70b9\n    TAILQ_HEAD(, ConfNode_) head;     \/\/ \u5b69\u5b50\u8282\u70b9\u4eec\n    TAILQ_ENTRY(ConfNode_) next;      \/\/ \u5144\u5f1f\u8282\u70b9\u4eec\n} ConfNode;\n\n\n\/**\n * \u9ed8\u8ba4\u65e5\u5fd7\u5730\u5740\n *\/\n#define DEFAULT_LOG_DIR \"\/var\/log\/yaml.log\"\n#define DEFAULT_DATA_DIR DATA_DIR\n\n#define unlikely(expr) __builtin_expect(!!(expr), 0)\n\nvoid ConfInit(void);\nvoid ConfDeInit(void);\nConfNode *ConfGetRootNode(void);\nint ConfGet(const char *name, const char **vptr);\nint ConfGetInt(const char *name, intmax_t *val);\nint ConfGetBool(const char *name, int *val);\nint ConfGetDouble(const char *name, double *val);\nint ConfGetFloat(const char *name, float *val);\nint ConfSet(const char *name, const char *val);\nint ConfSetFromString(const char *input, int final);\nint ConfSetFinal(const char *name, const char *val);\nvoid ConfDump(void);\nvoid ConfNodeDump(const ConfNode *node, const char *prefix);\nConfNode *ConfNodeNew(void);\nvoid ConfNodeFree(ConfNode *);\nConfNode *ConfGetNode(const char *key);\nvoid ConfCreateContextBackup(void);\nvoid ConfRestoreContextBackup(void);\nConfNode *ConfNodeLookupChild(const ConfNode *node, const char *key);\nconst char *ConfNodeLookupChildValue(const ConfNode *node, const char *key);\nvoid ConfNodeRemove(ConfNode *);\nvoid ConfRegisterTests(void);\nint ConfNodeChildValueIsTrue(const ConfNode *node, const char *key);\nint ConfValIsTrue(const char *val);\nint ConfValIsFalse(const char *val);\nvoid ConfNodePrune(ConfNode *node);\nint ConfRemove(const char *name);\nbool ConfNodeHasChildren(const ConfNode *node);\n\nConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name);\nConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value);\nint ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr);\nint ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val);\nint ConfGetChildValueBool(const ConfNode *base, const char *name, int *val);\nint ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr);\nint ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val);\nint ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val);\nchar *ConfLoadCompleteIncludePath(const char *);\nint ConfNodeIsSequence(const ConfNode *node);\nConfNode *ConfSetIfaceNode(const char *ifaces_node_name, const char *iface);\nint ConfSetRootAndDefaultNodes(\n        const char *ifaces_node_name, const char *iface, ConfNode **if_root, ConfNode **if_default);\nConfNode *ConfNodeGetNodeOrCreate(ConfNode *parent, const char *name, int final);\n\nint PathIsAbsolute(const char *path) ;\nint PathIsRelative(const char *path) ;\nint ConfGetList(const char *name, const char *(**val)&#91;]) ;\n\n#endif \/* !__CONF_YAML_H__ *\/\n<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u4ee3\u7801 queue.h<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ifndef YAML_QUEUE_H\n#define YAML_QUEUE_H\n\nif defined(HAVE_SYS_QUEUE_H) &amp;&amp; !defined(__clang_analyzer__)\n#include &lt;sys\/queue.h&gt;\n#endif\n\n#if defined(__clang_analyzer__)\n#define _Q_ASSERT(a) assert((a))\n#else\n#define _Q_ASSERT(a)\n#endif\n\n\/* The BSDs have removed CIRCLEQ but it still exists in Linux.\n *\n * This implementation from OpenBSD sys\/queue.h v1.40 as it still has\n * CIRCLEQ and includes the safe variations.\n * - _Q_INVALIDATE for some extra debugging has been removed as its\n *   not available on the Linux version of CIRCLEQ.\n *\/\n\n#ifndef CIRCLEQ_HEAD\n\n\/*\n * Circular queue definitions.\n *\/\n#define CIRCLEQ_HEAD(name, type)                    \\\nstruct name {                                \\\n    struct type *cqh_first;        \/* first element *\/        \\\n    struct type *cqh_last;        \/* last element *\/        \\\n}\n\n#define CIRCLEQ_HEAD_INITIALIZER(head)                    \\\n    { CIRCLEQ_END(&amp;head), CIRCLEQ_END(&amp;head) }\n\n#define CIRCLEQ_ENTRY(type)                        \\\nstruct {                                \\\n    struct type *cqe_next;        \/* next element *\/        \\\n    struct type *cqe_prev;        \/* previous element *\/        \\\n}\n\n\/*\n * Circular queue access methods\n *\/\n#define    CIRCLEQ_FIRST(head)        ((head)-&gt;cqh_first)\n#define    CIRCLEQ_LAST(head)        ((head)-&gt;cqh_last)\n#define    CIRCLEQ_NEXT(elm, field)    ((elm)-&gt;field.cqe_next)\n#define    CIRCLEQ_PREV(elm, field)    ((elm)-&gt;field.cqe_prev)\n#define    CIRCLEQ_EMPTY(head)                        \\\n    (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))\n\n#define CIRCLEQ_FOREACH(var, head, field)                \\\n    for((var) = CIRCLEQ_FIRST(head);                \\\n        (var) != CIRCLEQ_END(head);                    \\\n        (var) = CIRCLEQ_NEXT(var, field))\n\n#define    CIRCLEQ_FOREACH_SAFE(var, head, field, tvar)            \\\n    for ((var) = CIRCLEQ_FIRST(head);                \\\n        (var) != CIRCLEQ_END(head) &amp;&amp;                \\\n        ((tvar) = CIRCLEQ_NEXT(var, field), 1);            \\\n        (var) = (tvar))\n\n#define CIRCLEQ_FOREACH_REVERSE(var, head, field)            \\\n    for((var) = CIRCLEQ_LAST(head);                    \\\n        (var) != CIRCLEQ_END(head);                    \\\n        (var) = CIRCLEQ_PREV(var, field))\n\n#define    CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)    \\\n    for ((var) = CIRCLEQ_LAST(head, headname);            \\\n        (var) != CIRCLEQ_END(head) &amp;&amp;                 \\\n        ((tvar) = CIRCLEQ_PREV(var, headname, field), 1);        \\\n        (var) = (tvar))\n\n\/*\n * Circular queue functions.\n *\/\n#define    CIRCLEQ_INIT(head) do {                        \\\n    (head)-&gt;cqh_first = CIRCLEQ_END(head);                \\\n    (head)-&gt;cqh_last = CIRCLEQ_END(head);                \\\n} while (0)\n\n#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {        \\\n    (elm)-&gt;field.cqe_next = (listelm)-&gt;field.cqe_next;        \\\n    (elm)-&gt;field.cqe_prev = (listelm);                \\\n    if ((listelm)-&gt;field.cqe_next == CIRCLEQ_END(head))        \\\n        (head)-&gt;cqh_last = (elm);                \\\n    else                                \\\n        (listelm)-&gt;field.cqe_next-&gt;field.cqe_prev = (elm);    \\\n    (listelm)-&gt;field.cqe_next = (elm);                \\\n} while (0)\n\n#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {        \\\n    (elm)-&gt;field.cqe_next = (listelm);                \\\n    (elm)-&gt;field.cqe_prev = (listelm)-&gt;field.cqe_prev;        \\\n    if ((listelm)-&gt;field.cqe_prev == CIRCLEQ_END(head))        \\\n        (head)-&gt;cqh_first = (elm);                \\\n    else                                \\\n        (listelm)-&gt;field.cqe_prev-&gt;field.cqe_next = (elm);    \\\n    (listelm)-&gt;field.cqe_prev = (elm);                \\\n} while (0)\n\n#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {            \\\n    (elm)-&gt;field.cqe_next = (head)-&gt;cqh_first;            \\\n    (elm)-&gt;field.cqe_prev = CIRCLEQ_END(head);            \\\n    if ((head)-&gt;cqh_last == CIRCLEQ_END(head))            \\\n        (head)-&gt;cqh_last = (elm);                \\\n    else                                \\\n        (head)-&gt;cqh_first-&gt;field.cqe_prev = (elm);        \\\n    (head)-&gt;cqh_first = (elm);                    \\\n} while (0)\n\n#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {            \\\n    (elm)-&gt;field.cqe_next = CIRCLEQ_END(head);            \\\n    (elm)-&gt;field.cqe_prev = (head)-&gt;cqh_last;            \\\n    if ((head)-&gt;cqh_first == CIRCLEQ_END(head))            \\\n        (head)-&gt;cqh_first = (elm);                \\\n    else                                \\\n        (head)-&gt;cqh_last-&gt;field.cqe_next = (elm);        \\\n    (head)-&gt;cqh_last = (elm);                    \\\n} while (0)\n\n#define    CIRCLEQ_REMOVE(head, elm, field) do {                \\\n    if ((elm)-&gt;field.cqe_next == CIRCLEQ_END(head))            \\\n        (head)-&gt;cqh_last = (elm)-&gt;field.cqe_prev;        \\\n    else                                \\\n        (elm)-&gt;field.cqe_next-&gt;field.cqe_prev =            \\\n            (elm)-&gt;field.cqe_prev;                \\\n    if ((elm)-&gt;field.cqe_prev == CIRCLEQ_END(head))            \\\n        (head)-&gt;cqh_first = (elm)-&gt;field.cqe_next;        \\\n    else                                \\\n        (elm)-&gt;field.cqe_prev-&gt;field.cqe_next =            \\\n            (elm)-&gt;field.cqe_next;                \\\n} while (0)\n\n#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {            \\\n    if (((elm2)-&gt;field.cqe_next = (elm)-&gt;field.cqe_next) ==        \\\n        CIRCLEQ_END(head))                        \\\n        (head)-&gt;cqh_last = (elm2);                \\\n    else                                \\\n        (elm2)-&gt;field.cqe_next-&gt;field.cqe_prev = (elm2);    \\\n    if (((elm2)-&gt;field.cqe_prev = (elm)-&gt;field.cqe_prev) ==        \\\n        CIRCLEQ_END(head))                        \\\n        (head)-&gt;cqh_first = (elm2);                \\\n    else                                \\\n        (elm2)-&gt;field.cqe_prev-&gt;field.cqe_next = (elm2);    \\\n} while (0)\n\n#endif \/* !CIRCLEQ_HEAD *\/\n\n\/* Required by local implementation as well as _SAFE variations. *\/\n#ifndef CIRCLEQ_END\n#define CIRCLEQ_END(head)       ((void *)(head))\n#endif \/* !CIRCLEQ_END *\/\n\n#ifndef CIRCLEQ_FOREACH_SAFE\n#define    CIRCLEQ_FOREACH_SAFE(var, head, field, tvar)            \\\n    for ((var) = CIRCLEQ_FIRST(head);                \\\n        (var) != CIRCLEQ_END(head) &amp;&amp;                \\\n        ((tvar) = CIRCLEQ_NEXT(var, field), 1);            \\\n        (var) = (tvar))\n\n#define    CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)    \\\n    for ((var) = CIRCLEQ_LAST(head, headname);            \\\n        (var) != CIRCLEQ_END(head) &amp;&amp;                 \\\n        ((tvar) = CIRCLEQ_PREV(var, headname, field), 1);        \\\n        (var) = (tvar))\n#endif \/* !CIRCLEQ_FOREACH_SAFE *\/\n\n\/*\n * Complete TAILQ implementation as sys\/queue.h is not available on Windows\n * and used by Suricata.\n *\n * This implementation copied from FreeBSD sys\/queue.h with the addition\n * of our _Q_ASSERT macros to satisfy scan-build.\n *\/\n#ifndef TAILQ_HEAD\n\n\/*\n * Tail queue declarations.\n *\/\n#define    TAILQ_HEAD(name, type)                        \\\nstruct name {                                \\\n    struct type *tqh_first;    \/* first element *\/            \\\n    struct type **tqh_last;    \/* addr of last next element *\/        \\\n}\n\n#define    TAILQ_HEAD_INITIALIZER(head)                    \\\n    { NULL, &amp;(head).tqh_first }\n\n#define    TAILQ_ENTRY(type)                        \\\nstruct {                                \\\n    struct type *tqe_next;    \/* next element *\/            \\\n    struct type **tqe_prev;    \/* address of previous next element *\/    \\\n}\n\n\/*\n * Tail queue functions.\n *\/\n#define    TAILQ_EMPTY(head)    ((head)-&gt;tqh_first == NULL)\n\n#define    TAILQ_FIRST(head)    ((head)-&gt;tqh_first)\n\n#define    TAILQ_FOREACH(var, head, field)                    \\\n    for ((var) = TAILQ_FIRST((head));                \\\n        (var);                            \\\n        (var) = TAILQ_NEXT((var), field))\n\n#define    TAILQ_FOREACH_REVERSE(var, head, headname, field)        \\\n    for ((var) = TAILQ_LAST((head), headname);            \\\n        (var);                            \\\n        (var) = TAILQ_PREV((var), headname, field))\n\n#define    TAILQ_INIT(head) do {                        \\\n    TAILQ_FIRST((head)) = NULL;                    \\\n    (head)-&gt;tqh_last = &amp;TAILQ_FIRST((head));            \\\n} while (0)\n\n#define    TAILQ_INSERT_AFTER(head, listelm, elm, field) do {        \\\n    if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\\\n        TAILQ_NEXT((elm), field)-&gt;field.tqe_prev =         \\\n            &amp;TAILQ_NEXT((elm), field);                \\\n    else                                \\\n        (head)-&gt;tqh_last = &amp;TAILQ_NEXT((elm), field);        \\\n    TAILQ_NEXT((listelm), field) = (elm);                \\\n    (elm)-&gt;field.tqe_prev = &amp;TAILQ_NEXT((listelm), field);        \\\n} while (0)\n\n#define    TAILQ_INSERT_BEFORE(listelm, elm, field) do {            \\\n    (elm)-&gt;field.tqe_prev = (listelm)-&gt;field.tqe_prev;        \\\n    TAILQ_NEXT((elm), field) = (listelm);                \\\n    *(listelm)-&gt;field.tqe_prev = (elm);                \\\n    (listelm)-&gt;field.tqe_prev = &amp;TAILQ_NEXT((elm), field);        \\\n} while (0)\n\n#define    TAILQ_INSERT_HEAD(head, elm, field) do {            \\\n    if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)    \\\n        TAILQ_FIRST((head))-&gt;field.tqe_prev =            \\\n            &amp;TAILQ_NEXT((elm), field);                \\\n    else                                \\\n        (head)-&gt;tqh_last = &amp;TAILQ_NEXT((elm), field);        \\\n    TAILQ_FIRST((head)) = (elm);                    \\\n    (elm)-&gt;field.tqe_prev = &amp;TAILQ_FIRST((head));            \\\n} while (0)\n\n#define    TAILQ_INSERT_TAIL(head, elm, field) do {            \\\n    _Q_ASSERT((elm));                        \\\n    _Q_ASSERT((head));                        \\\n    TAILQ_NEXT((elm), field) = NULL;                \\\n    (elm)-&gt;field.tqe_prev = (head)-&gt;tqh_last;            \\\n    *(head)-&gt;tqh_last = (elm);                    \\\n    _Q_ASSERT(*(head)-&gt;tqh_last);                    \\\n    (head)-&gt;tqh_last = &amp;TAILQ_NEXT((elm), field);            \\\n} while (0)\n\n#define    TAILQ_LAST(head, headname)                    \\\n    (*(((struct headname *)((head)-&gt;tqh_last))-&gt;tqh_last))\n\n#define    TAILQ_NEXT(elm, field) ((elm)-&gt;field.tqe_next)\n\n#define    TAILQ_PREV(elm, headname, field)                \\\n    (*(((struct headname *)((elm)-&gt;field.tqe_prev))-&gt;tqh_last))\n\n#define    TAILQ_REMOVE(head, elm, field) do {                \\\n    if ((TAILQ_NEXT((elm), field)) != NULL)                \\\n        TAILQ_NEXT((elm), field)-&gt;field.tqe_prev =         \\\n            (elm)-&gt;field.tqe_prev;                \\\n    else                                \\\n        (head)-&gt;tqh_last = (elm)-&gt;field.tqe_prev;        \\\n    _Q_ASSERT((head)-&gt;tqh_first != (elm));                \\\n    *(elm)-&gt;field.tqe_prev = TAILQ_NEXT((elm), field);        \\\n} while (0)\n\n#endif \/* !TAILQ_HEAD *\/\n\n\/* Not included in Linux, but are in FreeBSD and friends.\n *\n * This implementation from FreeBSD's sys\/queue.h.\n *\/\n#ifndef TAILQ_FOREACH_SAFE\n#define    TAILQ_FOREACH_SAFE(var, head, field, tvar)            \\\n    for ((var) = TAILQ_FIRST((head));                \\\n        (var) &amp;&amp; ((tvar) = TAILQ_NEXT((var), field), 1);        \\\n        (var) = (tvar))\n#endif\n\n#endif    \/* !YAML_QUEUE_H *\/<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u6d4b\u8bd5\u4ee3\u7801 test.c<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n\n#include \"conf-yaml.h\"\n#include \"conf-yaml-loader.h\"\n\n\nconst char * yaml_path = \".\/tt.yaml\" ;\n\n\nint main(int argc, int argv) {\n\n    ConfInit() ;\n    ConfYamlLoadFile(yaml_path) ;\n\n    ConfNode *yaml_root = ConfGetRootNode() ;\n\n    printf(\"\\n\\n\\n\\n==============  result ===============\\n\\n\") ;\n    ConfDump() ;\n\n    const char * vptr ;\n\n    char * tnm = \"score.0.name\" ;\n    ConfGet(tnm, &amp;vptr) ;\n    printf(\"\\n\\n---------%s: %s\\n\", tnm, vptr) ;\n\n    tnm = \"aa\" ;\n    ConfGet(tnm, &amp;vptr) ;\n    printf(\"---------%s: %s\\n\", tnm, vptr) ;\n\n    tnm = \"t-inc.cc\" ;\n    ConfGet(tnm, &amp;vptr) ;\n    printf(\"---------%s: %s\\n\", tnm, vptr) ;\n    \n    const char *(*val)&#91;] ;\n    int ret = ConfGetList(\"score.1.fruit\", &amp;val) ;\n    printf(\"ret &#91;%d] \\n\", ret) ;\n    for(int i = 0  ; i &lt; ret ; ++i ) {\n        printf(\"idx &#91;%d] &#91;%s]\\n\", i, (*val)&#91;i]) ;\n    }\n    free(val) ;\n    return 0 ;\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u6d4b\u8bd5\u6570\u636e tt.yaml<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>%YAML 1.1\n---\n\n# --- \u4ee3\u8868\u6587\u6863\u7684\u5f00\u59cb\nscore:\n  # - \u4ee3\u8868\u8fd9\u4e9b\u662f\u6570\u7ec4\n  - name: Hanmeimei    # #\u53f7\u5f80\u540e\u5168\u662f\u6ce8\u91ca\n    age: 11\n    sessions:\n     chineses: 100\n     math: 100\n     english: 100\n     science: 100\n  - name: Lilei\n    age: 12\n\n    # \u4e2d\u62ec\u53f7\u4ee3\u8868\u662f\u4e00\u4e2a\u5217\u8868\n    # \u5217\u8868\u4e2d\u7684\u6570\u636e\u5b57\u6bb5\u53ef\u4ee5\u4e0d\u4e00\u81f4\n    fruit: &#91;apple, pear, banana, peach, orange]\n\n    # \u53ea\u8981\u4e0b\u4e00\u7ea7\u7684\u6570\u636e\u7f29\u8fdb\u957f\u5ea6\u76f8\u540c\uff0c\u4e14\u6bd4\u672c\u7ea7\u957f\u5c31\u53ef\u4ee5\n    sessions:\n           chineses: 95\n           math: 95\n           english: 95\n           science: 95\n...\n# ... \u4ee3\u8868\u6587\u6863\u7684\u7ed3\u675f\n\n%YAML 1.1\n---\nteachers:\n    &amp;anchorrrr\n  - name: Qiaofeng\n    age: 32\n    sex: 1\n    address: &gt;\n        CN\n        Shandong\n        Qingdao\n  - name: Wangyuyan\n    age: 19\n    sex: 2\n    # !!\u8868\u793a\u7528\u5b57\u7b26\u4e32\u89e3\u91ca\u4e0b\u8fb9\u7684\u6570\u636e\n    banner: !!str\n        Hello,       \n        my name is Wangyuyan.\n        I am your english teacher.\n    address: |\n      CN\n      Shandong\n      Jinan\n...\n\n%YAML 1.1\n---\nroot:\n   pppp:\n       name: Murongfu\n       age: 28\nanchor_t:\n   kongfu: Douzhuanxingyi\n\ninclude: t1.yaml\nt_inc:\n    include: t1.yaml\n\n...\n\n<\/code><\/pre>\n<\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"has-large-font-size\"><strong>\u6d4b\u8bd5\u6570\u636e t1.yaml<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>%YAML 1.1\n---\n\naa: aaaaaaaaaa\nbb: bbbbbbbbbbbbbb\ncc: ccccccccccccccc<\/code><\/pre>\n<\/div>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-large-font-size\"><strong>\u7f16\u8bd1\u6d4b\u8bd5<\/strong><\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u9700\u8981\u5148\u5b89\u88c5\u4e24\u4e2a\u4f9d\u8d56\u5e93\uff1a<\/p>\n\n\n\n<p>apt install libyaml-dev<\/p>\n\n\n\n<p>apt install libbsd-dev<\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"713\" height=\"342\" src=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-23.png\" alt=\"\" class=\"wp-image-1618\" srcset=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-23.png 713w, https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-23-300x144.png 300w\" sizes=\"auto, (max-width: 713px) 100vw, 713px\" \/><\/figure>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>\u6700\u540e\u6253\u5370\u7ed3\u679c\uff1a<\/p>\n\n\n\n<div style=\"margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);height:0px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"652\" height=\"687\" src=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-24.png\" alt=\"\" class=\"wp-image-1619\" srcset=\"https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-24.png 652w, https:\/\/www.madbull.site\/wp-content\/uploads\/2024\/10\/\u56fe\u7247-24-285x300.png 285w\" sizes=\"auto, (max-width: 652px) 100vw, 652px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>yaml\u5b98\u65b9\u63d0\u4f9b\u4e86\u4e00\u5957\u6587\u4ef6\u89e3\u6790\u7684\u65b9\u6cd5\uff0c\u52a8\u6001\u5e93\u662flibyaml.so\u3002\u5b98\u65b9\u5730\u5740\uff1ahttps:\/\/yaml.org\/spec\/1.1\/<\/p>\n<p>\u4f46\u662f\u8fd9\u4e2a\u5e93\u7684\u89e3\u6790\u65b9\u5f0f\u8fd8\u662f\u592a\u539f\u59cb\uff0c\u4e0d\u597d\u7528\u3002\u6211\u4eec\u60f3\u4e00\u4e2a\u6bd4\u8f83\u597d\u7528\u7684\u65b9\u5f0f\u83b7\u53d6\u6570\u636e\u3002\u60f3\u5230suricata\uff08\u5e93\u5728github\u4e0a\uff0c\u5730\u5740\uff1a\uff09\u6709\u4e00\u5957yaml\u7684\u89e3\u6790\u65b9\u6cd5\u3002\u4e8e\u662f\u628asuricata\u7684\u4ee3\u7801\u62ff\u8fc7\u6765\uff0c\u5c01\u88c5\u4e00\u4e0b\uff0c\u6539\u6210\u4e86lib\u5e93\uff0c\u65b9\u4fbf\u4ee5\u540e\u4f7f\u7528\u3002<br \/>\n\u4e0d\u8fc7suricata\u7684\u89e3\u6790\u65b9\u6cd5\u4e0d\u652f\u6301 \u951a\u70b9 \u548c \u5f15\u7528\uff0c\u4f7f\u7528\u65f6\u8981\u6ce8\u610f\u914d\u7f6e\u6587\u4ef6\u7684\u7f16\u5199\u3002<\/p>\n","protected":false},"author":1,"featured_media":559,"comment_status":"open","ping_status":"open","sticky":false,"template":"single-with-sidebar","format":"standard","meta":{"footnotes":""},"categories":[156,154],"tags":[378,175,518,288,471],"class_list":{"0":"post-1596","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-c-c","8":"category-154","9":"tag-c","11":"tag-libyaml","12":"tag-yaml","13":"tag-471"},"_links":{"self":[{"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/posts\/1596","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.madbull.site\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1596"}],"version-history":[{"count":15,"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/posts\/1596\/revisions"}],"predecessor-version":[{"id":2198,"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/posts\/1596\/revisions\/2198"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.madbull.site\/index.php?rest_route=\/wp\/v2\/media\/559"}],"wp:attachment":[{"href":"https:\/\/www.madbull.site\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1596"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.madbull.site\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1596"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.madbull.site\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1596"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}