blob: 762831ce09d6faa4e6b534d11ba38a8114bddc35 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
Michal Vasko59892dd2022-05-13 11:02:30 +02002 * @file tree_data_common.c
Radek Krejcie7b95092019-05-15 11:03:07 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko59892dd2022-05-13 11:02:30 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
5 * @brief Parsing and validation common functions for data trees
Radek Krejcie7b95092019-05-15 11:03:07 +02006 *
Michal Vasko8cc3f662022-03-29 11:25:51 +02007 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
Michal Vasko43297a02021-05-19 11:12:37 +020015
16#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejcie7b95092019-05-15 11:03:07 +020017
18#include <assert.h>
Michal Vasko43297a02021-05-19 11:12:37 +020019#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020022#include <string.h>
Michal Vasko43297a02021-05-19 11:12:37 +020023#include <time.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include "common.h"
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010026#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010028#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020029#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020031#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020032#include "parser_data.h"
Michal Vasko8cc3f662022-03-29 11:25:51 +020033#include "plugins_exts.h"
Michal Vaskoa820c312021-02-05 16:33:00 +010034#include "printer_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020035#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020037#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020038#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010039#include "tree_edit.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020040#include "tree_schema.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020041#include "tree_schema_internal.h"
Radek Krejci4f2e3e52021-03-30 14:20:28 +020042#include "validation.h"
Radek Krejci77114102021-03-10 15:21:57 +010043#include "xml.h"
aPiecekdf23eee2021-10-07 12:21:50 +020044#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020045
Michal Vaskod7c048c2021-05-18 16:12:55 +020046/**
47 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
48 *
49 * @param[in] first_inst Instance of the cache entry.
50 * @param[in,out] dup_inst_cache Duplicate instance cache.
51 * @return Instance cache entry.
52 */
53static struct lyd_dup_inst *
54lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
55{
56 struct lyd_dup_inst *item;
57 LY_ARRAY_COUNT_TYPE u;
58
59 LY_ARRAY_FOR(*dup_inst_cache, u) {
60 if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
61 return &(*dup_inst_cache)[u];
62 }
63 }
64
65 /* it was not added yet, add it now */
66 LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
67
68 return item;
69}
70
71LY_ERR
72lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
73{
74 struct lyd_dup_inst *dup_inst;
75
76 if (!*inst || !lysc_is_dup_inst_list((*inst)->schema)) {
77 /* no match or not dup-inst list, inst is unchanged */
78 return LY_SUCCESS;
79 }
80
81 /* there can be more exact same instances and we must make sure we do not match a single node more times */
82 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
83 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
84
85 if (!dup_inst->used) {
86 /* we did not cache these instances yet, do so */
87 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
88 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
89 }
90
91 if (dup_inst->used == dup_inst->inst_set->count) {
92 /* we have used all the instances */
93 *inst = NULL;
94 } else {
95 assert(dup_inst->used < dup_inst->inst_set->count);
96
97 /* use another instance */
98 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
99 ++dup_inst->used;
100 }
101
102 return LY_SUCCESS;
103}
104
105void
106lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
107{
108 LY_ARRAY_COUNT_TYPE u;
109
110 LY_ARRAY_FOR(dup_inst, u) {
111 ly_set_free(dup_inst[u].inst_set, NULL);
112 }
113 LY_ARRAY_FREE(dup_inst);
114}
115
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200116struct lyd_node *
117lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200118 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200119{
120 const struct lysc_node *siter = NULL;
121 struct lyd_node *match = NULL;
122
123 assert(parent || module);
124 assert(!last || (slast && *slast));
125
126 if (slast) {
127 siter = *slast;
128 }
129
130 if (last && last->next && (last->next->schema == siter)) {
131 /* return next data instance */
132 return last->next;
133 }
134
135 /* find next schema node data instance */
136 while ((siter = lys_getnext(siter, parent, module, 0))) {
137 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
138 break;
139 }
140 }
141
142 if (slast) {
143 *slast = siter;
144 }
145 return match;
146}
147
Radek Krejcie7b95092019-05-15 11:03:07 +0200148struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100149lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200150{
151 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100152
153 if (!node->schema) {
154 return &((struct lyd_node_opaq *)node)->child;
155 } else {
156 switch (node->schema->nodetype) {
157 case LYS_CONTAINER:
158 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100159 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100160 case LYS_ACTION:
161 case LYS_NOTIF:
162 return &((struct lyd_node_inner *)node)->child;
163 default:
164 return NULL;
165 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200166 }
167}
168
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100169LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200170lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
171{
172 LY_ERR ret = LY_SUCCESS;
173 char *var_name = NULL, *var_value = NULL;
174 struct lyxp_var *item;
175
176 if (!vars || !name || !value) {
177 return LY_EINVAL;
178 }
179
180 /* If variable is already defined then change its value. */
181 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
182 var_value = strdup(value);
183 LY_CHECK_RET(!var_value, LY_EMEM);
184
185 /* Set new value. */
186 free(item->value);
187 item->value = var_value;
188 } else {
189 var_name = strdup(name);
190 var_value = strdup(value);
191 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
192
193 /* Add new variable. */
194 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
195 item->name = var_name;
196 item->value = var_value;
197 }
198
199 return LY_SUCCESS;
200
201error:
202 free(var_name);
203 free(var_value);
204 return ret;
205}
206
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100207LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200208lyxp_vars_free(struct lyxp_var *vars)
209{
210 LY_ARRAY_COUNT_TYPE u;
211
212 if (!vars) {
213 return;
214 }
215
216 LY_ARRAY_FOR(vars, u) {
217 free(vars[u].name);
218 free(vars[u].value);
219 }
220
221 LY_ARRAY_FREE(vars);
222}
223
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100224LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200225lyd_child_no_keys(const struct lyd_node *node)
226{
227 struct lyd_node **children;
228
229 if (!node) {
230 return NULL;
231 }
232
233 if (!node->schema) {
234 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100235 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200236 }
237
Michal Vaskoe0665742021-02-11 11:08:44 +0100238 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200239 if (children) {
240 struct lyd_node *child = *children;
241 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
242 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200243 }
244 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200245 } else {
246 return NULL;
247 }
248}
Michal Vasko9b368d32020-02-14 13:53:31 +0100249
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100250LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100251lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100252{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100253 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100254
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100255 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100256 return NULL;
257 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100258
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100259 if (!node->schema) {
260 opaq = (struct lyd_node_opaq *)node;
261 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200262 case LY_VALUE_XML:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100263 return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
Radek Krejci8df109d2021-04-23 12:19:08 +0200264 case LY_VALUE_JSON:
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100265 return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
266 default:
267 return NULL;
268 }
269 }
270
Michal Vaskoef53c812021-10-13 10:21:03 +0200271 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100272}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100273
Michal Vasko598063b2021-07-19 11:39:05 +0200274void
275lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
276{
277 int cmp;
278 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200279 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200280
281 assert(node && mod);
282
283 if (!*node) {
284 return;
285 }
286
287 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200288 own_mod = lyd_owner_module(first);
289 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200290 if (cmp > 0) {
291 /* there may be some preceding data */
292 while (first->prev->next) {
293 first = first->prev;
294 if (lyd_owner_module(first) == mod) {
295 cmp = 0;
296 break;
297 }
298 }
299 }
300
301 if (cmp == 0) {
302 /* there may be some preceding data belonging to this module */
303 while (first->prev->next) {
304 if (lyd_owner_module(first->prev) != mod) {
305 break;
306 }
307 first = first->prev;
308 }
309 }
310
311 if (cmp < 0) {
312 /* there may be some following data */
313 LY_LIST_FOR(first, first) {
314 if (lyd_owner_module(first) == mod) {
315 cmp = 0;
316 break;
317 }
318 }
319 }
320
321 if (cmp == 0) {
322 /* we have found the first module data node */
323 *node = first;
324 }
325}
326
Michal Vaskob1b5c262020-03-05 14:29:47 +0100327const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200328lyd_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 +0200329 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100330{
331 struct lyd_node *iter;
332 const struct lys_module *mod;
333
334 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200335 if (module) {
336 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100337 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200338 } else {
339 mod = module;
340 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100341 }
342 } else {
343 do {
344 mod = ly_ctx_get_module_iter(ctx, i);
345 } while (mod && !mod->implemented);
346 }
347
348 /* find its data */
349 *first = NULL;
350 if (mod) {
351 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100352 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100353 *first = iter;
354 break;
355 }
356 }
357 }
358
359 return mod;
360}
361
362const struct lys_module *
363lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
364{
365 const struct lys_module *mod;
366
367 if (!*next) {
368 /* all data traversed */
369 *first = NULL;
370 return NULL;
371 }
372
373 *first = *next;
374
375 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100376 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100377 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100378 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100379 break;
380 }
381 }
382
383 return mod;
384}
Michal Vasko9f96a052020-03-10 09:41:45 +0100385
386LY_ERR
387lyd_parse_check_keys(struct lyd_node *node)
388{
389 const struct lysc_node *skey = NULL;
390 const struct lyd_node *key;
391
392 assert(node->schema->nodetype == LYS_LIST);
393
Radek Krejcia1c1e542020-09-29 16:06:52 +0200394 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100395 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
396 if (!key || (key->schema != skey)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100397 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100398 return LY_EVALID;
399 }
400
401 key = key->next;
402 }
403
404 return LY_SUCCESS;
405}
Michal Vasko60ea6352020-06-29 13:39:39 +0200406
Michal Vasko8cc3f662022-03-29 11:25:51 +0200407LY_ERR
408lyd_parse_set_data_flags(struct lyd_node *node, struct lyd_meta **meta, struct lyd_ctx *lydctx,
409 struct lysc_ext_instance *ext)
Michal Vasko60ea6352020-06-29 13:39:39 +0200410{
411 struct lyd_meta *meta2, *prev_meta = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200412 struct lyd_ctx_ext_val *ext_val;
Michal Vasko60ea6352020-06-29 13:39:39 +0200413
Michal Vaskoa5705e52020-12-09 18:15:14 +0100414 if (lysc_has_when(node->schema)) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200415 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200416 /* remember we need to evaluate this node's when */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200417 LY_CHECK_RET(ly_set_add(&lydctx->node_when, node, 1, NULL));
Michal Vasko60ea6352020-06-29 13:39:39 +0200418 }
419 }
420
Michal Vasko60ea6352020-06-29 13:39:39 +0200421 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200422 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
423 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200424 /* node is default according to the metadata */
425 node->flags |= LYD_DEFAULT;
426
427 /* delete the metadata */
428 if (prev_meta) {
429 prev_meta->next = meta2->next;
430 } else {
431 *meta = (*meta)->next;
432 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200433 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200434 break;
435 }
436
437 prev_meta = meta2;
438 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200439
440 if (ext) {
441 /* parsed for an extension */
442 node->flags |= LYD_EXT;
443
444 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
445 /* rememeber for validation */
446 ext_val = malloc(sizeof *ext_val);
447 LY_CHECK_ERR_RET(!ext_val, LOGMEM(LYD_CTX(node)), LY_EMEM);
448 ext_val->ext = ext;
449 ext_val->sibling = node;
450 LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
451 }
452 }
453
454 return LY_SUCCESS;
Michal Vasko60ea6352020-06-29 13:39:39 +0200455}
456
Michal Vasko59892dd2022-05-13 11:02:30 +0200457LY_ERR
458lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
459 size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
460 const struct lysc_node *ctx_node, ly_bool *incomplete)
461{
462 LY_ERR ret;
463 struct ly_err_item *err = NULL;
464 uint32_t options = (dynamic && *dynamic ? LYPLG_TYPE_STORE_DYNAMIC : 0);
465
466 if (!value) {
467 value = "";
468 }
469 if (incomplete) {
470 *incomplete = 0;
471 }
472
473 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
474 if (dynamic) {
475 *dynamic = 0;
476 }
477
478 if (ret == LY_EINCOMPLETE) {
479 if (incomplete) {
480 *incomplete = 1;
481 }
482 } else if (ret) {
483 if (err) {
484 LOGVAL_ERRITEM(ctx, err);
485 ly_err_free(err);
486 } else {
487 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
488 }
489 return ret;
490 }
491
492 return LY_SUCCESS;
493}
494
495LY_ERR
496lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
497 const struct lyd_node *ctx_node, const struct lyd_node *tree)
498{
499 LY_ERR ret;
500 struct ly_err_item *err = NULL;
501
502 assert(type->plugin->validate);
503
504 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
505 if (ret) {
506 if (err) {
507 LOGVAL_ERRITEM(ctx, err);
508 ly_err_free(err);
509 } else {
510 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.", type->plugin->print(ctx, val, LY_VALUE_CANON,
511 NULL, NULL, NULL));
512 }
513 return ret;
514 }
515
516 return LY_SUCCESS;
517}
518
519LY_ERR
520lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
521 LY_VALUE_FORMAT format, void *prefix_data)
522{
523 LY_ERR rc = LY_SUCCESS;
524 struct ly_err_item *err = NULL;
525 struct lyd_value storage;
526 struct lysc_type *type;
527
528 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
529
530 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
531 LOGARG(ctx, node);
532 return LY_EINVAL;
533 }
534
535 type = ((struct lysc_node_leaf *)node)->type;
536 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
537 LYD_HINT_SCHEMA, node, &storage, NULL, &err);
538 if (rc == LY_EINCOMPLETE) {
539 /* actually success since we do not provide the context tree and call validation with
540 * LY_TYPE_OPTS_INCOMPLETE_DATA */
541 rc = LY_SUCCESS;
542 } else if (rc && err) {
543 if (ctx) {
544 /* log only in case the ctx was provided as input parameter */
545 LOG_LOCSET(NULL, NULL, err->path, NULL);
546 LOGVAL_ERRITEM(ctx, err);
547 LOG_LOCBACK(0, 0, 1, 0);
548 }
549 ly_err_free(err);
550 }
551
552 if (!rc) {
553 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
554 }
555 return rc;
556}
557
558LIBYANG_API_DEF LY_ERR
559lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
560 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
561{
562 LY_ERR rc;
563 struct ly_err_item *err = NULL;
564 struct lysc_type *type;
565 struct lyd_value val = {0};
566 ly_bool stored = 0, log = 1;
567
568 LY_CHECK_ARG_RET(ctx, schema, value, LY_EINVAL);
569
570 if (!ctx) {
571 ctx = schema->module->ctx;
572 log = 0;
573 }
574 type = ((struct lysc_node_leaf *)schema)->type;
575
576 /* store */
577 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
578 LYD_HINT_DATA, schema, &val, NULL, &err);
579 if (!rc || (rc == LY_EINCOMPLETE)) {
580 stored = 1;
581 }
582
583 if (ctx_node && (rc == LY_EINCOMPLETE)) {
584 /* resolve */
585 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
586 }
587
588 if (rc && (rc != LY_EINCOMPLETE) && err) {
589 if (log) {
590 /* log error */
591 if (err->path) {
592 LOG_LOCSET(NULL, NULL, err->path, NULL);
593 } else if (ctx_node) {
594 LOG_LOCSET(NULL, ctx_node, NULL, NULL);
595 } else {
596 LOG_LOCSET(schema, NULL, NULL, NULL);
597 }
598 LOGVAL_ERRITEM(ctx, err);
599 if (err->path) {
600 LOG_LOCBACK(0, 0, 1, 0);
601 } else if (ctx_node) {
602 LOG_LOCBACK(0, 1, 0, 0);
603 } else {
604 LOG_LOCBACK(1, 0, 0, 0);
605 }
606 }
607 ly_err_free(err);
608 }
609
610 if (!rc || (rc == LY_EINCOMPLETE)) {
611 if (realtype) {
612 /* return realtype */
613 if (val.realtype->basetype == LY_TYPE_UNION) {
614 *realtype = val.subvalue->value.realtype;
615 } else {
616 *realtype = val.realtype;
617 }
618 }
619
620 if (canonical) {
621 /* return canonical value */
622 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
623 }
624 }
625
626 if (stored) {
627 /* free value */
628 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
629 }
630 return rc;
631}
632
633LIBYANG_API_DEF LY_ERR
634lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
635{
636 LY_ERR ret = LY_SUCCESS;
637 struct ly_ctx *ctx;
638 struct lysc_type *type;
639 struct lyd_value val = {0};
640
641 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
642
643 ctx = node->schema->module->ctx;
644 type = ((struct lysc_node_leaf *)node->schema)->type;
645
646 /* store the value */
647 LOG_LOCSET(node->schema, &node->node, NULL, NULL);
648 ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
649 LOG_LOCBACK(1, 1, 0, 0);
650 LY_CHECK_RET(ret);
651
652 /* compare values */
653 ret = type->plugin->compare(&node->value, &val);
654
655 type->plugin->free(ctx, &val);
656 return ret;
657}
658
659LIBYANG_API_DEF ly_bool
660lyd_is_default(const struct lyd_node *node)
661{
662 const struct lysc_node_leaf *leaf;
663 const struct lysc_node_leaflist *llist;
664 const struct lyd_node_term *term;
665 LY_ARRAY_COUNT_TYPE u;
666
667 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
668 return 0;
669 }
670
671 term = (const struct lyd_node_term *)node;
672
673 if (node->schema->nodetype == LYS_LEAF) {
674 leaf = (const struct lysc_node_leaf *)node->schema;
675 if (!leaf->dflt) {
676 return 0;
677 }
678
679 /* compare with the default value */
680 if (!leaf->type->plugin->compare(&term->value, leaf->dflt)) {
681 return 1;
682 }
683 } else {
684 llist = (const struct lysc_node_leaflist *)node->schema;
685 if (!llist->dflts) {
686 return 0;
687 }
688
689 LY_ARRAY_FOR(llist->dflts, u) {
690 /* compare with each possible default value */
691 if (!llist->type->plugin->compare(&term->value, llist->dflts[u])) {
692 return 1;
693 }
694 }
695 }
696
697 return 0;
698}
699
700LIBYANG_API_DEF uint32_t
701lyd_list_pos(const struct lyd_node *instance)
702{
703 const struct lyd_node *iter = NULL;
704 uint32_t pos = 0;
705
706 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
707 return 0;
708 }
709
710 /* data instances are ordered, so we can stop when we found instance of other schema node */
711 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
712 if (pos && (iter->next == NULL)) {
713 /* overrun to the end of the siblings list */
714 break;
715 }
716 ++pos;
717 }
718
719 return pos;
720}
721
722LIBYANG_API_DEF struct lyd_node *
723lyd_first_sibling(const struct lyd_node *node)
724{
725 struct lyd_node *start;
726
727 if (!node) {
728 return NULL;
729 }
730
731 /* get the first sibling */
732 if (node->parent) {
733 start = node->parent->child;
734 } else {
735 for (start = (struct lyd_node *)node; start->prev->next; start = start->prev) {}
736 }
737
738 return start;
739}
740
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100741/**
742 * @brief Check list node parsed into an opaque node for the reason.
743 *
744 * @param[in] node Opaque node.
745 * @param[in] snode Schema node of @p opaq.
746 * @return LY_SUCCESS if the node is valid;
747 * @return LY_ERR on error.
748 */
749static LY_ERR
750lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
751{
752 LY_ERR ret = LY_SUCCESS;
753 struct ly_set key_set = {0};
754 const struct lysc_node *key = NULL;
755 const struct lyd_node *child;
756 const struct lyd_node_opaq *opaq_k;
757 uint32_t i;
758
759 assert(!node->schema);
760
761 /* get all keys into a set */
762 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
763 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
764 }
765
766 LY_LIST_FOR(lyd_child(node), child) {
767 if (child->schema) {
768 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
769 LYD_NAME(child));
770 ret = LY_EINVAL;
771 goto cleanup;
772 }
773
774 opaq_k = (struct lyd_node_opaq *)child;
775
776 /* find the key schema node */
777 for (i = 0; i < key_set.count; ++i) {
778 key = key_set.snodes[i];
779 if (!strcmp(key->name, opaq_k->name.name)) {
780 break;
781 }
782 }
783 if (i == key_set.count) {
784 /* some other node, skip */
785 continue;
786 }
787
788 /* key found */
789 ly_set_rm_index(&key_set, i, NULL);
790
791 /* check value */
792 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
793 opaq_k->val_prefix_data);
794 LY_CHECK_GOTO(ret, cleanup);
795 }
796
797 if (key_set.count) {
798 /* missing keys */
799 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
800 ret = LY_EVALID;
801 goto cleanup;
802 }
803
804cleanup:
805 ly_set_erase(&key_set, NULL);
806 return ret;
807}
808
809LIBYANG_API_DEF LY_ERR
810lyd_parse_opaq_error(const struct lyd_node *node)
811{
812 const struct ly_ctx *ctx;
813 const struct lyd_node_opaq *opaq;
814 const struct lyd_node *parent;
815 const struct lys_module *mod;
816 const struct lysc_node *snode;
817
818 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
819
820 ctx = LYD_CTX(node);
821 opaq = (struct lyd_node_opaq *)node;
822 parent = lyd_parent(node);
823
Michal Vaskof4e63922022-05-10 10:32:13 +0200824 if (!opaq->name.module_ns) {
825 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
826 return LY_EVALID;
827 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100828
829 /* module */
830 switch (opaq->format) {
831 case LY_VALUE_XML:
832 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
833 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
834 if (!mod) {
835 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" in the context.",
836 opaq->name.module_ns);
837 return LY_EVALID;
838 }
839 } else {
840 /* inherit */
841 mod = parent->schema->module;
842 }
843 break;
844 case LY_VALUE_JSON:
845 case LY_VALUE_LYB:
846 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
847 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
848 if (!mod) {
849 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" in the context.", opaq->name.module_name);
850 return LY_EVALID;
851 }
852 } else {
853 /* inherit */
854 mod = parent->schema->module;
855 }
856 break;
857 default:
858 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
859 return LY_EINVAL;
860 }
861
862 /* schema */
863 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200864 if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
865 /* maybe output node */
Michal Vasko89afc6e2022-05-02 10:24:26 +0200866 snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200867 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100868 if (!snode) {
869 if (parent) {
870 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
871 LYD_NAME(parent));
872 } else {
873 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
874 }
875 return LY_EVALID;
876 }
877
878 if (snode->nodetype & LYD_NODE_TERM) {
879 /* leaf / leaf-list */
880 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
881 } else if (snode->nodetype == LYS_LIST) {
882 /* list */
883 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
884 } else if (snode->nodetype & LYD_NODE_INNER) {
885 /* inner node */
886 if (opaq->value) {
887 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
888 lys_nodetype2str(snode->nodetype), snode->name);
889 return LY_EVALID;
890 }
891 } else {
892 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
893 return LY_EINVAL;
894 }
895
896 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
897 return LY_EINVAL;
898}
899
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100900LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400901lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200902{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200903 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
904
Michal Vasko33876022021-04-27 16:42:24 +0200905 return value->_canonical ? value->_canonical :
906 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200907}
908
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100909LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100910lyd_any_value_str(const struct lyd_node *any, char **value_str)
911{
912 const struct lyd_node_any *a;
913 struct lyd_node *tree = NULL;
914 const char *str = NULL;
915 ly_bool dynamic = 0;
916 LY_ERR ret = LY_SUCCESS;
917
918 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200919 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100920
921 a = (struct lyd_node_any *)any;
922 *value_str = NULL;
923
924 if (!a->value.str) {
925 /* there is no value in the union */
926 return LY_SUCCESS;
927 }
928
929 switch (a->value_type) {
930 case LYD_ANYDATA_LYB:
931 /* parse into a data tree */
932 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
933 LY_CHECK_GOTO(ret, cleanup);
934 dynamic = 1;
935 break;
936 case LYD_ANYDATA_DATATREE:
937 tree = a->value.tree;
938 break;
939 case LYD_ANYDATA_STRING:
940 case LYD_ANYDATA_XML:
941 case LYD_ANYDATA_JSON:
942 /* simply use the string */
943 str = a->value.str;
944 break;
945 }
946
947 if (tree) {
948 /* print into a string */
949 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
950 LY_CHECK_GOTO(ret, cleanup);
951 } else {
952 assert(str);
953 *value_str = strdup(str);
954 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
955 }
956
957 /* success */
958
959cleanup:
960 if (dynamic) {
961 lyd_free_all(tree);
962 }
963 return ret;
964}
965
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100966LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200967lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
968{
969 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200970
Michal Vaskoa820c312021-02-05 16:33:00 +0100971 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200972 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200973
974 t = (struct lyd_node_any *)trg;
975
976 /* free trg */
977 switch (t->value_type) {
978 case LYD_ANYDATA_DATATREE:
979 lyd_free_all(t->value.tree);
980 break;
981 case LYD_ANYDATA_STRING:
982 case LYD_ANYDATA_XML:
983 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100984 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200985 break;
986 case LYD_ANYDATA_LYB:
987 free(t->value.mem);
988 break;
989 }
990 t->value.str = NULL;
991
992 if (!value) {
993 /* only free value in this case */
994 return LY_SUCCESS;
995 }
996
997 /* copy src */
998 t->value_type = value_type;
999 switch (value_type) {
1000 case LYD_ANYDATA_DATATREE:
1001 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02001002 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +02001003 }
1004 break;
1005 case LYD_ANYDATA_STRING:
1006 case LYD_ANYDATA_XML:
1007 case LYD_ANYDATA_JSON:
1008 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02001009 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +02001010 }
1011 break;
1012 case LYD_ANYDATA_LYB:
1013 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02001014 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +02001015 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +02001016 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001017 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +02001018 memcpy(t->value.mem, value->mem, len);
1019 }
1020 break;
1021 }
1022
1023 return LY_SUCCESS;
1024}
1025
Michal Vasko106f0862021-11-02 11:49:27 +01001026const struct lysc_node *
1027lyd_node_schema(const struct lyd_node *node)
1028{
1029 const struct lysc_node *schema = NULL;
1030 const struct lyd_node *prev_iter = NULL, *iter;
1031 const struct lys_module *mod;
1032
1033 if (!node) {
1034 return NULL;
1035 } else if (node->schema) {
1036 return node->schema;
1037 }
1038
1039 /* get schema node of an opaque node */
1040 do {
1041 /* get next data node */
1042 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
1043
1044 /* get equivalent schema node */
1045 if (iter->schema) {
1046 schema = iter->schema;
1047 } else {
1048 /* get module */
1049 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +01001050 if (!mod && !schema) {
1051 /* top-level opaque node has unknown module */
1052 break;
1053 }
Michal Vasko106f0862021-11-02 11:49:27 +01001054
1055 /* get schema node */
1056 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
1057 }
Michal Vaskod2f404f2021-11-04 15:37:11 +01001058
1059 /* remember to move to the descendant */
1060 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +01001061 } while (schema && (iter != node));
1062
1063 return schema;
1064}
1065
Michal Vasko59892dd2022-05-13 11:02:30 +02001066
1067/**
1068 * @brief Comparison callback to match schema node with a schema of a data node.
1069 *
1070 * @param[in] val1_p Pointer to the schema node
1071 * @param[in] val2_p Pointer to the data node
1072 * Implementation of ::lyht_value_equal_cb.
1073 */
1074static ly_bool
1075lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1076{
1077 struct lysc_node *val1;
1078 struct lyd_node *val2;
1079
1080 val1 = *((struct lysc_node **)val1_p);
1081 val2 = *((struct lyd_node **)val2_p);
1082
1083 if (val1 == val2->schema) {
1084 /* schema match is enough */
1085 return 1;
1086 } else {
1087 return 0;
1088 }
1089}
1090
1091LY_ERR
1092lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1093{
1094 struct lyd_node **match_p;
1095 struct lyd_node_inner *parent;
1096 uint32_t hash;
1097 lyht_value_equal_cb ht_cb;
1098
1099 assert(siblings && schema);
1100
1101 parent = siblings->parent;
1102 if (parent && parent->schema && parent->children_ht) {
1103 /* calculate our hash */
1104 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1105 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1106 hash = dict_hash_multi(hash, NULL, 0);
1107
1108 /* use special hash table function */
1109 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1110
1111 /* find by hash */
1112 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1113 siblings = *match_p;
1114 } else {
1115 /* not found */
1116 siblings = NULL;
1117 }
1118
1119 /* set the original hash table compare function back */
1120 lyht_set_cb(parent->children_ht, ht_cb);
1121 } else {
1122 /* find first sibling */
1123 if (siblings->parent) {
1124 siblings = siblings->parent->child;
1125 } else {
1126 while (siblings->prev->next) {
1127 siblings = siblings->prev;
1128 }
1129 }
1130
1131 /* search manually without hashes */
1132 for ( ; siblings; siblings = siblings->next) {
1133 if (siblings->schema == schema) {
1134 /* schema match is enough */
1135 break;
1136 }
1137 }
1138 }
1139
1140 if (!siblings) {
1141 if (match) {
1142 *match = NULL;
1143 }
1144 return LY_ENOTFOUND;
1145 }
1146
1147 if (match) {
1148 *match = (struct lyd_node *)siblings;
1149 }
1150 return LY_SUCCESS;
1151}
1152
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001153void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001154lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1155{
1156 if (*root && (lyd_owner_module(*root) != mod)) {
1157 /* there are no data of mod so this is simply the first top-level sibling */
1158 mod = NULL;
1159 }
1160
1161 if ((*root != to_del) || (*root)->parent) {
1162 return;
1163 }
1164
Michal Vasko598063b2021-07-19 11:39:05 +02001165 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1166 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001167 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001168 } else {
1169 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001170 }
1171}
1172
Michal Vasko8cc3f662022-03-29 11:25:51 +02001173LY_ERR
1174ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1175 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1176 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1177{
1178 LY_ERR r;
1179 LY_ARRAY_COUNT_TYPE u;
1180 struct lysc_ext_instance *nested_exts = NULL;
1181 lyplg_ext_data_snode_clb ext_snode_cb;
1182
1183 /* check if there are any nested extension instances */
1184 if (parent && parent->schema) {
1185 nested_exts = parent->schema->exts;
1186 } else if (sparent) {
1187 nested_exts = sparent->exts;
1188 }
1189 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001190 if (!nested_exts[u].def->plugin) {
1191 /* no plugin */
1192 continue;
1193 }
1194
Michal Vasko8cc3f662022-03-29 11:25:51 +02001195 ext_snode_cb = nested_exts[u].def->plugin->snode;
1196 if (!ext_snode_cb) {
1197 /* not an extension with nested data */
1198 continue;
1199 }
1200
1201 /* try to get the schema node */
1202 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1203 if (!r) {
1204 /* data successfully created, remember the ext instance */
1205 *ext = &nested_exts[u];
1206 return LY_SUCCESS;
1207 } else if (r != LY_ENOT) {
1208 /* fatal error */
1209 return r;
1210 }
1211 /* data was not from this module, continue */
1212 }
1213
1214 /* no extensions or none matched */
1215 return LY_ENOT;
1216}
1217
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001218void
Radek Krejci8df109d2021-04-23 12:19:08 +02001219ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001220{
1221 struct ly_set *ns_list;
1222 struct lysc_prefix *prefixes;
1223 uint32_t i;
1224 LY_ARRAY_COUNT_TYPE u;
1225
1226 if (!prefix_data) {
1227 return;
1228 }
1229
1230 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001231 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001232 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001233 ns_list = prefix_data;
1234 for (i = 0; i < ns_list->count; ++i) {
1235 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1236 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1237 }
1238 ly_set_free(ns_list, free);
1239 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001240 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001241 prefixes = prefix_data;
1242 LY_ARRAY_FOR(prefixes, u) {
1243 free(prefixes[u].prefix);
1244 }
1245 LY_ARRAY_FREE(prefixes);
1246 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001247 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001248 case LY_VALUE_SCHEMA:
1249 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001250 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001251 break;
1252 }
1253}
1254
1255LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001256ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001257 void **prefix_data_p)
1258{
1259 LY_ERR ret = LY_SUCCESS;
1260 struct lyxml_ns *ns;
1261 struct lysc_prefix *prefixes = NULL, *orig_pref;
1262 struct ly_set *ns_list, *orig_ns;
1263 uint32_t i;
1264 LY_ARRAY_COUNT_TYPE u;
1265
1266 assert(!*prefix_data_p);
1267
1268 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001269 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001270 *prefix_data_p = (void *)prefix_data;
1271 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001272 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001273 /* copy all the value prefixes */
1274 orig_pref = (struct lysc_prefix *)prefix_data;
1275 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1276 *prefix_data_p = prefixes;
1277
1278 LY_ARRAY_FOR(orig_pref, u) {
1279 if (orig_pref[u].prefix) {
1280 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1281 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1282 }
1283 prefixes[u].mod = orig_pref[u].mod;
1284 LY_ARRAY_INCREMENT(prefixes);
1285 }
1286 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001287 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001288 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001289 /* copy all the namespaces */
1290 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1291 *prefix_data_p = ns_list;
1292
1293 orig_ns = (struct ly_set *)prefix_data;
1294 for (i = 0; i < orig_ns->count; ++i) {
1295 ns = calloc(1, sizeof *ns);
1296 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1297 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1298
1299 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1300 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1301 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1302 }
1303 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1304 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1305 }
1306 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001307 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001308 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001309 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001310 assert(!prefix_data);
1311 *prefix_data_p = NULL;
1312 break;
1313 }
1314
1315cleanup:
1316 if (ret) {
1317 ly_free_prefix_data(format, *prefix_data_p);
1318 *prefix_data_p = NULL;
1319 }
1320 return ret;
1321}
1322
1323LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001324ly_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 +02001325 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001326{
1327 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001328 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001329 const struct lyxml_ns *ns;
1330 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001331 struct ly_set *ns_list;
1332 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001333 const char *value_iter, *value_next, *value_end;
1334 uint32_t substr_len;
1335 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001336
1337 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001338 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001339 /* copy all referenced modules as prefix - module pairs */
1340 if (!*prefix_data_p) {
1341 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001342 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001343 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001344 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001345 } else {
1346 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001347 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001348 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001349 }
1350
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001351 /* add current module for unprefixed values */
1352 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1353 *prefix_data_p = prefixes;
1354
1355 val_pref->prefix = NULL;
1356 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1357
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001358 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001359 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001360 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001361 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 +02001362 if (is_prefix) {
1363 /* we have a possible prefix. Do we already have the prefix? */
1364 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1365 if (!mod) {
1366 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1367 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001368 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001369 /* store a new prefix - module pair */
1370 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1371 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001372
aPiecek83436bc2021-03-30 12:20:45 +02001373 val_pref->prefix = strndup(value_iter, substr_len);
1374 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1375 val_pref->mod = mod;
1376 } /* else it is not even defined */
1377 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001378 }
1379 }
1380 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001381 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001382 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001383 /* copy all referenced namespaces as prefix - namespace pairs */
1384 if (!*prefix_data_p) {
1385 /* new prefix data */
1386 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001387 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001388 *prefix_data_p = ns_list;
1389 } else {
1390 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001391 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001392 ns_list = *prefix_data_p;
1393 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001394
Michal Vasko294e7f02022-02-28 13:59:00 +01001395 /* store default namespace */
1396 ns = lyxml_ns_get(prefix_data, NULL, 0);
1397 if (ns) {
1398 new_ns = calloc(1, sizeof *new_ns);
1399 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1400 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1401
1402 new_ns->prefix = NULL;
1403 new_ns->uri = strdup(ns->uri);
1404 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1405 }
1406
Michal Vaskofc2cd072021-02-24 13:17:17 +01001407 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001408 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001409 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001410 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 +02001411 if (is_prefix) {
1412 /* we have a possible prefix. Do we already have the prefix? */
1413 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1414 if (!ns) {
1415 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1416 if (ns) {
1417 /* store a new prefix - namespace pair */
1418 new_ns = calloc(1, sizeof *new_ns);
1419 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1420 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001421
aPiecek83436bc2021-03-30 12:20:45 +02001422 new_ns->prefix = strndup(value_iter, substr_len);
1423 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1424 new_ns->uri = strdup(ns->uri);
1425 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1426 } /* else it is not even defined */
1427 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001428 }
1429 }
1430 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001431 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001432 case LY_VALUE_SCHEMA_RESOLVED:
1433 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001434 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001435 if (!*prefix_data_p) {
1436 /* new prefix data - simply copy all the prefix data */
1437 *format_p = format;
1438 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1439 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001440 break;
1441 }
1442
1443cleanup:
1444 if (ret) {
1445 ly_free_prefix_data(*format_p, *prefix_data_p);
1446 *prefix_data_p = NULL;
1447 }
1448 return ret;
1449}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001450
1451const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001452ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001453{
1454 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001455 case LY_VALUE_CANON:
1456 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001457 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001458 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001459 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001460 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001461 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001462 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001463 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001464 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001465 case LY_VALUE_LYB:
1466 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001467 default:
1468 break;
1469 }
1470
1471 return NULL;
1472}
Michal Vasko43297a02021-05-19 11:12:37 +02001473
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001474LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001475ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1476{
1477 struct tm tm = {0};
1478 uint32_t i, frac_len;
1479 const char *frac;
1480 int64_t shift, shift_m;
1481 time_t t;
1482
1483 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1484
1485 tm.tm_year = atoi(&value[0]) - 1900;
1486 tm.tm_mon = atoi(&value[5]) - 1;
1487 tm.tm_mday = atoi(&value[8]);
1488 tm.tm_hour = atoi(&value[11]);
1489 tm.tm_min = atoi(&value[14]);
1490 tm.tm_sec = atoi(&value[17]);
1491
1492 t = timegm(&tm);
1493 i = 19;
1494
1495 /* fractions of a second */
1496 if (value[i] == '.') {
1497 ++i;
1498 frac = &value[i];
1499 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1500
1501 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001502 } else {
1503 frac = NULL;
1504 }
1505
1506 /* apply offset */
1507 if ((value[i] == 'Z') || (value[i] == 'z')) {
1508 /* zero shift */
1509 shift = 0;
1510 } else {
1511 shift = strtol(&value[i], NULL, 10);
1512 shift = shift * 60 * 60; /* convert from hours to seconds */
1513 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1514 /* correct sign */
1515 if (shift < 0) {
1516 shift_m *= -1;
1517 }
1518 /* connect hours and minutes of the shift */
1519 shift = shift + shift_m;
1520 }
1521
1522 /* we have to shift to the opposite way to correct the time */
1523 t -= shift;
1524
1525 *time = t;
1526 if (fractions_s) {
1527 if (frac) {
1528 *fractions_s = strndup(frac, frac_len);
1529 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1530 } else {
1531 *fractions_s = NULL;
1532 }
1533 }
1534 return LY_SUCCESS;
1535}
1536
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001537LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001538ly_time_time2str(time_t time, const char *fractions_s, char **str)
1539{
1540 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +02001541 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +02001542 int32_t zonediff_h, zonediff_m;
1543
1544 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1545
1546 /* initialize the local timezone */
1547 tzset();
1548
Jan Kundrátb17efe92022-02-14 18:32:18 +01001549#ifdef HAVE_TM_GMTOFF
Michal Vasko43297a02021-05-19 11:12:37 +02001550 /* convert */
1551 if (!localtime_r(&time, &tm)) {
1552 return LY_ESYS;
1553 }
1554
1555 /* get timezone offset */
1556 if (tm.tm_gmtoff == 0) {
1557 /* time is Zulu (UTC) */
1558 zonediff_h = 0;
1559 zonediff_m = 0;
1560 } else {
1561 /* timezone offset */
1562 zonediff_h = tm.tm_gmtoff / 60 / 60;
1563 zonediff_m = tm.tm_gmtoff / 60 % 60;
1564 }
1565 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
Jan Kundráte182a272021-12-09 23:25:15 +01001566#else
Jan Kundrátb17efe92022-02-14 18:32:18 +01001567 /* convert */
1568 if (!gmtime_r(&time, &tm)) {
1569 return LY_ESYS;
1570 }
1571
Jan Kundráte182a272021-12-09 23:25:15 +01001572 (void)zonediff_h;
1573 (void)zonediff_m;
1574 sprintf(zoneshift, "-00:00");
1575#endif
Michal Vasko43297a02021-05-19 11:12:37 +02001576
1577 /* print */
1578 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1579 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1580 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1581 return LY_EMEM;
1582 }
1583
1584 return LY_SUCCESS;
1585}
1586
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001587LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001588ly_time_str2ts(const char *value, struct timespec *ts)
1589{
1590 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001591 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001592 int frac_len;
1593
1594 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1595
1596 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1597 LY_CHECK_RET(rc);
1598
1599 /* convert fractions of a second to nanoseconds */
1600 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001601 /* init frac_buf with zeroes */
1602 memset(frac_buf, '0', 9);
1603 frac_buf[9] = '\0';
1604
Michal Vasko43297a02021-05-19 11:12:37 +02001605 frac_len = strlen(fractions_s);
1606 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1607 ts->tv_nsec = atol(frac_buf);
1608 free(fractions_s);
1609 } else {
1610 ts->tv_nsec = 0;
1611 }
1612
1613 return LY_SUCCESS;
1614}
1615
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001616LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001617ly_time_ts2str(const struct timespec *ts, char **str)
1618{
1619 char frac_buf[10];
1620
Jan Kundrátbd157002021-08-30 14:02:22 +02001621 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001622
1623 /* convert nanoseconds to fractions of a second */
1624 if (ts->tv_nsec) {
1625 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1626 }
1627
1628 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1629}