blob: b375c71279341f2c7b76ca561284aa01ba53025a [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 {
David Sedlák18730132019-03-15 15:51:34 +010026 YIN_ARG_NONE = 0, /**< unrecognized argument */
27 YIN_ARG_NAME, /**< argument name */
28 YIN_ARG_TARGET_NODE, /**<argument target-node */
29 YIN_ARG_MODULE, /**< argument module */
30 YIN_ARG_VALUE, /**< argument value */
31 YIN_ARG_TEXT, /**< argument text */
32 YIN_ARG_CONDITION, /**< argument condition */
33 YIN_ARG_URI, /**< argument uri */
34 YIN_ARG_DATE, /**< argument data */
35 YIN_ARG_TAG, /**< argument tag */
36 YIN_ARG_XMLNS, /**< argument xmlns */
David Sedlák872c7b42018-10-26 13:15:20 +020037};
David Sedlákf824ad52018-10-14 23:58:15 +020038
David Sedlákc136b972019-03-08 13:39:06 +010039/**
David Sedlákd5318ee2019-02-15 10:14:50 +010040 * @brief Match argument name.
41 *
42 * @param[in] name String representing name.
43 * @param[in] len Lenght of the name.
44 *
45 * @reurn YIN_ARGUMENT value.
46 */
David Sedlák872c7b42018-10-26 13:15:20 +020047enum YIN_ARGUMENT
David Sedláke4889912018-11-02 09:52:40 +010048match_argument_name(const char *name, size_t len)
David Sedlák3b4db242018-10-19 16:11:01 +020049{
David Sedlák872c7b42018-10-26 13:15:20 +020050 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
51 size_t already_read = 0;
David Sedlák24d90b92019-03-29 10:00:35 +010052 LY_CHECK_RET(len == 0, YIN_ARG_NONE);
David Sedlák3b4db242018-10-19 16:11:01 +020053
David Sedlák94de2aa2019-02-15 12:42:11 +010054#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;arg=STMT;}
55#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;
David Sedlákc10e7902018-12-17 02:17:59 +010056#define IF_ARG_PREFIX_END }
57
David Sedlák1c8b2702019-02-22 11:03:02 +010058 switch (*name) {
David Sedlák18730132019-03-15 15:51:34 +010059 case 'x':
60 already_read += 1;
61 IF_ARG("mlns", 4, YIN_ARG_XMLNS);
62 break;
David Sedlák94de2aa2019-02-15 12:42:11 +010063 case 'c':
64 already_read += 1;
65 IF_ARG("ondition", 8, YIN_ARG_CONDITION);
David Sedlák3b4db242018-10-19 16:11:01 +020066 break;
David Sedlák872c7b42018-10-26 13:15:20 +020067
David Sedlák94de2aa2019-02-15 12:42:11 +010068 case 'd':
69 already_read += 1;
70 IF_ARG("ate", 3, YIN_ARG_DATE);
David Sedlák3b4db242018-10-19 16:11:01 +020071 break;
David Sedlák872c7b42018-10-26 13:15:20 +020072
David Sedlák94de2aa2019-02-15 12:42:11 +010073 case 'm':
74 already_read += 1;
75 IF_ARG("odule", 5, YIN_ARG_MODULE);
David Sedlák872c7b42018-10-26 13:15:20 +020076 break;
77
David Sedlák94de2aa2019-02-15 12:42:11 +010078 case 'n':
79 already_read += 1;
80 IF_ARG("ame", 3, YIN_ARG_NAME);
David Sedlák872c7b42018-10-26 13:15:20 +020081 break;
82
David Sedlák94de2aa2019-02-15 12:42:11 +010083 case 't':
84 already_read += 1;
85 IF_ARG_PREFIX("a", 1)
86 IF_ARG("g", 1, YIN_ARG_TAG)
87 else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
88 IF_ARG_PREFIX_END
89 else IF_ARG("ext", 3, YIN_ARG_TEXT)
David Sedlák3b4db242018-10-19 16:11:01 +020090 break;
David Sedlák872c7b42018-10-26 13:15:20 +020091
David Sedlák94de2aa2019-02-15 12:42:11 +010092 case 'u':
93 already_read += 1;
94 IF_ARG("ri", 2, YIN_ARG_URI)
David Sedlák3b4db242018-10-19 16:11:01 +020095 break;
David Sedlák872c7b42018-10-26 13:15:20 +020096
David Sedlák94de2aa2019-02-15 12:42:11 +010097 case 'v':
98 already_read += 1;
99 IF_ARG("alue", 4, YIN_ARG_VALUE);
David Sedlák3b4db242018-10-19 16:11:01 +0200100 break;
101 }
102
David Sedlákc10e7902018-12-17 02:17:59 +0100103 /* whole argument must be matched */
David Sedlák872c7b42018-10-26 13:15:20 +0200104 if (already_read != len) {
105 arg = YIN_ARG_NONE;
106 }
107
David Sedlák18730132019-03-15 15:51:34 +0100108#undef IF_ARG
109#undef IF_ARG_PREFIX
110#undef IF_ARG_PREFIX_END
111
David Sedlák872c7b42018-10-26 13:15:20 +0200112 return arg;
David Sedlák3b4db242018-10-19 16:11:01 +0200113}
114
David Sedlák18730132019-03-15 15:51:34 +0100115/**
116 * @brief parse xmlns statement
117 *
118 * @param[in] xml_ctx XML parser context.
119 * @param[in, out] data Data to reda from.
120 * @param[in] prefix
121 */
122LY_ERR
123parse_xmlns(struct lyxml_context *xml_ctx, const char **data, const char *prefix, size_t prefix_len, char *element)
124{
125 char *buf = NULL, *out = NULL;
126 size_t buf_len = 0, out_len = 0;
127 int dynamic = 0;
128 LY_ERR ret = LY_SUCCESS;
129
130 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
131 LY_CHECK_RET(ret != LY_SUCCESS, ret);
132 LY_CHECK_ERR_RET(out_len == 0, LOGVAL_YANG(xml_ctx, LYVE_SYNTAX_YIN, "Missing value of xmlns attribute"), LY_EEXIST);
133 lyxml_ns_add(xml_ctx, element, prefix, prefix_len, out, out_len);
134
135 return LY_SUCCESS;
136}
137
David Sedlák0daba9a2019-03-22 14:07:49 +0100138/**
139 * @brief Parse content of whole element as text.
140 *
141 * @param[in] xml_ctx Xml context.
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100142 * @param[in] element_name Name of element, name is necesary to remove xmlns definitions at the end of element
David Sedlák0daba9a2019-03-22 14:07:49 +0100143 * @param[in] data Data to read from.
144 * @param[out] value Where content of element should be stored.
145 */
146LY_ERR
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100147parse_text_element(struct lyxml_context *xml_ctx, char *element_name, const char **data, const char **value)
David Sedlák0daba9a2019-03-22 14:07:49 +0100148{
149 LY_ERR ret = LY_SUCCESS;
150 char *buf = NULL, *out = NULL;
151 size_t buf_len = 0, out_len = 0;
152 int dynamic;
153 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
154
155 const char *prefix, *name;
156 size_t prefix_len, name_len;
157
158 /* parse module attributes */
159 while (xml_ctx->status == LYXML_ATTRIBUTE) {
160 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
161 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
162
163 arg = match_argument_name(name, name_len);
164 if (arg) {
165 parse_xmlns(xml_ctx, data, prefix, prefix_len, "module");
166 } else {
167 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
168 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
169 /* in this case prefix of namespace is actually name of attribute */
170 parse_xmlns(xml_ctx, data, name, name_len, "module");
171 } else {
172 /* unrecognized or unexpected attribute */
173 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in module element");
174 return LY_EVALID;
175 }
176 break;
177 }
178 }
179
David Sedlák0daba9a2019-03-22 14:07:49 +0100180 LY_CHECK_RET(xml_ctx->status != LYXML_ELEM_CONTENT, LY_EVALID);
181
182 if (xml_ctx->status == LYXML_ELEM_CONTENT) {
183 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
184 LY_CHECK_RET(ret);
185 *value = lydict_insert(xml_ctx->ctx, out, out_len);
186 LY_CHECK_ERR_RET(!(*value), LOGMEM(xml_ctx->ctx), LY_EMEM);
187 }
188
189 lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100190 lyxml_ns_rm(xml_ctx, element_name);
191 return LY_SUCCESS;
David Sedlák0daba9a2019-03-22 14:07:49 +0100192}
193
David Sedlák3017da42019-02-15 09:48:04 +0100194// LY_ERR
195// parser_belongs_to(struct lyxml_context *xml_ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext **extensions)
196// {
197// enum yang_keyword kw = YANG_NONE;
198// LY_ERR ret = LY_SUCCESS;
199// const char *prefix_out, *name;
200// size_t prefix_len, name_len;
David Sedláka5004e62018-12-16 23:54:47 +0100201
David Sedlák3017da42019-02-15 09:48:04 +0100202// char *buf = NULL, *out = NULL;
203// size_t buf_len = 0, out_len = 0;
204// int dynamic;
David Sedláka5004e62018-12-16 23:54:47 +0100205
David Sedlák3017da42019-02-15 09:48:04 +0100206// /* check if belongs-to has argument module */
207// ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
208// LY_CHECK_RET1(ret);
209// if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
210// LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
211// return LY_EINVAL;
212// }
David Sedláka5004e62018-12-16 23:54:47 +0100213
David Sedlák3017da42019-02-15 09:48:04 +0100214// /* read content of argument */
215// ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
216// LY_CHECK_RET1(ret);
217// *belongsto = lydict_insert(xml_ctx->ctx, out, out_len);
218// LY_CHECK_ERR_RET(!belongsto, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedláka5004e62018-12-16 23:54:47 +0100219
David Sedlák3017da42019-02-15 09:48:04 +0100220// /* read substatements */
221// while (xml_ctx->status == LYXML_ATTRIBUTE) {
222// ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
223// LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), ret);
224// kw = match_keyword(name);
David Sedláka5004e62018-12-16 23:54:47 +0100225
David Sedlák3017da42019-02-15 09:48:04 +0100226// switch (kw) {
227// case YANG_PREFIX:
228// ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
229// *prefix = lydict_insert(xml_ctx->ctx, out, out_len);
230// break;
231// case YANG_CUSTOM:
232// /* TODO parse extension */
233// break;
234// default:
235// LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected attribute");
236// return LY_EVALID;
237// }
238// }
David Sedláka5004e62018-12-16 23:54:47 +0100239
David Sedlák3017da42019-02-15 09:48:04 +0100240// if (!prefix) {
241// LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing prefix");
242// return LY_EVALID;
243// }
David Sedlákc10e7902018-12-17 02:17:59 +0100244
David Sedlák3017da42019-02-15 09:48:04 +0100245// return LY_SUCCESS;
246// }
David Sedláka5004e62018-12-16 23:54:47 +0100247
David Sedlákd5318ee2019-02-15 10:14:50 +0100248/**
249 * @brief Parse namespace statement.
250 *
251 * @param[in] xml_ctx xml context.
252 * @param[in, out] data Data to read from.
253 * @param[in, out] mod_p Module to write to.
254 *
255 * @return LY_ERR values.
256 */
David Sedláka5004e62018-12-16 23:54:47 +0100257LY_ERR
David Sedlák0daba9a2019-03-22 14:07:49 +0100258parse_namespace(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák4a4c0722018-11-26 17:03:10 +0100259{
260 LY_ERR ret = LY_SUCCESS;
261 const char *prefix, *name;
262 size_t prefix_len, name_len;
263
264 char *buf = NULL, *out = NULL;
265 size_t buf_len = 0, out_len = 0;
266 int dynamic;
David Sedlák0daba9a2019-03-22 14:07:49 +0100267 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
David Sedlák4a4c0722018-11-26 17:03:10 +0100268
David Sedlák0daba9a2019-03-22 14:07:49 +0100269 /* parse namespace attributes */
270 while (xml_ctx->status == LYXML_ATTRIBUTE) {
271 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
272 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
273
274 arg = match_argument_name(name, name_len);
275
276 switch (arg) {
277 case YIN_ARG_XMLNS:
David Sedlák24d90b92019-03-29 10:00:35 +0100278 parse_xmlns(xml_ctx, data, prefix, prefix_len, "namespace");
David Sedlák0daba9a2019-03-22 14:07:49 +0100279 break;
280 case YIN_ARG_URI:
281 LY_CHECK_RET(ret);
282 if (match_argument_name(name, name_len) != YIN_ARG_URI) {
283 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"uri\".", name);
284 return LY_EVALID;
285 }
286 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
287 LY_CHECK_RET(ret);
288 (*mod)->mod->ns = lydict_insert(xml_ctx->ctx, out, out_len);
289 LY_CHECK_ERR_RET(!(*mod)->mod->ns, LOGMEM(xml_ctx->ctx), LY_EMEM);
290 break;
291 default:
292 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
293 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
294 /* in this case prefix of namespace is actually name of attribute */
David Sedlák24d90b92019-03-29 10:00:35 +0100295 parse_xmlns(xml_ctx, data, name, name_len, "namespace");
David Sedlák0daba9a2019-03-22 14:07:49 +0100296 } else {
297 /* unrecognized or unexpected attribute */
David Sedlák720f8852019-03-29 09:04:04 +0100298 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in namespace element");
David Sedlák0daba9a2019-03-22 14:07:49 +0100299 return LY_EVALID;
300 }
301 break;
302 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100303 }
304
David Sedlák24d90b92019-03-29 10:00:35 +0100305 /* remove local xmlns definitions */
306 lyxml_ns_rm(xml_ctx, "namespace");
David Sedlák4a4c0722018-11-26 17:03:10 +0100307 return LY_SUCCESS;
308}
309
David Sedlákcd0c9512019-03-29 13:23:06 +0100310static LY_ERR
311yin_parse_arguments(struct lyxml_context *xml_ctx, const char **data, enum YIN_ARGUMENT arg_type, const char **arg_val, char *elem_name)
312{
313 LY_ERR ret = LY_SUCCESS;
314 const char *prefix, *name;
315 size_t prefix_len, name_len;
316
317 char *buf = NULL, *out = NULL;
318 size_t buf_len = 0, out_len = 0;
319 int dynamic;
320 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
321
322 while (xml_ctx->status == LYXML_ATTRIBUTE) {
323 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
324 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
325
326 arg = match_argument_name(name, name_len);
327
328 if (arg == YIN_ARG_XMLNS) {
329 parse_xmlns(xml_ctx, data, prefix, prefix_len, elem_name);
330 break;
331 } else if (arg == arg_type) {
332 LY_CHECK_RET(ret);
333 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
334 LY_CHECK_RET(ret);
335 *arg_val = lydict_insert(xml_ctx->ctx, out, out_len);
336 LY_CHECK_ERR_RET(!(*arg_val), LOGMEM(xml_ctx->ctx), LY_EMEM);
337 break;
338 } else {
339 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
340 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
341 /* in this case prefix of namespace is actually name of attribute */
342 parse_xmlns(xml_ctx, data, name, name_len, elem_name);
343 } else {
344 /* unrecognized or unexpected attribute */
345 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in namespace element");
346 return LY_EVALID;
347 }
348 }
349 }
350
351 return LY_SUCCESS;
352}
353
David Sedlákd5318ee2019-02-15 10:14:50 +0100354/**
355 * @brief Parse prefix statement.
356 *
357 * @param[in] xml_ctx Xml context.
358 * @param[in, out] data Data to reda from.
David Sedlák24d90b92019-03-29 10:00:35 +0100359 * @param[out] mod Module to write to.
David Sedlákd5318ee2019-02-15 10:14:50 +0100360 *
361 * @return LY_ERR values.
362 */
David Sedlák4a4c0722018-11-26 17:03:10 +0100363LY_ERR
David Sedlák24d90b92019-03-29 10:00:35 +0100364parse_prefix(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák4a4c0722018-11-26 17:03:10 +0100365{
366 LY_ERR ret = LY_SUCCESS;
David Sedlák4a4c0722018-11-26 17:03:10 +0100367
David Sedlákcd0c9512019-03-29 13:23:06 +0100368 /* parse attributes */
369 ret = yin_parse_arguments(xml_ctx, data, YIN_ARG_VALUE, &(*mod)->mod->prefix, "prefix");
370 LY_CHECK_RET(ret != LY_SUCCESS, ret);
371 /* remove local xmlns definitions */
372 ret = lyxml_ns_rm(xml_ctx, "prefix");
373 return ret;
David Sedlák4a4c0722018-11-26 17:03:10 +0100374}
375
David Sedlákcd0c9512019-03-29 13:23:06 +0100376// static LY_ERR
377// yin_parse_revision_date(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
378// {
379
380// return LY_SUCCESS;
381// }
382
David Sedlák736fd0d2019-02-15 16:06:31 +0100383static LY_ERR
David Sedlákcd0c9512019-03-29 13:23:06 +0100384yin_parse_import(struct lyxml_context *xml_ctx, const char *module_prefix, const char **data, struct lysp_module **mod)
David Sedlák736fd0d2019-02-15 16:06:31 +0100385{
386 LY_ERR ret = LY_SUCCESS;
387 enum yang_keyword kw;
388 struct lysp_import *imp;
389 const char *prefix, *name;
390 size_t prefix_len, name_len;
391
392 char *buf = NULL, *out = NULL;
393 size_t buf_len = 0, out_len = 0;
394 int dynamic;
David Sedlákcd0c9512019-03-29 13:23:06 +0100395 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
David Sedlák736fd0d2019-02-15 16:06:31 +0100396
David Sedlákcd0c9512019-03-29 13:23:06 +0100397 /* TODO fix attribute parsing and yin_parse_revision_date function */
398 /* valid attributes module, xmlns */
399 /* parse import attributes */
400 while (xml_ctx->status == LYXML_ATTRIBUTE) {
401 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
402 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
403
404 arg = match_argument_name(name, name_len);
405
406 switch (arg) {
407 case YIN_ARG_XMLNS:
408 parse_xmlns(xml_ctx, data, prefix, prefix_len, "prefix");
409 break;
410 case YIN_ARG_MODULE:
411 LY_CHECK_RET(ret);
412 if (match_argument_name(name, name_len) != YIN_ARG_VALUE) {
413 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"value\".", name);
414 return LY_EVALID;
415 }
416 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
417 LY_CHECK_RET(ret);
418 (*mod)->mod->prefix = lydict_insert(xml_ctx->ctx, out, out_len);
419 LY_CHECK_ERR_RET(!(*mod)->mod->ns, LOGMEM(xml_ctx->ctx), LY_EMEM);
420 break;
421 default:
422 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
423 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
424 /* in this case prefix of namespace is actually name of attribute */
425 parse_xmlns(xml_ctx, data, name, name_len, "prefix");
426 } else {
427 /* unrecognized or unexpected attribute */
428 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in prefix element");
429 return LY_EVALID;
430 }
431 break;
432 }
433 }
434
435
436
437 /* valid subelements description, prefix, reference, revision-data */
David Sedlák736fd0d2019-02-15 16:06:31 +0100438 /* allocate sized array for imports */
David Sedlákcd0c9512019-03-29 13:23:06 +0100439 LY_ARRAY_NEW_RET(xml_ctx->ctx, (*mod)->imports, imp, LY_EVALID);
David Sedlák736fd0d2019-02-15 16:06:31 +0100440
441 /* get value */
442 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
443 LY_CHECK_RET(ret);
444 if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
David Sedlák1c8b2702019-02-22 11:03:02 +0100445 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
David Sedlák736fd0d2019-02-15 16:06:31 +0100446 return LY_EVALID;
447 }
448 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
449 LY_CHECK_RET(ret);
450 imp->name = lydict_insert(xml_ctx->ctx, out, out_len);
451 LY_CHECK_ERR_RET(!imp->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
452
David Sedlák736fd0d2019-02-15 16:06:31 +0100453 while ((ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS && name != NULL)) {
David Sedlák18730132019-03-15 15:51:34 +0100454 kw = match_keyword(name, name_len, prefix_len);
David Sedlák736fd0d2019-02-15 16:06:31 +0100455 switch (kw) {
456 case YANG_PREFIX:
David Sedlákcd0c9512019-03-29 13:23:06 +0100457 parse_prefix(xml_ctx, data, mod);
458 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100459 case YANG_DESCRIPTION:
David Sedlákcd0c9512019-03-29 13:23:06 +0100460 parse_text_element(xml_ctx, "description", data, &((*mod)->mod->dsc));
461 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100462 case YANG_REFERENCE:
David Sedlákcd0c9512019-03-29 13:23:06 +0100463 parse_text_element(xml_ctx, "reference", data, &((*mod)->imports->ref));
464 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100465 case YANG_REVISION_DATE:
David Sedlákcd0c9512019-03-29 13:23:06 +0100466 /* this is attribute of import element */
David Sedlák736fd0d2019-02-15 16:06:31 +0100467 case YANG_CUSTOM:
468 /* TODO parse extension */
469 default:
470 /* TODO log error */
471 return LY_EVALID;
472 }
473 }
474
475 /* TODO add log macro and log error */
476 LY_CHECK_RET(!imp->prefix);
477 return ret;
478}
479
David Sedlákd5318ee2019-02-15 10:14:50 +0100480/**
481 * @brief Parse module substatements.
482 *
483 * @param[in] xml_ctx xml context.
484 * @param[in, out] data Data to read from.
485 * @param[out] mod Parsed module structure
486 *
487 * @return LY_ERR values.
488 */
David Sedlák4a4c0722018-11-26 17:03:10 +0100489LY_ERR
David Sedlák3017da42019-02-15 09:48:04 +0100490parse_mod(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák3b4db242018-10-19 16:11:01 +0200491{
David Sedlákf3b24f62018-11-02 10:40:47 +0100492 LY_ERR ret = LY_SUCCESS;
David Sedlák4a4c0722018-11-26 17:03:10 +0100493 enum yang_keyword kw = YANG_NONE;
David Sedláke4889912018-11-02 09:52:40 +0100494 const char *prefix, *name;
David Sedlák3b4db242018-10-19 16:11:01 +0200495 size_t prefix_len, name_len;
David Sedlák4b4713f2019-02-15 13:47:45 +0100496 enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
David Sedlák18730132019-03-15 15:51:34 +0100497 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200498
David Sedlákf3b24f62018-11-02 10:40:47 +0100499 char *buf = NULL, *out = NULL;
500 size_t buf_len = 0, out_len = 0;
501 int dynamic;
502
David Sedlák18730132019-03-15 15:51:34 +0100503 /* parse module attributes */
504 while (xml_ctx->status == LYXML_ATTRIBUTE) {
505 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
506 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
507
508 arg = match_argument_name(name, name_len);
509
510 switch (arg) {
511 case YIN_ARG_XMLNS:
512 parse_xmlns(xml_ctx, data, prefix, prefix_len, "module");
513 break;
514 case YIN_ARG_NAME:
515 /* check for multiple definitions of name */
516 LY_CHECK_ERR_RET((*mod)->mod->name, LOGVAL_YANG(xml_ctx, LYVE_SYNTAX_YIN, "Duplicit definition of module name \"%s\"", (*mod)->mod->name), LY_EEXIST);
517
518 /* read module name */
519 if (xml_ctx->status != LYXML_ATTR_CONTENT) {
520 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing value of argument \"name\".");
521 }
522 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
523 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
524 (*mod)->mod->name = lydict_insert(xml_ctx->ctx, out, out_len);
525 LY_CHECK_ERR_RET(!(*mod)->mod->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
526 break;
527 default:
528 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
529 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
530 /* in this case prefix of namespace is actually name of attribute */
531 parse_xmlns(xml_ctx, data, name, name_len, "module");
532 } else {
533 /* unrecognized or unexpected attribute */
534 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in module element");
535 return LY_EVALID;
536 }
537 break;
538 }
David Sedlák3b4db242018-10-19 16:11:01 +0200539 }
540
David Sedlák18730132019-03-15 15:51:34 +0100541 LY_CHECK_ERR_RET(!(*mod)->mod->name, LOGVAL_YANG(xml_ctx, LYVE_SYNTAX_YIN, "Missing argument name of a module", (*mod)->mod->name), LY_ENOTFOUND);
David Sedlákf3b24f62018-11-02 10:40:47 +0100542
David Sedlákc136b972019-03-08 13:39:06 +0100543 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlák18730132019-03-15 15:51:34 +0100544 LY_CHECK_ERR_RET(ret != LY_EINVAL, LOGVAL_YANG(xml_ctx, LYVE_SYNTAX_YIN, "Expected new xml element after module element."), LY_EINVAL);
David Sedlák4a4c0722018-11-26 17:03:10 +0100545
David Sedlák736fd0d2019-02-15 16:06:31 +0100546 /* loop over all elements and parse them */
David Sedlákc136b972019-03-08 13:39:06 +0100547 while (xml_ctx->status != LYXML_END) {
David Sedlák4b4713f2019-02-15 13:47:45 +0100548/* TODO ADD error log to macro */
549#define CHECK_ORDER(SECTION) \
550 if (mod_stmt > SECTION) {return LY_EVALID;}mod_stmt = SECTION
551
552 switch (kw) {
553 /* module header */
554 case YANG_NAMESPACE:
555 case YANG_PREFIX:
556 CHECK_ORDER(Y_MOD_MODULE_HEADER);
557 break;
558 case YANG_YANG_VERSION:
559 CHECK_ORDER(Y_MOD_MODULE_HEADER);
560 break;
561 /* linkage */
562 case YANG_INCLUDE:
563 case YANG_IMPORT:
564 CHECK_ORDER(Y_MOD_LINKAGE);
565 break;
566 /* meta */
567 case YANG_ORGANIZATION:
568 case YANG_CONTACT:
569 case YANG_DESCRIPTION:
570 case YANG_REFERENCE:
571 CHECK_ORDER(Y_MOD_META);
572 break;
573
574 /* revision */
575 case YANG_REVISION:
576 CHECK_ORDER(Y_MOD_REVISION);
577 break;
578 /* body */
579 case YANG_ANYDATA:
580 case YANG_ANYXML:
581 case YANG_AUGMENT:
582 case YANG_CHOICE:
583 case YANG_CONTAINER:
584 case YANG_DEVIATION:
585 case YANG_EXTENSION:
586 case YANG_FEATURE:
587 case YANG_GROUPING:
588 case YANG_IDENTITY:
589 case YANG_LEAF:
590 case YANG_LEAF_LIST:
591 case YANG_LIST:
592 case YANG_NOTIFICATION:
593 case YANG_RPC:
594 case YANG_TYPEDEF:
595 case YANG_USES:
596 case YANG_CUSTOM:
597 mod_stmt = Y_MOD_BODY;
598 break;
599 default:
600 /* error will be handled in the next switch */
601 break;
602 }
603#undef CHECK_ORDER
604
David Sedlák4a4c0722018-11-26 17:03:10 +0100605 ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc136b972019-03-08 13:39:06 +0100606 LY_CHECK_RET(ret != LY_SUCCESS, LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100607
David Sedlákc136b972019-03-08 13:39:06 +0100608 if (name) {
David Sedlák18730132019-03-15 15:51:34 +0100609 kw = match_keyword(name, name_len, prefix_len);
David Sedlákc136b972019-03-08 13:39:06 +0100610 switch (kw) {
David Sedlák736fd0d2019-02-15 16:06:31 +0100611
David Sedlákc136b972019-03-08 13:39:06 +0100612 /* module header */
613 case YANG_NAMESPACE:
614 LY_CHECK_RET(parse_namespace(xml_ctx, data, mod));
615 break;
616 case YANG_PREFIX:
617 LY_CHECK_RET(parse_prefix(xml_ctx, data, mod));
David Sedlákc136b972019-03-08 13:39:06 +0100618 break;
David Sedlák4a4c0722018-11-26 17:03:10 +0100619
David Sedlákc136b972019-03-08 13:39:06 +0100620 /* linkage */
621 case YANG_IMPORT:
David Sedlákcd0c9512019-03-29 13:23:06 +0100622 yin_parse_import(xml_ctx, (*mod)->mod->prefix, data, mod);
David Sedlákc136b972019-03-08 13:39:06 +0100623 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100624
David Sedlákc136b972019-03-08 13:39:06 +0100625 /* meta */
626 case YANG_ORGANIZATION:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100627 LY_CHECK_RET(parse_text_element(xml_ctx, "organization", data, &(*mod)->mod->org));
David Sedlákc136b972019-03-08 13:39:06 +0100628 break;
629 case YANG_CONTACT:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100630 LY_CHECK_RET(parse_text_element(xml_ctx, "contact", data, &(*mod)->mod->contact));
David Sedlákc136b972019-03-08 13:39:06 +0100631 break;
632 case YANG_DESCRIPTION:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100633 LY_CHECK_RET(parse_text_element(xml_ctx, "description", data, &(*mod)->mod->dsc));
David Sedlákc136b972019-03-08 13:39:06 +0100634 break;
635 case YANG_REFERENCE:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100636 LY_CHECK_RET(parse_text_element(xml_ctx, "reference", data, &(*mod)->mod->ref));
David Sedlákc136b972019-03-08 13:39:06 +0100637 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100638
David Sedlákc136b972019-03-08 13:39:06 +0100639 default:
David Sedlák18730132019-03-15 15:51:34 +0100640 return LY_EVALID;
David Sedlákc136b972019-03-08 13:39:06 +0100641 break;
642 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100643 }
644 }
645
David Sedlák18730132019-03-15 15:51:34 +0100646 lyxml_ns_rm(xml_ctx, "module");
David Sedlákf3b24f62018-11-02 10:40:47 +0100647 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200648}
649
David Sedlákd5318ee2019-02-15 10:14:50 +0100650/**
651 * @brief Parse yin submodule.
652 *
653 * @param[in] ctx Context of YANG schemas.
654 * @param[in] data Data to read from.
655 * @param[out] submod Module to write to.
656 *
657 * @return LY_ERR values.
658 */
659LY_ERR
660yin_parse_submodule(struct ly_ctx *ctx, const char *data, struct lysp_submodule **submod)
661{
662 LY_ERR ret = LY_SUCCESS;
663 enum yang_keyword kw = YANG_NONE;
664 struct lyxml_context xml_ctx;
665 struct lysp_submodule *mod_p = NULL;
666 const char *prefix, *name;
667 size_t prefix_len, name_len;
David Sedlák3017da42019-02-15 09:48:04 +0100668
David Sedlákd5318ee2019-02-15 10:14:50 +0100669 /* initialize xml context */
670 memset(&xml_ctx, 0, sizeof xml_ctx);
671 xml_ctx.ctx = ctx;
672 xml_ctx.line = 1;
David Sedlák3017da42019-02-15 09:48:04 +0100673
David Sedlákd5318ee2019-02-15 10:14:50 +0100674 /* check submodule */
675 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
676 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
David Sedlák18730132019-03-15 15:51:34 +0100677 kw = match_keyword(name, name_len, prefix_len);
David Sedlákd5318ee2019-02-15 10:14:50 +0100678 if (kw == YANG_MODULE) {
679 LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
680 ret = LY_EINVAL;
681 goto cleanup;
682 } else if (kw != YANG_SUBMODULE) {
David Sedlák0a875b42019-03-07 22:24:05 +0100683 LOGVAL_YANG(&xml_ctx, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
684 ly_stmt2str(kw));
David Sedlákd5318ee2019-02-15 10:14:50 +0100685 ret = LY_EVALID;
686 goto cleanup;
687 }
David Sedlák3017da42019-02-15 09:48:04 +0100688
David Sedlákd5318ee2019-02-15 10:14:50 +0100689 /* allocate module */
690 mod_p = calloc(1, sizeof *mod_p);
691 LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
692 mod_p->parsing = 1;
David Sedlák3017da42019-02-15 09:48:04 +0100693
David Sedlákd5318ee2019-02-15 10:14:50 +0100694 /* parser submodule substatements */
695 //ret = parse_submod(&xml_ctx, &data, mod_p);
696 LY_CHECK_GOTO(ret, cleanup);
David Sedlák3017da42019-02-15 09:48:04 +0100697
David Sedlákd5318ee2019-02-15 10:14:50 +0100698 mod_p->parsing = 0;
699 *submod = mod_p;
David Sedlák3017da42019-02-15 09:48:04 +0100700
David Sedlákd5318ee2019-02-15 10:14:50 +0100701cleanup:
702 if (ret) {
703 lysp_submodule_free(ctx, mod_p);
704 }
David Sedlák3017da42019-02-15 09:48:04 +0100705
David Sedlákd5318ee2019-02-15 10:14:50 +0100706 lyxml_context_clear(&xml_ctx);
707 return ret;
708}
David Sedlák3017da42019-02-15 09:48:04 +0100709
David Sedlákd5318ee2019-02-15 10:14:50 +0100710/**
711 * @brief Parse yin module.
712 *
713 * @param[in] ctx Context of YANG schemas.
714 * @param[in] data Data to read from.
715 * @param[out] mod Module to write to.
716 *
717 * @return LY_ERR values.
718 */
David Sedlák3b4db242018-10-19 16:11:01 +0200719LY_ERR
David Sedlák3017da42019-02-15 09:48:04 +0100720yin_parse_module(struct ly_ctx *ctx, const char *data, struct lys_module *mod)
David Sedlák3b4db242018-10-19 16:11:01 +0200721{
David Sedláke4889912018-11-02 09:52:40 +0100722 LY_ERR ret = LY_SUCCESS;
723 enum yang_keyword kw = YANG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200724 struct lyxml_context xml_ctx;
David Sedlák3017da42019-02-15 09:48:04 +0100725 struct lysp_module *mod_p = NULL;
726 const char *prefix, *name;
727 size_t prefix_len, name_len;
David Sedlák3b4db242018-10-19 16:11:01 +0200728
David Sedlák3017da42019-02-15 09:48:04 +0100729 /* initialize xml context */
David Sedláke4889912018-11-02 09:52:40 +0100730 memset(&xml_ctx, 0, sizeof xml_ctx);
731 xml_ctx.ctx = ctx;
732 xml_ctx.line = 1;
733
David Sedlák3017da42019-02-15 09:48:04 +0100734 /* check submodule */
David Sedláke4889912018-11-02 09:52:40 +0100735 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
David Sedlák3017da42019-02-15 09:48:04 +0100736 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
David Sedlák18730132019-03-15 15:51:34 +0100737 kw = match_keyword(name, name_len, prefix_len);
David Sedláke4889912018-11-02 09:52:40 +0100738 if (kw == YANG_SUBMODULE) {
David Sedlák3017da42019-02-15 09:48:04 +0100739 LOGERR(ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
740 ret = LY_EINVAL;
741 goto cleanup;
742 } else if (kw != YANG_MODULE) {
David Sedlák0a875b42019-03-07 22:24:05 +0100743 LOGVAL_YANG(&xml_ctx, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
744 ly_stmt2str(kw));
David Sedlák3017da42019-02-15 09:48:04 +0100745 ret = LY_EVALID;
746 goto cleanup;
David Sedláke4889912018-11-02 09:52:40 +0100747 }
748
David Sedlák3017da42019-02-15 09:48:04 +0100749 /* allocate module */
750 mod_p = calloc(1, sizeof *mod_p);
751 LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
752 mod_p->mod = mod;
753 mod_p->parsing = 1;
David Sedláke4889912018-11-02 09:52:40 +0100754
David Sedlák3017da42019-02-15 09:48:04 +0100755 /* parser module substatements */
756 ret = parse_mod(&xml_ctx, &data, &mod_p);
757 LY_CHECK_GOTO(ret, cleanup);
David Sedlák2e411422018-12-17 02:35:39 +0100758
David Sedlák3017da42019-02-15 09:48:04 +0100759 mod_p->parsing = 0;
760 mod->parsed = mod_p;
761
762cleanup:
763 if (ret) {
764 lysp_module_free(mod_p);
765 }
766
David Sedlák2e411422018-12-17 02:35:39 +0100767 lyxml_context_clear(&xml_ctx);
768 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200769}