blob: 7b48c3833f21b93841ddf037f942a3f5be34318b [file] [log] [blame]
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001/**
Michal Vaskoafac7822020-10-20 14:22:26 +02002 * @file in.c
Radek Krejcif0e1ba52020-05-22 15:14:35 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskoafac7822020-10-20 14:22:26 +02004 * @brief libyang input functions.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02005 *
Michal Vaskoafac7822020-10-20 14:22:26 +02006 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02007 *
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
13 */
14
15#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
17
18#ifdef __APPLE__
19#define _DARWIN_C_SOURCE /* F_GETPATH */
20#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +020021
Christian Hopps6f326212021-03-23 12:37:29 -040022#if defined(__NetBSD__) || defined(__OpenBSD__)
23/* realpath */
24#define _XOPEN_SOURCE
25#define _XOPEN_SOURCE_EXTENDED /* realpath */
26#endif
27
Michal Vaskoafac7822020-10-20 14:22:26 +020028#include "in.h"
29#include "in_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020030
Radek Krejcif0e1ba52020-05-22 15:14:35 +020031#include <errno.h>
32#include <fcntl.h>
33#include <limits.h>
Radek Krejci47fab892020-11-05 17:02:41 +010034#include <stdint.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020035#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020036#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020037#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020038#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020039
Radek Krejcica376bd2020-06-11 16:04:06 +020040#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020041#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020042#include "dict.h"
43#include "log.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020044#include "parser_data.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020045#include "parser_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010046#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010047#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010048#include "tree_data.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020049#include "tree_data_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010050#include "tree_schema.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020051#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020052
53API LY_IN_TYPE
54ly_in_type(const struct ly_in *in)
55{
56 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
57 return in->type;
58}
59
60API LY_ERR
61ly_in_new_fd(int fd, struct ly_in **in)
62{
63 size_t length;
64 char *addr;
65
66 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
67
68 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
69 if (!addr) {
70 LOGERR(NULL, LY_EINVAL, "Empty input file.");
71 return LY_EINVAL;
72 }
73
74 *in = calloc(1, sizeof **in);
75 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
76
77 (*in)->type = LY_IN_FD;
78 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020079 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +010080 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020081 (*in)->length = length;
82
83 return LY_SUCCESS;
84}
85
86API int
87ly_in_fd(struct ly_in *in, int fd)
88{
89 int prev_fd;
90 size_t length;
91 const char *addr;
92
93 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
94
95 prev_fd = in->method.fd;
96
97 if (fd != -1) {
98 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
99 if (!addr) {
100 LOGERR(NULL, LY_EINVAL, "Empty input file.");
101 return -1;
102 }
103
Michal Vasko22df3f02020-08-24 13:29:22 +0200104 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200105
106 in->method.fd = fd;
107 in->current = in->start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +0100108 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200109 in->length = length;
110 }
111
112 return prev_fd;
113}
114
115API LY_ERR
116ly_in_new_file(FILE *f, struct ly_in **in)
117{
118 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
119
120 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
121
122 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
123 (*in)->type = LY_IN_FILE;
124 (*in)->method.f = f;
125
126 return LY_SUCCESS;
127}
128
129API FILE *
130ly_in_file(struct ly_in *in, FILE *f)
131{
132 FILE *prev_f;
133
134 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
135
136 prev_f = in->method.f;
137
138 if (f) {
139 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
140 in->type = LY_IN_FD;
141 in->method.fd = fileno(prev_f);
142 if (ly_in_fd(in, fileno(f)) == -1) {
143 in->type = LY_IN_FILE;
144 in->method.f = prev_f;
145 return NULL;
146 }
147
148 /* if success, convert the result back */
149 in->type = LY_IN_FILE;
150 in->method.f = f;
151 }
152
153 return prev_f;
154}
155
156API LY_ERR
157ly_in_new_memory(const char *str, struct ly_in **in)
158{
159 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
160
161 *in = calloc(1, sizeof **in);
162 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
163
164 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200165 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100166 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200167
168 return LY_SUCCESS;
169}
170
Michal Vasko63f3d842020-07-08 10:10:14 +0200171API const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200172ly_in_memory(struct ly_in *in, const char *str)
173{
174 const char *data;
175
176 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
177
178 data = in->current;
179
180 if (str) {
181 in->start = in->current = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100182 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200183 }
184
185 return data;
186}
187
188API LY_ERR
189ly_in_reset(struct ly_in *in)
190{
191 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
192
Michal Vasko63f3d842020-07-08 10:10:14 +0200193 in->current = in->func_start = in->start;
Radek Krejcid54412f2020-12-17 20:25:35 +0100194 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200195 return LY_SUCCESS;
196}
197
198API LY_ERR
199ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
200{
Radek Krejci0f969882020-08-21 16:56:47 +0200201 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200202 char *fp;
203 int fd;
204
205 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
206
207 if (len) {
208 fp = strndup(filepath, len);
209 } else {
210 fp = strdup(filepath);
211 }
212
213 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200214 LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp),
Michal Vasko69730152020-10-09 16:30:07 +0200215 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200216
217 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
218
219 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
220 (*in)->type = LY_IN_FILEPATH;
221 (*in)->method.fpath.fd = fd;
222 (*in)->method.fpath.filepath = fp;
223
224 return LY_SUCCESS;
225}
226
227API const char *
228ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
229{
230 int fd, prev_fd;
231 char *fp = NULL;
232
233 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
234
235 if (!filepath) {
236 return in->method.fpath.filepath;
237 }
238
239 if (len) {
240 fp = strndup(filepath, len);
241 } else {
242 fp = strdup(filepath);
243 }
244
245 /* replace filepath */
246 fd = open(fp, O_RDONLY);
247 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
248
249 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
250 in->type = LY_IN_FD;
251 prev_fd = ly_in_fd(in, fd);
252 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
253
254 /* and convert the result back */
255 in->type = LY_IN_FILEPATH;
256 close(prev_fd);
257 free(in->method.fpath.filepath);
258 in->method.fpath.fd = fd;
259 in->method.fpath.filepath = fp;
260
261 return NULL;
262}
263
264void
265lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
266{
267 char path[PATH_MAX];
Michal Vasko69730152020-10-09 16:30:07 +0200268
Michal Vasko5aa44c02020-06-29 11:47:02 +0200269#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200270 char proc_path[32];
271 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200272#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200273
274 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
275 if (*filepath) {
276 /* filepath already set */
277 return;
278 }
279
280 switch (in->type) {
281 case LY_IN_FILEPATH:
282 if (realpath(in->method.fpath.filepath, path) != NULL) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200283 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200284 } else {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200285 lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200286 }
287
288 break;
289 case LY_IN_FD:
290#ifdef __APPLE__
291 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200292 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200293 }
294#else
295 /* get URI if there is /proc */
296 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
297 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200298 lydict_insert(ctx, path, len, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200299 }
300#endif
301 break;
302 case LY_IN_MEMORY:
303 case LY_IN_FILE:
304 /* nothing to do */
305 break;
306 default:
307 LOGINT(ctx);
308 break;
309 }
310
311}
312
313API void
Radek Krejci857189e2020-09-01 13:26:36 +0200314ly_in_free(struct ly_in *in, ly_bool destroy)
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200315{
316 if (!in) {
317 return;
318 } else if (in->type == LY_IN_ERROR) {
319 LOGINT(NULL);
320 return;
321 }
322
323 if (destroy) {
324 if (in->type == LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200325 free((char *)in->start);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200326 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +0200327 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200328
329 if (in->type == LY_IN_FILE) {
330 fclose(in->method.f);
331 } else {
332 close(in->method.fd);
333
334 if (in->type == LY_IN_FILEPATH) {
335 free(in->method.fpath.filepath);
336 }
337 }
338 }
339 } else if (in->type != LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200340 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200341
342 if (in->type == LY_IN_FILEPATH) {
343 close(in->method.fpath.fd);
344 free(in->method.fpath.filepath);
345 }
346 }
347
348 free(in);
349}
Michal Vasko63f3d842020-07-08 10:10:14 +0200350
351LY_ERR
352ly_in_read(struct ly_in *in, void *buf, size_t count)
353{
354 if (in->length && (in->length - (in->current - in->start) < count)) {
355 /* EOF */
356 return LY_EDENIED;
357 }
358
359 memcpy(buf, in->current, count);
360 in->current += count;
361 return LY_SUCCESS;
362}
363
364API size_t
365ly_in_parsed(const struct ly_in *in)
366{
367 return in->current - in->func_start;
368}
369
370LY_ERR
371ly_in_skip(struct ly_in *in, size_t count)
372{
373 if (in->length && (in->length - (in->current - in->start) < count)) {
374 /* EOF */
375 return LY_EDENIED;
376 }
377
378 in->current += count;
379 return LY_SUCCESS;
380}
Radek Krejci1798aae2020-07-14 13:26:06 +0200381
382void
383lyd_ctx_free(struct lyd_ctx *lydctx)
384{
Michal Vasko32711382020-12-03 14:14:31 +0100385 ly_set_erase(&lydctx->node_types, NULL);
386 ly_set_erase(&lydctx->meta_types, NULL);
387 ly_set_erase(&lydctx->node_when, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200388}
389
390LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100391lyd_parser_find_operation(const struct lyd_node *parent, uint32_t int_opts, struct lyd_node **op)
392{
393 const struct lyd_node *iter;
394
395 *op = NULL;
396
397 if (!parent) {
398 /* no parent, nothing to look for */
399 return LY_SUCCESS;
400 }
401
402 /* we need to find the operation node if it already exists */
403 for (iter = parent; iter; iter = lyd_parent(iter)) {
404 if (iter->schema && (iter->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
405 break;
406 }
407 }
408
409 if (!iter) {
410 /* no operation found */
411 return LY_SUCCESS;
412 }
413
414 if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY))) {
415 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent %s \"%s\" node when not parsing any operation.",
416 lys_nodetype2str(iter->schema->nodetype), iter->schema->name);
417 return LY_EINVAL;
418 } else if ((iter->schema->nodetype == LYS_RPC) && !(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY))) {
419 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent RPC \"%s\" node when not parsing RPC nor rpc-reply.",
420 iter->schema->name);
421 return LY_EINVAL;
422 } else if ((iter->schema->nodetype == LYS_ACTION) && !(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY))) {
423 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent action \"%s\" node when not parsing action nor rpc-reply.",
424 iter->schema->name);
425 return LY_EINVAL;
426 } else if ((iter->schema->nodetype == LYS_NOTIF) && !(int_opts & LYD_INTOPT_NOTIF)) {
427 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent notification \"%s\" node when not parsing a notification.",
428 iter->schema->name);
429 return LY_EINVAL;
430 }
431
432 *op = (struct lyd_node *)iter;
433 return LY_SUCCESS;
434}
435
436LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200437lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
438{
Michal Vaskoe0665742021-02-11 11:08:44 +0100439 LY_ERR rc = LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100440
Radek Krejciddace2c2021-01-08 11:30:56 +0100441 LOG_LOCSET(snode, NULL, NULL, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200442
Michal Vaskoe0665742021-02-11 11:08:44 +0100443 if ((lydctx->parse_opts & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Michal Vasko224e7772021-02-18 14:22:33 +0100444 LOGVAL(lydctx->data_ctx->ctx, LY_VCODE_UNEXPNODE, "state", snode->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100445 rc = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100446 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200447 }
448
Michal Vaskoe0665742021-02-11 11:08:44 +0100449 if (snode->nodetype == LYS_RPC) {
Michal Vasko2552ea32020-12-08 15:32:34 +0100450 if (lydctx->int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200451 if (lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100452 goto error_node_dup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200453 }
454 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100455 goto error_node_inval;
456 }
457 } else if (snode->nodetype == LYS_ACTION) {
458 if (lydctx->int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) {
459 if (lydctx->op_node) {
460 goto error_node_dup;
461 }
462 } else {
463 goto error_node_inval;
Radek Krejci1798aae2020-07-14 13:26:06 +0200464 }
465 } else if (snode->nodetype == LYS_NOTIF) {
466 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
467 if (lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100468 goto error_node_dup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200469 }
470 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100471 goto error_node_inval;
Radek Krejci1798aae2020-07-14 13:26:06 +0200472 }
473 }
474
Michal Vaskoe0665742021-02-11 11:08:44 +0100475 /* success */
476 goto cleanup;
477
478error_node_dup:
479 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
480 lys_nodetype2str(snode->nodetype), snode->name, lys_nodetype2str(lydctx->op_node->schema->nodetype),
481 lydctx->op_node->schema->name);
482 rc = LY_EVALID;
483 goto cleanup;
484
485error_node_inval:
486 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\".", lys_nodetype2str(snode->nodetype),
487 snode->name);
488 rc = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100489
490cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100491 LOG_LOCBACK(1, 0, 0, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100492 return rc;
Radek Krejci1798aae2020-07-14 13:26:06 +0200493}
494
495LY_ERR
496lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const char *value, size_t value_len,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200497 ly_bool *dynamic, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, struct lyd_node **node)
Radek Krejci1798aae2020-07-14 13:26:06 +0200498{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200499 ly_bool incomplete;
Radek Krejci1798aae2020-07-14 13:26:06 +0200500
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200501 LY_CHECK_RET(lyd_create_term(schema, value, value_len, dynamic, format, prefix_data, hints, &incomplete, node));
502
Michal Vaskoe0665742021-02-11 11:08:44 +0100503 if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko32711382020-12-03 14:14:31 +0100504 LY_CHECK_RET(ly_set_add(&lydctx->node_types, *node, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200505 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200506 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200507}
508
509LY_ERR
510lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200511 const char *name, size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
512 void *prefix_data, uint32_t hints)
Radek Krejci1798aae2020-07-14 13:26:06 +0200513{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200514 ly_bool incomplete;
Michal Vaskob68571a2020-11-06 17:18:41 +0100515 struct lyd_meta *first = NULL;
516
517 if (meta && *meta) {
518 /* remember the first metadata */
519 first = *meta;
520 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200521
522 LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
Michal Vasko871a0252020-11-11 18:35:24 +0100523 hints, 0, &incomplete));
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200524
Michal Vaskoe0665742021-02-11 11:08:44 +0100525 if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko32711382020-12-03 14:14:31 +0100526 LY_CHECK_RET(ly_set_add(&lydctx->meta_types, *meta, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200527 }
Michal Vaskob68571a2020-11-06 17:18:41 +0100528
529 if (first) {
530 /* always return the first metadata */
531 *meta = first;
532 }
533
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200534 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200535}