blob: c5a0e2a270a1063531e91805cdc3b407de17e601 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_data_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions for data trees
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
13 */
Michal Vasko43297a02021-05-19 11:12:37 +020014
15#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejcie7b95092019-05-15 11:03:07 +020016
17#include <assert.h>
Michal Vasko43297a02021-05-19 11:12:37 +020018#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020019#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020020#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020021#include <string.h>
Michal Vasko43297a02021-05-19 11:12:37 +020022#include <time.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023
Radek Krejci535ea9f2020-05-29 16:01:05 +020024#include "common.h"
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010025#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020026#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020028#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020031#include "parser_data.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010032#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020033#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020036#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010037#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020038#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020039#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020040#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010041#include "xml.h"
aPiecekdf23eee2021-10-07 12:21:50 +020042#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020043
Michal Vaskod7c048c2021-05-18 16:12:55 +020044/**
45 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
46 *
47 * @param[in] first_inst Instance of the cache entry.
48 * @param[in,out] dup_inst_cache Duplicate instance cache.
49 * @return Instance cache entry.
50 */
51static struct lyd_dup_inst *
52lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
53{
54 struct lyd_dup_inst *item;
55 LY_ARRAY_COUNT_TYPE u;
56
57 LY_ARRAY_FOR(*dup_inst_cache, u) {
58 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
59 return &(*dup_inst_cache)[u];
60 }
61 }
62
63 /* it was not added yet, add it now */
64 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
65
66 return item;
67}
68
69LY_ERR
70lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
71{
72 struct lyd_dup_inst *dup_inst;
73
74 if (!*inst || !lysc_is_dup_inst_list((*inst)->schema)) {
75 /* no match or not dup-inst list, inst is unchanged */
76 return LY_SUCCESS;
77 }
78
79 /* there can be more exact same instances and we must make sure we do not match a single node more times */
80 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
81 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
82
83 if (!dup_inst->used) {
84 /* we did not cache these instances yet, do so */
85 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
86 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
87 }
88
89 if (dup_inst->used == dup_inst->inst_set->count) {
90 /* we have used all the instances */
91 *inst = NULL;
92 } else {
93 assert(dup_inst->used < dup_inst->inst_set->count);
94
95 /* use another instance */
96 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
97 ++dup_inst->used;
98 }
99
100 return LY_SUCCESS;
101}
102
103void
104lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
105{
106 LY_ARRAY_COUNT_TYPE u;
107
108 LY_ARRAY_FOR(dup_inst, u) {
109 ly_set_free(dup_inst[u].inst_set, NULL);
110 }
111 LY_ARRAY_FREE(dup_inst);
112}
113
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200114struct lyd_node *
115lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200116 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200117{
118 const struct lysc_node *siter = NULL;
119 struct lyd_node *match = NULL;
120
121 assert(parent || module);
122 assert(!last || (slast && *slast));
123
124 if (slast) {
125 siter = *slast;
126 }
127
128 if (last && last->next && (last->next->schema == siter)) {
129 /* return next data instance */
130 return last->next;
131 }
132
133 /* find next schema node data instance */
134 while ((siter = lys_getnext(siter, parent, module, 0))) {
135 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
136 break;
137 }
138 }
139
140 if (slast) {
141 *slast = siter;
142 }
143 return match;
144}
145
Radek Krejcie7b95092019-05-15 11:03:07 +0200146struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100147lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200148{
149 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100150
151 if (!node->schema) {
152 return &((struct lyd_node_opaq *)node)->child;
153 } else {
154 switch (node->schema->nodetype) {
155 case LYS_CONTAINER:
156 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100157 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100158 case LYS_ACTION:
159 case LYS_NOTIF:
160 return &((struct lyd_node_inner *)node)->child;
161 default:
162 return NULL;
163 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200164 }
165}
166
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100167LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200168lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
169{
170 LY_ERR ret = LY_SUCCESS;
171 char *var_name = NULL, *var_value = NULL;
172 struct lyxp_var *item;
173
174 if (!vars || !name || !value) {
175 return LY_EINVAL;
176 }
177
178 /* If variable is already defined then change its value. */
179 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
180 var_value = strdup(value);
181 LY_CHECK_RET(!var_value, LY_EMEM);
182
183 /* Set new value. */
184 free(item->value);
185 item->value = var_value;
186 } else {
187 var_name = strdup(name);
188 var_value = strdup(value);
189 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
190
191 /* Add new variable. */
192 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
193 item->name = var_name;
194 item->value = var_value;
195 }
196
197 return LY_SUCCESS;
198
199error:
200 free(var_name);
201 free(var_value);
202 return ret;
203}
204
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100205LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200206lyxp_vars_free(struct lyxp_var *vars)
207{
208 LY_ARRAY_COUNT_TYPE u;
209
210 if (!vars) {
211 return;
212 }
213
214 LY_ARRAY_FOR(vars, u) {
215 free(vars[u].name);
216 free(vars[u].value);
217 }
218
219 LY_ARRAY_FREE(vars);
220}
221
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100222LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200223lyd_child_no_keys(const struct lyd_node *node)
224{
225 struct lyd_node **children;
226
227 if (!node) {
228 return NULL;
229 }
230
231 if (!node->schema) {
232 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100233 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200234 }
235
Michal Vaskoe0665742021-02-11 11:08:44 +0100236 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200237 if (children) {
238 struct lyd_node *child = *children;
239 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
240 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200241 }
242 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200243 } else {
244 return NULL;
245 }
246}
Michal Vasko9b368d32020-02-14 13:53:31 +0100247
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100248LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100249lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100250{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100251 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100252
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100253 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100254 return NULL;
255 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100256
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100257 if (!node->schema) {
258 opaq = (struct lyd_node_opaq *)node;
259 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200260 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100261 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200262 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100263 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
264 default:
265 return NULL;
266 }
267 }
268
Michal Vaskoef53c812021-10-13 10:21:03 +0200269 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100270}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100271
Michal Vasko598063b2021-07-19 11:39:05 +0200272void
273lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
274{
275 int cmp;
276 struct lyd_node *first;
277
278 assert(node && mod);
279
280 if (!*node) {
281 return;
282 }
283
284 first = *node;
285 cmp = strcmp(lyd_owner_module(first)->name, mod->name);
286 if (cmp > 0) {
287 /* there may be some preceding data */
288 while (first->prev->next) {
289 first = first->prev;
290 if (lyd_owner_module(first) == mod) {
291 cmp = 0;
292 break;
293 }
294 }
295 }
296
297 if (cmp == 0) {
298 /* there may be some preceding data belonging to this module */
299 while (first->prev->next) {
300 if (lyd_owner_module(first->prev) != mod) {
301 break;
302 }
303 first = first->prev;
304 }
305 }
306
307 if (cmp < 0) {
308 /* there may be some following data */
309 LY_LIST_FOR(first, first) {
310 if (lyd_owner_module(first) == mod) {
311 cmp = 0;
312 break;
313 }
314 }
315 }
316
317 if (cmp == 0) {
318 /* we have found the first module data node */
319 *node = first;
320 }
321}
322
Michal Vaskob1b5c262020-03-05 14:29:47 +0100323const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200324lyd_mod_next_module(struct lyd_node *tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t *i,
Radek Krejci0f969882020-08-21 16:56:47 +0200325 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100326{
327 struct lyd_node *iter;
328 const struct lys_module *mod;
329
330 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200331 if (module) {
332 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100333 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200334 } else {
335 mod = module;
336 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100337 }
338 } else {
339 do {
340 mod = ly_ctx_get_module_iter(ctx, i);
341 } while (mod && !mod->implemented);
342 }
343
344 /* find its data */
345 *first = NULL;
346 if (mod) {
347 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100348 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100349 *first = iter;
350 break;
351 }
352 }
353 }
354
355 return mod;
356}
357
358const struct lys_module *
359lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
360{
361 const struct lys_module *mod;
362
363 if (!*next) {
364 /* all data traversed */
365 *first = NULL;
366 return NULL;
367 }
368
369 *first = *next;
370
371 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100372 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100373 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100374 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100375 break;
376 }
377 }
378
379 return mod;
380}
Michal Vasko9f96a052020-03-10 09:41:45 +0100381
382LY_ERR
383lyd_parse_check_keys(struct lyd_node *node)
384{
385 const struct lysc_node *skey = NULL;
386 const struct lyd_node *key;
387
388 assert(node->schema->nodetype == LYS_LIST);
389
Radek Krejcia1c1e542020-09-29 16:06:52 +0200390 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100391 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
392 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100393 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100394 return LY_EVALID;
395 }
396
397 key = key->next;
398 }
399
400 return LY_SUCCESS;
401}
Michal Vasko60ea6352020-06-29 13:39:39 +0200402
403void
Michal Vaskoaac267d2022-01-17 13:34:48 +0100404lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts)
Michal Vasko60ea6352020-06-29 13:39:39 +0200405{
406 struct lyd_meta *meta2, *prev_meta = NULL;
407
Michal Vaskoa5705e52020-12-09 18:15:14 +0100408 if (lysc_has_when(node->schema)) {
Michal Vaskof9b68342021-07-23 13:50:59 +0200409 if (!(parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200410 /* remember we need to evaluate this node's when */
Michal Vaskof9b68342021-07-23 13:50:59 +0200411 LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200412 }
413 }
414
Michal Vasko60ea6352020-06-29 13:39:39 +0200415 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200416 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
417 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200418 /* node is default according to the metadata */
419 node->flags |= LYD_DEFAULT;
420
421 /* delete the metadata */
422 if (prev_meta) {
423 prev_meta->next = meta2->next;
424 } else {
425 *meta = (*meta)->next;
426 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200427 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200428 break;
429 }
430
431 prev_meta = meta2;
432 }
433}
434
Michal Vasko213d3f72022-02-23 16:22:53 +0100435/**
436 * @brief Check list node parsed into an opaque node for the reason.
437 *
438 * @param[in] node Opaque node.
439 * @param[in] snode Schema node of @p opaq.
440 * @return LY_SUCCESS if the node is valid;
441 * @return LY_ERR on error.
442 */
443static LY_ERR
444lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
445{
446 LY_ERR ret = LY_SUCCESS;
447 struct ly_set key_set = {0};
448 const struct lysc_node *key = NULL;
449 const struct lyd_node *child;
450 const struct lyd_node_opaq *opaq_k;
451 uint32_t i;
452
453 assert(!node->schema);
454
455 /* get all keys into a set */
456 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
457 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
458 }
459
460 LY_LIST_FOR(lyd_child(node), child) {
461 if (child->schema) {
462 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
463 LYD_NAME(child));
464 ret = LY_EINVAL;
465 goto cleanup;
466 }
467
468 opaq_k = (struct lyd_node_opaq *)child;
469
470 /* find the key schema node */
471 for (i = 0; i < key_set.count; ++i) {
472 key = key_set.snodes[i];
473 if (!strcmp(key->name, opaq_k->name.name)) {
474 break;
475 }
476 }
477 if (i == key_set.count) {
478 /* some other node, skip */
479 continue;
480 }
481
482 /* key found */
483 ly_set_rm_index(&key_set, i, NULL);
484
485 /* check value */
486 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
487 opaq_k->val_prefix_data);
488 LY_CHECK_GOTO(ret, cleanup);
489 }
490
491 if (key_set.count) {
492 /* missing keys */
493 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
494 ret = LY_EVALID;
495 goto cleanup;
496 }
497
498cleanup:
499 ly_set_erase(&key_set, NULL);
500 return ret;
501}
502
503LIBYANG_API_DEF LY_ERR
504lyd_parse_opaq_error(const struct lyd_node *node)
505{
506 const struct ly_ctx *ctx;
507 const struct lyd_node_opaq *opaq;
508 const struct lyd_node *parent;
509 const struct lys_module *mod;
510 const struct lysc_node *snode;
511
512 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
513
514 ctx = LYD_CTX(node);
515 opaq = (struct lyd_node_opaq *)node;
516 parent = lyd_parent(node);
517
518 /* is always filled by parsers */
519 LY_CHECK_ARG_RET(ctx, opaq->name.module_ns, LY_EINVAL);
520
521 /* module */
522 switch (opaq->format) {
523 case LY_VALUE_XML:
524 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
525 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
526 if (!mod) {
527 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" in the context.",
528 opaq->name.module_ns);
529 return LY_EVALID;
530 }
531 } else {
532 /* inherit */
533 mod = parent->schema->module;
534 }
535 break;
536 case LY_VALUE_JSON:
537 case LY_VALUE_LYB:
538 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
539 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
540 if (!mod) {
541 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" in the context.", opaq->name.module_name);
542 return LY_EVALID;
543 }
544 } else {
545 /* inherit */
546 mod = parent->schema->module;
547 }
548 break;
549 default:
550 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
551 return LY_EINVAL;
552 }
553
554 /* schema */
555 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
556 if (!snode) {
557 if (parent) {
558 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
559 LYD_NAME(parent));
560 } else {
561 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
562 }
563 return LY_EVALID;
564 }
565
566 if (snode->nodetype & LYD_NODE_TERM) {
567 /* leaf / leaf-list */
568 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
569 } else if (snode->nodetype == LYS_LIST) {
570 /* list */
571 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
572 } else if (snode->nodetype & LYD_NODE_INNER) {
573 /* inner node */
574 if (opaq->value) {
575 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
576 lys_nodetype2str(snode->nodetype), snode->name);
577 return LY_EVALID;
578 }
579 } else {
580 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
581 return LY_EINVAL;
582 }
583
584 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
585 return LY_EINVAL;
586}
587
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100588LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400589lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200590{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200591 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
592
Michal Vasko33876022021-04-27 16:42:24 +0200593 return value->_canonical ? value->_canonical :
594 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200595}
596
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100597LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100598lyd_any_value_str(const struct lyd_node *any, char **value_str)
599{
600 const struct lyd_node_any *a;
601 struct lyd_node *tree = NULL;
602 const char *str = NULL;
603 ly_bool dynamic = 0;
604 LY_ERR ret = LY_SUCCESS;
605
606 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200607 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100608
609 a = (struct lyd_node_any *)any;
610 *value_str = NULL;
611
612 if (!a->value.str) {
613 /* there is no value in the union */
614 return LY_SUCCESS;
615 }
616
617 switch (a->value_type) {
618 case LYD_ANYDATA_LYB:
619 /* parse into a data tree */
620 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
621 LY_CHECK_GOTO(ret, cleanup);
622 dynamic = 1;
623 break;
624 case LYD_ANYDATA_DATATREE:
625 tree = a->value.tree;
626 break;
627 case LYD_ANYDATA_STRING:
628 case LYD_ANYDATA_XML:
629 case LYD_ANYDATA_JSON:
630 /* simply use the string */
631 str = a->value.str;
632 break;
633 }
634
635 if (tree) {
636 /* print into a string */
637 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
638 LY_CHECK_GOTO(ret, cleanup);
639 } else {
640 assert(str);
641 *value_str = strdup(str);
642 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
643 }
644
645 /* success */
646
647cleanup:
648 if (dynamic) {
649 lyd_free_all(tree);
650 }
651 return ret;
652}
653
Jan Kundrátc6e39de2021-12-09 16:01:19 +0100654LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200655lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
656{
657 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200658
Michal Vaskoa820c312021-02-05 16:33:00 +0100659 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200660 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200661
662 t = (struct lyd_node_any *)trg;
663
664 /* free trg */
665 switch (t->value_type) {
666 case LYD_ANYDATA_DATATREE:
667 lyd_free_all(t->value.tree);
668 break;
669 case LYD_ANYDATA_STRING:
670 case LYD_ANYDATA_XML:
671 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100672 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200673 break;
674 case LYD_ANYDATA_LYB:
675 free(t->value.mem);
676 break;
677 }
678 t->value.str = NULL;
679
680 if (!value) {
681 /* only free value in this case */
682 return LY_SUCCESS;
683 }
684
685 /* copy src */
686 t->value_type = value_type;
687 switch (value_type) {
688 case LYD_ANYDATA_DATATREE:
689 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200690 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200691 }
692 break;
693 case LYD_ANYDATA_STRING:
694 case LYD_ANYDATA_XML:
695 case LYD_ANYDATA_JSON:
696 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200697 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200698 }
699 break;
700 case LYD_ANYDATA_LYB:
701 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200702 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200703 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200704 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200705 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200706 memcpy(t->value.mem, value->mem, len);
707 }
708 break;
709 }
710
711 return LY_SUCCESS;
712}
713
Michal Vasko106f0862021-11-02 11:49:27 +0100714const struct lysc_node *
715lyd_node_schema(const struct lyd_node *node)
716{
717 const struct lysc_node *schema = NULL;
718 const struct lyd_node *prev_iter = NULL, *iter;
719 const struct lys_module *mod;
720
721 if (!node) {
722 return NULL;
723 } else if (node->schema) {
724 return node->schema;
725 }
726
727 /* get schema node of an opaque node */
728 do {
729 /* get next data node */
730 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
731
732 /* get equivalent schema node */
733 if (iter->schema) {
734 schema = iter->schema;
735 } else {
736 /* get module */
737 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +0100738 if (!mod && !schema) {
739 /* top-level opaque node has unknown module */
740 break;
741 }
Michal Vasko106f0862021-11-02 11:49:27 +0100742
743 /* get schema node */
744 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
745 }
Michal Vaskod2f404f2021-11-04 15:37:11 +0100746
747 /* remember to move to the descendant */
748 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +0100749 } while (schema && (iter != node));
750
751 return schema;
752}
753
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100754void
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100755lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
756{
757 if (*root && (lyd_owner_module(*root) != mod)) {
758 /* there are no data of mod so this is simply the first top-level sibling */
759 mod = NULL;
760 }
761
762 if ((*root != to_del) || (*root)->parent) {
763 return;
764 }
765
Michal Vasko598063b2021-07-19 11:39:05 +0200766 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
767 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100768 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +0200769 } else {
770 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100771 }
772}
773
774void
Radek Krejci8df109d2021-04-23 12:19:08 +0200775ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100776{
777 struct ly_set *ns_list;
778 struct lysc_prefix *prefixes;
779 uint32_t i;
780 LY_ARRAY_COUNT_TYPE u;
781
782 if (!prefix_data) {
783 return;
784 }
785
786 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200787 case LY_VALUE_XML:
Michal Vaskoaac267d2022-01-17 13:34:48 +0100788 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100789 ns_list = prefix_data;
790 for (i = 0; i < ns_list->count; ++i) {
791 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
792 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
793 }
794 ly_set_free(ns_list, free);
795 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200796 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100797 prefixes = prefix_data;
798 LY_ARRAY_FOR(prefixes, u) {
799 free(prefixes[u].prefix);
800 }
801 LY_ARRAY_FREE(prefixes);
802 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200803 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200804 case LY_VALUE_SCHEMA:
805 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200806 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100807 break;
808 }
809}
810
811LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +0200812ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100813 void **prefix_data_p)
814{
815 LY_ERR ret = LY_SUCCESS;
816 struct lyxml_ns *ns;
817 struct lysc_prefix *prefixes = NULL, *orig_pref;
818 struct ly_set *ns_list, *orig_ns;
819 uint32_t i;
820 LY_ARRAY_COUNT_TYPE u;
821
822 assert(!*prefix_data_p);
823
824 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200825 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100826 *prefix_data_p = (void *)prefix_data;
827 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200828 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100829 /* copy all the value prefixes */
830 orig_pref = (struct lysc_prefix *)prefix_data;
831 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
832 *prefix_data_p = prefixes;
833
834 LY_ARRAY_FOR(orig_pref, u) {
835 if (orig_pref[u].prefix) {
836 prefixes[u].prefix = strdup(orig_pref[u].prefix);
837 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
838 }
839 prefixes[u].mod = orig_pref[u].mod;
840 LY_ARRAY_INCREMENT(prefixes);
841 }
842 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200843 case LY_VALUE_XML:
Michal Vaskoaac267d2022-01-17 13:34:48 +0100844 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100845 /* copy all the namespaces */
846 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
847 *prefix_data_p = ns_list;
848
849 orig_ns = (struct ly_set *)prefix_data;
850 for (i = 0; i < orig_ns->count; ++i) {
851 ns = calloc(1, sizeof *ns);
852 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
853 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
854
855 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
856 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
857 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
858 }
859 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
860 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
861 }
862 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200863 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200864 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200865 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100866 assert(!prefix_data);
867 *prefix_data_p = NULL;
868 break;
869 }
870
871cleanup:
872 if (ret) {
873 ly_free_prefix_data(format, *prefix_data_p);
874 *prefix_data_p = NULL;
875 }
876 return ret;
877}
878
879LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +0200880ly_store_prefix_data(const struct ly_ctx *ctx, const void *value, size_t value_len, LY_VALUE_FORMAT format,
Radek Krejci8df109d2021-04-23 12:19:08 +0200881 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100882{
883 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100884 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100885 const struct lyxml_ns *ns;
886 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100887 struct ly_set *ns_list;
888 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +0200889 const char *value_iter, *value_next, *value_end;
890 uint32_t substr_len;
891 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100892
893 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200894 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100895 /* copy all referenced modules as prefix - module pairs */
896 if (!*prefix_data_p) {
897 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100898 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +0200899 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100900 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100901 } else {
902 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +0200903 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100904 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100905 }
906
907 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +0200908 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +0200909 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200910 LY_CHECK_GOTO(ret = ly_value_prefix_next(value_iter, value_end, &substr_len, &is_prefix, &value_next), cleanup);
aPiecek83436bc2021-03-30 12:20:45 +0200911 if (is_prefix) {
912 /* we have a possible prefix. Do we already have the prefix? */
913 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
914 if (!mod) {
915 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
916 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200917 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +0200918 /* store a new prefix - module pair */
919 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
920 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100921
aPiecek83436bc2021-03-30 12:20:45 +0200922 val_pref->prefix = strndup(value_iter, substr_len);
923 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
924 val_pref->mod = mod;
925 } /* else it is not even defined */
926 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100927 }
928 }
929 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200930 case LY_VALUE_XML:
Michal Vaskoaac267d2022-01-17 13:34:48 +0100931 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100932 /* copy all referenced namespaces as prefix - namespace pairs */
933 if (!*prefix_data_p) {
934 /* new prefix data */
935 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoaac267d2022-01-17 13:34:48 +0100936 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100937 *prefix_data_p = ns_list;
938 } else {
939 /* reuse prefix data */
Michal Vaskoaac267d2022-01-17 13:34:48 +0100940 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100941 ns_list = *prefix_data_p;
942 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100943
Michal Vasko9fbd9692022-02-28 13:59:00 +0100944 /* store default namespace */
945 ns = lyxml_ns_get(prefix_data, NULL, 0);
946 if (ns) {
947 new_ns = calloc(1, sizeof *new_ns);
948 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
949 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
950
951 new_ns->prefix = NULL;
952 new_ns->uri = strdup(ns->uri);
953 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
954 }
955
Michal Vaskofc2cd072021-02-24 13:17:17 +0100956 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +0200957 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +0200958 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +0200959 LY_CHECK_GOTO(ret = ly_value_prefix_next(value_iter, value_end, &substr_len, &is_prefix, &value_next), cleanup);
aPiecek83436bc2021-03-30 12:20:45 +0200960 if (is_prefix) {
961 /* we have a possible prefix. Do we already have the prefix? */
962 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
963 if (!ns) {
964 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
965 if (ns) {
966 /* store a new prefix - namespace pair */
967 new_ns = calloc(1, sizeof *new_ns);
968 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
969 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +0100970
aPiecek83436bc2021-03-30 12:20:45 +0200971 new_ns->prefix = strndup(value_iter, substr_len);
972 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
973 new_ns->uri = strdup(ns->uri);
974 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
975 } /* else it is not even defined */
976 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100977 }
978 }
979 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200980 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200981 case LY_VALUE_SCHEMA_RESOLVED:
982 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +0200983 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +0100984 if (!*prefix_data_p) {
985 /* new prefix data - simply copy all the prefix data */
986 *format_p = format;
987 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
988 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100989 break;
990 }
991
992cleanup:
993 if (ret) {
994 ly_free_prefix_data(*format_p, *prefix_data_p);
995 *prefix_data_p = NULL;
996 }
997 return ret;
998}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100999
1000const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001001ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001002{
1003 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001004 case LY_VALUE_CANON:
1005 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001006 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001007 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001008 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001009 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001010 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001011 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001012 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001013 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001014 case LY_VALUE_LYB:
1015 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001016 default:
1017 break;
1018 }
1019
1020 return NULL;
1021}
Michal Vasko43297a02021-05-19 11:12:37 +02001022
Jan Kundrátc6e39de2021-12-09 16:01:19 +01001023LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001024ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1025{
1026 struct tm tm = {0};
1027 uint32_t i, frac_len;
1028 const char *frac;
1029 int64_t shift, shift_m;
1030 time_t t;
1031
1032 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1033
1034 tm.tm_year = atoi(&value[0]) - 1900;
1035 tm.tm_mon = atoi(&value[5]) - 1;
1036 tm.tm_mday = atoi(&value[8]);
1037 tm.tm_hour = atoi(&value[11]);
1038 tm.tm_min = atoi(&value[14]);
1039 tm.tm_sec = atoi(&value[17]);
1040
1041 t = timegm(&tm);
1042 i = 19;
1043
1044 /* fractions of a second */
1045 if (value[i] == '.') {
1046 ++i;
1047 frac = &value[i];
1048 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1049
1050 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001051 } else {
1052 frac = NULL;
1053 }
1054
1055 /* apply offset */
1056 if ((value[i] == 'Z') || (value[i] == 'z')) {
1057 /* zero shift */
1058 shift = 0;
1059 } else {
1060 shift = strtol(&value[i], NULL, 10);
1061 shift = shift * 60 * 60; /* convert from hours to seconds */
1062 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1063 /* correct sign */
1064 if (shift < 0) {
1065 shift_m *= -1;
1066 }
1067 /* connect hours and minutes of the shift */
1068 shift = shift + shift_m;
1069 }
1070
1071 /* we have to shift to the opposite way to correct the time */
1072 t -= shift;
1073
1074 *time = t;
1075 if (fractions_s) {
1076 if (frac) {
1077 *fractions_s = strndup(frac, frac_len);
1078 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1079 } else {
1080 *fractions_s = NULL;
1081 }
1082 }
1083 return LY_SUCCESS;
1084}
1085
Jan Kundrátc6e39de2021-12-09 16:01:19 +01001086LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001087ly_time_time2str(time_t time, const char *fractions_s, char **str)
1088{
1089 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +02001090 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +02001091 int32_t zonediff_h, zonediff_m;
1092
1093 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1094
1095 /* initialize the local timezone */
1096 tzset();
1097
Jan Kundrátf0737532022-02-14 18:32:18 +01001098#ifdef HAVE_TM_GMTOFF
Michal Vasko43297a02021-05-19 11:12:37 +02001099 /* convert */
1100 if (!localtime_r(&time, &tm)) {
1101 return LY_ESYS;
1102 }
1103
1104 /* get timezone offset */
1105 if (tm.tm_gmtoff == 0) {
1106 /* time is Zulu (UTC) */
1107 zonediff_h = 0;
1108 zonediff_m = 0;
1109 } else {
1110 /* timezone offset */
1111 zonediff_h = tm.tm_gmtoff / 60 / 60;
1112 zonediff_m = tm.tm_gmtoff / 60 % 60;
1113 }
1114 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
Jan Kundrátaac59c22021-12-09 23:25:15 +01001115#else
Jan Kundrátf0737532022-02-14 18:32:18 +01001116 /* convert */
1117 if (!gmtime_r(&time, &tm)) {
1118 return LY_ESYS;
1119 }
1120
Jan Kundrátaac59c22021-12-09 23:25:15 +01001121 (void)zonediff_h;
1122 (void)zonediff_m;
1123 sprintf(zoneshift, "-00:00");
1124#endif
Michal Vasko43297a02021-05-19 11:12:37 +02001125
1126 /* print */
1127 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1128 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1129 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1130 return LY_EMEM;
1131 }
1132
1133 return LY_SUCCESS;
1134}
1135
Jan Kundrátc6e39de2021-12-09 16:01:19 +01001136LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001137ly_time_str2ts(const char *value, struct timespec *ts)
1138{
1139 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001140 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001141 int frac_len;
1142
1143 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1144
1145 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1146 LY_CHECK_RET(rc);
1147
1148 /* convert fractions of a second to nanoseconds */
1149 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001150 /* init frac_buf with zeroes */
1151 memset(frac_buf, '0', 9);
1152 frac_buf[9] = '\0';
1153
Michal Vasko43297a02021-05-19 11:12:37 +02001154 frac_len = strlen(fractions_s);
1155 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1156 ts->tv_nsec = atol(frac_buf);
1157 free(fractions_s);
1158 } else {
1159 ts->tv_nsec = 0;
1160 }
1161
1162 return LY_SUCCESS;
1163}
1164
Jan Kundrátc6e39de2021-12-09 16:01:19 +01001165LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001166ly_time_ts2str(const struct timespec *ts, char **str)
1167{
1168 char frac_buf[10];
1169
Jan Kundrátbd157002021-08-30 14:02:22 +02001170 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001171
1172 /* convert nanoseconds to fractions of a second */
1173 if (ts->tv_nsec) {
1174 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1175 }
1176
1177 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1178}