blob: f479511fed2da9567c9899fa6b03870c02dc83a0 [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ákd5318ee2019-02-15 10:14:50 +0100310/**
311 * @brief Parse prefix statement.
312 *
313 * @param[in] xml_ctx Xml context.
314 * @param[in, out] data Data to reda from.
David Sedlák24d90b92019-03-29 10:00:35 +0100315 * @param[out] mod Module to write to.
David Sedlákd5318ee2019-02-15 10:14:50 +0100316 *
317 * @return LY_ERR values.
318 */
David Sedlák4a4c0722018-11-26 17:03:10 +0100319LY_ERR
David Sedlák24d90b92019-03-29 10:00:35 +0100320parse_prefix(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák4a4c0722018-11-26 17:03:10 +0100321{
322 LY_ERR ret = LY_SUCCESS;
323 const char *prefix, *name;
324 size_t prefix_len, name_len;
325
326 char *buf = NULL, *out = NULL;
327 size_t buf_len = 0, out_len = 0;
328 int dynamic;
329
David Sedlákc10e7902018-12-17 02:17:59 +0100330 /* check if prefix has argument value */
David Sedlák4a4c0722018-11-26 17:03:10 +0100331 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlák94de2aa2019-02-15 12:42:11 +0100332 LY_CHECK_RET(ret);
David Sedlák4a4c0722018-11-26 17:03:10 +0100333 if (match_argument_name(name, name_len) != YIN_ARG_VALUE) {
David Sedlákc10e7902018-12-17 02:17:59 +0100334 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"value\".", name);
335 return LY_EVALID;
David Sedlák4a4c0722018-11-26 17:03:10 +0100336 }
337
David Sedlákc10e7902018-12-17 02:17:59 +0100338 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlák94de2aa2019-02-15 12:42:11 +0100339 LY_CHECK_RET(ret);
David Sedlák3017da42019-02-15 09:48:04 +0100340 (*mod_p)->mod->prefix = lydict_insert(xml_ctx->ctx, out, out_len);
341 LY_CHECK_ERR_RET(!(*mod_p)->mod->prefix, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100342
David Sedlák3017da42019-02-15 09:48:04 +0100343 /* prefix element can have only one argument */
David Sedlákc136b972019-03-08 13:39:06 +0100344 if (xml_ctx->status != LYXML_ELEMENT) {
David Sedlákc10e7902018-12-17 02:17:59 +0100345 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
346 return LY_EVALID;
347 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100348 return LY_SUCCESS;
349}
350
David Sedlák736fd0d2019-02-15 16:06:31 +0100351static LY_ERR
352yin_parse_import(struct lyxml_context *xml_ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
353{
354 LY_ERR ret = LY_SUCCESS;
355 enum yang_keyword kw;
356 struct lysp_import *imp;
357 const char *prefix, *name;
358 size_t prefix_len, name_len;
359
360 char *buf = NULL, *out = NULL;
361 size_t buf_len = 0, out_len = 0;
362 int dynamic;
363
364 /* allocate sized array for imports */
365 LY_ARRAY_NEW_RET(xml_ctx->ctx, *imports, imp, LY_EVALID);
366
367 /* get value */
368 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
369 LY_CHECK_RET(ret);
370 if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
David Sedlák1c8b2702019-02-22 11:03:02 +0100371 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 +0100372 return LY_EVALID;
373 }
374 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
375 LY_CHECK_RET(ret);
376 imp->name = lydict_insert(xml_ctx->ctx, out, out_len);
377 LY_CHECK_ERR_RET(!imp->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
378
379
380 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 +0100381 kw = match_keyword(name, name_len, prefix_len);
David Sedlák736fd0d2019-02-15 16:06:31 +0100382 switch (kw) {
383 case YANG_PREFIX:
384 /* TODO parse prefix */
385 case YANG_DESCRIPTION:
386 /* TODO parse description */
387 case YANG_REFERENCE:
388 /* TODO parse reference */
389 case YANG_REVISION_DATE:
390 /* TODO parse revision date */
391 case YANG_CUSTOM:
392 /* TODO parse extension */
393 default:
394 /* TODO log error */
395 return LY_EVALID;
396 }
397 }
398
399 /* TODO add log macro and log error */
400 LY_CHECK_RET(!imp->prefix);
401 return ret;
402}
403
David Sedlákd5318ee2019-02-15 10:14:50 +0100404/**
405 * @brief Parse module substatements.
406 *
407 * @param[in] xml_ctx xml context.
408 * @param[in, out] data Data to read from.
409 * @param[out] mod Parsed module structure
410 *
411 * @return LY_ERR values.
412 */
David Sedlák4a4c0722018-11-26 17:03:10 +0100413LY_ERR
David Sedlák3017da42019-02-15 09:48:04 +0100414parse_mod(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák3b4db242018-10-19 16:11:01 +0200415{
David Sedlákf3b24f62018-11-02 10:40:47 +0100416 LY_ERR ret = LY_SUCCESS;
David Sedlák4a4c0722018-11-26 17:03:10 +0100417 enum yang_keyword kw = YANG_NONE;
David Sedláke4889912018-11-02 09:52:40 +0100418 const char *prefix, *name;
David Sedlák3b4db242018-10-19 16:11:01 +0200419 size_t prefix_len, name_len;
David Sedlák4b4713f2019-02-15 13:47:45 +0100420 enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
David Sedlák18730132019-03-15 15:51:34 +0100421 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200422
David Sedlákf3b24f62018-11-02 10:40:47 +0100423 char *buf = NULL, *out = NULL;
424 size_t buf_len = 0, out_len = 0;
425 int dynamic;
426
David Sedlák18730132019-03-15 15:51:34 +0100427 /* parse module attributes */
428 while (xml_ctx->status == LYXML_ATTRIBUTE) {
429 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
430 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
431
432 arg = match_argument_name(name, name_len);
433
434 switch (arg) {
435 case YIN_ARG_XMLNS:
436 parse_xmlns(xml_ctx, data, prefix, prefix_len, "module");
437 break;
438 case YIN_ARG_NAME:
439 /* check for multiple definitions of name */
440 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);
441
442 /* read module name */
443 if (xml_ctx->status != LYXML_ATTR_CONTENT) {
444 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing value of argument \"name\".");
445 }
446 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
447 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
448 (*mod)->mod->name = lydict_insert(xml_ctx->ctx, out, out_len);
449 LY_CHECK_ERR_RET(!(*mod)->mod->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
450 break;
451 default:
452 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
453 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
454 /* in this case prefix of namespace is actually name of attribute */
455 parse_xmlns(xml_ctx, data, name, name_len, "module");
456 } else {
457 /* unrecognized or unexpected attribute */
458 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in module element");
459 return LY_EVALID;
460 }
461 break;
462 }
David Sedlák3b4db242018-10-19 16:11:01 +0200463 }
464
David Sedlák18730132019-03-15 15:51:34 +0100465 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 +0100466
David Sedlákc136b972019-03-08 13:39:06 +0100467 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlák18730132019-03-15 15:51:34 +0100468 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 +0100469
David Sedlák736fd0d2019-02-15 16:06:31 +0100470 /* loop over all elements and parse them */
David Sedlákc136b972019-03-08 13:39:06 +0100471 while (xml_ctx->status != LYXML_END) {
David Sedlák4b4713f2019-02-15 13:47:45 +0100472/* TODO ADD error log to macro */
473#define CHECK_ORDER(SECTION) \
474 if (mod_stmt > SECTION) {return LY_EVALID;}mod_stmt = SECTION
475
476 switch (kw) {
477 /* module header */
478 case YANG_NAMESPACE:
479 case YANG_PREFIX:
480 CHECK_ORDER(Y_MOD_MODULE_HEADER);
481 break;
482 case YANG_YANG_VERSION:
483 CHECK_ORDER(Y_MOD_MODULE_HEADER);
484 break;
485 /* linkage */
486 case YANG_INCLUDE:
487 case YANG_IMPORT:
488 CHECK_ORDER(Y_MOD_LINKAGE);
489 break;
490 /* meta */
491 case YANG_ORGANIZATION:
492 case YANG_CONTACT:
493 case YANG_DESCRIPTION:
494 case YANG_REFERENCE:
495 CHECK_ORDER(Y_MOD_META);
496 break;
497
498 /* revision */
499 case YANG_REVISION:
500 CHECK_ORDER(Y_MOD_REVISION);
501 break;
502 /* body */
503 case YANG_ANYDATA:
504 case YANG_ANYXML:
505 case YANG_AUGMENT:
506 case YANG_CHOICE:
507 case YANG_CONTAINER:
508 case YANG_DEVIATION:
509 case YANG_EXTENSION:
510 case YANG_FEATURE:
511 case YANG_GROUPING:
512 case YANG_IDENTITY:
513 case YANG_LEAF:
514 case YANG_LEAF_LIST:
515 case YANG_LIST:
516 case YANG_NOTIFICATION:
517 case YANG_RPC:
518 case YANG_TYPEDEF:
519 case YANG_USES:
520 case YANG_CUSTOM:
521 mod_stmt = Y_MOD_BODY;
522 break;
523 default:
524 /* error will be handled in the next switch */
525 break;
526 }
527#undef CHECK_ORDER
528
David Sedlák4a4c0722018-11-26 17:03:10 +0100529 ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc136b972019-03-08 13:39:06 +0100530 LY_CHECK_RET(ret != LY_SUCCESS, LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100531
David Sedlákc136b972019-03-08 13:39:06 +0100532 if (name) {
David Sedlák18730132019-03-15 15:51:34 +0100533 kw = match_keyword(name, name_len, prefix_len);
David Sedlákc136b972019-03-08 13:39:06 +0100534 switch (kw) {
David Sedlák736fd0d2019-02-15 16:06:31 +0100535
David Sedlákc136b972019-03-08 13:39:06 +0100536 /* module header */
537 case YANG_NAMESPACE:
538 LY_CHECK_RET(parse_namespace(xml_ctx, data, mod));
539 break;
540 case YANG_PREFIX:
541 LY_CHECK_RET(parse_prefix(xml_ctx, data, mod));
David Sedlákc136b972019-03-08 13:39:06 +0100542 break;
David Sedlák4a4c0722018-11-26 17:03:10 +0100543
David Sedlákc136b972019-03-08 13:39:06 +0100544 /* linkage */
545 case YANG_IMPORT:
546 yin_parse_import(xml_ctx, (*mod)->mod->prefix, data, &(*mod)->imports);
547 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100548
David Sedlákc136b972019-03-08 13:39:06 +0100549 /* meta */
550 case YANG_ORGANIZATION:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100551 LY_CHECK_RET(parse_text_element(xml_ctx, "organization", data, &(*mod)->mod->org));
David Sedlákc136b972019-03-08 13:39:06 +0100552 break;
553 case YANG_CONTACT:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100554 LY_CHECK_RET(parse_text_element(xml_ctx, "contact", data, &(*mod)->mod->contact));
David Sedlákc136b972019-03-08 13:39:06 +0100555 break;
556 case YANG_DESCRIPTION:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100557 LY_CHECK_RET(parse_text_element(xml_ctx, "description", data, &(*mod)->mod->dsc));
David Sedlákc136b972019-03-08 13:39:06 +0100558 break;
559 case YANG_REFERENCE:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100560 LY_CHECK_RET(parse_text_element(xml_ctx, "reference", data, &(*mod)->mod->ref));
David Sedlákc136b972019-03-08 13:39:06 +0100561 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100562
David Sedlákc136b972019-03-08 13:39:06 +0100563 default:
David Sedlák18730132019-03-15 15:51:34 +0100564 return LY_EVALID;
David Sedlákc136b972019-03-08 13:39:06 +0100565 break;
566 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100567 }
568 }
569
David Sedlák18730132019-03-15 15:51:34 +0100570 lyxml_ns_rm(xml_ctx, "module");
David Sedlákf3b24f62018-11-02 10:40:47 +0100571 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200572}
573
David Sedlákd5318ee2019-02-15 10:14:50 +0100574/**
575 * @brief Parse yin submodule.
576 *
577 * @param[in] ctx Context of YANG schemas.
578 * @param[in] data Data to read from.
579 * @param[out] submod Module to write to.
580 *
581 * @return LY_ERR values.
582 */
583LY_ERR
584yin_parse_submodule(struct ly_ctx *ctx, const char *data, struct lysp_submodule **submod)
585{
586 LY_ERR ret = LY_SUCCESS;
587 enum yang_keyword kw = YANG_NONE;
588 struct lyxml_context xml_ctx;
589 struct lysp_submodule *mod_p = NULL;
590 const char *prefix, *name;
591 size_t prefix_len, name_len;
David Sedlák3017da42019-02-15 09:48:04 +0100592
David Sedlákd5318ee2019-02-15 10:14:50 +0100593 /* initialize xml context */
594 memset(&xml_ctx, 0, sizeof xml_ctx);
595 xml_ctx.ctx = ctx;
596 xml_ctx.line = 1;
David Sedlák3017da42019-02-15 09:48:04 +0100597
David Sedlákd5318ee2019-02-15 10:14:50 +0100598 /* check submodule */
599 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
600 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
David Sedlák18730132019-03-15 15:51:34 +0100601 kw = match_keyword(name, name_len, prefix_len);
David Sedlákd5318ee2019-02-15 10:14:50 +0100602 if (kw == YANG_MODULE) {
603 LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
604 ret = LY_EINVAL;
605 goto cleanup;
606 } else if (kw != YANG_SUBMODULE) {
David Sedlák0a875b42019-03-07 22:24:05 +0100607 LOGVAL_YANG(&xml_ctx, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
608 ly_stmt2str(kw));
David Sedlákd5318ee2019-02-15 10:14:50 +0100609 ret = LY_EVALID;
610 goto cleanup;
611 }
David Sedlák3017da42019-02-15 09:48:04 +0100612
David Sedlákd5318ee2019-02-15 10:14:50 +0100613 /* allocate module */
614 mod_p = calloc(1, sizeof *mod_p);
615 LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
616 mod_p->parsing = 1;
David Sedlák3017da42019-02-15 09:48:04 +0100617
David Sedlákd5318ee2019-02-15 10:14:50 +0100618 /* parser submodule substatements */
619 //ret = parse_submod(&xml_ctx, &data, mod_p);
620 LY_CHECK_GOTO(ret, cleanup);
David Sedlák3017da42019-02-15 09:48:04 +0100621
David Sedlákd5318ee2019-02-15 10:14:50 +0100622 mod_p->parsing = 0;
623 *submod = mod_p;
David Sedlák3017da42019-02-15 09:48:04 +0100624
David Sedlákd5318ee2019-02-15 10:14:50 +0100625cleanup:
626 if (ret) {
627 lysp_submodule_free(ctx, mod_p);
628 }
David Sedlák3017da42019-02-15 09:48:04 +0100629
David Sedlákd5318ee2019-02-15 10:14:50 +0100630 lyxml_context_clear(&xml_ctx);
631 return ret;
632}
David Sedlák3017da42019-02-15 09:48:04 +0100633
David Sedlákd5318ee2019-02-15 10:14:50 +0100634/**
635 * @brief Parse yin module.
636 *
637 * @param[in] ctx Context of YANG schemas.
638 * @param[in] data Data to read from.
639 * @param[out] mod Module to write to.
640 *
641 * @return LY_ERR values.
642 */
David Sedlák3b4db242018-10-19 16:11:01 +0200643LY_ERR
David Sedlák3017da42019-02-15 09:48:04 +0100644yin_parse_module(struct ly_ctx *ctx, const char *data, struct lys_module *mod)
David Sedlák3b4db242018-10-19 16:11:01 +0200645{
David Sedláke4889912018-11-02 09:52:40 +0100646 LY_ERR ret = LY_SUCCESS;
647 enum yang_keyword kw = YANG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200648 struct lyxml_context xml_ctx;
David Sedlák3017da42019-02-15 09:48:04 +0100649 struct lysp_module *mod_p = NULL;
650 const char *prefix, *name;
651 size_t prefix_len, name_len;
David Sedlák3b4db242018-10-19 16:11:01 +0200652
David Sedlák3017da42019-02-15 09:48:04 +0100653 /* initialize xml context */
David Sedláke4889912018-11-02 09:52:40 +0100654 memset(&xml_ctx, 0, sizeof xml_ctx);
655 xml_ctx.ctx = ctx;
656 xml_ctx.line = 1;
657
David Sedlák3017da42019-02-15 09:48:04 +0100658 /* check submodule */
David Sedláke4889912018-11-02 09:52:40 +0100659 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
David Sedlák3017da42019-02-15 09:48:04 +0100660 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
David Sedlák18730132019-03-15 15:51:34 +0100661 kw = match_keyword(name, name_len, prefix_len);
David Sedláke4889912018-11-02 09:52:40 +0100662 if (kw == YANG_SUBMODULE) {
David Sedlák3017da42019-02-15 09:48:04 +0100663 LOGERR(ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
664 ret = LY_EINVAL;
665 goto cleanup;
666 } else if (kw != YANG_MODULE) {
David Sedlák0a875b42019-03-07 22:24:05 +0100667 LOGVAL_YANG(&xml_ctx, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
668 ly_stmt2str(kw));
David Sedlák3017da42019-02-15 09:48:04 +0100669 ret = LY_EVALID;
670 goto cleanup;
David Sedláke4889912018-11-02 09:52:40 +0100671 }
672
David Sedlák3017da42019-02-15 09:48:04 +0100673 /* allocate module */
674 mod_p = calloc(1, sizeof *mod_p);
675 LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
676 mod_p->mod = mod;
677 mod_p->parsing = 1;
David Sedláke4889912018-11-02 09:52:40 +0100678
David Sedlák3017da42019-02-15 09:48:04 +0100679 /* parser module substatements */
680 ret = parse_mod(&xml_ctx, &data, &mod_p);
681 LY_CHECK_GOTO(ret, cleanup);
David Sedlák2e411422018-12-17 02:35:39 +0100682
David Sedlák3017da42019-02-15 09:48:04 +0100683 mod_p->parsing = 0;
684 mod->parsed = mod_p;
685
686cleanup:
687 if (ret) {
688 lysp_module_free(mod_p);
689 }
690
David Sedlák2e411422018-12-17 02:35:39 +0100691 lyxml_context_clear(&xml_ctx);
692 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200693}