blob: 383b5c829ccb524ccd848affa8106f6d01f5b58f [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ák3b4db242018-10-19 16:11:01 +020052
David Sedlák94de2aa2019-02-15 12:42:11 +010053#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;arg=STMT;}
54#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;
David Sedlákc10e7902018-12-17 02:17:59 +010055#define IF_ARG_PREFIX_END }
56
David Sedlák1c8b2702019-02-22 11:03:02 +010057 switch (*name) {
David Sedlák18730132019-03-15 15:51:34 +010058 case 'x':
59 already_read += 1;
60 IF_ARG("mlns", 4, YIN_ARG_XMLNS);
61 break;
David Sedlák94de2aa2019-02-15 12:42:11 +010062 case 'c':
63 already_read += 1;
64 IF_ARG("ondition", 8, YIN_ARG_CONDITION);
David Sedlák3b4db242018-10-19 16:11:01 +020065 break;
David Sedlák872c7b42018-10-26 13:15:20 +020066
David Sedlák94de2aa2019-02-15 12:42:11 +010067 case 'd':
68 already_read += 1;
69 IF_ARG("ate", 3, YIN_ARG_DATE);
David Sedlák3b4db242018-10-19 16:11:01 +020070 break;
David Sedlák872c7b42018-10-26 13:15:20 +020071
David Sedlák94de2aa2019-02-15 12:42:11 +010072 case 'm':
73 already_read += 1;
74 IF_ARG("odule", 5, YIN_ARG_MODULE);
David Sedlák872c7b42018-10-26 13:15:20 +020075 break;
76
David Sedlák94de2aa2019-02-15 12:42:11 +010077 case 'n':
78 already_read += 1;
79 IF_ARG("ame", 3, YIN_ARG_NAME);
David Sedlák872c7b42018-10-26 13:15:20 +020080 break;
81
David Sedlák94de2aa2019-02-15 12:42:11 +010082 case 't':
83 already_read += 1;
84 IF_ARG_PREFIX("a", 1)
85 IF_ARG("g", 1, YIN_ARG_TAG)
86 else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
87 IF_ARG_PREFIX_END
88 else IF_ARG("ext", 3, YIN_ARG_TEXT)
David Sedlák3b4db242018-10-19 16:11:01 +020089 break;
David Sedlák872c7b42018-10-26 13:15:20 +020090
David Sedlák94de2aa2019-02-15 12:42:11 +010091 case 'u':
92 already_read += 1;
93 IF_ARG("ri", 2, YIN_ARG_URI)
David Sedlák3b4db242018-10-19 16:11:01 +020094 break;
David Sedlák872c7b42018-10-26 13:15:20 +020095
David Sedlák94de2aa2019-02-15 12:42:11 +010096 case 'v':
97 already_read += 1;
98 IF_ARG("alue", 4, YIN_ARG_VALUE);
David Sedlák3b4db242018-10-19 16:11:01 +020099 break;
100 }
101
David Sedlákc10e7902018-12-17 02:17:59 +0100102 /* whole argument must be matched */
David Sedlák872c7b42018-10-26 13:15:20 +0200103 if (already_read != len) {
104 arg = YIN_ARG_NONE;
105 }
106
David Sedlák18730132019-03-15 15:51:34 +0100107#undef IF_ARG
108#undef IF_ARG_PREFIX
109#undef IF_ARG_PREFIX_END
110
David Sedlák872c7b42018-10-26 13:15:20 +0200111 return arg;
David Sedlák3b4db242018-10-19 16:11:01 +0200112}
113
David Sedlák18730132019-03-15 15:51:34 +0100114/**
115 * @brief parse xmlns statement
116 *
117 * @param[in] xml_ctx XML parser context.
118 * @param[in, out] data Data to reda from.
119 * @param[in] prefix
120 */
121LY_ERR
122parse_xmlns(struct lyxml_context *xml_ctx, const char **data, const char *prefix, size_t prefix_len, char *element)
123{
124 char *buf = NULL, *out = NULL;
125 size_t buf_len = 0, out_len = 0;
126 int dynamic = 0;
127 LY_ERR ret = LY_SUCCESS;
128
129 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
130 LY_CHECK_RET(ret != LY_SUCCESS, ret);
131 LY_CHECK_ERR_RET(out_len == 0, LOGVAL_YANG(xml_ctx, LYVE_SYNTAX_YIN, "Missing value of xmlns attribute"), LY_EEXIST);
132 lyxml_ns_add(xml_ctx, element, prefix, prefix_len, out, out_len);
133
134 return LY_SUCCESS;
135}
136
David Sedlák0daba9a2019-03-22 14:07:49 +0100137/**
138 * @brief Parse content of whole element as text.
139 *
140 * @param[in] xml_ctx Xml context.
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100141 * @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 +0100142 * @param[in] data Data to read from.
143 * @param[out] value Where content of element should be stored.
144 */
145LY_ERR
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100146parse_text_element(struct lyxml_context *xml_ctx, char *element_name, const char **data, const char **value)
David Sedlák0daba9a2019-03-22 14:07:49 +0100147{
148 LY_ERR ret = LY_SUCCESS;
149 char *buf = NULL, *out = NULL;
150 size_t buf_len = 0, out_len = 0;
151 int dynamic;
152 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
153
154 const char *prefix, *name;
155 size_t prefix_len, name_len;
156
157 /* parse module attributes */
158 while (xml_ctx->status == LYXML_ATTRIBUTE) {
159 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
160 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
161
162 arg = match_argument_name(name, name_len);
163 if (arg) {
164 parse_xmlns(xml_ctx, data, prefix, prefix_len, "module");
165 } else {
166 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
167 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
168 /* in this case prefix of namespace is actually name of attribute */
169 parse_xmlns(xml_ctx, data, name, name_len, "module");
170 } else {
171 /* unrecognized or unexpected attribute */
172 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in module element");
173 return LY_EVALID;
174 }
175 break;
176 }
177 }
178
David Sedlák0daba9a2019-03-22 14:07:49 +0100179 LY_CHECK_RET(xml_ctx->status != LYXML_ELEM_CONTENT, LY_EVALID);
180
181 if (xml_ctx->status == LYXML_ELEM_CONTENT) {
182 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
183 LY_CHECK_RET(ret);
184 *value = lydict_insert(xml_ctx->ctx, out, out_len);
185 LY_CHECK_ERR_RET(!(*value), LOGMEM(xml_ctx->ctx), LY_EMEM);
186 }
187
188 lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100189 lyxml_ns_rm(xml_ctx, element_name);
190 return LY_SUCCESS;
David Sedlák0daba9a2019-03-22 14:07:49 +0100191}
192
David Sedlák3017da42019-02-15 09:48:04 +0100193// LY_ERR
194// parser_belongs_to(struct lyxml_context *xml_ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext **extensions)
195// {
196// enum yang_keyword kw = YANG_NONE;
197// LY_ERR ret = LY_SUCCESS;
198// const char *prefix_out, *name;
199// size_t prefix_len, name_len;
David Sedláka5004e62018-12-16 23:54:47 +0100200
David Sedlák3017da42019-02-15 09:48:04 +0100201// char *buf = NULL, *out = NULL;
202// size_t buf_len = 0, out_len = 0;
203// int dynamic;
David Sedláka5004e62018-12-16 23:54:47 +0100204
David Sedlák3017da42019-02-15 09:48:04 +0100205// /* check if belongs-to has argument module */
206// ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
207// LY_CHECK_RET1(ret);
208// if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
209// LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"module\".", name);
210// return LY_EINVAL;
211// }
David Sedláka5004e62018-12-16 23:54:47 +0100212
David Sedlák3017da42019-02-15 09:48:04 +0100213// /* read content of argument */
214// ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
215// LY_CHECK_RET1(ret);
216// *belongsto = lydict_insert(xml_ctx->ctx, out, out_len);
217// LY_CHECK_ERR_RET(!belongsto, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedláka5004e62018-12-16 23:54:47 +0100218
David Sedlák3017da42019-02-15 09:48:04 +0100219// /* read substatements */
220// while (xml_ctx->status == LYXML_ATTRIBUTE) {
221// ret = lyxml_get_attribute(xml_ctx, data, &prefix_out, &prefix_len, &name, &name_len);
222// LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), ret);
223// kw = match_keyword(name);
David Sedláka5004e62018-12-16 23:54:47 +0100224
David Sedlák3017da42019-02-15 09:48:04 +0100225// switch (kw) {
226// case YANG_PREFIX:
227// ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
228// *prefix = lydict_insert(xml_ctx->ctx, out, out_len);
229// break;
230// case YANG_CUSTOM:
231// /* TODO parse extension */
232// break;
233// default:
234// LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected attribute");
235// return LY_EVALID;
236// }
237// }
David Sedláka5004e62018-12-16 23:54:47 +0100238
David Sedlák3017da42019-02-15 09:48:04 +0100239// if (!prefix) {
240// LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing prefix");
241// return LY_EVALID;
242// }
David Sedlákc10e7902018-12-17 02:17:59 +0100243
David Sedlák3017da42019-02-15 09:48:04 +0100244// return LY_SUCCESS;
245// }
David Sedláka5004e62018-12-16 23:54:47 +0100246
David Sedlákd5318ee2019-02-15 10:14:50 +0100247/**
248 * @brief Parse namespace statement.
249 *
250 * @param[in] xml_ctx xml context.
251 * @param[in, out] data Data to read from.
252 * @param[in, out] mod_p Module to write to.
253 *
254 * @return LY_ERR values.
255 */
David Sedláka5004e62018-12-16 23:54:47 +0100256LY_ERR
David Sedlák0daba9a2019-03-22 14:07:49 +0100257parse_namespace(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák4a4c0722018-11-26 17:03:10 +0100258{
259 LY_ERR ret = LY_SUCCESS;
260 const char *prefix, *name;
261 size_t prefix_len, name_len;
262
263 char *buf = NULL, *out = NULL;
264 size_t buf_len = 0, out_len = 0;
265 int dynamic;
David Sedlák0daba9a2019-03-22 14:07:49 +0100266 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
David Sedlák4a4c0722018-11-26 17:03:10 +0100267
David Sedlák0daba9a2019-03-22 14:07:49 +0100268 /* parse namespace attributes */
269 while (xml_ctx->status == LYXML_ATTRIBUTE) {
270 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
271 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
272
273 arg = match_argument_name(name, name_len);
274
275 switch (arg) {
276 case YIN_ARG_XMLNS:
277 parse_xmlns(xml_ctx, data, prefix, prefix_len, "module");
278 break;
279 case YIN_ARG_URI:
280 LY_CHECK_RET(ret);
281 if (match_argument_name(name, name_len) != YIN_ARG_URI) {
282 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"uri\".", name);
283 return LY_EVALID;
284 }
285 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
286 LY_CHECK_RET(ret);
287 (*mod)->mod->ns = lydict_insert(xml_ctx->ctx, out, out_len);
288 LY_CHECK_ERR_RET(!(*mod)->mod->ns, LOGMEM(xml_ctx->ctx), LY_EMEM);
289 break;
290 default:
291 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
292 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
293 /* in this case prefix of namespace is actually name of attribute */
294 parse_xmlns(xml_ctx, data, name, name_len, "module");
295 } else {
296 /* unrecognized or unexpected attribute */
297 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in module element");
298 return LY_EVALID;
299 }
300 break;
301 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100302 }
303
David Sedlákd5318ee2019-02-15 10:14:50 +0100304 /* namespace can have only one argument */
David Sedlákc136b972019-03-08 13:39:06 +0100305 if (xml_ctx->status != LYXML_ELEMENT) {
David Sedlákc10e7902018-12-17 02:17:59 +0100306 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
307 return LY_EVALID;
308 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100309
310 return LY_SUCCESS;
311}
312
David Sedlákd5318ee2019-02-15 10:14:50 +0100313/**
314 * @brief Parse prefix statement.
315 *
316 * @param[in] xml_ctx Xml context.
317 * @param[in, out] data Data to reda from.
318 * @param[out] mod_p Module to write to.
319 *
320 * @return LY_ERR values.
321 */
David Sedlák4a4c0722018-11-26 17:03:10 +0100322LY_ERR
323parse_prefix(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod_p)
324{
325 LY_ERR ret = LY_SUCCESS;
326 const char *prefix, *name;
327 size_t prefix_len, name_len;
328
329 char *buf = NULL, *out = NULL;
330 size_t buf_len = 0, out_len = 0;
331 int dynamic;
332
David Sedlákc10e7902018-12-17 02:17:59 +0100333 /* check if prefix has argument value */
David Sedlák4a4c0722018-11-26 17:03:10 +0100334 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlák94de2aa2019-02-15 12:42:11 +0100335 LY_CHECK_RET(ret);
David Sedlák4a4c0722018-11-26 17:03:10 +0100336 if (match_argument_name(name, name_len) != YIN_ARG_VALUE) {
David Sedlákc10e7902018-12-17 02:17:59 +0100337 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Invalid argument name \"%s\", expected \"value\".", name);
338 return LY_EVALID;
David Sedlák4a4c0722018-11-26 17:03:10 +0100339 }
340
David Sedlákc10e7902018-12-17 02:17:59 +0100341 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlák94de2aa2019-02-15 12:42:11 +0100342 LY_CHECK_RET(ret);
David Sedlák3017da42019-02-15 09:48:04 +0100343 (*mod_p)->mod->prefix = lydict_insert(xml_ctx->ctx, out, out_len);
344 LY_CHECK_ERR_RET(!(*mod_p)->mod->prefix, LOGMEM(xml_ctx->ctx), LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100345
David Sedlák3017da42019-02-15 09:48:04 +0100346 /* prefix element can have only one argument */
David Sedlákc136b972019-03-08 13:39:06 +0100347 if (xml_ctx->status != LYXML_ELEMENT) {
David Sedlákc10e7902018-12-17 02:17:59 +0100348 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Unexpected argument \"%s\".", name);
349 return LY_EVALID;
350 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100351 return LY_SUCCESS;
352}
353
David Sedlák736fd0d2019-02-15 16:06:31 +0100354static LY_ERR
355yin_parse_import(struct lyxml_context *xml_ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
356{
357 LY_ERR ret = LY_SUCCESS;
358 enum yang_keyword kw;
359 struct lysp_import *imp;
360 const char *prefix, *name;
361 size_t prefix_len, name_len;
362
363 char *buf = NULL, *out = NULL;
364 size_t buf_len = 0, out_len = 0;
365 int dynamic;
366
367 /* allocate sized array for imports */
368 LY_ARRAY_NEW_RET(xml_ctx->ctx, *imports, imp, LY_EVALID);
369
370 /* get value */
371 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
372 LY_CHECK_RET(ret);
373 if (match_argument_name(name, name_len) != YIN_ARG_MODULE) {
David Sedlák1c8b2702019-02-22 11:03:02 +0100374 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 +0100375 return LY_EVALID;
376 }
377 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
378 LY_CHECK_RET(ret);
379 imp->name = lydict_insert(xml_ctx->ctx, out, out_len);
380 LY_CHECK_ERR_RET(!imp->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
381
382
383 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 +0100384 kw = match_keyword(name, name_len, prefix_len);
David Sedlák736fd0d2019-02-15 16:06:31 +0100385 switch (kw) {
386 case YANG_PREFIX:
387 /* TODO parse prefix */
388 case YANG_DESCRIPTION:
389 /* TODO parse description */
390 case YANG_REFERENCE:
391 /* TODO parse reference */
392 case YANG_REVISION_DATE:
393 /* TODO parse revision date */
394 case YANG_CUSTOM:
395 /* TODO parse extension */
396 default:
397 /* TODO log error */
398 return LY_EVALID;
399 }
400 }
401
402 /* TODO add log macro and log error */
403 LY_CHECK_RET(!imp->prefix);
404 return ret;
405}
406
David Sedlákd5318ee2019-02-15 10:14:50 +0100407/**
408 * @brief Parse module substatements.
409 *
410 * @param[in] xml_ctx xml context.
411 * @param[in, out] data Data to read from.
412 * @param[out] mod Parsed module structure
413 *
414 * @return LY_ERR values.
415 */
David Sedlák4a4c0722018-11-26 17:03:10 +0100416LY_ERR
David Sedlák3017da42019-02-15 09:48:04 +0100417parse_mod(struct lyxml_context *xml_ctx, const char **data, struct lysp_module **mod)
David Sedlák3b4db242018-10-19 16:11:01 +0200418{
David Sedlákf3b24f62018-11-02 10:40:47 +0100419 LY_ERR ret = LY_SUCCESS;
David Sedlák4a4c0722018-11-26 17:03:10 +0100420 enum yang_keyword kw = YANG_NONE;
David Sedláke4889912018-11-02 09:52:40 +0100421 const char *prefix, *name;
David Sedlák3b4db242018-10-19 16:11:01 +0200422 size_t prefix_len, name_len;
David Sedlák4b4713f2019-02-15 13:47:45 +0100423 enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
David Sedlák18730132019-03-15 15:51:34 +0100424 enum YIN_ARGUMENT arg = YIN_ARG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200425
David Sedlákf3b24f62018-11-02 10:40:47 +0100426 char *buf = NULL, *out = NULL;
427 size_t buf_len = 0, out_len = 0;
428 int dynamic;
429
David Sedlák18730132019-03-15 15:51:34 +0100430 /* parse module attributes */
431 while (xml_ctx->status == LYXML_ATTRIBUTE) {
432 ret = lyxml_get_attribute(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
433 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
434
435 arg = match_argument_name(name, name_len);
436
437 switch (arg) {
438 case YIN_ARG_XMLNS:
439 parse_xmlns(xml_ctx, data, prefix, prefix_len, "module");
440 break;
441 case YIN_ARG_NAME:
442 /* check for multiple definitions of name */
443 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);
444
445 /* read module name */
446 if (xml_ctx->status != LYXML_ATTR_CONTENT) {
447 LOGVAL(xml_ctx->ctx, LY_VLOG_LINE, &xml_ctx->line, LYVE_SYNTAX, "Missing value of argument \"name\".");
448 }
449 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
450 LY_CHECK_ERR_RET(ret != LY_SUCCESS, LOGMEM(xml_ctx->ctx), LY_EMEM);
451 (*mod)->mod->name = lydict_insert(xml_ctx->ctx, out, out_len);
452 LY_CHECK_ERR_RET(!(*mod)->mod->name, LOGMEM(xml_ctx->ctx), LY_EMEM);
453 break;
454 default:
455 /* unrecognized attribute, still can be namespace definition eg. xmlns:foo=.... */
456 if (match_argument_name(prefix, prefix_len) == YIN_ARG_XMLNS) {
457 /* in this case prefix of namespace is actually name of attribute */
458 parse_xmlns(xml_ctx, data, name, name_len, "module");
459 } else {
460 /* unrecognized or unexpected attribute */
461 LOGERR(xml_ctx->ctx, LY_EDENIED, "Invalid argument in module element");
462 return LY_EVALID;
463 }
464 break;
465 }
David Sedlák3b4db242018-10-19 16:11:01 +0200466 }
467
David Sedlák18730132019-03-15 15:51:34 +0100468 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 +0100469
David Sedlákc136b972019-03-08 13:39:06 +0100470 ret = lyxml_get_string(xml_ctx, data, &buf, &buf_len, &out, &out_len, &dynamic);
David Sedlák18730132019-03-15 15:51:34 +0100471 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 +0100472
David Sedlák736fd0d2019-02-15 16:06:31 +0100473 /* loop over all elements and parse them */
David Sedlákc136b972019-03-08 13:39:06 +0100474 while (xml_ctx->status != LYXML_END) {
David Sedlák4b4713f2019-02-15 13:47:45 +0100475/* TODO ADD error log to macro */
476#define CHECK_ORDER(SECTION) \
477 if (mod_stmt > SECTION) {return LY_EVALID;}mod_stmt = SECTION
478
479 switch (kw) {
480 /* module header */
481 case YANG_NAMESPACE:
482 case YANG_PREFIX:
483 CHECK_ORDER(Y_MOD_MODULE_HEADER);
484 break;
485 case YANG_YANG_VERSION:
486 CHECK_ORDER(Y_MOD_MODULE_HEADER);
487 break;
488 /* linkage */
489 case YANG_INCLUDE:
490 case YANG_IMPORT:
491 CHECK_ORDER(Y_MOD_LINKAGE);
492 break;
493 /* meta */
494 case YANG_ORGANIZATION:
495 case YANG_CONTACT:
496 case YANG_DESCRIPTION:
497 case YANG_REFERENCE:
498 CHECK_ORDER(Y_MOD_META);
499 break;
500
501 /* revision */
502 case YANG_REVISION:
503 CHECK_ORDER(Y_MOD_REVISION);
504 break;
505 /* body */
506 case YANG_ANYDATA:
507 case YANG_ANYXML:
508 case YANG_AUGMENT:
509 case YANG_CHOICE:
510 case YANG_CONTAINER:
511 case YANG_DEVIATION:
512 case YANG_EXTENSION:
513 case YANG_FEATURE:
514 case YANG_GROUPING:
515 case YANG_IDENTITY:
516 case YANG_LEAF:
517 case YANG_LEAF_LIST:
518 case YANG_LIST:
519 case YANG_NOTIFICATION:
520 case YANG_RPC:
521 case YANG_TYPEDEF:
522 case YANG_USES:
523 case YANG_CUSTOM:
524 mod_stmt = Y_MOD_BODY;
525 break;
526 default:
527 /* error will be handled in the next switch */
528 break;
529 }
530#undef CHECK_ORDER
531
David Sedlák4a4c0722018-11-26 17:03:10 +0100532 ret = lyxml_get_element(xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
David Sedlákc136b972019-03-08 13:39:06 +0100533 LY_CHECK_RET(ret != LY_SUCCESS, LY_EMEM);
David Sedlák4a4c0722018-11-26 17:03:10 +0100534
David Sedlákc136b972019-03-08 13:39:06 +0100535 if (name) {
David Sedlák18730132019-03-15 15:51:34 +0100536 kw = match_keyword(name, name_len, prefix_len);
David Sedlákc136b972019-03-08 13:39:06 +0100537 switch (kw) {
David Sedlák736fd0d2019-02-15 16:06:31 +0100538
David Sedlákc136b972019-03-08 13:39:06 +0100539 /* module header */
540 case YANG_NAMESPACE:
541 LY_CHECK_RET(parse_namespace(xml_ctx, data, mod));
542 break;
543 case YANG_PREFIX:
544 LY_CHECK_RET(parse_prefix(xml_ctx, data, mod));
David Sedlákc136b972019-03-08 13:39:06 +0100545 break;
David Sedlák4a4c0722018-11-26 17:03:10 +0100546
David Sedlákc136b972019-03-08 13:39:06 +0100547 /* linkage */
548 case YANG_IMPORT:
549 yin_parse_import(xml_ctx, (*mod)->mod->prefix, data, &(*mod)->imports);
550 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100551
David Sedlákc136b972019-03-08 13:39:06 +0100552 /* meta */
553 case YANG_ORGANIZATION:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100554 LY_CHECK_RET(parse_text_element(xml_ctx, "organization", data, &(*mod)->mod->org));
David Sedlákc136b972019-03-08 13:39:06 +0100555 break;
556 case YANG_CONTACT:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100557 LY_CHECK_RET(parse_text_element(xml_ctx, "contact", data, &(*mod)->mod->contact));
David Sedlákc136b972019-03-08 13:39:06 +0100558 break;
559 case YANG_DESCRIPTION:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100560 LY_CHECK_RET(parse_text_element(xml_ctx, "description", data, &(*mod)->mod->dsc));
David Sedlákc136b972019-03-08 13:39:06 +0100561 break;
562 case YANG_REFERENCE:
David Sedlák6b7ac2d2019-03-22 14:40:29 +0100563 LY_CHECK_RET(parse_text_element(xml_ctx, "reference", data, &(*mod)->mod->ref));
David Sedlákc136b972019-03-08 13:39:06 +0100564 break;
David Sedlák736fd0d2019-02-15 16:06:31 +0100565
David Sedlákc136b972019-03-08 13:39:06 +0100566 default:
David Sedlák18730132019-03-15 15:51:34 +0100567 return LY_EVALID;
David Sedlákc136b972019-03-08 13:39:06 +0100568 break;
569 }
David Sedlák4a4c0722018-11-26 17:03:10 +0100570 }
571 }
572
David Sedlák18730132019-03-15 15:51:34 +0100573 lyxml_ns_rm(xml_ctx, "module");
David Sedlákf3b24f62018-11-02 10:40:47 +0100574 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200575}
576
David Sedlákd5318ee2019-02-15 10:14:50 +0100577/**
578 * @brief Parse yin submodule.
579 *
580 * @param[in] ctx Context of YANG schemas.
581 * @param[in] data Data to read from.
582 * @param[out] submod Module to write to.
583 *
584 * @return LY_ERR values.
585 */
586LY_ERR
587yin_parse_submodule(struct ly_ctx *ctx, const char *data, struct lysp_submodule **submod)
588{
589 LY_ERR ret = LY_SUCCESS;
590 enum yang_keyword kw = YANG_NONE;
591 struct lyxml_context xml_ctx;
592 struct lysp_submodule *mod_p = NULL;
593 const char *prefix, *name;
594 size_t prefix_len, name_len;
David Sedlák3017da42019-02-15 09:48:04 +0100595
David Sedlákd5318ee2019-02-15 10:14:50 +0100596 /* initialize xml context */
597 memset(&xml_ctx, 0, sizeof xml_ctx);
598 xml_ctx.ctx = ctx;
599 xml_ctx.line = 1;
David Sedlák3017da42019-02-15 09:48:04 +0100600
David Sedlákd5318ee2019-02-15 10:14:50 +0100601 /* check submodule */
602 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
603 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
David Sedlák18730132019-03-15 15:51:34 +0100604 kw = match_keyword(name, name_len, prefix_len);
David Sedlákd5318ee2019-02-15 10:14:50 +0100605 if (kw == YANG_MODULE) {
606 LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
607 ret = LY_EINVAL;
608 goto cleanup;
609 } else if (kw != YANG_SUBMODULE) {
David Sedlák0a875b42019-03-07 22:24:05 +0100610 LOGVAL_YANG(&xml_ctx, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
611 ly_stmt2str(kw));
David Sedlákd5318ee2019-02-15 10:14:50 +0100612 ret = LY_EVALID;
613 goto cleanup;
614 }
David Sedlák3017da42019-02-15 09:48:04 +0100615
David Sedlákd5318ee2019-02-15 10:14:50 +0100616 /* allocate module */
617 mod_p = calloc(1, sizeof *mod_p);
618 LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
619 mod_p->parsing = 1;
David Sedlák3017da42019-02-15 09:48:04 +0100620
David Sedlákd5318ee2019-02-15 10:14:50 +0100621 /* parser submodule substatements */
622 //ret = parse_submod(&xml_ctx, &data, mod_p);
623 LY_CHECK_GOTO(ret, cleanup);
David Sedlák3017da42019-02-15 09:48:04 +0100624
David Sedlákd5318ee2019-02-15 10:14:50 +0100625 mod_p->parsing = 0;
626 *submod = mod_p;
David Sedlák3017da42019-02-15 09:48:04 +0100627
David Sedlákd5318ee2019-02-15 10:14:50 +0100628cleanup:
629 if (ret) {
630 lysp_submodule_free(ctx, mod_p);
631 }
David Sedlák3017da42019-02-15 09:48:04 +0100632
David Sedlákd5318ee2019-02-15 10:14:50 +0100633 lyxml_context_clear(&xml_ctx);
634 return ret;
635}
David Sedlák3017da42019-02-15 09:48:04 +0100636
David Sedlákd5318ee2019-02-15 10:14:50 +0100637/**
638 * @brief Parse yin module.
639 *
640 * @param[in] ctx Context of YANG schemas.
641 * @param[in] data Data to read from.
642 * @param[out] mod Module to write to.
643 *
644 * @return LY_ERR values.
645 */
David Sedlák3b4db242018-10-19 16:11:01 +0200646LY_ERR
David Sedlák3017da42019-02-15 09:48:04 +0100647yin_parse_module(struct ly_ctx *ctx, const char *data, struct lys_module *mod)
David Sedlák3b4db242018-10-19 16:11:01 +0200648{
David Sedláke4889912018-11-02 09:52:40 +0100649 LY_ERR ret = LY_SUCCESS;
650 enum yang_keyword kw = YANG_NONE;
David Sedlák3b4db242018-10-19 16:11:01 +0200651 struct lyxml_context xml_ctx;
David Sedlák3017da42019-02-15 09:48:04 +0100652 struct lysp_module *mod_p = NULL;
653 const char *prefix, *name;
654 size_t prefix_len, name_len;
David Sedlák3b4db242018-10-19 16:11:01 +0200655
David Sedlák3017da42019-02-15 09:48:04 +0100656 /* initialize xml context */
David Sedláke4889912018-11-02 09:52:40 +0100657 memset(&xml_ctx, 0, sizeof xml_ctx);
658 xml_ctx.ctx = ctx;
659 xml_ctx.line = 1;
660
David Sedlák3017da42019-02-15 09:48:04 +0100661 /* check submodule */
David Sedláke4889912018-11-02 09:52:40 +0100662 ret = lyxml_get_element(&xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
David Sedlák3017da42019-02-15 09:48:04 +0100663 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
David Sedlák18730132019-03-15 15:51:34 +0100664 kw = match_keyword(name, name_len, prefix_len);
David Sedláke4889912018-11-02 09:52:40 +0100665 if (kw == YANG_SUBMODULE) {
David Sedlák3017da42019-02-15 09:48:04 +0100666 LOGERR(ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
667 ret = LY_EINVAL;
668 goto cleanup;
669 } else if (kw != YANG_MODULE) {
David Sedlák0a875b42019-03-07 22:24:05 +0100670 LOGVAL_YANG(&xml_ctx, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
671 ly_stmt2str(kw));
David Sedlák3017da42019-02-15 09:48:04 +0100672 ret = LY_EVALID;
673 goto cleanup;
David Sedláke4889912018-11-02 09:52:40 +0100674 }
675
David Sedlák3017da42019-02-15 09:48:04 +0100676 /* allocate module */
677 mod_p = calloc(1, sizeof *mod_p);
678 LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
679 mod_p->mod = mod;
680 mod_p->parsing = 1;
David Sedláke4889912018-11-02 09:52:40 +0100681
David Sedlák3017da42019-02-15 09:48:04 +0100682 /* parser module substatements */
683 ret = parse_mod(&xml_ctx, &data, &mod_p);
684 LY_CHECK_GOTO(ret, cleanup);
David Sedlák2e411422018-12-17 02:35:39 +0100685
David Sedlák3017da42019-02-15 09:48:04 +0100686 mod_p->parsing = 0;
687 mod->parsed = mod_p;
688
689cleanup:
690 if (ret) {
691 lysp_module_free(mod_p);
692 }
693
David Sedlák2e411422018-12-17 02:35:39 +0100694 lyxml_context_clear(&xml_ctx);
695 return ret;
David Sedlák3b4db242018-10-19 16:11:01 +0200696}