blob: 16db9c3090998d9f6a38000b8f657594057ddd8a [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/**
Michal Vasko271d2e32023-01-31 15:43:19 +010047 * @brief Callback for checking first instance hash table values equivalence.
48 *
49 * @param[in] val1_p If not @p mod, pointer to the first instance.
50 * @param[in] val2_p If not @p mod, pointer to the found dup inst item.
51 */
52static ly_bool
53lyht_dup_inst_ht_equal_cb(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
54{
55 if (mod) {
56 struct lyd_dup_inst **item1 = val1_p, **item2 = val2_p;
57
58 /* equal on 2 dup inst items */
59 return *item1 == *item2 ? 1 : 0;
60 } else {
61 struct lyd_node **first_inst = val1_p;
62 struct lyd_dup_inst **item = val2_p;
63
64 /* equal on dup inst item and a first instance */
65 return (*item)->set->dnodes[0] == *first_inst ? 1 : 0;
66 }
67}
68
69/**
Michal Vaskod7c048c2021-05-18 16:12:55 +020070 * @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
71 *
Michal Vasko271d2e32023-01-31 15:43:19 +010072 * @param[in] first_inst First instance of the cache entry.
73 * @param[in] dup_inst_ht Duplicate instance cache hash table.
Michal Vaskod7c048c2021-05-18 16:12:55 +020074 * @return Instance cache entry.
75 */
76static struct lyd_dup_inst *
Michal Vasko271d2e32023-01-31 15:43:19 +010077lyd_dup_inst_get(const struct lyd_node *first_inst, struct hash_table **dup_inst_ht)
Michal Vaskod7c048c2021-05-18 16:12:55 +020078{
Michal Vasko271d2e32023-01-31 15:43:19 +010079 struct lyd_dup_inst **item_p, *item;
Michal Vaskod7c048c2021-05-18 16:12:55 +020080
Michal Vasko271d2e32023-01-31 15:43:19 +010081 if (*dup_inst_ht) {
82 /* find the item of the first instance */
83 if (!lyht_find(*dup_inst_ht, &first_inst, first_inst->hash, (void **)&item_p)) {
84 return *item_p;
Michal Vaskod7c048c2021-05-18 16:12:55 +020085 }
Michal Vasko271d2e32023-01-31 15:43:19 +010086 } else {
87 /* create the hash table */
88 *dup_inst_ht = lyht_new(2, sizeof item, lyht_dup_inst_ht_equal_cb, NULL, 1);
89 LY_CHECK_RET(!*dup_inst_ht, NULL);
Michal Vaskod7c048c2021-05-18 16:12:55 +020090 }
91
Michal Vasko271d2e32023-01-31 15:43:19 +010092 /* first instance has no dup inst item, create it */
93 item = calloc(1, sizeof *item);
94 LY_CHECK_RET(!item, NULL);
95
96 /* add into the hash table */
97 if (lyht_insert(*dup_inst_ht, &item, first_inst->hash, NULL)) {
98 return NULL;
99 }
Michal Vaskod7c048c2021-05-18 16:12:55 +0200100
101 return item;
102}
103
104LY_ERR
Michal Vasko271d2e32023-01-31 15:43:19 +0100105lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct hash_table **dup_inst_ht)
Michal Vaskod7c048c2021-05-18 16:12:55 +0200106{
107 struct lyd_dup_inst *dup_inst;
108
Michal Vasko83ae7772022-06-08 10:01:55 +0200109 if (!*inst) {
110 /* no match, inst is unchanged */
Michal Vaskod7c048c2021-05-18 16:12:55 +0200111 return LY_SUCCESS;
112 }
113
Michal Vasko83ae7772022-06-08 10:01:55 +0200114 /* there can be more exact same instances (even if not allowed in invalid data) and we must make sure we do not
115 * match a single node more times */
Michal Vasko271d2e32023-01-31 15:43:19 +0100116 dup_inst = lyd_dup_inst_get(*inst, dup_inst_ht);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200117 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
118
119 if (!dup_inst->used) {
120 /* we did not cache these instances yet, do so */
Michal Vasko271d2e32023-01-31 15:43:19 +0100121 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->set);
122 assert(dup_inst->set->count && (dup_inst->set->dnodes[0] == *inst));
Michal Vaskod7c048c2021-05-18 16:12:55 +0200123 }
124
Michal Vasko271d2e32023-01-31 15:43:19 +0100125 if (dup_inst->used == dup_inst->set->count) {
Michal Vasko4525e1f2022-07-13 16:20:59 +0200126 if (lysc_is_dup_inst_list((*inst)->schema)) {
127 /* we have used all the instances */
128 *inst = NULL;
129 } /* else just keep using the last (ideally only) instance */
Michal Vaskod7c048c2021-05-18 16:12:55 +0200130 } else {
Michal Vasko271d2e32023-01-31 15:43:19 +0100131 assert(dup_inst->used < dup_inst->set->count);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200132
133 /* use another instance */
Michal Vasko271d2e32023-01-31 15:43:19 +0100134 *inst = dup_inst->set->dnodes[dup_inst->used];
Michal Vaskod7c048c2021-05-18 16:12:55 +0200135 ++dup_inst->used;
136 }
137
138 return LY_SUCCESS;
139}
140
Michal Vasko271d2e32023-01-31 15:43:19 +0100141/**
142 * @brief Callback for freeing first instance hash table values.
143 */
144static void
145lyht_dup_inst_ht_free_cb(void *val_p)
Michal Vaskod7c048c2021-05-18 16:12:55 +0200146{
Michal Vasko271d2e32023-01-31 15:43:19 +0100147 struct lyd_dup_inst **item = val_p;
Michal Vaskod7c048c2021-05-18 16:12:55 +0200148
Michal Vasko271d2e32023-01-31 15:43:19 +0100149 ly_set_free((*item)->set, NULL);
150 free(*item);
151}
152
153void
154lyd_dup_inst_free(struct hash_table *dup_inst_ht)
155{
156 lyht_free(dup_inst_ht, lyht_dup_inst_ht_free_cb);
Michal Vaskod7c048c2021-05-18 16:12:55 +0200157}
158
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200159struct lyd_node *
160lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200161 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200162{
163 const struct lysc_node *siter = NULL;
164 struct lyd_node *match = NULL;
165
166 assert(parent || module);
167 assert(!last || (slast && *slast));
168
169 if (slast) {
170 siter = *slast;
171 }
172
173 if (last && last->next && (last->next->schema == siter)) {
174 /* return next data instance */
175 return last->next;
176 }
177
178 /* find next schema node data instance */
179 while ((siter = lys_getnext(siter, parent, module, 0))) {
180 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
181 break;
182 }
183 }
184
185 if (slast) {
186 *slast = siter;
187 }
188 return match;
189}
190
Radek Krejcie7b95092019-05-15 11:03:07 +0200191struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100192lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200193{
194 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100195
196 if (!node->schema) {
197 return &((struct lyd_node_opaq *)node)->child;
198 } else {
199 switch (node->schema->nodetype) {
200 case LYS_CONTAINER:
201 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100202 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100203 case LYS_ACTION:
204 case LYS_NOTIF:
205 return &((struct lyd_node_inner *)node)->child;
206 default:
207 return NULL;
208 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200209 }
210}
211
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100212LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200213lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
214{
215 LY_ERR ret = LY_SUCCESS;
216 char *var_name = NULL, *var_value = NULL;
217 struct lyxp_var *item;
218
219 if (!vars || !name || !value) {
220 return LY_EINVAL;
221 }
222
223 /* If variable is already defined then change its value. */
224 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
225 var_value = strdup(value);
226 LY_CHECK_RET(!var_value, LY_EMEM);
227
228 /* Set new value. */
229 free(item->value);
230 item->value = var_value;
231 } else {
232 var_name = strdup(name);
233 var_value = strdup(value);
234 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
235
236 /* Add new variable. */
237 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
238 item->name = var_name;
239 item->value = var_value;
240 }
241
242 return LY_SUCCESS;
243
244error:
245 free(var_name);
246 free(var_value);
247 return ret;
248}
249
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100250LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200251lyxp_vars_free(struct lyxp_var *vars)
252{
253 LY_ARRAY_COUNT_TYPE u;
254
255 if (!vars) {
256 return;
257 }
258
259 LY_ARRAY_FOR(vars, u) {
260 free(vars[u].name);
261 free(vars[u].value);
262 }
263
264 LY_ARRAY_FREE(vars);
265}
266
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100267LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200268lyd_child_no_keys(const struct lyd_node *node)
269{
270 struct lyd_node **children;
271
272 if (!node) {
273 return NULL;
274 }
275
276 if (!node->schema) {
277 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100278 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200279 }
280
Michal Vaskoe0665742021-02-11 11:08:44 +0100281 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200282 if (children) {
283 struct lyd_node *child = *children;
Michal Vasko26bbb272022-08-02 14:54:33 +0200284
Radek Krejcia1c1e542020-09-29 16:06:52 +0200285 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
286 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200287 }
288 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200289 } else {
290 return NULL;
291 }
292}
Michal Vasko9b368d32020-02-14 13:53:31 +0100293
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100294LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100295lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100296{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100297 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100298
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100299 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100300 return NULL;
301 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100302
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100303 if (!node->schema) {
304 opaq = (struct lyd_node_opaq *)node;
305 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200306 case LY_VALUE_XML:
Michal Vaskoebc3f402022-12-06 08:45:15 +0100307 return opaq->name.module_ns ? ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns) : NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200308 case LY_VALUE_JSON:
Michal Vaskoebc3f402022-12-06 08:45:15 +0100309 return opaq->name.module_name ? ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name) : NULL;
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100310 default:
311 return NULL;
312 }
313 }
314
Michal Vaskoef53c812021-10-13 10:21:03 +0200315 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100316}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100317
Michal Vasko598063b2021-07-19 11:39:05 +0200318void
319lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
320{
321 int cmp;
322 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200323 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200324
325 assert(node && mod);
326
327 if (!*node) {
328 return;
329 }
330
331 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200332 own_mod = lyd_owner_module(first);
333 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200334 if (cmp > 0) {
335 /* there may be some preceding data */
336 while (first->prev->next) {
337 first = first->prev;
338 if (lyd_owner_module(first) == mod) {
339 cmp = 0;
340 break;
341 }
342 }
343 }
344
345 if (cmp == 0) {
346 /* there may be some preceding data belonging to this module */
347 while (first->prev->next) {
348 if (lyd_owner_module(first->prev) != mod) {
349 break;
350 }
351 first = first->prev;
352 }
353 }
354
355 if (cmp < 0) {
356 /* there may be some following data */
357 LY_LIST_FOR(first, first) {
358 if (lyd_owner_module(first) == mod) {
359 cmp = 0;
360 break;
361 }
362 }
363 }
364
365 if (cmp == 0) {
366 /* we have found the first module data node */
367 *node = first;
368 }
369}
370
Michal Vaskob1b5c262020-03-05 14:29:47 +0100371const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200372lyd_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 +0200373 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100374{
375 struct lyd_node *iter;
376 const struct lys_module *mod;
377
378 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200379 if (module) {
380 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100381 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200382 } else {
383 mod = module;
384 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100385 }
386 } else {
387 do {
388 mod = ly_ctx_get_module_iter(ctx, i);
389 } while (mod && !mod->implemented);
390 }
391
392 /* find its data */
393 *first = NULL;
394 if (mod) {
395 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100396 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100397 *first = iter;
398 break;
399 }
400 }
401 }
402
403 return mod;
404}
405
406const struct lys_module *
407lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
408{
409 const struct lys_module *mod;
410
411 if (!*next) {
412 /* all data traversed */
413 *first = NULL;
414 return NULL;
415 }
416
417 *first = *next;
418
419 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100420 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100421 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100422 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100423 break;
424 }
425 }
426
427 return mod;
428}
Michal Vasko9f96a052020-03-10 09:41:45 +0100429
430LY_ERR
Michal Vasko59892dd2022-05-13 11:02:30 +0200431lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
432 size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
433 const struct lysc_node *ctx_node, ly_bool *incomplete)
434{
435 LY_ERR ret;
436 struct ly_err_item *err = NULL;
437 uint32_t options = (dynamic && *dynamic ? LYPLG_TYPE_STORE_DYNAMIC : 0);
438
439 if (!value) {
440 value = "";
441 }
442 if (incomplete) {
443 *incomplete = 0;
444 }
445
446 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
447 if (dynamic) {
448 *dynamic = 0;
449 }
450
451 if (ret == LY_EINCOMPLETE) {
452 if (incomplete) {
453 *incomplete = 1;
454 }
455 } else if (ret) {
456 if (err) {
457 LOGVAL_ERRITEM(ctx, err);
458 ly_err_free(err);
459 } else {
460 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
461 }
462 return ret;
463 }
464
465 return LY_SUCCESS;
466}
467
468LY_ERR
469lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
470 const struct lyd_node *ctx_node, const struct lyd_node *tree)
471{
472 LY_ERR ret;
473 struct ly_err_item *err = NULL;
474
475 assert(type->plugin->validate);
476
477 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
478 if (ret) {
479 if (err) {
480 LOGVAL_ERRITEM(ctx, err);
481 ly_err_free(err);
482 } else {
483 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.", type->plugin->print(ctx, val, LY_VALUE_CANON,
484 NULL, NULL, NULL));
485 }
486 return ret;
487 }
488
489 return LY_SUCCESS;
490}
491
492LY_ERR
493lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
494 LY_VALUE_FORMAT format, void *prefix_data)
495{
496 LY_ERR rc = LY_SUCCESS;
497 struct ly_err_item *err = NULL;
498 struct lyd_value storage;
499 struct lysc_type *type;
500
501 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
502
503 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
504 LOGARG(ctx, node);
505 return LY_EINVAL;
506 }
507
508 type = ((struct lysc_node_leaf *)node)->type;
509 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
510 LYD_HINT_SCHEMA, node, &storage, NULL, &err);
511 if (rc == LY_EINCOMPLETE) {
512 /* actually success since we do not provide the context tree and call validation with
513 * LY_TYPE_OPTS_INCOMPLETE_DATA */
514 rc = LY_SUCCESS;
515 } else if (rc && err) {
516 if (ctx) {
517 /* log only in case the ctx was provided as input parameter */
Michal Vaskof8da2682022-06-16 07:52:37 +0200518 if (err->path) {
519 LOG_LOCSET(NULL, NULL, err->path, NULL);
520 } else {
521 /* use at least the schema path */
522 LOG_LOCSET(node, NULL, NULL, NULL);
523 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200524 LOGVAL_ERRITEM(ctx, err);
Michal Vaskof8da2682022-06-16 07:52:37 +0200525 if (err->path) {
526 LOG_LOCBACK(0, 0, 1, 0);
527 } else {
528 LOG_LOCBACK(1, 0, 0, 0);
529 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200530 }
531 ly_err_free(err);
532 }
533
534 if (!rc) {
535 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
536 }
537 return rc;
538}
539
540LIBYANG_API_DEF LY_ERR
541lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
542 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
543{
544 LY_ERR rc;
545 struct ly_err_item *err = NULL;
546 struct lysc_type *type;
547 struct lyd_value val = {0};
548 ly_bool stored = 0, log = 1;
549
Michal Vasko3dd16da2022-06-15 07:58:41 +0200550 LY_CHECK_ARG_RET(ctx, schema, !value_len || value, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200551
552 if (!ctx) {
553 ctx = schema->module->ctx;
554 log = 0;
555 }
Michal Vasko3dd16da2022-06-15 07:58:41 +0200556 if (!value_len) {
557 value = "";
558 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200559 type = ((struct lysc_node_leaf *)schema)->type;
560
561 /* store */
562 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
563 LYD_HINT_DATA, schema, &val, NULL, &err);
564 if (!rc || (rc == LY_EINCOMPLETE)) {
565 stored = 1;
566 }
567
568 if (ctx_node && (rc == LY_EINCOMPLETE)) {
569 /* resolve */
570 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
571 }
572
573 if (rc && (rc != LY_EINCOMPLETE) && err) {
574 if (log) {
575 /* log error */
576 if (err->path) {
577 LOG_LOCSET(NULL, NULL, err->path, NULL);
578 } else if (ctx_node) {
579 LOG_LOCSET(NULL, ctx_node, NULL, NULL);
580 } else {
581 LOG_LOCSET(schema, NULL, NULL, NULL);
582 }
583 LOGVAL_ERRITEM(ctx, err);
584 if (err->path) {
585 LOG_LOCBACK(0, 0, 1, 0);
586 } else if (ctx_node) {
587 LOG_LOCBACK(0, 1, 0, 0);
588 } else {
589 LOG_LOCBACK(1, 0, 0, 0);
590 }
591 }
592 ly_err_free(err);
593 }
594
595 if (!rc || (rc == LY_EINCOMPLETE)) {
596 if (realtype) {
597 /* return realtype */
598 if (val.realtype->basetype == LY_TYPE_UNION) {
599 *realtype = val.subvalue->value.realtype;
600 } else {
601 *realtype = val.realtype;
602 }
603 }
604
605 if (canonical) {
606 /* return canonical value */
607 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
608 }
609 }
610
611 if (stored) {
612 /* free value */
613 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
614 }
615 return rc;
616}
617
618LIBYANG_API_DEF LY_ERR
619lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
620{
621 LY_ERR ret = LY_SUCCESS;
622 struct ly_ctx *ctx;
623 struct lysc_type *type;
624 struct lyd_value val = {0};
625
626 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
627
628 ctx = node->schema->module->ctx;
629 type = ((struct lysc_node_leaf *)node->schema)->type;
630
631 /* store the value */
632 LOG_LOCSET(node->schema, &node->node, NULL, NULL);
633 ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
634 LOG_LOCBACK(1, 1, 0, 0);
635 LY_CHECK_RET(ret);
636
637 /* compare values */
638 ret = type->plugin->compare(&node->value, &val);
639
640 type->plugin->free(ctx, &val);
641 return ret;
642}
643
644LIBYANG_API_DEF ly_bool
645lyd_is_default(const struct lyd_node *node)
646{
647 const struct lysc_node_leaf *leaf;
648 const struct lysc_node_leaflist *llist;
649 const struct lyd_node_term *term;
650 LY_ARRAY_COUNT_TYPE u;
651
652 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
653 return 0;
654 }
655
656 term = (const struct lyd_node_term *)node;
657
658 if (node->schema->nodetype == LYS_LEAF) {
659 leaf = (const struct lysc_node_leaf *)node->schema;
660 if (!leaf->dflt) {
661 return 0;
662 }
663
664 /* compare with the default value */
665 if (!leaf->type->plugin->compare(&term->value, leaf->dflt)) {
666 return 1;
667 }
668 } else {
669 llist = (const struct lysc_node_leaflist *)node->schema;
670 if (!llist->dflts) {
671 return 0;
672 }
673
674 LY_ARRAY_FOR(llist->dflts, u) {
675 /* compare with each possible default value */
676 if (!llist->type->plugin->compare(&term->value, llist->dflts[u])) {
677 return 1;
678 }
679 }
680 }
681
682 return 0;
683}
684
685LIBYANG_API_DEF uint32_t
686lyd_list_pos(const struct lyd_node *instance)
687{
688 const struct lyd_node *iter = NULL;
689 uint32_t pos = 0;
690
691 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
692 return 0;
693 }
694
695 /* data instances are ordered, so we can stop when we found instance of other schema node */
696 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
697 if (pos && (iter->next == NULL)) {
698 /* overrun to the end of the siblings list */
699 break;
700 }
701 ++pos;
702 }
703
704 return pos;
705}
706
707LIBYANG_API_DEF struct lyd_node *
708lyd_first_sibling(const struct lyd_node *node)
709{
710 struct lyd_node *start;
711
712 if (!node) {
713 return NULL;
714 }
715
716 /* get the first sibling */
717 if (node->parent) {
718 start = node->parent->child;
719 } else {
720 for (start = (struct lyd_node *)node; start->prev->next; start = start->prev) {}
721 }
722
723 return start;
724}
725
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100726/**
727 * @brief Check list node parsed into an opaque node for the reason.
728 *
729 * @param[in] node Opaque node.
730 * @param[in] snode Schema node of @p opaq.
731 * @return LY_SUCCESS if the node is valid;
732 * @return LY_ERR on error.
733 */
734static LY_ERR
735lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
736{
737 LY_ERR ret = LY_SUCCESS;
738 struct ly_set key_set = {0};
739 const struct lysc_node *key = NULL;
740 const struct lyd_node *child;
741 const struct lyd_node_opaq *opaq_k;
742 uint32_t i;
743
744 assert(!node->schema);
745
746 /* get all keys into a set */
747 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
748 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
749 }
750
751 LY_LIST_FOR(lyd_child(node), child) {
752 if (child->schema) {
753 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
754 LYD_NAME(child));
755 ret = LY_EINVAL;
756 goto cleanup;
757 }
758
759 opaq_k = (struct lyd_node_opaq *)child;
760
761 /* find the key schema node */
762 for (i = 0; i < key_set.count; ++i) {
763 key = key_set.snodes[i];
764 if (!strcmp(key->name, opaq_k->name.name)) {
765 break;
766 }
767 }
768 if (i == key_set.count) {
769 /* some other node, skip */
770 continue;
771 }
772
773 /* key found */
774 ly_set_rm_index(&key_set, i, NULL);
775
776 /* check value */
777 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
778 opaq_k->val_prefix_data);
779 LY_CHECK_GOTO(ret, cleanup);
780 }
781
782 if (key_set.count) {
783 /* missing keys */
784 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
785 ret = LY_EVALID;
786 goto cleanup;
787 }
788
789cleanup:
790 ly_set_erase(&key_set, NULL);
791 return ret;
792}
793
794LIBYANG_API_DEF LY_ERR
795lyd_parse_opaq_error(const struct lyd_node *node)
796{
797 const struct ly_ctx *ctx;
798 const struct lyd_node_opaq *opaq;
799 const struct lyd_node *parent;
800 const struct lys_module *mod;
801 const struct lysc_node *snode;
802
803 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
804
805 ctx = LYD_CTX(node);
806 opaq = (struct lyd_node_opaq *)node;
807 parent = lyd_parent(node);
808
Michal Vaskof4e63922022-05-10 10:32:13 +0200809 if (!opaq->name.module_ns) {
810 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
811 return LY_EVALID;
812 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100813
814 /* module */
815 switch (opaq->format) {
816 case LY_VALUE_XML:
817 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
818 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
819 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200820 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" of node \"%s\" in the context.",
821 opaq->name.module_ns, opaq->name.name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100822 return LY_EVALID;
823 }
824 } else {
825 /* inherit */
826 mod = parent->schema->module;
827 }
828 break;
829 case LY_VALUE_JSON:
830 case LY_VALUE_LYB:
831 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
832 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
833 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200834 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" of node \"%s\" in the context.",
835 opaq->name.module_name, opaq->name.name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100836 return LY_EVALID;
837 }
838 } else {
839 /* inherit */
840 mod = parent->schema->module;
841 }
842 break;
843 default:
844 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
845 return LY_EINVAL;
846 }
847
848 /* schema */
849 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200850 if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
851 /* maybe output node */
Michal Vasko89afc6e2022-05-02 10:24:26 +0200852 snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200853 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100854 if (!snode) {
855 if (parent) {
856 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
857 LYD_NAME(parent));
858 } else {
859 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
860 }
861 return LY_EVALID;
862 }
863
864 if (snode->nodetype & LYD_NODE_TERM) {
865 /* leaf / leaf-list */
866 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
867 } else if (snode->nodetype == LYS_LIST) {
868 /* list */
869 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
870 } else if (snode->nodetype & LYD_NODE_INNER) {
871 /* inner node */
872 if (opaq->value) {
873 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
874 lys_nodetype2str(snode->nodetype), snode->name);
875 return LY_EVALID;
876 }
877 } else {
878 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
879 return LY_EINVAL;
880 }
881
882 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
883 return LY_EINVAL;
884}
885
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100886LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400887lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200888{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200889 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
890
Michal Vasko33876022021-04-27 16:42:24 +0200891 return value->_canonical ? value->_canonical :
892 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200893}
894
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100895LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100896lyd_any_value_str(const struct lyd_node *any, char **value_str)
897{
898 const struct lyd_node_any *a;
899 struct lyd_node *tree = NULL;
900 const char *str = NULL;
901 ly_bool dynamic = 0;
902 LY_ERR ret = LY_SUCCESS;
903
904 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200905 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100906
907 a = (struct lyd_node_any *)any;
908 *value_str = NULL;
909
910 if (!a->value.str) {
911 /* there is no value in the union */
912 return LY_SUCCESS;
913 }
914
915 switch (a->value_type) {
916 case LYD_ANYDATA_LYB:
917 /* parse into a data tree */
918 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
919 LY_CHECK_GOTO(ret, cleanup);
920 dynamic = 1;
921 break;
922 case LYD_ANYDATA_DATATREE:
923 tree = a->value.tree;
924 break;
925 case LYD_ANYDATA_STRING:
926 case LYD_ANYDATA_XML:
927 case LYD_ANYDATA_JSON:
928 /* simply use the string */
929 str = a->value.str;
930 break;
931 }
932
933 if (tree) {
934 /* print into a string */
935 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
936 LY_CHECK_GOTO(ret, cleanup);
937 } else {
938 assert(str);
939 *value_str = strdup(str);
940 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
941 }
942
943 /* success */
944
945cleanup:
946 if (dynamic) {
947 lyd_free_all(tree);
948 }
949 return ret;
950}
951
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100952LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200953lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
954{
955 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200956
Michal Vaskoa820c312021-02-05 16:33:00 +0100957 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200958 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200959
960 t = (struct lyd_node_any *)trg;
961
962 /* free trg */
963 switch (t->value_type) {
964 case LYD_ANYDATA_DATATREE:
965 lyd_free_all(t->value.tree);
966 break;
967 case LYD_ANYDATA_STRING:
968 case LYD_ANYDATA_XML:
969 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100970 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200971 break;
972 case LYD_ANYDATA_LYB:
973 free(t->value.mem);
974 break;
975 }
976 t->value.str = NULL;
977
978 if (!value) {
979 /* only free value in this case */
980 return LY_SUCCESS;
981 }
982
983 /* copy src */
984 t->value_type = value_type;
985 switch (value_type) {
986 case LYD_ANYDATA_DATATREE:
987 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200988 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200989 }
990 break;
991 case LYD_ANYDATA_STRING:
992 case LYD_ANYDATA_XML:
993 case LYD_ANYDATA_JSON:
994 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200995 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200996 }
997 break;
998 case LYD_ANYDATA_LYB:
999 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02001000 int len = lyd_lyb_data_length(value->mem);
Michal Vasko26bbb272022-08-02 14:54:33 +02001001
Radek Krejci82fa8d42020-07-11 22:00:59 +02001002 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +02001003 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001004 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +02001005 memcpy(t->value.mem, value->mem, len);
1006 }
1007 break;
1008 }
1009
1010 return LY_SUCCESS;
1011}
1012
Michal Vasko106f0862021-11-02 11:49:27 +01001013const struct lysc_node *
1014lyd_node_schema(const struct lyd_node *node)
1015{
1016 const struct lysc_node *schema = NULL;
1017 const struct lyd_node *prev_iter = NULL, *iter;
1018 const struct lys_module *mod;
1019
1020 if (!node) {
1021 return NULL;
1022 } else if (node->schema) {
1023 return node->schema;
1024 }
1025
1026 /* get schema node of an opaque node */
1027 do {
1028 /* get next data node */
1029 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
1030
1031 /* get equivalent schema node */
1032 if (iter->schema) {
1033 schema = iter->schema;
1034 } else {
1035 /* get module */
1036 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +01001037 if (!mod && !schema) {
1038 /* top-level opaque node has unknown module */
1039 break;
1040 }
Michal Vasko106f0862021-11-02 11:49:27 +01001041
1042 /* get schema node */
1043 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
1044 }
Michal Vaskod2f404f2021-11-04 15:37:11 +01001045
1046 /* remember to move to the descendant */
1047 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +01001048 } while (schema && (iter != node));
1049
1050 return schema;
1051}
1052
Michal Vasko4754d4a2022-12-01 10:11:21 +01001053void
1054lyd_cont_set_dflt(struct lyd_node *node)
1055{
1056 const struct lyd_node *child;
1057
1058 while (node) {
1059 if (!node->schema || (node->flags & LYD_DEFAULT) || !lysc_is_np_cont(node->schema)) {
1060 /* not a non-dflt NP container */
1061 break;
1062 }
1063
1064 LY_LIST_FOR(lyd_child(node), child) {
1065 if (!(child->flags & LYD_DEFAULT)) {
1066 break;
1067 }
1068 }
1069 if (child) {
1070 /* explicit child, no dflt change */
1071 break;
1072 }
1073
1074 /* set the dflt flag */
1075 node->flags |= LYD_DEFAULT;
1076
1077 /* check all parent containers */
1078 node = lyd_parent(node);
1079 }
1080}
1081
Michal Vasko59892dd2022-05-13 11:02:30 +02001082/**
1083 * @brief Comparison callback to match schema node with a schema of a data node.
1084 *
1085 * @param[in] val1_p Pointer to the schema node
1086 * @param[in] val2_p Pointer to the data node
1087 * Implementation of ::lyht_value_equal_cb.
1088 */
1089static ly_bool
1090lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1091{
1092 struct lysc_node *val1;
1093 struct lyd_node *val2;
1094
1095 val1 = *((struct lysc_node **)val1_p);
1096 val2 = *((struct lyd_node **)val2_p);
1097
1098 if (val1 == val2->schema) {
1099 /* schema match is enough */
1100 return 1;
1101 } else {
1102 return 0;
1103 }
1104}
1105
1106LY_ERR
1107lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1108{
1109 struct lyd_node **match_p;
1110 struct lyd_node_inner *parent;
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001111 const struct lysc_node *cur_schema;
Michal Vasko59892dd2022-05-13 11:02:30 +02001112 uint32_t hash;
1113 lyht_value_equal_cb ht_cb;
1114
Michal Vasko21beaeb2022-08-02 10:42:48 +02001115 assert(schema);
1116 if (!siblings) {
1117 /* no data */
1118 if (match) {
1119 *match = NULL;
1120 }
1121 return LY_ENOTFOUND;
1122 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001123
1124 parent = siblings->parent;
1125 if (parent && parent->schema && parent->children_ht) {
1126 /* calculate our hash */
1127 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1128 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1129 hash = dict_hash_multi(hash, NULL, 0);
1130
1131 /* use special hash table function */
1132 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1133
1134 /* find by hash */
1135 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1136 siblings = *match_p;
1137 } else {
1138 /* not found */
1139 siblings = NULL;
1140 }
1141
1142 /* set the original hash table compare function back */
1143 lyht_set_cb(parent->children_ht, ht_cb);
1144 } else {
1145 /* find first sibling */
1146 if (siblings->parent) {
1147 siblings = siblings->parent->child;
1148 } else {
1149 while (siblings->prev->next) {
1150 siblings = siblings->prev;
1151 }
1152 }
1153
1154 /* search manually without hashes */
1155 for ( ; siblings; siblings = siblings->next) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001156 cur_schema = lyd_node_schema(siblings);
1157 if (!cur_schema) {
1158 /* some unknown opaque node */
1159 continue;
Michal Vasko31bac382022-07-20 08:07:59 +02001160 }
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001161
1162 /* schema match is enough */
1163 if (cur_schema->module->ctx == schema->module->ctx) {
1164 if (cur_schema == schema) {
1165 break;
1166 }
1167 } else {
1168 if (!strcmp(cur_schema->name, schema->name) && !strcmp(cur_schema->module->name, schema->module->name)) {
1169 break;
1170 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001171 }
1172 }
1173 }
1174
1175 if (!siblings) {
1176 if (match) {
1177 *match = NULL;
1178 }
1179 return LY_ENOTFOUND;
1180 }
1181
1182 if (match) {
1183 *match = (struct lyd_node *)siblings;
1184 }
1185 return LY_SUCCESS;
1186}
1187
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001188void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001189lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1190{
1191 if (*root && (lyd_owner_module(*root) != mod)) {
1192 /* there are no data of mod so this is simply the first top-level sibling */
1193 mod = NULL;
1194 }
1195
1196 if ((*root != to_del) || (*root)->parent) {
1197 return;
1198 }
1199
Michal Vasko598063b2021-07-19 11:39:05 +02001200 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1201 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001202 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001203 } else {
1204 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001205 }
1206}
1207
Michal Vasko8cc3f662022-03-29 11:25:51 +02001208LY_ERR
1209ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1210 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1211 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1212{
1213 LY_ERR r;
1214 LY_ARRAY_COUNT_TYPE u;
1215 struct lysc_ext_instance *nested_exts = NULL;
1216 lyplg_ext_data_snode_clb ext_snode_cb;
1217
1218 /* check if there are any nested extension instances */
1219 if (parent && parent->schema) {
1220 nested_exts = parent->schema->exts;
1221 } else if (sparent) {
1222 nested_exts = sparent->exts;
1223 }
1224 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001225 if (!nested_exts[u].def->plugin) {
1226 /* no plugin */
1227 continue;
1228 }
1229
Michal Vasko8cc3f662022-03-29 11:25:51 +02001230 ext_snode_cb = nested_exts[u].def->plugin->snode;
1231 if (!ext_snode_cb) {
1232 /* not an extension with nested data */
1233 continue;
1234 }
1235
1236 /* try to get the schema node */
1237 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1238 if (!r) {
Michal Vasko66330fc2022-11-21 15:52:24 +01001239 if (ext) {
1240 /* data successfully created, remember the ext instance */
1241 *ext = &nested_exts[u];
1242 }
Michal Vasko8cc3f662022-03-29 11:25:51 +02001243 return LY_SUCCESS;
1244 } else if (r != LY_ENOT) {
1245 /* fatal error */
1246 return r;
1247 }
1248 /* data was not from this module, continue */
1249 }
1250
1251 /* no extensions or none matched */
1252 return LY_ENOT;
1253}
1254
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001255void
Radek Krejci8df109d2021-04-23 12:19:08 +02001256ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001257{
1258 struct ly_set *ns_list;
1259 struct lysc_prefix *prefixes;
1260 uint32_t i;
1261 LY_ARRAY_COUNT_TYPE u;
1262
1263 if (!prefix_data) {
1264 return;
1265 }
1266
1267 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001268 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001269 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001270 ns_list = prefix_data;
1271 for (i = 0; i < ns_list->count; ++i) {
1272 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1273 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1274 }
1275 ly_set_free(ns_list, free);
1276 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001277 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001278 prefixes = prefix_data;
1279 LY_ARRAY_FOR(prefixes, u) {
1280 free(prefixes[u].prefix);
1281 }
1282 LY_ARRAY_FREE(prefixes);
1283 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001284 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001285 case LY_VALUE_SCHEMA:
1286 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001287 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001288 break;
1289 }
1290}
1291
1292LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001293ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001294 void **prefix_data_p)
1295{
1296 LY_ERR ret = LY_SUCCESS;
1297 struct lyxml_ns *ns;
1298 struct lysc_prefix *prefixes = NULL, *orig_pref;
1299 struct ly_set *ns_list, *orig_ns;
1300 uint32_t i;
1301 LY_ARRAY_COUNT_TYPE u;
1302
1303 assert(!*prefix_data_p);
1304
1305 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001306 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001307 *prefix_data_p = (void *)prefix_data;
1308 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001309 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001310 /* copy all the value prefixes */
1311 orig_pref = (struct lysc_prefix *)prefix_data;
1312 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1313 *prefix_data_p = prefixes;
1314
1315 LY_ARRAY_FOR(orig_pref, u) {
1316 if (orig_pref[u].prefix) {
1317 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1318 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1319 }
1320 prefixes[u].mod = orig_pref[u].mod;
1321 LY_ARRAY_INCREMENT(prefixes);
1322 }
1323 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001324 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001325 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001326 /* copy all the namespaces */
1327 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1328 *prefix_data_p = ns_list;
1329
1330 orig_ns = (struct ly_set *)prefix_data;
1331 for (i = 0; i < orig_ns->count; ++i) {
1332 ns = calloc(1, sizeof *ns);
1333 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1334 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1335
1336 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1337 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1338 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1339 }
1340 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1341 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1342 }
1343 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001344 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001345 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001346 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001347 assert(!prefix_data);
1348 *prefix_data_p = NULL;
1349 break;
1350 }
1351
1352cleanup:
1353 if (ret) {
1354 ly_free_prefix_data(format, *prefix_data_p);
1355 *prefix_data_p = NULL;
1356 }
1357 return ret;
1358}
1359
1360LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001361ly_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 +02001362 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001363{
1364 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001365 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001366 const struct lyxml_ns *ns;
1367 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001368 struct ly_set *ns_list;
1369 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001370 const char *value_iter, *value_next, *value_end;
1371 uint32_t substr_len;
1372 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001373
1374 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001375 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001376 /* copy all referenced modules as prefix - module pairs */
1377 if (!*prefix_data_p) {
1378 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001379 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001380 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001381 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001382 } else {
1383 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001384 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001385 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001386 }
1387
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001388 /* add current module for unprefixed values */
1389 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1390 *prefix_data_p = prefixes;
1391
1392 val_pref->prefix = NULL;
1393 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1394
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001395 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001396 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001397 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001398 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 +02001399 if (is_prefix) {
1400 /* we have a possible prefix. Do we already have the prefix? */
1401 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1402 if (!mod) {
1403 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1404 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001405 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001406 /* store a new prefix - module pair */
1407 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1408 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001409
aPiecek83436bc2021-03-30 12:20:45 +02001410 val_pref->prefix = strndup(value_iter, substr_len);
1411 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1412 val_pref->mod = mod;
1413 } /* else it is not even defined */
1414 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001415 }
1416 }
1417 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001418 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001419 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001420 /* copy all referenced namespaces as prefix - namespace pairs */
1421 if (!*prefix_data_p) {
1422 /* new prefix data */
1423 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001424 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001425 *prefix_data_p = ns_list;
1426 } else {
1427 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001428 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001429 ns_list = *prefix_data_p;
1430 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001431
Michal Vasko294e7f02022-02-28 13:59:00 +01001432 /* store default namespace */
1433 ns = lyxml_ns_get(prefix_data, NULL, 0);
1434 if (ns) {
1435 new_ns = calloc(1, sizeof *new_ns);
1436 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1437 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1438
1439 new_ns->prefix = NULL;
1440 new_ns->uri = strdup(ns->uri);
1441 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1442 }
1443
Michal Vaskofc2cd072021-02-24 13:17:17 +01001444 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001445 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001446 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001447 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 +02001448 if (is_prefix) {
1449 /* we have a possible prefix. Do we already have the prefix? */
1450 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1451 if (!ns) {
1452 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1453 if (ns) {
1454 /* store a new prefix - namespace pair */
1455 new_ns = calloc(1, sizeof *new_ns);
1456 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1457 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001458
aPiecek83436bc2021-03-30 12:20:45 +02001459 new_ns->prefix = strndup(value_iter, substr_len);
1460 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1461 new_ns->uri = strdup(ns->uri);
1462 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1463 } /* else it is not even defined */
1464 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001465 }
1466 }
1467 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001468 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001469 case LY_VALUE_SCHEMA_RESOLVED:
1470 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001471 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001472 if (!*prefix_data_p) {
1473 /* new prefix data - simply copy all the prefix data */
1474 *format_p = format;
1475 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1476 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001477 break;
1478 }
1479
1480cleanup:
1481 if (ret) {
1482 ly_free_prefix_data(*format_p, *prefix_data_p);
1483 *prefix_data_p = NULL;
1484 }
1485 return ret;
1486}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001487
1488const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001489ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001490{
1491 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001492 case LY_VALUE_CANON:
1493 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001494 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001495 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001496 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001497 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001498 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001499 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001500 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001501 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001502 case LY_VALUE_LYB:
1503 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001504 default:
1505 break;
1506 }
1507
1508 return NULL;
1509}
Michal Vasko43297a02021-05-19 11:12:37 +02001510
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001511LIBYANG_API_DEF int
1512ly_time_tz_offset(void)
1513{
1514 const time_t epoch_plus_11h = 60 * 60 * 11;
1515 struct tm tm_local, tm_utc;
1516 int result = 0;
1517
1518 /* init timezone */
1519 tzset();
1520
1521 /* get local and UTC time */
1522 localtime_r(&epoch_plus_11h, &tm_local);
1523 gmtime_r(&epoch_plus_11h, &tm_utc);
1524
1525 /* hours shift in seconds */
1526 result += (tm_local.tm_hour - tm_utc.tm_hour) * 3600;
1527
1528 /* minutes shift in seconds */
1529 result += (tm_local.tm_min - tm_utc.tm_min) * 60;
1530
1531 /* seconds shift */
1532 result += tm_local.tm_sec - tm_utc.tm_sec;
1533
1534 return result;
1535}
1536
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001537LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001538ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1539{
1540 struct tm tm = {0};
1541 uint32_t i, frac_len;
1542 const char *frac;
1543 int64_t shift, shift_m;
1544 time_t t;
1545
1546 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1547
1548 tm.tm_year = atoi(&value[0]) - 1900;
1549 tm.tm_mon = atoi(&value[5]) - 1;
1550 tm.tm_mday = atoi(&value[8]);
1551 tm.tm_hour = atoi(&value[11]);
1552 tm.tm_min = atoi(&value[14]);
1553 tm.tm_sec = atoi(&value[17]);
1554
1555 t = timegm(&tm);
1556 i = 19;
1557
1558 /* fractions of a second */
1559 if (value[i] == '.') {
1560 ++i;
1561 frac = &value[i];
1562 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1563
1564 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001565 } else {
1566 frac = NULL;
1567 }
1568
1569 /* apply offset */
1570 if ((value[i] == 'Z') || (value[i] == 'z')) {
1571 /* zero shift */
1572 shift = 0;
1573 } else {
1574 shift = strtol(&value[i], NULL, 10);
1575 shift = shift * 60 * 60; /* convert from hours to seconds */
1576 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1577 /* correct sign */
1578 if (shift < 0) {
1579 shift_m *= -1;
1580 }
1581 /* connect hours and minutes of the shift */
1582 shift = shift + shift_m;
1583 }
1584
1585 /* we have to shift to the opposite way to correct the time */
1586 t -= shift;
1587
1588 *time = t;
1589 if (fractions_s) {
1590 if (frac) {
1591 *fractions_s = strndup(frac, frac_len);
1592 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1593 } else {
1594 *fractions_s = NULL;
1595 }
1596 }
1597 return LY_SUCCESS;
1598}
1599
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001600LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001601ly_time_time2str(time_t time, const char *fractions_s, char **str)
1602{
1603 struct tm tm;
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001604 char zoneshift[12];
1605 int zonediff_s, zonediff_h, zonediff_m;
Michal Vasko43297a02021-05-19 11:12:37 +02001606
1607 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1608
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001609 /* init timezone */
Michal Vasko43297a02021-05-19 11:12:37 +02001610 tzset();
1611
1612 /* convert */
1613 if (!localtime_r(&time, &tm)) {
1614 return LY_ESYS;
1615 }
1616
1617 /* get timezone offset */
Michal Vaskof17bb2a2023-02-10 11:34:55 +01001618 zonediff_s = ly_time_tz_offset();
1619 zonediff_h = zonediff_s / 60 / 60;
1620 zonediff_m = zonediff_s / 60 % 60;
Michal Vasko43297a02021-05-19 11:12:37 +02001621 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
1622
1623 /* print */
1624 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1625 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1626 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1627 return LY_EMEM;
1628 }
1629
1630 return LY_SUCCESS;
1631}
1632
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001633LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001634ly_time_str2ts(const char *value, struct timespec *ts)
1635{
1636 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001637 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001638 int frac_len;
1639
1640 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1641
1642 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1643 LY_CHECK_RET(rc);
1644
1645 /* convert fractions of a second to nanoseconds */
1646 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001647 /* init frac_buf with zeroes */
1648 memset(frac_buf, '0', 9);
1649 frac_buf[9] = '\0';
1650
Michal Vasko43297a02021-05-19 11:12:37 +02001651 frac_len = strlen(fractions_s);
1652 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1653 ts->tv_nsec = atol(frac_buf);
1654 free(fractions_s);
1655 } else {
1656 ts->tv_nsec = 0;
1657 }
1658
1659 return LY_SUCCESS;
1660}
1661
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001662LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001663ly_time_ts2str(const struct timespec *ts, char **str)
1664{
1665 char frac_buf[10];
1666
Jan Kundrátbd157002021-08-30 14:02:22 +02001667 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001668
1669 /* convert nanoseconds to fractions of a second */
1670 if (ts->tv_nsec) {
1671 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1672 }
1673
1674 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1675}