blob: f35f8f5155c694bc390af343333ef2796813b3a9 [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
Michal Vasko83ae7772022-06-08 10:01:55 +020076 if (!*inst) {
77 /* no match, inst is unchanged */
Michal Vaskod7c048c2021-05-18 16:12:55 +020078 return LY_SUCCESS;
79 }
80
Michal Vasko83ae7772022-06-08 10:01:55 +020081 /* there can be more exact same instances (even if not allowed in invalid data) and we must make sure we do not
82 * match a single node more times */
Michal Vaskod7c048c2021-05-18 16:12:55 +020083 dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
84 LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
85
86 if (!dup_inst->used) {
87 /* we did not cache these instances yet, do so */
88 lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
89 assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
90 }
91
92 if (dup_inst->used == dup_inst->inst_set->count) {
Michal Vasko4525e1f2022-07-13 16:20:59 +020093 if (lysc_is_dup_inst_list((*inst)->schema)) {
94 /* we have used all the instances */
95 *inst = NULL;
96 } /* else just keep using the last (ideally only) instance */
Michal Vaskod7c048c2021-05-18 16:12:55 +020097 } else {
98 assert(dup_inst->used < dup_inst->inst_set->count);
99
100 /* use another instance */
101 *inst = dup_inst->inst_set->dnodes[dup_inst->used];
102 ++dup_inst->used;
103 }
104
105 return LY_SUCCESS;
106}
107
108void
109lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
110{
111 LY_ARRAY_COUNT_TYPE u;
112
113 LY_ARRAY_FOR(dup_inst, u) {
114 ly_set_free(dup_inst[u].inst_set, NULL);
115 }
116 LY_ARRAY_FREE(dup_inst);
117}
118
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200119struct lyd_node *
120lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +0200121 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200122{
123 const struct lysc_node *siter = NULL;
124 struct lyd_node *match = NULL;
125
126 assert(parent || module);
127 assert(!last || (slast && *slast));
128
129 if (slast) {
130 siter = *slast;
131 }
132
133 if (last && last->next && (last->next->schema == siter)) {
134 /* return next data instance */
135 return last->next;
136 }
137
138 /* find next schema node data instance */
139 while ((siter = lys_getnext(siter, parent, module, 0))) {
140 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
141 break;
142 }
143 }
144
145 if (slast) {
146 *slast = siter;
147 }
148 return match;
149}
150
Radek Krejcie7b95092019-05-15 11:03:07 +0200151struct lyd_node **
Michal Vaskoe0665742021-02-11 11:08:44 +0100152lyd_node_child_p(struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200153{
154 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +0100155
156 if (!node->schema) {
157 return &((struct lyd_node_opaq *)node)->child;
158 } else {
159 switch (node->schema->nodetype) {
160 case LYS_CONTAINER:
161 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +0100162 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100163 case LYS_ACTION:
164 case LYS_NOTIF:
165 return &((struct lyd_node_inner *)node)->child;
166 default:
167 return NULL;
168 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200169 }
170}
171
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100172LIBYANG_API_DEF LY_ERR
aPiecekdf23eee2021-10-07 12:21:50 +0200173lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
174{
175 LY_ERR ret = LY_SUCCESS;
176 char *var_name = NULL, *var_value = NULL;
177 struct lyxp_var *item;
178
179 if (!vars || !name || !value) {
180 return LY_EINVAL;
181 }
182
183 /* If variable is already defined then change its value. */
184 if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
185 var_value = strdup(value);
186 LY_CHECK_RET(!var_value, LY_EMEM);
187
188 /* Set new value. */
189 free(item->value);
190 item->value = var_value;
191 } else {
192 var_name = strdup(name);
193 var_value = strdup(value);
194 LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
195
196 /* Add new variable. */
197 LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
198 item->name = var_name;
199 item->value = var_value;
200 }
201
202 return LY_SUCCESS;
203
204error:
205 free(var_name);
206 free(var_value);
207 return ret;
208}
209
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100210LIBYANG_API_DEF void
aPiecekdf23eee2021-10-07 12:21:50 +0200211lyxp_vars_free(struct lyxp_var *vars)
212{
213 LY_ARRAY_COUNT_TYPE u;
214
215 if (!vars) {
216 return;
217 }
218
219 LY_ARRAY_FOR(vars, u) {
220 free(vars[u].name);
221 free(vars[u].value);
222 }
223
224 LY_ARRAY_FREE(vars);
225}
226
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100227LIBYANG_API_DEF struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +0200228lyd_child_no_keys(const struct lyd_node *node)
229{
230 struct lyd_node **children;
231
232 if (!node) {
233 return NULL;
234 }
235
236 if (!node->schema) {
237 /* opaq node */
Michal Vasko9e685082021-01-29 14:49:09 +0100238 return ((struct lyd_node_opaq *)node)->child;
Radek Krejcia1c1e542020-09-29 16:06:52 +0200239 }
240
Michal Vaskoe0665742021-02-11 11:08:44 +0100241 children = lyd_node_child_p((struct lyd_node *)node);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200242 if (children) {
243 struct lyd_node *child = *children;
Michal Vasko26bbb272022-08-02 14:54:33 +0200244
Radek Krejcia1c1e542020-09-29 16:06:52 +0200245 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
246 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200247 }
248 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200249 } else {
250 return NULL;
251 }
252}
Michal Vasko9b368d32020-02-14 13:53:31 +0100253
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100254LIBYANG_API_DEF const struct lys_module *
Michal Vaskoc193ce92020-03-06 11:04:48 +0100255lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100256{
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100257 const struct lyd_node_opaq *opaq;
Michal Vasko9b368d32020-02-14 13:53:31 +0100258
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100259 if (!node) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100260 return NULL;
261 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100262
Michal Vaskod5cfa6e2020-11-23 16:56:08 +0100263 if (!node->schema) {
264 opaq = (struct lyd_node_opaq *)node;
265 switch (opaq->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200266 case LY_VALUE_XML:
Michal Vaskoebc3f402022-12-06 08:45:15 +0100267 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 +0200268 case LY_VALUE_JSON:
Michal Vaskoebc3f402022-12-06 08:45:15 +0100269 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 +0100270 default:
271 return NULL;
272 }
273 }
274
Michal Vaskoef53c812021-10-13 10:21:03 +0200275 return lysc_owner_module(node->schema);
Michal Vasko9b368d32020-02-14 13:53:31 +0100276}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100277
Michal Vasko598063b2021-07-19 11:39:05 +0200278void
279lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
280{
281 int cmp;
282 struct lyd_node *first;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200283 const struct lys_module *own_mod;
Michal Vasko598063b2021-07-19 11:39:05 +0200284
285 assert(node && mod);
286
287 if (!*node) {
288 return;
289 }
290
291 first = *node;
Michal Vaskoec139eb2022-05-10 10:08:40 +0200292 own_mod = lyd_owner_module(first);
293 cmp = own_mod ? strcmp(own_mod->name, mod->name) : 1;
Michal Vasko598063b2021-07-19 11:39:05 +0200294 if (cmp > 0) {
295 /* there may be some preceding data */
296 while (first->prev->next) {
297 first = first->prev;
298 if (lyd_owner_module(first) == mod) {
299 cmp = 0;
300 break;
301 }
302 }
303 }
304
305 if (cmp == 0) {
306 /* there may be some preceding data belonging to this module */
307 while (first->prev->next) {
308 if (lyd_owner_module(first->prev) != mod) {
309 break;
310 }
311 first = first->prev;
312 }
313 }
314
315 if (cmp < 0) {
316 /* there may be some following data */
317 LY_LIST_FOR(first, first) {
318 if (lyd_owner_module(first) == mod) {
319 cmp = 0;
320 break;
321 }
322 }
323 }
324
325 if (cmp == 0) {
326 /* we have found the first module data node */
327 *node = first;
328 }
329}
330
Michal Vaskob1b5c262020-03-05 14:29:47 +0100331const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200332lyd_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 +0200333 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100334{
335 struct lyd_node *iter;
336 const struct lys_module *mod;
337
338 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200339 if (module) {
340 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100341 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200342 } else {
343 mod = module;
344 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100345 }
346 } else {
347 do {
348 mod = ly_ctx_get_module_iter(ctx, i);
349 } while (mod && !mod->implemented);
350 }
351
352 /* find its data */
353 *first = NULL;
354 if (mod) {
355 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100356 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100357 *first = iter;
358 break;
359 }
360 }
361 }
362
363 return mod;
364}
365
366const struct lys_module *
367lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
368{
369 const struct lys_module *mod;
370
371 if (!*next) {
372 /* all data traversed */
373 *first = NULL;
374 return NULL;
375 }
376
377 *first = *next;
378
379 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100380 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100381 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100382 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100383 break;
384 }
385 }
386
387 return mod;
388}
Michal Vasko9f96a052020-03-10 09:41:45 +0100389
390LY_ERR
Michal Vasko59892dd2022-05-13 11:02:30 +0200391lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
392 size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
393 const struct lysc_node *ctx_node, ly_bool *incomplete)
394{
395 LY_ERR ret;
396 struct ly_err_item *err = NULL;
397 uint32_t options = (dynamic && *dynamic ? LYPLG_TYPE_STORE_DYNAMIC : 0);
398
399 if (!value) {
400 value = "";
401 }
402 if (incomplete) {
403 *incomplete = 0;
404 }
405
406 ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
407 if (dynamic) {
408 *dynamic = 0;
409 }
410
411 if (ret == LY_EINCOMPLETE) {
412 if (incomplete) {
413 *incomplete = 1;
414 }
415 } else if (ret) {
416 if (err) {
417 LOGVAL_ERRITEM(ctx, err);
418 ly_err_free(err);
419 } else {
420 LOGVAL(ctx, LYVE_OTHER, "Storing value failed.");
421 }
422 return ret;
423 }
424
425 return LY_SUCCESS;
426}
427
428LY_ERR
429lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *type, struct lyd_value *val,
430 const struct lyd_node *ctx_node, const struct lyd_node *tree)
431{
432 LY_ERR ret;
433 struct ly_err_item *err = NULL;
434
435 assert(type->plugin->validate);
436
437 ret = type->plugin->validate(ctx, type, ctx_node, tree, val, &err);
438 if (ret) {
439 if (err) {
440 LOGVAL_ERRITEM(ctx, err);
441 ly_err_free(err);
442 } else {
443 LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.", type->plugin->print(ctx, val, LY_VALUE_CANON,
444 NULL, NULL, NULL));
445 }
446 return ret;
447 }
448
449 return LY_SUCCESS;
450}
451
452LY_ERR
453lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
454 LY_VALUE_FORMAT format, void *prefix_data)
455{
456 LY_ERR rc = LY_SUCCESS;
457 struct ly_err_item *err = NULL;
458 struct lyd_value storage;
459 struct lysc_type *type;
460
461 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
462
463 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
464 LOGARG(ctx, node);
465 return LY_EINVAL;
466 }
467
468 type = ((struct lysc_node_leaf *)node)->type;
469 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
470 LYD_HINT_SCHEMA, node, &storage, NULL, &err);
471 if (rc == LY_EINCOMPLETE) {
472 /* actually success since we do not provide the context tree and call validation with
473 * LY_TYPE_OPTS_INCOMPLETE_DATA */
474 rc = LY_SUCCESS;
475 } else if (rc && err) {
476 if (ctx) {
477 /* log only in case the ctx was provided as input parameter */
Michal Vaskof8da2682022-06-16 07:52:37 +0200478 if (err->path) {
479 LOG_LOCSET(NULL, NULL, err->path, NULL);
480 } else {
481 /* use at least the schema path */
482 LOG_LOCSET(node, NULL, NULL, NULL);
483 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200484 LOGVAL_ERRITEM(ctx, err);
Michal Vaskof8da2682022-06-16 07:52:37 +0200485 if (err->path) {
486 LOG_LOCBACK(0, 0, 1, 0);
487 } else {
488 LOG_LOCBACK(1, 0, 0, 0);
489 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200490 }
491 ly_err_free(err);
492 }
493
494 if (!rc) {
495 type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
496 }
497 return rc;
498}
499
500LIBYANG_API_DEF LY_ERR
501lyd_value_validate(const struct ly_ctx *ctx, const struct lysc_node *schema, const char *value, size_t value_len,
502 const struct lyd_node *ctx_node, const struct lysc_type **realtype, const char **canonical)
503{
504 LY_ERR rc;
505 struct ly_err_item *err = NULL;
506 struct lysc_type *type;
507 struct lyd_value val = {0};
508 ly_bool stored = 0, log = 1;
509
Michal Vasko3dd16da2022-06-15 07:58:41 +0200510 LY_CHECK_ARG_RET(ctx, schema, !value_len || value, LY_EINVAL);
Michal Vasko59892dd2022-05-13 11:02:30 +0200511
512 if (!ctx) {
513 ctx = schema->module->ctx;
514 log = 0;
515 }
Michal Vasko3dd16da2022-06-15 07:58:41 +0200516 if (!value_len) {
517 value = "";
518 }
Michal Vasko59892dd2022-05-13 11:02:30 +0200519 type = ((struct lysc_node_leaf *)schema)->type;
520
521 /* store */
522 rc = type->plugin->store(ctx, type, value, value_len, 0, LY_VALUE_JSON, NULL,
523 LYD_HINT_DATA, schema, &val, NULL, &err);
524 if (!rc || (rc == LY_EINCOMPLETE)) {
525 stored = 1;
526 }
527
528 if (ctx_node && (rc == LY_EINCOMPLETE)) {
529 /* resolve */
530 rc = type->plugin->validate(ctx, type, ctx_node, ctx_node, &val, &err);
531 }
532
533 if (rc && (rc != LY_EINCOMPLETE) && err) {
534 if (log) {
535 /* log error */
536 if (err->path) {
537 LOG_LOCSET(NULL, NULL, err->path, NULL);
538 } else if (ctx_node) {
539 LOG_LOCSET(NULL, ctx_node, NULL, NULL);
540 } else {
541 LOG_LOCSET(schema, NULL, NULL, NULL);
542 }
543 LOGVAL_ERRITEM(ctx, err);
544 if (err->path) {
545 LOG_LOCBACK(0, 0, 1, 0);
546 } else if (ctx_node) {
547 LOG_LOCBACK(0, 1, 0, 0);
548 } else {
549 LOG_LOCBACK(1, 0, 0, 0);
550 }
551 }
552 ly_err_free(err);
553 }
554
555 if (!rc || (rc == LY_EINCOMPLETE)) {
556 if (realtype) {
557 /* return realtype */
558 if (val.realtype->basetype == LY_TYPE_UNION) {
559 *realtype = val.subvalue->value.realtype;
560 } else {
561 *realtype = val.realtype;
562 }
563 }
564
565 if (canonical) {
566 /* return canonical value */
567 lydict_insert(ctx, val.realtype->plugin->print(ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), 0, canonical);
568 }
569 }
570
571 if (stored) {
572 /* free value */
573 type->plugin->free(ctx ? ctx : schema->module->ctx, &val);
574 }
575 return rc;
576}
577
578LIBYANG_API_DEF LY_ERR
579lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len)
580{
581 LY_ERR ret = LY_SUCCESS;
582 struct ly_ctx *ctx;
583 struct lysc_type *type;
584 struct lyd_value val = {0};
585
586 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
587
588 ctx = node->schema->module->ctx;
589 type = ((struct lysc_node_leaf *)node->schema)->type;
590
591 /* store the value */
592 LOG_LOCSET(node->schema, &node->node, NULL, NULL);
593 ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
594 LOG_LOCBACK(1, 1, 0, 0);
595 LY_CHECK_RET(ret);
596
597 /* compare values */
598 ret = type->plugin->compare(&node->value, &val);
599
600 type->plugin->free(ctx, &val);
601 return ret;
602}
603
604LIBYANG_API_DEF ly_bool
605lyd_is_default(const struct lyd_node *node)
606{
607 const struct lysc_node_leaf *leaf;
608 const struct lysc_node_leaflist *llist;
609 const struct lyd_node_term *term;
610 LY_ARRAY_COUNT_TYPE u;
611
612 if (!(node->schema->nodetype & LYD_NODE_TERM)) {
613 return 0;
614 }
615
616 term = (const struct lyd_node_term *)node;
617
618 if (node->schema->nodetype == LYS_LEAF) {
619 leaf = (const struct lysc_node_leaf *)node->schema;
620 if (!leaf->dflt) {
621 return 0;
622 }
623
624 /* compare with the default value */
625 if (!leaf->type->plugin->compare(&term->value, leaf->dflt)) {
626 return 1;
627 }
628 } else {
629 llist = (const struct lysc_node_leaflist *)node->schema;
630 if (!llist->dflts) {
631 return 0;
632 }
633
634 LY_ARRAY_FOR(llist->dflts, u) {
635 /* compare with each possible default value */
636 if (!llist->type->plugin->compare(&term->value, llist->dflts[u])) {
637 return 1;
638 }
639 }
640 }
641
642 return 0;
643}
644
645LIBYANG_API_DEF uint32_t
646lyd_list_pos(const struct lyd_node *instance)
647{
648 const struct lyd_node *iter = NULL;
649 uint32_t pos = 0;
650
651 if (!instance || !(instance->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
652 return 0;
653 }
654
655 /* data instances are ordered, so we can stop when we found instance of other schema node */
656 for (iter = instance; iter->schema == instance->schema; iter = iter->prev) {
657 if (pos && (iter->next == NULL)) {
658 /* overrun to the end of the siblings list */
659 break;
660 }
661 ++pos;
662 }
663
664 return pos;
665}
666
667LIBYANG_API_DEF struct lyd_node *
668lyd_first_sibling(const struct lyd_node *node)
669{
670 struct lyd_node *start;
671
672 if (!node) {
673 return NULL;
674 }
675
676 /* get the first sibling */
677 if (node->parent) {
678 start = node->parent->child;
679 } else {
680 for (start = (struct lyd_node *)node; start->prev->next; start = start->prev) {}
681 }
682
683 return start;
684}
685
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100686/**
687 * @brief Check list node parsed into an opaque node for the reason.
688 *
689 * @param[in] node Opaque node.
690 * @param[in] snode Schema node of @p opaq.
691 * @return LY_SUCCESS if the node is valid;
692 * @return LY_ERR on error.
693 */
694static LY_ERR
695lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *snode)
696{
697 LY_ERR ret = LY_SUCCESS;
698 struct ly_set key_set = {0};
699 const struct lysc_node *key = NULL;
700 const struct lyd_node *child;
701 const struct lyd_node_opaq *opaq_k;
702 uint32_t i;
703
704 assert(!node->schema);
705
706 /* get all keys into a set */
707 while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
708 LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
709 }
710
711 LY_LIST_FOR(lyd_child(node), child) {
712 if (child->schema) {
713 LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
714 LYD_NAME(child));
715 ret = LY_EINVAL;
716 goto cleanup;
717 }
718
719 opaq_k = (struct lyd_node_opaq *)child;
720
721 /* find the key schema node */
722 for (i = 0; i < key_set.count; ++i) {
723 key = key_set.snodes[i];
724 if (!strcmp(key->name, opaq_k->name.name)) {
725 break;
726 }
727 }
728 if (i == key_set.count) {
729 /* some other node, skip */
730 continue;
731 }
732
733 /* key found */
734 ly_set_rm_index(&key_set, i, NULL);
735
736 /* check value */
737 ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
738 opaq_k->val_prefix_data);
739 LY_CHECK_GOTO(ret, cleanup);
740 }
741
742 if (key_set.count) {
743 /* missing keys */
744 LOGVAL(LYD_CTX(node), LY_VCODE_NOKEY, key_set.snodes[0]->name);
745 ret = LY_EVALID;
746 goto cleanup;
747 }
748
749cleanup:
750 ly_set_erase(&key_set, NULL);
751 return ret;
752}
753
754LIBYANG_API_DEF LY_ERR
755lyd_parse_opaq_error(const struct lyd_node *node)
756{
757 const struct ly_ctx *ctx;
758 const struct lyd_node_opaq *opaq;
759 const struct lyd_node *parent;
760 const struct lys_module *mod;
761 const struct lysc_node *snode;
762
763 LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
764
765 ctx = LYD_CTX(node);
766 opaq = (struct lyd_node_opaq *)node;
767 parent = lyd_parent(node);
768
Michal Vaskof4e63922022-05-10 10:32:13 +0200769 if (!opaq->name.module_ns) {
770 LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
771 return LY_EVALID;
772 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100773
774 /* module */
775 switch (opaq->format) {
776 case LY_VALUE_XML:
777 if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
778 mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
779 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200780 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" of node \"%s\" in the context.",
781 opaq->name.module_ns, opaq->name.name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100782 return LY_EVALID;
783 }
784 } else {
785 /* inherit */
786 mod = parent->schema->module;
787 }
788 break;
789 case LY_VALUE_JSON:
790 case LY_VALUE_LYB:
791 if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
792 mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
793 if (!mod) {
Michal Vasko959f8d82022-06-16 07:51:50 +0200794 LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" of node \"%s\" in the context.",
795 opaq->name.module_name, opaq->name.name);
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100796 return LY_EVALID;
797 }
798 } else {
799 /* inherit */
800 mod = parent->schema->module;
801 }
802 break;
803 default:
804 LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
805 return LY_EINVAL;
806 }
807
808 /* schema */
809 snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200810 if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
811 /* maybe output node */
Michal Vasko89afc6e2022-05-02 10:24:26 +0200812 snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
Michal Vaskoac6f4be2022-05-02 10:16:50 +0200813 }
Michal Vaskobfff6ac2022-02-23 16:22:53 +0100814 if (!snode) {
815 if (parent) {
816 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
817 LYD_NAME(parent));
818 } else {
819 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
820 }
821 return LY_EVALID;
822 }
823
824 if (snode->nodetype & LYD_NODE_TERM) {
825 /* leaf / leaf-list */
826 LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
827 } else if (snode->nodetype == LYS_LIST) {
828 /* list */
829 LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
830 } else if (snode->nodetype & LYD_NODE_INNER) {
831 /* inner node */
832 if (opaq->value) {
833 LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
834 lys_nodetype2str(snode->nodetype), snode->name);
835 return LY_EVALID;
836 }
837 } else {
838 LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
839 return LY_EINVAL;
840 }
841
842 LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
843 return LY_EINVAL;
844}
845
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100846LIBYANG_API_DEF const char *
Christian Hopps46bd21b2021-04-27 09:43:58 -0400847lyd_value_get_canonical(const struct ly_ctx *ctx, const struct lyd_value *value)
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200848{
Michal Vaskoab40e7e2021-04-28 17:04:24 +0200849 LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
850
Michal Vasko33876022021-04-27 16:42:24 +0200851 return value->_canonical ? value->_canonical :
852 (const char *)value->realtype->plugin->print(ctx, value, LY_VALUE_CANON, NULL, NULL, NULL);
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200853}
854
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100855LIBYANG_API_DEF LY_ERR
Michal Vaskoa820c312021-02-05 16:33:00 +0100856lyd_any_value_str(const struct lyd_node *any, char **value_str)
857{
858 const struct lyd_node_any *a;
859 struct lyd_node *tree = NULL;
860 const char *str = NULL;
861 ly_bool dynamic = 0;
862 LY_ERR ret = LY_SUCCESS;
863
864 LY_CHECK_ARG_RET(NULL, any, value_str, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200865 LY_CHECK_ARG_RET(NULL, any->schema, any->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vaskoa820c312021-02-05 16:33:00 +0100866
867 a = (struct lyd_node_any *)any;
868 *value_str = NULL;
869
870 if (!a->value.str) {
871 /* there is no value in the union */
872 return LY_SUCCESS;
873 }
874
875 switch (a->value_type) {
876 case LYD_ANYDATA_LYB:
877 /* parse into a data tree */
878 ret = lyd_parse_data_mem(LYD_CTX(any), a->value.mem, LYD_LYB, LYD_PARSE_ONLY, 0, &tree);
879 LY_CHECK_GOTO(ret, cleanup);
880 dynamic = 1;
881 break;
882 case LYD_ANYDATA_DATATREE:
883 tree = a->value.tree;
884 break;
885 case LYD_ANYDATA_STRING:
886 case LYD_ANYDATA_XML:
887 case LYD_ANYDATA_JSON:
888 /* simply use the string */
889 str = a->value.str;
890 break;
891 }
892
893 if (tree) {
894 /* print into a string */
895 ret = lyd_print_mem(value_str, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
896 LY_CHECK_GOTO(ret, cleanup);
897 } else {
898 assert(str);
899 *value_str = strdup(str);
900 LY_CHECK_ERR_GOTO(!*value_str, LOGMEM(LYD_CTX(any)), cleanup);
901 }
902
903 /* success */
904
905cleanup:
906 if (dynamic) {
907 lyd_free_all(tree);
908 }
909 return ret;
910}
911
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100912LIBYANG_API_DEF LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200913lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
914{
915 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200916
Michal Vaskoa820c312021-02-05 16:33:00 +0100917 LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
Radek Krejci71877df2021-04-06 17:24:06 +0200918 LY_CHECK_ARG_RET(NULL, trg->schema, trg->schema->nodetype & LYS_ANYDATA, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200919
920 t = (struct lyd_node_any *)trg;
921
922 /* free trg */
923 switch (t->value_type) {
924 case LYD_ANYDATA_DATATREE:
925 lyd_free_all(t->value.tree);
926 break;
927 case LYD_ANYDATA_STRING:
928 case LYD_ANYDATA_XML:
929 case LYD_ANYDATA_JSON:
Michal Vaskoe180ed02021-02-05 16:31:20 +0100930 lydict_remove(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200931 break;
932 case LYD_ANYDATA_LYB:
933 free(t->value.mem);
934 break;
935 }
936 t->value.str = NULL;
937
938 if (!value) {
939 /* only free value in this case */
940 return LY_SUCCESS;
941 }
942
943 /* copy src */
944 t->value_type = value_type;
945 switch (value_type) {
946 case LYD_ANYDATA_DATATREE:
947 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200948 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200949 }
950 break;
951 case LYD_ANYDATA_STRING:
952 case LYD_ANYDATA_XML:
953 case LYD_ANYDATA_JSON:
954 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200955 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200956 }
957 break;
958 case LYD_ANYDATA_LYB:
959 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200960 int len = lyd_lyb_data_length(value->mem);
Michal Vasko26bbb272022-08-02 14:54:33 +0200961
Radek Krejci82fa8d42020-07-11 22:00:59 +0200962 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200963 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200964 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200965 memcpy(t->value.mem, value->mem, len);
966 }
967 break;
968 }
969
970 return LY_SUCCESS;
971}
972
Michal Vasko106f0862021-11-02 11:49:27 +0100973const struct lysc_node *
974lyd_node_schema(const struct lyd_node *node)
975{
976 const struct lysc_node *schema = NULL;
977 const struct lyd_node *prev_iter = NULL, *iter;
978 const struct lys_module *mod;
979
980 if (!node) {
981 return NULL;
982 } else if (node->schema) {
983 return node->schema;
984 }
985
986 /* get schema node of an opaque node */
987 do {
988 /* get next data node */
989 for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
990
991 /* get equivalent schema node */
992 if (iter->schema) {
993 schema = iter->schema;
994 } else {
995 /* get module */
996 mod = lyd_owner_module(iter);
Michal Vaskoa41826a2021-11-02 12:13:03 +0100997 if (!mod && !schema) {
998 /* top-level opaque node has unknown module */
999 break;
1000 }
Michal Vasko106f0862021-11-02 11:49:27 +01001001
1002 /* get schema node */
1003 schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
1004 }
Michal Vaskod2f404f2021-11-04 15:37:11 +01001005
1006 /* remember to move to the descendant */
1007 prev_iter = iter;
Michal Vasko106f0862021-11-02 11:49:27 +01001008 } while (schema && (iter != node));
1009
1010 return schema;
1011}
1012
Michal Vasko4754d4a2022-12-01 10:11:21 +01001013void
1014lyd_cont_set_dflt(struct lyd_node *node)
1015{
1016 const struct lyd_node *child;
1017
1018 while (node) {
1019 if (!node->schema || (node->flags & LYD_DEFAULT) || !lysc_is_np_cont(node->schema)) {
1020 /* not a non-dflt NP container */
1021 break;
1022 }
1023
1024 LY_LIST_FOR(lyd_child(node), child) {
1025 if (!(child->flags & LYD_DEFAULT)) {
1026 break;
1027 }
1028 }
1029 if (child) {
1030 /* explicit child, no dflt change */
1031 break;
1032 }
1033
1034 /* set the dflt flag */
1035 node->flags |= LYD_DEFAULT;
1036
1037 /* check all parent containers */
1038 node = lyd_parent(node);
1039 }
1040}
1041
Michal Vasko59892dd2022-05-13 11:02:30 +02001042/**
1043 * @brief Comparison callback to match schema node with a schema of a data node.
1044 *
1045 * @param[in] val1_p Pointer to the schema node
1046 * @param[in] val2_p Pointer to the data node
1047 * Implementation of ::lyht_value_equal_cb.
1048 */
1049static ly_bool
1050lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
1051{
1052 struct lysc_node *val1;
1053 struct lyd_node *val2;
1054
1055 val1 = *((struct lysc_node **)val1_p);
1056 val2 = *((struct lyd_node **)val2_p);
1057
1058 if (val1 == val2->schema) {
1059 /* schema match is enough */
1060 return 1;
1061 } else {
1062 return 0;
1063 }
1064}
1065
1066LY_ERR
1067lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1068{
1069 struct lyd_node **match_p;
1070 struct lyd_node_inner *parent;
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001071 const struct lysc_node *cur_schema;
Michal Vasko59892dd2022-05-13 11:02:30 +02001072 uint32_t hash;
1073 lyht_value_equal_cb ht_cb;
1074
Michal Vasko21beaeb2022-08-02 10:42:48 +02001075 assert(schema);
1076 if (!siblings) {
1077 /* no data */
1078 if (match) {
1079 *match = NULL;
1080 }
1081 return LY_ENOTFOUND;
1082 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001083
1084 parent = siblings->parent;
1085 if (parent && parent->schema && parent->children_ht) {
1086 /* calculate our hash */
1087 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1088 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1089 hash = dict_hash_multi(hash, NULL, 0);
1090
1091 /* use special hash table function */
1092 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1093
1094 /* find by hash */
1095 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1096 siblings = *match_p;
1097 } else {
1098 /* not found */
1099 siblings = NULL;
1100 }
1101
1102 /* set the original hash table compare function back */
1103 lyht_set_cb(parent->children_ht, ht_cb);
1104 } else {
1105 /* find first sibling */
1106 if (siblings->parent) {
1107 siblings = siblings->parent->child;
1108 } else {
1109 while (siblings->prev->next) {
1110 siblings = siblings->prev;
1111 }
1112 }
1113
1114 /* search manually without hashes */
1115 for ( ; siblings; siblings = siblings->next) {
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001116 cur_schema = lyd_node_schema(siblings);
1117 if (!cur_schema) {
1118 /* some unknown opaque node */
1119 continue;
Michal Vasko31bac382022-07-20 08:07:59 +02001120 }
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001121
1122 /* schema match is enough */
1123 if (cur_schema->module->ctx == schema->module->ctx) {
1124 if (cur_schema == schema) {
1125 break;
1126 }
1127 } else {
1128 if (!strcmp(cur_schema->name, schema->name) && !strcmp(cur_schema->module->name, schema->module->name)) {
1129 break;
1130 }
Michal Vasko59892dd2022-05-13 11:02:30 +02001131 }
1132 }
1133 }
1134
1135 if (!siblings) {
1136 if (match) {
1137 *match = NULL;
1138 }
1139 return LY_ENOTFOUND;
1140 }
1141
1142 if (match) {
1143 *match = (struct lyd_node *)siblings;
1144 }
1145 return LY_SUCCESS;
1146}
1147
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001148void
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001149lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod)
1150{
1151 if (*root && (lyd_owner_module(*root) != mod)) {
1152 /* there are no data of mod so this is simply the first top-level sibling */
1153 mod = NULL;
1154 }
1155
1156 if ((*root != to_del) || (*root)->parent) {
1157 return;
1158 }
1159
Michal Vasko598063b2021-07-19 11:39:05 +02001160 if (mod && (*root)->prev->next && (!(*root)->next || (lyd_owner_module(to_del) != lyd_owner_module((*root)->next)))) {
1161 /* there are no more nodes from mod, simply get the first top-level sibling */
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001162 *root = lyd_first_sibling(*root);
Michal Vasko598063b2021-07-19 11:39:05 +02001163 } else {
1164 *root = (*root)->next;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001165 }
1166}
1167
Michal Vasko8cc3f662022-03-29 11:25:51 +02001168LY_ERR
1169ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
1170 size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
1171 const struct lysc_node **snode, struct lysc_ext_instance **ext)
1172{
1173 LY_ERR r;
1174 LY_ARRAY_COUNT_TYPE u;
1175 struct lysc_ext_instance *nested_exts = NULL;
1176 lyplg_ext_data_snode_clb ext_snode_cb;
1177
1178 /* check if there are any nested extension instances */
1179 if (parent && parent->schema) {
1180 nested_exts = parent->schema->exts;
1181 } else if (sparent) {
1182 nested_exts = sparent->exts;
1183 }
1184 LY_ARRAY_FOR(nested_exts, u) {
Michal Vasko305c6cb2022-04-27 10:33:04 +02001185 if (!nested_exts[u].def->plugin) {
1186 /* no plugin */
1187 continue;
1188 }
1189
Michal Vasko8cc3f662022-03-29 11:25:51 +02001190 ext_snode_cb = nested_exts[u].def->plugin->snode;
1191 if (!ext_snode_cb) {
1192 /* not an extension with nested data */
1193 continue;
1194 }
1195
1196 /* try to get the schema node */
1197 r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
1198 if (!r) {
Michal Vasko66330fc2022-11-21 15:52:24 +01001199 if (ext) {
1200 /* data successfully created, remember the ext instance */
1201 *ext = &nested_exts[u];
1202 }
Michal Vasko8cc3f662022-03-29 11:25:51 +02001203 return LY_SUCCESS;
1204 } else if (r != LY_ENOT) {
1205 /* fatal error */
1206 return r;
1207 }
1208 /* data was not from this module, continue */
1209 }
1210
1211 /* no extensions or none matched */
1212 return LY_ENOT;
1213}
1214
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001215void
Radek Krejci8df109d2021-04-23 12:19:08 +02001216ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001217{
1218 struct ly_set *ns_list;
1219 struct lysc_prefix *prefixes;
1220 uint32_t i;
1221 LY_ARRAY_COUNT_TYPE u;
1222
1223 if (!prefix_data) {
1224 return;
1225 }
1226
1227 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001228 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001229 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001230 ns_list = prefix_data;
1231 for (i = 0; i < ns_list->count; ++i) {
1232 free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
1233 free(((struct lyxml_ns *)ns_list->objs[i])->uri);
1234 }
1235 ly_set_free(ns_list, free);
1236 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001237 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001238 prefixes = prefix_data;
1239 LY_ARRAY_FOR(prefixes, u) {
1240 free(prefixes[u].prefix);
1241 }
1242 LY_ARRAY_FREE(prefixes);
1243 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001244 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001245 case LY_VALUE_SCHEMA:
1246 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001247 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001248 break;
1249 }
1250}
1251
1252LY_ERR
Radek Krejci8df109d2021-04-23 12:19:08 +02001253ly_dup_prefix_data(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *prefix_data,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001254 void **prefix_data_p)
1255{
1256 LY_ERR ret = LY_SUCCESS;
1257 struct lyxml_ns *ns;
1258 struct lysc_prefix *prefixes = NULL, *orig_pref;
1259 struct ly_set *ns_list, *orig_ns;
1260 uint32_t i;
1261 LY_ARRAY_COUNT_TYPE u;
1262
1263 assert(!*prefix_data_p);
1264
1265 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001266 case LY_VALUE_SCHEMA:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001267 *prefix_data_p = (void *)prefix_data;
1268 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001269 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001270 /* copy all the value prefixes */
1271 orig_pref = (struct lysc_prefix *)prefix_data;
1272 LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
1273 *prefix_data_p = prefixes;
1274
1275 LY_ARRAY_FOR(orig_pref, u) {
1276 if (orig_pref[u].prefix) {
1277 prefixes[u].prefix = strdup(orig_pref[u].prefix);
1278 LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1279 }
1280 prefixes[u].mod = orig_pref[u].mod;
1281 LY_ARRAY_INCREMENT(prefixes);
1282 }
1283 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001284 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001285 case LY_VALUE_STR_NS:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001286 /* copy all the namespaces */
1287 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
1288 *prefix_data_p = ns_list;
1289
1290 orig_ns = (struct ly_set *)prefix_data;
1291 for (i = 0; i < orig_ns->count; ++i) {
1292 ns = calloc(1, sizeof *ns);
1293 LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1294 LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
1295
1296 if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
1297 ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
1298 LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1299 }
1300 ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
1301 LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1302 }
1303 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001304 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001305 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001306 case LY_VALUE_LYB:
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001307 assert(!prefix_data);
1308 *prefix_data_p = NULL;
1309 break;
1310 }
1311
1312cleanup:
1313 if (ret) {
1314 ly_free_prefix_data(format, *prefix_data_p);
1315 *prefix_data_p = NULL;
1316 }
1317 return ret;
1318}
1319
1320LY_ERR
Radek Krejcif9943642021-04-26 10:18:21 +02001321ly_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 +02001322 const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001323{
1324 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001325 const struct lys_module *mod;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001326 const struct lyxml_ns *ns;
1327 struct lyxml_ns *new_ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001328 struct ly_set *ns_list;
1329 struct lysc_prefix *prefixes = NULL, *val_pref;
aPiecek83436bc2021-03-30 12:20:45 +02001330 const char *value_iter, *value_next, *value_end;
1331 uint32_t substr_len;
1332 ly_bool is_prefix;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001333
1334 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001335 case LY_VALUE_SCHEMA:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001336 /* copy all referenced modules as prefix - module pairs */
1337 if (!*prefix_data_p) {
1338 /* new prefix data */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001339 LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
Radek Krejci8df109d2021-04-23 12:19:08 +02001340 *format_p = LY_VALUE_SCHEMA_RESOLVED;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001341 *prefix_data_p = prefixes;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001342 } else {
1343 /* reuse prefix data */
Radek Krejci8df109d2021-04-23 12:19:08 +02001344 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001345 prefixes = *prefix_data_p;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001346 }
1347
Michal Vaskoc0f9c4c2022-05-06 12:12:17 +02001348 /* add current module for unprefixed values */
1349 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1350 *prefix_data_p = prefixes;
1351
1352 val_pref->prefix = NULL;
1353 val_pref->mod = ((const struct lysp_module *)prefix_data)->mod;
1354
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001355 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001356 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001357 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001358 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 +02001359 if (is_prefix) {
1360 /* we have a possible prefix. Do we already have the prefix? */
1361 mod = ly_resolve_prefix(ctx, value_iter, substr_len, *format_p, *prefix_data_p);
1362 if (!mod) {
1363 mod = ly_resolve_prefix(ctx, value_iter, substr_len, format, prefix_data);
1364 if (mod) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001365 assert(*format_p == LY_VALUE_SCHEMA_RESOLVED);
aPiecek83436bc2021-03-30 12:20:45 +02001366 /* store a new prefix - module pair */
1367 LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
1368 *prefix_data_p = prefixes;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001369
aPiecek83436bc2021-03-30 12:20:45 +02001370 val_pref->prefix = strndup(value_iter, substr_len);
1371 LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1372 val_pref->mod = mod;
1373 } /* else it is not even defined */
1374 } /* else the prefix is already present */
Michal Vaskofc2cd072021-02-24 13:17:17 +01001375 }
1376 }
1377 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02001378 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +01001379 case LY_VALUE_STR_NS:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001380 /* copy all referenced namespaces as prefix - namespace pairs */
1381 if (!*prefix_data_p) {
1382 /* new prefix data */
1383 LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +01001384 *format_p = format;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001385 *prefix_data_p = ns_list;
1386 } else {
1387 /* reuse prefix data */
Michal Vaskoddd76592022-01-17 13:34:48 +01001388 assert(*format_p == format);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001389 ns_list = *prefix_data_p;
1390 }
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001391
Michal Vasko294e7f02022-02-28 13:59:00 +01001392 /* store default namespace */
1393 ns = lyxml_ns_get(prefix_data, NULL, 0);
1394 if (ns) {
1395 new_ns = calloc(1, sizeof *new_ns);
1396 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1397 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
1398
1399 new_ns->prefix = NULL;
1400 new_ns->uri = strdup(ns->uri);
1401 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1402 }
1403
Michal Vaskofc2cd072021-02-24 13:17:17 +01001404 /* add all used prefixes */
Michal Vasko59e90fc2021-09-22 12:17:08 +02001405 value_end = (char *)value + value_len;
aPiecek83436bc2021-03-30 12:20:45 +02001406 for (value_iter = value; value_iter; value_iter = value_next) {
aPieceke3f828d2021-05-10 15:34:41 +02001407 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 +02001408 if (is_prefix) {
1409 /* we have a possible prefix. Do we already have the prefix? */
1410 ns = lyxml_ns_get(ns_list, value_iter, substr_len);
1411 if (!ns) {
1412 ns = lyxml_ns_get(prefix_data, value_iter, substr_len);
1413 if (ns) {
1414 /* store a new prefix - namespace pair */
1415 new_ns = calloc(1, sizeof *new_ns);
1416 LY_CHECK_ERR_GOTO(!new_ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1417 LY_CHECK_GOTO(ret = ly_set_add(ns_list, new_ns, 1, NULL), cleanup);
Michal Vaskofc2cd072021-02-24 13:17:17 +01001418
aPiecek83436bc2021-03-30 12:20:45 +02001419 new_ns->prefix = strndup(value_iter, substr_len);
1420 LY_CHECK_ERR_GOTO(!new_ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1421 new_ns->uri = strdup(ns->uri);
1422 LY_CHECK_ERR_GOTO(!new_ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1423 } /* else it is not even defined */
1424 } /* else the prefix is already present */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001425 }
1426 }
1427 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02001428 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02001429 case LY_VALUE_SCHEMA_RESOLVED:
1430 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02001431 case LY_VALUE_LYB:
Michal Vaskofc2cd072021-02-24 13:17:17 +01001432 if (!*prefix_data_p) {
1433 /* new prefix data - simply copy all the prefix data */
1434 *format_p = format;
1435 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
1436 } /* else reuse prefix data - the prefix data are always the same, nothing to do */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001437 break;
1438 }
1439
1440cleanup:
1441 if (ret) {
1442 ly_free_prefix_data(*format_p, *prefix_data_p);
1443 *prefix_data_p = NULL;
1444 }
1445 return ret;
1446}
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001447
1448const char *
Radek Krejci8df109d2021-04-23 12:19:08 +02001449ly_format2str(LY_VALUE_FORMAT format)
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001450{
1451 switch (format) {
Radek Krejci224d4b42021-04-23 13:54:59 +02001452 case LY_VALUE_CANON:
1453 return "canonical";
Radek Krejci8df109d2021-04-23 12:19:08 +02001454 case LY_VALUE_SCHEMA:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001455 return "schema imports";
Radek Krejci8df109d2021-04-23 12:19:08 +02001456 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001457 return "schema stored mapping";
Radek Krejci8df109d2021-04-23 12:19:08 +02001458 case LY_VALUE_XML:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001459 return "XML prefixes";
Radek Krejci8df109d2021-04-23 12:19:08 +02001460 case LY_VALUE_JSON:
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001461 return "JSON module names";
Radek Krejcif9943642021-04-26 10:18:21 +02001462 case LY_VALUE_LYB:
1463 return "LYB prefixes";
Michal Vasko7ed1fcb2020-12-03 14:15:22 +01001464 default:
1465 break;
1466 }
1467
1468 return NULL;
1469}
Michal Vasko43297a02021-05-19 11:12:37 +02001470
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001471LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001472ly_time_str2time(const char *value, time_t *time, char **fractions_s)
1473{
1474 struct tm tm = {0};
1475 uint32_t i, frac_len;
1476 const char *frac;
1477 int64_t shift, shift_m;
1478 time_t t;
1479
1480 LY_CHECK_ARG_RET(NULL, value, time, LY_EINVAL);
1481
1482 tm.tm_year = atoi(&value[0]) - 1900;
1483 tm.tm_mon = atoi(&value[5]) - 1;
1484 tm.tm_mday = atoi(&value[8]);
1485 tm.tm_hour = atoi(&value[11]);
1486 tm.tm_min = atoi(&value[14]);
1487 tm.tm_sec = atoi(&value[17]);
1488
1489 t = timegm(&tm);
1490 i = 19;
1491
1492 /* fractions of a second */
1493 if (value[i] == '.') {
1494 ++i;
1495 frac = &value[i];
1496 for (frac_len = 0; isdigit(frac[frac_len]); ++frac_len) {}
1497
1498 i += frac_len;
Michal Vasko43297a02021-05-19 11:12:37 +02001499 } else {
1500 frac = NULL;
1501 }
1502
1503 /* apply offset */
1504 if ((value[i] == 'Z') || (value[i] == 'z')) {
1505 /* zero shift */
1506 shift = 0;
1507 } else {
1508 shift = strtol(&value[i], NULL, 10);
1509 shift = shift * 60 * 60; /* convert from hours to seconds */
1510 shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
1511 /* correct sign */
1512 if (shift < 0) {
1513 shift_m *= -1;
1514 }
1515 /* connect hours and minutes of the shift */
1516 shift = shift + shift_m;
1517 }
1518
1519 /* we have to shift to the opposite way to correct the time */
1520 t -= shift;
1521
1522 *time = t;
1523 if (fractions_s) {
1524 if (frac) {
1525 *fractions_s = strndup(frac, frac_len);
1526 LY_CHECK_RET(!*fractions_s, LY_EMEM);
1527 } else {
1528 *fractions_s = NULL;
1529 }
1530 }
1531 return LY_SUCCESS;
1532}
1533
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001534LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001535ly_time_time2str(time_t time, const char *fractions_s, char **str)
1536{
1537 struct tm tm;
Michal Vasko143ffa82021-05-20 11:11:39 +02001538 char zoneshift[8];
Michal Vasko43297a02021-05-19 11:12:37 +02001539 int32_t zonediff_h, zonediff_m;
1540
1541 LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
1542
1543 /* initialize the local timezone */
1544 tzset();
1545
Jan Kundrátb17efe92022-02-14 18:32:18 +01001546#ifdef HAVE_TM_GMTOFF
Michal Vasko43297a02021-05-19 11:12:37 +02001547 /* convert */
1548 if (!localtime_r(&time, &tm)) {
1549 return LY_ESYS;
1550 }
1551
1552 /* get timezone offset */
1553 if (tm.tm_gmtoff == 0) {
1554 /* time is Zulu (UTC) */
1555 zonediff_h = 0;
1556 zonediff_m = 0;
1557 } else {
1558 /* timezone offset */
1559 zonediff_h = tm.tm_gmtoff / 60 / 60;
1560 zonediff_m = tm.tm_gmtoff / 60 % 60;
1561 }
1562 sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
Jan Kundráte182a272021-12-09 23:25:15 +01001563#else
Jan Kundrátb17efe92022-02-14 18:32:18 +01001564 /* convert */
1565 if (!gmtime_r(&time, &tm)) {
1566 return LY_ESYS;
1567 }
1568
Jan Kundráte182a272021-12-09 23:25:15 +01001569 (void)zonediff_h;
1570 (void)zonediff_m;
1571 sprintf(zoneshift, "-00:00");
1572#endif
Michal Vasko43297a02021-05-19 11:12:37 +02001573
1574 /* print */
1575 if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",
1576 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1577 fractions_s ? "." : "", fractions_s ? fractions_s : "", zoneshift) == -1) {
1578 return LY_EMEM;
1579 }
1580
1581 return LY_SUCCESS;
1582}
1583
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001584LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001585ly_time_str2ts(const char *value, struct timespec *ts)
1586{
1587 LY_ERR rc;
Michal Vasko72975062021-08-25 08:13:04 +02001588 char *fractions_s, frac_buf[10];
Michal Vasko43297a02021-05-19 11:12:37 +02001589 int frac_len;
1590
1591 LY_CHECK_ARG_RET(NULL, value, ts, LY_EINVAL);
1592
1593 rc = ly_time_str2time(value, &ts->tv_sec, &fractions_s);
1594 LY_CHECK_RET(rc);
1595
1596 /* convert fractions of a second to nanoseconds */
1597 if (fractions_s) {
Michal Vasko72975062021-08-25 08:13:04 +02001598 /* init frac_buf with zeroes */
1599 memset(frac_buf, '0', 9);
1600 frac_buf[9] = '\0';
1601
Michal Vasko43297a02021-05-19 11:12:37 +02001602 frac_len = strlen(fractions_s);
1603 memcpy(frac_buf, fractions_s, frac_len > 9 ? 9 : frac_len);
1604 ts->tv_nsec = atol(frac_buf);
1605 free(fractions_s);
1606 } else {
1607 ts->tv_nsec = 0;
1608 }
1609
1610 return LY_SUCCESS;
1611}
1612
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001613LIBYANG_API_DEF LY_ERR
Michal Vasko43297a02021-05-19 11:12:37 +02001614ly_time_ts2str(const struct timespec *ts, char **str)
1615{
1616 char frac_buf[10];
1617
Jan Kundrátbd157002021-08-30 14:02:22 +02001618 LY_CHECK_ARG_RET(NULL, ts, str, ((ts->tv_nsec <= 999999999) && (ts->tv_nsec >= 0)), LY_EINVAL);
Michal Vasko43297a02021-05-19 11:12:37 +02001619
1620 /* convert nanoseconds to fractions of a second */
1621 if (ts->tv_nsec) {
1622 sprintf(frac_buf, "%09ld", ts->tv_nsec);
1623 }
1624
1625 return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str);
1626}