blob: e8b033364097b7eec734358ee18a16f880bbac59 [file] [log] [blame]
David Sedlákf824ad52018-10-14 23:58:15 +02001/**
2 * @file parser_yin.c
3 * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
David Sedlák3b4db242018-10-19 16:11:01 +02004 * @brief YIN parser.
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
David Sedlákf824ad52018-10-14 23:58:15 +020013 */
David Sedlák3b4db242018-10-19 16:11:01 +020014#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
David Sedlák872c7b42018-10-26 13:15:20 +020017#include <string.h>
David Sedlákf824ad52018-10-14 23:58:15 +020018
19#include "common.h"
20#include "context.h"
21#include "libyang.h"
David Sedlák3b4db242018-10-19 16:11:01 +020022#include "xml.h"
23#include "tree_schema_internal.h"
David Sedlákf824ad52018-10-14 23:58:15 +020024
David Sedlák872c7b42018-10-26 13:15:20 +020025enum YIN_ARGUMENT {
26 YIN_ARG_NONE = 0,
27 YIN_ARG_NAME,
28 YIN_ARG_TARGET_NODE,
29 YIN_ARG_MODULE,
30 YIN_ARG_VALUE,
31 YIN_ARG_TEXT,
32 YIN_ARG_CONDITION,
33 YIN_ARG_URI,
34 YIN_ARG_DATE,
35 YIN_ARG_TAG,
36};
David Sedlákf824ad52018-10-14 23:58:15 +020037
David Sedlák872c7b42018-10-26 13:15:20 +020038enum YIN_ARGUMENT
David Sedláke4889912018-11-02 09:52:40 +010039match_argument_name(const char *name, size_t len)
David Sedlák3b4db242018-10-19 16:11:01 +020040{
David Sedlák872c7b42018-10-26 13:15:20 +020041 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
42 size_t already_read = 0;
David Sedlák3b4db242018-10-19 16:11:01 +020043
David Sedlákc10e7902018-12-17 02:17:59 +010044#define MOVE_DATA(DATA, COUNT) already_read+=COUNT;
45#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {MOVE_DATA(name, LEN);arg=STMT;}
46#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {MOVE_DATA(name, LEN);
47#define IF_ARG_PREFIX_END }
48
David Sedlák872c7b42018-10-26 13:15:20 +020049 switch(*name) {
50 case 'c':
David Sedlákc10e7902018-12-17 02:17:59 +010051 MOVE_DATA(name, 1);
52 IF_ARG("ondition", 8, YIN_ARG_CONDITION);
David Sedlák3b4db242018-10-19 16:11:01 +020053 break;
David Sedlák872c7b42018-10-26 13:15:20 +020054
55 case 'd':
David Sedlákc10e7902018-12-17 02:17:59 +010056 MOVE_DATA(name, 1);
57 IF_ARG("ate", 3, YIN_ARG_DATE);
David Sedlák3b4db242018-10-19 16:11:01 +020058 break;
David Sedlák872c7b42018-10-26 13:15:20 +020059
60 case 'm':
David Sedlákc10e7902018-12-17 02:17:59 +010061 MOVE_DATA(name, 1);
62 IF_ARG("odule", 5, YIN_ARG_MODULE);
David Sedlák872c7b42018-10-26 13:15:20 +020063 break;
64
65 case 'n':
David Sedlákc10e7902018-12-17 02:17:59 +010066 MOVE_DATA(name, 1);
67 IF_ARG("ame", 3, YIN_ARG_NAME);
David Sedlák872c7b42018-10-26 13:15:20 +020068 break;
69
70 case 't':
David Sedlákc10e7902018-12-17 02:17:59 +010071 MOVE_DATA(name, 1);
72 IF_ARG_PREFIX("a", 1)
73 IF_ARG("g", 1, YIN_ARG_TAG)
74 else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
75 IF_ARG_PREFIX_END
76 else IF_ARG("ext", 3, YIN_ARG_TEXT)
David Sedlák3b4db242018-10-19 16:11:01 +020077 break;
David Sedlák872c7b42018-10-26 13:15:20 +020078
79 case 'u':
David Sedlákc10e7902018-12-17 02:17:59 +010080 MOVE_DATA(name, 1);
81 IF_ARG("ri", 2, YIN_ARG_URI)
David Sedlák3b4db242018-10-19 16:11:01 +020082 break;
David Sedlák872c7b42018-10-26 13:15:20 +020083
84 case 'v':
David Sedlákc10e7902018-12-17 02:17:59 +010085 MOVE_DATA(name, 1);
86 IF_ARG("alue", 4, YIN_ARG_VALUE);
David Sedlák3b4db242018-10-19 16:11:01 +020087 break;
88 }
89
David Sedlákc10e7902018-12-17 02:17:59 +010090 /* whole argument must be matched */
David Sedlák872c7b42018-10-26 13:15:20 +020091 if (already_read != len) {
92 arg = YIN_ARG_NONE;
93 }
94
95 return arg;
David Sedlák3b4db242018-10-19 16:11:01 +020096}
97
98LY_ERR
David Sedláka5004e62018-12-16 23:54:47 +010099parser_belongs_to(struct lyxml_context *xml_ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext **extensions)
100{
101 enum yang_keyword kw = YANG_NONE;
102 LY_ERR ret = LY_SUCCESS;
103 const char *prefix_out, *name;
104 size_t prefix_len, name_len;
105
106 char *buf = NULL, *out = NULL;
107 size_t buf_len = 0, out_len = 0;
108 int dynamic;
109
110 /* check if belongs-to has argument module */
111 ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100112 LY_CHECK_RET1(ret);
David Sedláka5004e62018-12-16 23:54:47 +0100113 if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
114 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
David Sedlákc10e7902018-12-17 02:17:59 +0100115 return LY_EINVAL;
David Sedláka5004e62018-12-16 23:54:47 +0100116 }
117
David Sedlákc10e7902018-12-17 02:17:59 +0100118 /* read content of argument */
David Sedláka5004e62018-12-16 23:54:47 +0100119 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlákc10e7902018-12-17 02:17:59 +0100120 LY_CHECK_RET1(ret);
David Sedláka5004e62018-12-16 23:54:47 +0100121 *belongsto = lydict_insert(xml_ctx->ctx, out, out_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100122 LY_CHECK_ERR_RET(!belongsto, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedláka5004e62018-12-16 23:54:47 +0100123
124 /* read substatements */
125 while (xml_ctx->status == LYXML_ATTRIBUTE) {
126 ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
127 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), ret);
128 kw = match_keyword(name);
129
130 switch (kw) {
131 case YANG_PREFIX:
132 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
133 *prefix = lydict_insert(xml_ctx->ctx, out, out_len);
134 break;
135 case YANG_CUSTOM:
136 /* TODO parse extension */
137 break;
138 default:
David Sedlákc10e7902018-12-17 02:17:59 +0100139 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected attribute");
David Sedláka5004e62018-12-16 23:54:47 +0100140 return LY_EVALID;
141 }
142 }
143
144 if (!prefix) {
145 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing prefix");
David Sedlákc10e7902018-12-17 02:17:59 +0100146 return LY_EVALID;
David Sedláka5004e62018-12-16 23:54:47 +0100147 }
David Sedlákc10e7902018-12-17 02:17:59 +0100148
149 return LY_SUCCESS;
David Sedláka5004e62018-12-16 23:54:47 +0100150}
151
152LY_ERR
David Sedlák4a4c0722018-11-26 17:03:10 +0100153parse_namespace(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
154{
155 LY_ERR ret = LY_SUCCESS;
156 const char *prefix, *name;
157 size_t prefix_len, name_len;
158
159 char *buf = NULL, *out = NULL;
160 size_t buf_len = 0, out_len = 0;
161 int dynamic;
162
David Sedlák4a4c0722018-11-26 17:03:10 +0100163 /* check if namespace has argument uri */
164 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100165 LY_CHECK_RET1(ret);
David Sedlák4a4c0722018-11-26 17:03:10 +0100166 if (match_argument_name(name, name_len) != YIN_ARG_URI) {
David Sedlákc10e7902018-12-17 02:17:59 +0100167 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"uri\".", name);
168 return LY_EVALID;
David Sedlák4a4c0722018-11-26 17:03:10 +0100169 }
170
David Sedlákc10e7902018-12-17 02:17:59 +0100171 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
172 LY_CHECK_RET1(ret);
173 (*mod_p)->ns = lydict_insert(xml_ctx->ctx, out, out_len);
174 LY_CHECK_ERR_RET(!(*mod_p)->ns, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100175
David Sedlákc10e7902018-12-17 02:17:59 +0100176 /* namespace can only have one argument */
David Sedlák4a4c0722018-11-26 17:03:10 +0100177 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100178 LY_CHECK_RET1(ret);
179 if (name) {
180 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
181 return LY_EVALID;
182 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100183
184 return LY_SUCCESS;
185}
186
187LY_ERR
188parse_prefix(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
189{
190 LY_ERR ret = LY_SUCCESS;
191 const char *prefix, *name;
192 size_t prefix_len, name_len;
193
194 char *buf = NULL, *out = NULL;
195 size_t buf_len = 0, out_len = 0;
196 int dynamic;
197
David Sedlákc10e7902018-12-17 02:17:59 +0100198 /* check if prefix has argument value */
David Sedlák4a4c0722018-11-26 17:03:10 +0100199 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100200 LY_CHECK_RET1(ret);
David Sedlák4a4c0722018-11-26 17:03:10 +0100201 if (match_argument_name(name, name_len) != YIN_ARG_VALUE) {
David Sedlákc10e7902018-12-17 02:17:59 +0100202 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"value\".", name);
203 return LY_EVALID;
David Sedlák4a4c0722018-11-26 17:03:10 +0100204 }
205
David Sedlákc10e7902018-12-17 02:17:59 +0100206 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
207 LY_CHECK_RET1(ret);
208 (*mod_p)->prefix = lydict_insert(xml_ctx->ctx, out, out_len);
209 LY_CHECK_ERR_RET(!(*mod_p)->prefix, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100210
David Sedlákc10e7902018-12-17 02:17:59 +0100211 /* prefix element can only have one argument */
David Sedlák4a4c0722018-11-26 17:03:10 +0100212 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100213 LY_CHECK_RET1(ret);
214 if (name) {
215 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
216 return LY_EVALID;
217 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100218 return LY_SUCCESS;
219}
220
221LY_ERR
David Sedlák3b4db242018-10-19 16:11:01 +0200222parse_submodule(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
223{
David Sedlákf3b24f62018-11-02 10:40:47 +0100224 LY_ERR ret = LY_SUCCESS;
David Sedlák4a4c0722018-11-26 17:03:10 +0100225 enum yang_keyword kw = YANG_NONE;
David Sedláke4889912018-11-02 09:52:40 +0100226 const char *prefix, *name;
David Sedlák3b4db242018-10-19 16:11:01 +0200227 size_t prefix_len, name_len;
228
David Sedlákf3b24f62018-11-02 10:40:47 +0100229 char *buf = NULL, *out = NULL;
230 size_t buf_len = 0, out_len = 0;
231 int dynamic;
232
David Sedlák872c7b42018-10-26 13:15:20 +0200233 /* check if module/submodule has argument "name" */
David Sedlák3b4db242018-10-19 16:11:01 +0200234 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
235 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlák872c7b42018-10-26 13:15:20 +0200236 if (match_argument_name(name, name_len) != YIN_ARG_NAME) {
David Sedlákc10e7902018-12-17 02:17:59 +0100237 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"name\".", name);
David Sedlák3b4db242018-10-19 16:11:01 +0200238 }
239
David Sedlákf3b24f62018-11-02 10:40:47 +0100240 /* read module name */
David Sedlák4a4c0722018-11-26 17:03:10 +0100241 if (xml_ctx->status != LYXML_ATTR_CONTENT) {
David Sedlákc10e7902018-12-17 02:17:59 +0100242 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing value of argument \"name\"");
David Sedlák4a4c0722018-11-26 17:03:10 +0100243 }
David Sedlák3b4db242018-10-19 16:11:01 +0200244 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
245 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlák3b4db242018-10-19 16:11:01 +0200246 (*mod_p)->name = lydict_insert(xml_ctx->ctx, out, out_len);
David Sedláke4889912018-11-02 09:52:40 +0100247 LY_CHECK_ERR_RET(!(*mod_p)->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlákf3b24f62018-11-02 10:40:47 +0100248
David Sedlákc10e7902018-12-17 02:17:59 +0100249 /* read all attributes and their content only for testing */
David Sedlák4a4c0722018-11-26 17:03:10 +0100250 while (xml_ctx->status == LYXML_ATTRIBUTE) {
251 lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc10e7902018-12-17 02:17:59 +0100252 while (xml_ctx->status == LYXML_ATTR_CONTENT) {
253 lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlák4a4c0722018-11-26 17:03:10 +0100254 }
255 }
256
David Sedlákc10e7902018-12-17 02:17:59 +0100257
David Sedlák4a4c0722018-11-26 17:03:10 +0100258 while (xml_ctx->status == LYXML_ELEMENT || xml_ctx->status == LYXML_ELEM_CONTENT) {
259 ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlák4a4c0722018-11-26 17:03:10 +0100260 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
261 kw = match_keyword(name);
262
263 switch (kw) {
David Sedlák4a4c0722018-11-26 17:03:10 +0100264 case YANG_NAMESPACE:
265 ret = parse_namespace(xml_ctx, data, mod_p);
266 break;
David Sedláka5004e62018-12-16 23:54:47 +0100267 case YANG_PREFIX:
268 ret = parse_prefix(xml_ctx, data, mod_p);
David Sedlákc10e7902018-12-17 02:17:59 +0100269 /* TODO change lysp_check_prefix function to work with ctx and not parser_ctx */
270 //LY_CHECK_RET(lysp_check_prefix(&xml_ctx->ctx, *mod_p, &((*mod_p)->prefix)), LY_EVALID);
David Sedláka5004e62018-12-16 23:54:47 +0100271 break;
272 case YANG_BELONGS_TO:
273 ret = parser_belongs_to(xml_ctx, data, &(*mod_p)->belongsto, &(*mod_p)->prefix, &(*mod_p)->extensions);
274 break;
David Sedlák4a4c0722018-11-26 17:03:10 +0100275
276 default:
David Sedláka5004e62018-12-16 23:54:47 +0100277 /* error */
David Sedlák4a4c0722018-11-26 17:03:10 +0100278 break;
279 }
280 }
281
David Sedlákf3b24f62018-11-02 10:40:47 +0100282 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200283}
284
285LY_ERR
286yin_parse(struct ly_ctx *ctx, const char *data, struct lysp_module **mod_p)
287{
David Sedláke4889912018-11-02 09:52:40 +0100288 LY_ERR ret = LY_SUCCESS;
289 enum yang_keyword kw = YANG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200290 struct lyxml_context xml_ctx;
David Sedlák3b4db242018-10-19 16:11:01 +0200291
David Sedláke4889912018-11-02 09:52:40 +0100292 memset(&xml_ctx, 0, sizeof xml_ctx);
293 xml_ctx.ctx = ctx;
294 xml_ctx.line = 1;
295
296 const char *prefix, *name;
David Sedlák3b4db242018-10-19 16:11:01 +0200297 size_t prefix_len, name_len;
298
David Sedlákf3b24f62018-11-02 10:40:47 +0100299 /* check if root element is module or submodule */
David Sedláke4889912018-11-02 09:52:40 +0100300 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
David Sedlák2e411422018-12-17 02:35:39 +0100301 LY_CHECK_GOTO(ret != LY_SUCCESS, error);
David Sedláke4889912018-11-02 09:52:40 +0100302 kw = match_keyword(name);
303 if (kw != YANG_MODULE && kw != YANG_SUBMODULE) {
David Sedlákc10e7902018-12-17 02:17:59 +0100304 LOGVAL(xml_ctx.ctx, LY_VLOG_LINE, &xml_ctx.line, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".", name);
David Sedláke4889912018-11-02 09:52:40 +0100305 }
David Sedlák3b4db242018-10-19 16:11:01 +0200306
David Sedláke4889912018-11-02 09:52:40 +0100307 if (kw == YANG_SUBMODULE) {
308 (*mod_p)->submodule = 1;
309 }
310
311 ret = parse_submodule(&xml_ctx, &data, mod_p);
312
David Sedlákf3b24f62018-11-02 10:40:47 +0100313 lyxml_context_clear(&xml_ctx);
David Sedláke4889912018-11-02 09:52:40 +0100314 return ret;
David Sedlák2e411422018-12-17 02:35:39 +0100315
316error:
317 lyxml_context_clear(&xml_ctx);
318 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200319}