1 /**
2 * @file common.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief common libyang routines implementations
5 *
6 * Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15 #define _GNU_SOURCE /*strndup */
16
17 #include <assert.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include "common.h"
30 #include "parser.h"
31 #include "xpath.h"
32 #include "context.h"
33
34 THREAD_LOCAL enum int_log_opts log_opt;
35 THREAD_LOCAL LY_ERR ly_errno_glob;
36
37 API LY_ERR *
ly_errno_glob_address(void)38 ly_errno_glob_address(void)
39 {
40 FUN_IN;
41
42 return &ly_errno_glob;
43 }
44
45 API LY_VECODE
ly_vecode(const struct ly_ctx * ctx)46 ly_vecode(const struct ly_ctx *ctx)
47 {
48 FUN_IN;
49
50 struct ly_err_item *i;
51
52 i = ly_err_first(ctx);
53 if (i) {
54 return i->prev->vecode;
55 }
56
57 return 0;
58 }
59
60 API const char *
ly_errmsg(const struct ly_ctx * ctx)61 ly_errmsg(const struct ly_ctx *ctx)
62 {
63 FUN_IN;
64
65 struct ly_err_item *i;
66
67 i = ly_err_first(ctx);
68 if (i) {
69 return i->prev->msg;
70 }
71
72 return NULL;
73 }
74
75 API const char *
ly_errpath(const struct ly_ctx * ctx)76 ly_errpath(const struct ly_ctx *ctx)
77 {
78 FUN_IN;
79
80 struct ly_err_item *i;
81
82 i = ly_err_first(ctx);
83 if (i) {
84 return i->prev->path;
85 }
86
87 return NULL;
88 }
89
90 API const char *
ly_errapptag(const struct ly_ctx * ctx)91 ly_errapptag(const struct ly_ctx *ctx)
92 {
93 FUN_IN;
94
95 struct ly_err_item *i;
96
97 i = ly_err_first(ctx);
98 if (i) {
99 return i->prev->apptag;
100 }
101
102 return NULL;
103 }
104
105 API struct ly_err_item *
ly_err_first(const struct ly_ctx * ctx)106 ly_err_first(const struct ly_ctx *ctx)
107 {
108 FUN_IN;
109
110 if (!ctx) {
111 return NULL;
112 }
113
114 return pthread_getspecific(ctx->errlist_key);
115 }
116
117 void
ly_err_free(void * ptr)118 ly_err_free(void *ptr)
119 {
120 struct ly_err_item *i, *next;
121
122 /* clean the error list */
123 for (i = (struct ly_err_item *)ptr; i; i = next) {
124 next = i->next;
125 free(i->msg);
126 free(i->path);
127 free(i->apptag);
128 free(i);
129 }
130 }
131
132 API void
ly_err_clean(struct ly_ctx * ctx,struct ly_err_item * eitem)133 ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
134 {
135 FUN_IN;
136
137 struct ly_err_item *i, *first;
138
139 first = ly_err_first(ctx);
140 if (first == eitem) {
141 eitem = NULL;
142 }
143 if (eitem) {
144 /* disconnect the error */
145 for (i = first; i && (i->next != eitem); i = i->next);
146 assert(i);
147 i->next = NULL;
148 first->prev = i;
149 /* free this err and newer */
150 ly_err_free(eitem);
151 /* update errno */
152 ly_errno = i->no;
153 } else {
154 /* free all err */
155 ly_err_free(first);
156 pthread_setspecific(ctx->errlist_key, NULL);
157 /* also clean errno */
158 ly_errno = LY_SUCCESS;
159 }
160 }
161
162 const char *
strpbrk_backwards(const char * s,const char * accept,unsigned int s_len)163 strpbrk_backwards(const char *s, const char *accept, unsigned int s_len)
164 {
165 const char *sc;
166
167 for (; *s != '\0' && s_len; --s, --s_len) {
168 for (sc = accept; *sc != '\0'; ++sc) {
169 if (*s == *sc) {
170 return s;
171 }
172 }
173 }
174 return s;
175 }
176
177 char *
strnchr(const char * s,int c,unsigned int len)178 strnchr(const char *s, int c, unsigned int len)
179 {
180 for (; *s != (char)c; ++s, --len) {
181 if ((*s == '\0') || (!len)) {
182 return NULL;
183 }
184 }
185 return (char *)s;
186 }
187
188 const char *
strnodetype(LYS_NODE type)189 strnodetype(LYS_NODE type)
190 {
191 switch (type) {
192 case LYS_UNKNOWN:
193 return NULL;
194 case LYS_AUGMENT:
195 return "augment";
196 case LYS_CONTAINER:
197 return "container";
198 case LYS_CHOICE:
199 return "choice";
200 case LYS_LEAF:
201 return "leaf";
202 case LYS_LEAFLIST:
203 return "leaf-list";
204 case LYS_LIST:
205 return "list";
206 case LYS_ANYXML:
207 return "anyxml";
208 case LYS_GROUPING:
209 return "grouping";
210 case LYS_CASE:
211 return "case";
212 case LYS_INPUT:
213 return "input";
214 case LYS_OUTPUT:
215 return "output";
216 case LYS_NOTIF:
217 return "notification";
218 case LYS_RPC:
219 return "rpc";
220 case LYS_USES:
221 return "uses";
222 case LYS_ACTION:
223 return "action";
224 case LYS_ANYDATA:
225 return "anydata";
226 case LYS_EXT:
227 return "extension instance";
228 }
229
230 return NULL;
231 }
232
233 const char *
transform_module_name2import_prefix(const struct lys_module * module,const char * module_name)234 transform_module_name2import_prefix(const struct lys_module *module, const char *module_name)
235 {
236 uint16_t i;
237
238 if (!module_name) {
239 return NULL;
240 }
241
242 if (!strcmp(lys_main_module(module)->name, module_name)) {
243 /* the same for module and submodule */
244 return module->prefix;
245 }
246
247 for (i = 0; i < module->imp_size; ++i) {
248 if (!strcmp(module->imp[i].module->name, module_name)) {
249 return module->imp[i].prefix;
250 }
251 }
252
253 return NULL;
254 }
255
256 static int
_transform_json2xml_subexp(const struct lys_module * module,const char * expr,char ** out,size_t * out_used,size_t * out_size,int schema,int inst_id,const char *** prefixes,const char *** namespaces,uint32_t * ns_count)257 _transform_json2xml_subexp(const struct lys_module *module, const char *expr, char **out, size_t *out_used, size_t *out_size,
258 int schema, int inst_id, const char ***prefixes, const char ***namespaces, uint32_t *ns_count)
259 {
260 const char *cur_expr, *end, *prefix, *literal;
261 char *name;
262 size_t name_len;
263 const struct lys_module *mod = NULL, *prev_mod = NULL;
264 uint32_t i, j;
265 struct lyxp_expr *exp;
266 struct ly_ctx *ctx = module->ctx;
267 enum int_log_opts prev_ilo;
268
269 assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count)));
270
271 exp = lyxp_parse_expr(ctx, expr);
272 LY_CHECK_RETURN(!exp, 1);
273
274 for (i = 0; i < exp->used; ++i) {
275 cur_expr = &exp->expr[exp->expr_pos[i]];
276
277 /* copy WS */
278 if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
279 strncpy(&(*out)[*out_used], end, cur_expr - end);
280 (*out_used) += cur_expr - end;
281 }
282
283 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && ((end = strnchr(cur_expr, ':', exp->tok_len[i])) || inst_id)) {
284 /* get the module */
285 if (!schema) {
286 if (end) {
287 name_len = end - cur_expr;
288 name = strndup(cur_expr, name_len);
289 mod = ly_ctx_get_module(module->ctx, name, NULL, 0);
290 if (module->ctx->data_clb) {
291 if (!mod) {
292 mod = module->ctx->data_clb(module->ctx, name, NULL, 0, module->ctx->data_clb_data);
293 } else if (!mod->implemented) {
294 mod = module->ctx->data_clb(module->ctx, name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, module->ctx->data_clb_data);
295 }
296 }
297 free(name);
298 if (!mod) {
299 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
300 goto error;
301 }
302 prev_mod = mod;
303 } else {
304 mod = prev_mod;
305 if (!mod) {
306 LOGINT(ctx);
307 goto error;
308 }
309 name_len = 0;
310 end = cur_expr;
311 }
312 prefix = mod->prefix;
313 } else {
314 if (end) {
315 name_len = end - cur_expr;
316 } else {
317 name_len = strlen(cur_expr);
318 end = cur_expr;
319 }
320 name = strndup(cur_expr, name_len);
321 prefix = transform_module_name2import_prefix(module, name);
322 free(name);
323 if (!prefix) {
324 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
325 goto error;
326 }
327 }
328
329 /* remember the namespace definition (only if it's new) */
330 if (!schema && ns_count) {
331 for (j = 0; j < *ns_count; ++j) {
332 if (ly_strequal((*namespaces)[j], mod->ns, 1)) {
333 break;
334 }
335 }
336 if (j == *ns_count) {
337 ++(*ns_count);
338 *prefixes = ly_realloc(*prefixes, *ns_count * sizeof **prefixes);
339 LY_CHECK_ERR_GOTO(!(*prefixes), LOGMEM(ctx), error);
340 *namespaces = ly_realloc(*namespaces, *ns_count * sizeof **namespaces);
341 LY_CHECK_ERR_GOTO(!(*namespaces), LOGMEM(ctx), error);
342 (*prefixes)[*ns_count - 1] = mod->prefix;
343 (*namespaces)[*ns_count - 1] = mod->ns;
344 }
345 }
346
347 /* adjust out size (it can even decrease in some strange cases) */
348 *out_size += strlen(prefix) + 1 - name_len;
349 *out = ly_realloc(*out, *out_size);
350 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
351
352 /* copy the model name */
353 strcpy(&(*out)[*out_used], prefix);
354 *out_used += strlen(prefix);
355
356 if (!name_len) {
357 /* we are adding the prefix, so also ':' */
358 (*out)[*out_used] = ':';
359 ++(*out_used);
360 }
361
362 /* copy the rest */
363 strncpy(&(*out)[*out_used], end, exp->tok_len[i] - name_len);
364 *out_used += exp->tok_len[i] - name_len;
365 } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
366 /* copy begin quote */
367 (*out)[*out_used] = cur_expr[0];
368 ++(*out_used);
369
370 /* skip quotes */
371 literal = lydict_insert(module->ctx, cur_expr + 1, exp->tok_len[i] - 2);
372
373 /* parse literals as subexpressions if possible, otherwise treat as a literal */
374 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
375 if (_transform_json2xml_subexp(module, literal, out, out_used, out_size, schema, inst_id, prefixes, namespaces, ns_count)) {
376 strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2);
377 *out_used += exp->tok_len[i] - 2;
378 }
379 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
380
381 lydict_remove(module->ctx, literal);
382
383 /* copy end quote */
384 (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1];
385 ++(*out_used);
386 } else {
387 strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
388 *out_used += exp->tok_len[i];
389 }
390 }
391
392 lyxp_expr_free(exp);
393 return 0;
394
395 error:
396 lyxp_expr_free(exp);
397 return 1;
398 }
399
400 static const char *
_transform_json2xml(const struct lys_module * module,const char * expr,int schema,int inst_id,const char *** prefixes,const char *** namespaces,uint32_t * ns_count)401 _transform_json2xml(const struct lys_module *module, const char *expr, int schema, int inst_id, const char ***prefixes,
402 const char ***namespaces, uint32_t *ns_count)
403 {
404 char *out;
405 size_t out_size, out_used;
406 int ret;
407
408 assert(module && expr && ((!prefixes && !namespaces && !ns_count) || (prefixes && namespaces && ns_count)));
409
410 if (ns_count) {
411 *ns_count = 0;
412 *prefixes = NULL;
413 *namespaces = NULL;
414 }
415
416 if (!expr[0]) {
417 /* empty value */
418 return lydict_insert(module->ctx, expr, 0);
419 }
420
421 out_size = strlen(expr) + 1;
422 out = malloc(out_size);
423 LY_CHECK_ERR_RETURN(!out, LOGMEM(module->ctx), NULL);
424 out_used = 0;
425
426 ret = _transform_json2xml_subexp(module, expr, &out, &out_used, &out_size, schema, inst_id, prefixes, namespaces, ns_count);
427 if (!ret) {
428 out[out_used] = '\0';
429 return lydict_insert_zc(module->ctx, out);
430 }
431
432 /* fail */
433 if (ns_count) {
434 *ns_count = 0;
435 free(*prefixes);
436 *prefixes = NULL;
437 free(*namespaces);
438 *namespaces = NULL;
439 }
440 free(out);
441 return NULL;
442 }
443
444 const char *
transform_json2xml(const struct lys_module * module,const char * expr,int inst_id,const char *** prefixes,const char *** namespaces,uint32_t * ns_count)445 transform_json2xml(const struct lys_module *module, const char *expr, int inst_id, const char ***prefixes,
446 const char ***namespaces, uint32_t *ns_count)
447 {
448 return _transform_json2xml(module, expr, 0, inst_id, prefixes, namespaces, ns_count);
449 }
450
451 const char *
transform_json2schema(const struct lys_module * module,const char * expr)452 transform_json2schema(const struct lys_module *module, const char *expr)
453 {
454 return _transform_json2xml(module, expr, 1, 0, NULL, NULL, NULL);
455 }
456
457 static int
transform_xml2json_subexp(struct ly_ctx * ctx,const char * expr,char ** out,size_t * out_used,size_t * out_size,struct lyxml_elem * xml,int inst_id,int use_ctx_data_clb)458 transform_xml2json_subexp(struct ly_ctx *ctx, const char *expr, char **out, size_t *out_used, size_t *out_size,
459 struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb)
460 {
461 const char *end, *cur_expr, *literal;
462 char *prefix;
463 uint16_t i;
464 enum int_log_opts prev_ilo;
465 size_t pref_len;
466 const struct lys_module *mod, *prev_mod = NULL;
467 const struct lyxml_ns *ns;
468 struct lyxp_expr *exp;
469
470 exp = lyxp_parse_expr(ctx, expr);
471 if (!exp) {
472 return 1;
473 }
474
475 for (i = 0; i < exp->used; ++i) {
476 cur_expr = &exp->expr[exp->expr_pos[i]];
477
478 /* copy WS */
479 if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
480 strncpy(&(*out)[*out_used], end, cur_expr - end);
481 (*out_used) += cur_expr - end;
482 }
483
484 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
485 /* get the module */
486 pref_len = end - cur_expr;
487 prefix = strndup(cur_expr, pref_len);
488 if (!prefix) {
489 LOGMEM(ctx);
490 goto error;
491 }
492 ns = lyxml_get_ns(xml, prefix);
493 free(prefix);
494 if (!ns) {
495 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prefix");
496 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "XML namespace with prefix \"%.*s\" not defined.", pref_len, cur_expr);
497 goto error;
498 }
499 mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 0);
500 if (use_ctx_data_clb && ctx->data_clb) {
501 if (!mod) {
502 mod = ctx->data_clb(ctx, NULL, ns->value, 0, ctx->data_clb_data);
503 } else if (!mod->implemented) {
504 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
505 }
506 }
507 if (!mod) {
508 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "module namespace");
509 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Module with the namespace \"%s\" could not be found.", ns->value);
510 goto error;
511 }
512
513 if (!inst_id || (mod != prev_mod)) {
514 /* adjust out size (it can even decrease in some strange cases) */
515 *out_size += strlen(mod->name) - pref_len;
516 *out = ly_realloc(*out, *out_size);
517 if (!(*out)) {
518 LOGMEM(ctx);
519 goto error;
520 }
521
522 /* copy the model name */
523 strcpy(&(*out)[*out_used], mod->name);
524 *out_used += strlen(mod->name);
525 } else {
526 /* skip ':' */
527 ++end;
528 ++pref_len;
529 }
530
531 /* remember previous model name */
532 prev_mod = mod;
533
534 /* copy the rest */
535 strncpy(&(*out)[*out_used], end, exp->tok_len[i] - pref_len);
536 *out_used += exp->tok_len[i] - pref_len;
537 } else if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && inst_id) {
538 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prefix");
539 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Node name is missing module prefix.");
540 goto error;
541 } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
542 /* copy begin quote */
543 (*out)[*out_used] = cur_expr[0];
544 ++(*out_used);
545
546 /* skip quotes */
547 literal = lydict_insert(ctx, cur_expr + 1, exp->tok_len[i] - 2);
548
549 /* parse literals as subexpressions if possible, otherwise treat as a literal, do not log */
550 prev_ilo = log_opt;
551 log_opt = ILO_IGNORE;
552 if (transform_xml2json_subexp(ctx, literal, out, out_used, out_size, xml, inst_id, use_ctx_data_clb)) {
553 strncpy(&(*out)[*out_used], literal, exp->tok_len[i] - 2);
554 *out_used += exp->tok_len[i] - 2;
555 }
556 log_opt = prev_ilo;
557
558 lydict_remove(ctx, literal);
559
560 /* copy end quote */
561 (*out)[*out_used] = cur_expr[exp->tok_len[i] - 1];
562 ++(*out_used);
563 } else {
564 strncpy(&(*out)[*out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
565 *out_used += exp->tok_len[i];
566 }
567 }
568
569 lyxp_expr_free(exp);
570 return 0;
571
572 error:
573 lyxp_expr_free(exp);
574 return 1;
575 }
576
577 const char *
transform_xml2json(struct ly_ctx * ctx,const char * expr,struct lyxml_elem * xml,int inst_id,int use_ctx_data_clb)578 transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int inst_id, int use_ctx_data_clb)
579 {
580 char *out;
581 size_t out_size, out_used;
582 int ret;
583
584 out_size = strlen(expr) + 1;
585 out = malloc(out_size);
586 if (!out) {
587 LOGMEM(ctx);
588 return NULL;
589 }
590 out_used = 0;
591
592 ret = transform_xml2json_subexp(ctx, expr, &out, &out_used, &out_size, xml, inst_id, use_ctx_data_clb);
593 if (!ret) {
594 out[out_used] = '\0';
595 return lydict_insert_zc(ctx, out);
596 }
597
598 free(out);
599 return NULL;
600 }
601
602 API char *
ly_path_xml2json(struct ly_ctx * ctx,const char * xml_path,struct lyxml_elem * xml)603 ly_path_xml2json(struct ly_ctx *ctx, const char *xml_path, struct lyxml_elem *xml)
604 {
605 FUN_IN;
606
607 const char *json_path;
608 char *ret = NULL;
609
610 if (!ctx || !xml_path || !xml) {
611 LOGARG;
612 return NULL;
613 }
614
615 json_path = transform_xml2json(ctx, xml_path, xml, 0, 1);
616 if (json_path) {
617 ret = strdup(json_path);
618 lydict_remove(ctx, json_path);
619 }
620
621 return ret;
622 }
623
624 const char *
transform_schema2json(const struct lys_module * module,const char * expr)625 transform_schema2json(const struct lys_module *module, const char *expr)
626 {
627 const char *end, *cur_expr, *ptr;
628 char *out;
629 uint16_t i;
630 size_t out_size, out_used, pref_len;
631 const struct lys_module *mod;
632 struct ly_ctx *ctx = module->ctx;
633 struct lyxp_expr *exp = NULL;
634
635 out_size = strlen(expr) + 1;
636 out = malloc(out_size);
637 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
638 out_used = 0;
639
640 exp = lyxp_parse_expr(ctx, expr);
641 LY_CHECK_ERR_GOTO(!exp, , error);
642
643 for (i = 0; i < exp->used; ++i) {
644 cur_expr = &exp->expr[exp->expr_pos[i]];
645
646 /* copy WS */
647 if (i && ((end = exp->expr + exp->expr_pos[i - 1] + exp->tok_len[i - 1]) != cur_expr)) {
648 strncpy(&out[out_used], end, cur_expr - end);
649 out_used += cur_expr - end;
650 }
651
652 if ((exp->tokens[i] == LYXP_TOKEN_NAMETEST) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
653 /* get the module */
654 pref_len = end - cur_expr;
655 mod = lyp_get_module(module, cur_expr, pref_len, NULL, 0, 0);
656 if (!mod) {
657 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, pref_len, cur_expr);
658 goto error;
659 }
660
661 /* adjust out size (it can even decrease in some strange cases) */
662 out_size += strlen(mod->name) - pref_len;
663 out = ly_realloc(out, out_size);
664 LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error);
665
666 /* copy the model name */
667 strcpy(&out[out_used], mod->name);
668 out_used += strlen(mod->name);
669
670 /* copy the rest */
671 strncpy(&out[out_used], end, exp->tok_len[i] - pref_len);
672 out_used += exp->tok_len[i] - pref_len;
673 } else if ((exp->tokens[i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[i]))) {
674 ptr = end;
675 while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
676 --ptr;
677 }
678
679 /* get the module */
680 pref_len = end - ptr;
681 mod = lyp_get_module(module, ptr, pref_len, NULL, 0, 0);
682 if (mod) {
683 /* adjust out size (it can even decrease in some strange cases) */
684 out_size += strlen(mod->name) - pref_len;
685 out = ly_realloc(out, out_size);
686 LY_CHECK_ERR_GOTO(!out, LOGMEM(ctx), error);
687
688 /* copy any beginning */
689 strncpy(&out[out_used], cur_expr, ptr - cur_expr);
690 out_used += ptr - cur_expr;
691
692 /* copy the model name */
693 strcpy(&out[out_used], mod->name);
694 out_used += strlen(mod->name);
695
696 /* copy the rest */
697 strncpy(&out[out_used], end, (exp->tok_len[i] - pref_len) - (ptr - cur_expr));
698 out_used += (exp->tok_len[i] - pref_len) - (ptr - cur_expr);
699 } else {
700 strncpy(&out[out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
701 out_used += exp->tok_len[i];
702 }
703 } else {
704 strncpy(&out[out_used], &exp->expr[exp->expr_pos[i]], exp->tok_len[i]);
705 out_used += exp->tok_len[i];
706 }
707 }
708 out[out_used] = '\0';
709
710 lyxp_expr_free(exp);
711 return lydict_insert_zc(module->ctx, out);
712
713 error:
714 free(out);
715 lyxp_expr_free(exp);
716 return NULL;
717 }
718
719 const char *
transform_iffeat_schema2json(const struct lys_module * module,const char * expr)720 transform_iffeat_schema2json(const struct lys_module *module, const char *expr)
721 {
722 const char *in, *id;
723 char *out, *col;
724 size_t out_size, out_used, id_len, rc;
725 const struct lys_module *mod;
726 struct ly_ctx *ctx = module->ctx;
727
728 in = expr;
729 out_size = strlen(in) + 1;
730 out = malloc(out_size);
731 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
732 out_used = 0;
733
734 while (1) {
735 col = strchr(in, ':');
736 /* we're finished, copy the remaining part */
737 if (!col) {
738 strcpy(&out[out_used], in);
739 out_used += strlen(in) + 1;
740 assert(out_size == out_used);
741 return lydict_insert_zc(ctx, out);
742 }
743 id = strpbrk_backwards(col - 1, " \f\n\r\t\v(", (col - in) - 1);
744 if ((id[0] == ' ') || (id[0] == '\f') || (id[0] == '\n') || (id[0] == '\r') ||
745 (id[0] == '\t') || (id[0] == '\v') || (id[0] == '(')) {
746 ++id;
747 }
748 id_len = col - id;
749 rc = parse_identifier(id);
750 if (rc < id_len) {
751 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, id[rc], &id[rc]);
752 free(out);
753 return NULL;
754 }
755
756 /* get the module */
757 mod = lyp_get_module(module, id, id_len, NULL, 0, 0);
758 if (!mod) {
759 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Module prefix \"%.*s\" is unknown.", id_len, id);
760 free(out);
761 return NULL;
762 }
763
764 /* adjust out size (it can even decrease in some strange cases) */
765 out_size += strlen(mod->name) - id_len;
766 out = ly_realloc(out, out_size);
767 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
768
769 /* copy the data before prefix */
770 strncpy(&out[out_used], in, id - in);
771 out_used += id - in;
772
773 /* copy the model name */
774 strcpy(&out[out_used], mod->name);
775 out_used += strlen(mod->name);
776
777 /* copy ':' */
778 out[out_used] = ':';
779 ++out_used;
780
781 /* finally adjust in pointer for next round */
782 in = col + 1;
783 }
784
785 /* unreachable */
786 LOGINT(ctx);
787 return NULL;
788 }
789
790 static int
transform_json2xpath_subexpr(const struct lys_module * cur_module,const struct lys_module * prev_mod,struct lyxp_expr * exp,uint32_t * i,enum lyxp_token end_token,char ** out,size_t * out_used,size_t * out_size)791 transform_json2xpath_subexpr(const struct lys_module *cur_module, const struct lys_module *prev_mod, struct lyxp_expr *exp,
792 uint32_t *i, enum lyxp_token end_token, char **out, size_t *out_used, size_t *out_size)
793 {
794 const char *cur_expr, *end, *ptr;
795 size_t name_len;
796 char *name;
797 const struct lys_module *mod;
798 struct ly_ctx *ctx = cur_module->ctx;
799
800 while (*i < exp->used) {
801 if (exp->tokens[*i] == end_token) {
802 return 0;
803 }
804
805 cur_expr = &exp->expr[exp->expr_pos[*i]];
806
807 /* copy WS */
808 if (*i && ((end = exp->expr + exp->expr_pos[*i - 1] + exp->tok_len[*i - 1]) != cur_expr)) {
809 strncpy(*out + *out_used, end, cur_expr - end);
810 *out_used += cur_expr - end;
811 }
812
813 if (exp->tokens[*i] == LYXP_TOKEN_BRACK1) {
814 /* copy "[" */
815 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
816 *out_used += exp->tok_len[*i];
817 ++(*i);
818
819 /* call recursively because we need to remember current prev_mod for after the predicate */
820 if (transform_json2xpath_subexpr(cur_module, prev_mod, exp, i, LYXP_TOKEN_BRACK2, out, out_used, out_size)) {
821 return -1;
822 }
823
824 if (*i >= exp->used) {
825 LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL);
826 return -1;
827 }
828
829 /* copy "]" */
830 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
831 *out_used += exp->tok_len[*i];
832 } else if (exp->tokens[*i] == LYXP_TOKEN_NAMETEST) {
833 if ((end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
834 /* there is a prefix, get the module */
835 name_len = end - cur_expr;
836 name = strndup(cur_expr, name_len);
837 prev_mod = ly_ctx_get_module(ctx, name, NULL, 1);
838 free(name);
839 if (!prev_mod) {
840 LOGVAL(ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len ? name_len : exp->tok_len[*i], cur_expr);
841 return -1;
842 }
843 /* skip ":" */
844 ++end;
845 ++name_len;
846 } else {
847 end = cur_expr;
848 name_len = 0;
849 }
850
851 /* do we print the module name? (always for "*" if there was any, it's an exception) */
852 if (((prev_mod != cur_module) && (end[0] != '*')) || (name_len && (end[0] == '*'))) {
853 /* adjust out size (it can even decrease in some strange cases) */
854 *out_size += (strlen(prev_mod->name) - name_len) + 1;
855 *out = ly_realloc(*out, *out_size);
856 LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1);
857
858 /* copy the model name */
859 strcpy(*out + *out_used, prev_mod->name);
860 *out_used += strlen(prev_mod->name);
861
862 /* print ":" */
863 (*out)[*out_used] = ':';
864 ++(*out_used);
865 }
866
867 /* copy the rest */
868 strncpy(*out + *out_used, end, exp->tok_len[*i] - name_len);
869 *out_used += exp->tok_len[*i] - name_len;
870 } else if ((exp->tokens[*i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
871 ptr = end;
872 while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
873 --ptr;
874 }
875
876 /* get the module, but it may actually not be a module name */
877 name_len = end - ptr;
878 name = strndup(ptr, name_len);
879 mod = ly_ctx_get_module(ctx, name, NULL, 1);
880 free(name);
881
882 if (mod && (mod != cur_module)) {
883 /* adjust out size (it can even decrease in some strange cases) */
884 *out_size += strlen(mod->name) - name_len;
885 *out = ly_realloc(*out, *out_size);
886 LY_CHECK_ERR_RETURN(!*out, LOGMEM(ctx), -1);
887
888 /* copy any beginning */
889 strncpy(*out + *out_used, cur_expr, ptr - cur_expr);
890 *out_used += ptr - cur_expr;
891
892 /* copy the model name */
893 strcpy(*out + *out_used, mod->name);
894 *out_used += strlen(mod->name);
895
896 /* copy the rest */
897 strncpy(*out + *out_used, end, (exp->tok_len[*i] - name_len) - (ptr - cur_expr));
898 *out_used += (exp->tok_len[*i] - name_len) - (ptr - cur_expr);
899 } else {
900 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
901 *out_used += exp->tok_len[*i];
902 }
903 } else {
904 strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
905 *out_used += exp->tok_len[*i];
906 }
907
908 ++(*i);
909 }
910
911 return 0;
912 }
913
914 char *
transform_json2xpath(const struct lys_module * cur_module,const char * expr)915 transform_json2xpath(const struct lys_module *cur_module, const char *expr)
916 {
917 char *out;
918 size_t out_size, out_used;
919 uint32_t i;
920 struct lyxp_expr *exp;
921
922 assert(cur_module && expr);
923
924 out_size = strlen(expr) + 1;
925 out = malloc(out_size);
926 LY_CHECK_ERR_RETURN(!out, LOGMEM(cur_module->ctx), NULL);
927 out_used = 0;
928
929 exp = lyxp_parse_expr(cur_module->ctx, expr);
930 LY_CHECK_ERR_RETURN(!exp, free(out), NULL);
931
932 i = 0;
933 if (transform_json2xpath_subexpr(cur_module, cur_module, exp, &i, LYXP_TOKEN_NONE, &out, &out_used, &out_size)) {
934 goto error;
935 }
936 out[out_used] = '\0';
937
938 lyxp_expr_free(exp);
939 return out;
940
941 error:
942 free(out);
943 lyxp_expr_free(exp);
944 return NULL;
945 }
946
947 static int
ly_path_data2schema_copy_token(const struct ly_ctx * ctx,struct lyxp_expr * exp,uint16_t cur_exp,char ** out,uint16_t * out_used)948 ly_path_data2schema_copy_token(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t cur_exp, char **out, uint16_t *out_used)
949 {
950 uint16_t len;
951
952 for (len = exp->tok_len[cur_exp]; isspace(exp->expr[exp->expr_pos[cur_exp] + len]); ++len);
953 *out = ly_realloc(*out, *out_used + len);
954 LY_CHECK_ERR_RETURN(!(*out), LOGMEM(ctx), -1);
955 sprintf(*out + *out_used - 1, "%.*s", len, exp->expr + exp->expr_pos[cur_exp]);
956 *out_used += len;
957
958 return 0;
959 }
960
961 static int
ly_path_data2schema_subexp(const struct ly_ctx * ctx,const struct lys_node * orig_parent,const struct lys_module * cur_mod,struct lyxp_expr * exp,uint16_t * cur_exp,char ** out,uint16_t * out_used)962 ly_path_data2schema_subexp(const struct ly_ctx *ctx, const struct lys_node *orig_parent, const struct lys_module *cur_mod,
963 struct lyxp_expr *exp, uint16_t *cur_exp, char **out, uint16_t *out_used)
964 {
965 uint16_t j, k, len, slash;
966 char *str = NULL, *col;
967 const struct lys_node *node, *node2, *parent;
968 enum lyxp_token end_token = 0;
969 int first, path_lost;
970
971 switch (exp->tokens[*cur_exp]) {
972 case LYXP_TOKEN_BRACK1:
973 end_token = LYXP_TOKEN_BRACK2;
974
975 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
976 goto error;
977 }
978 ++(*cur_exp);
979 first = 0;
980 break;
981 case LYXP_TOKEN_PAR1:
982 end_token = LYXP_TOKEN_PAR2;
983
984 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
985 goto error;
986 }
987 ++(*cur_exp);
988 first = 0;
989 break;
990 case LYXP_TOKEN_OPERATOR_PATH:
991 first = (orig_parent) ? 0 : 1;
992 break;
993 default:
994 first = 1;
995 break;
996 }
997
998 path_lost = 0;
999 parent = orig_parent;
1000 while (*cur_exp < exp->used) {
1001 switch (exp->tokens[*cur_exp]) {
1002 case LYXP_TOKEN_DOT:
1003 case LYXP_TOKEN_DDOT:
1004 case LYXP_TOKEN_NAMETEST:
1005 if (path_lost) {
1006 /* we do not know anything anymore, just copy it */
1007 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1008 goto error;
1009 }
1010 break;
1011 }
1012
1013 str = strndup(exp->expr + exp->expr_pos[*cur_exp], exp->tok_len[*cur_exp]);
1014 LY_CHECK_ERR_GOTO(!str, LOGMEM(ctx), error);
1015
1016 col = strchr(str, ':');
1017 if (col) {
1018 *col = '\0';
1019 ++col;
1020 }
1021
1022 /* special node test */
1023 if (((col ? col[0] : str[0]) == '.') || ((col ? col[0] : str[0]) == '*')) {
1024 free(str);
1025 str = NULL;
1026
1027 if (end_token) {
1028 LOGERR(ctx, LY_EINVAL, "Invalid path used (%s in a subexpression).", str);
1029 goto error;
1030 }
1031
1032 /* we can no longer evaluate the path, so just copy the rest */
1033 path_lost = 1;
1034 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1035 goto error;
1036 }
1037 first = 0;
1038 break;
1039 }
1040
1041 /* first node */
1042 if (first) {
1043 if (!col) {
1044 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_NONE, NULL);
1045 goto error;
1046 }
1047
1048 cur_mod = ly_ctx_get_module(ctx, str, NULL, 0);
1049 if (!cur_mod) {
1050 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1051 goto error;
1052 }
1053
1054 first = 0;
1055 }
1056
1057 /* create schema path for this data node */
1058 node = NULL;
1059 while ((node = lys_getnext(node, parent, cur_mod, LYS_GETNEXT_NOSTATECHECK))) {
1060 if (strcmp(node->name, col ? col : str)) {
1061 continue;
1062 }
1063
1064 if (col && strcmp(lys_node_module(node)->name, str)) {
1065 continue;
1066 }
1067 if (!col && (lys_node_module(node) != lys_node_module(parent))) {
1068 continue;
1069 }
1070
1071 /* determine how deep the node actually is, we must generate the path from the highest parent */
1072 j = 0;
1073 node2 = node;
1074 while (node2 != parent) {
1075 node2 = lys_parent(node2);
1076 if (!node2 || (node2->nodetype != LYS_USES)) {
1077 ++j;
1078 }
1079 }
1080
1081 /* first node, do not print '/' */
1082 slash = 0;
1083 while (j) {
1084 k = j - 1;
1085 node2 = node;
1086 while (k) {
1087 node2 = lys_parent(node2);
1088 assert(node2);
1089 if (node2->nodetype != LYS_USES) {
1090 --k;
1091 }
1092 }
1093
1094 if ((lys_node_module(node2) != cur_mod) || !parent) {
1095 /* module name and node name */
1096 len = slash + strlen(lys_node_module(node2)->name) + 1 + strlen(node2->name);
1097 *out = ly_realloc(*out, *out_used + len);
1098 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
1099 sprintf(*out + *out_used - 1, "%s%s:%s", slash ? "/" : "", lys_node_module(node2)->name, node2->name);
1100 *out_used += len;
1101 } else {
1102 /* only node name */
1103 len = slash + strlen(node2->name);
1104 *out = ly_realloc(*out, *out_used + len);
1105 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
1106 sprintf(*out + *out_used - 1, "%s%s", slash ? "/" : "", node2->name);
1107 *out_used += len;
1108 }
1109
1110 slash = 1;
1111 --j;
1112 }
1113
1114 break;
1115 }
1116 if (!node) {
1117 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, col ? col : str);
1118 goto error;
1119 }
1120
1121 /* copy any whitespaces */
1122 for (len = 0; isspace(exp->expr[exp->expr_pos[*cur_exp] + exp->tok_len[*cur_exp] + len]); ++len);
1123 if (len) {
1124 *out = ly_realloc(*out, *out_used + len);
1125 LY_CHECK_ERR_GOTO(!(*out), LOGMEM(ctx), error);
1126 sprintf(*out + *out_used - 1, "%*s", len, " ");
1127 *out_used += len;
1128 }
1129
1130 /* next iteration */
1131 free(str);
1132 str = NULL;
1133 parent = node;
1134 break;
1135 case LYXP_TOKEN_COMMA:
1136 case LYXP_TOKEN_OPERATOR_LOG:
1137 case LYXP_TOKEN_OPERATOR_COMP:
1138 case LYXP_TOKEN_OPERATOR_MATH:
1139 case LYXP_TOKEN_OPERATOR_UNI:
1140 /* reset the processing */
1141 first = 1;
1142 path_lost = 0;
1143 parent = orig_parent;
1144
1145 /* fallthrough */
1146 case LYXP_TOKEN_OPERATOR_PATH:
1147 if ((exp->tokens[*cur_exp] == LYXP_TOKEN_OPERATOR_PATH) && (exp->tok_len[*cur_exp] == 2)) {
1148 /* we can no longer evaluate the path further */
1149 path_lost = 1;
1150 }
1151 /* fallthrough */
1152 case LYXP_TOKEN_NODETYPE:
1153 case LYXP_TOKEN_FUNCNAME:
1154 case LYXP_TOKEN_LITERAL:
1155 case LYXP_TOKEN_NUMBER:
1156 /* just copy it */
1157 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1158 goto error;
1159 }
1160 break;
1161 case LYXP_TOKEN_BRACK1:
1162 case LYXP_TOKEN_PAR1:
1163 if (ly_path_data2schema_subexp(ctx, parent, cur_mod, exp, cur_exp, out, out_used)) {
1164 goto error;
1165 }
1166 break;
1167 default:
1168 if (end_token && (exp->tokens[*cur_exp] == end_token)) {
1169 /* we are done (with this subexpression) */
1170 if (ly_path_data2schema_copy_token(ctx, exp, *cur_exp, out, out_used)) {
1171 goto error;
1172 }
1173
1174 return 0;
1175 }
1176 LOGERR(ctx, LY_EINVAL, "Invalid token used (%.*s).", exp->tok_len[*cur_exp], exp->expr + exp->expr_pos[*cur_exp]);
1177 goto error;
1178 }
1179
1180 ++(*cur_exp);
1181 }
1182
1183 if (end_token) {
1184 LOGVAL(ctx, LYE_XPATH_EOF, LY_VLOG_NONE, NULL);
1185 return -1;
1186 }
1187
1188 return 0;
1189
1190 error:
1191 free(str);
1192 return -1;
1193 }
1194
1195 API char *
ly_path_data2schema(struct ly_ctx * ctx,const char * data_path)1196 ly_path_data2schema(struct ly_ctx *ctx, const char *data_path)
1197 {
1198 FUN_IN;
1199
1200 struct lyxp_expr *exp;
1201 uint16_t out_used, cur_exp = 0;
1202 char *out;
1203 int r, mod_name_len, nam_len, is_relative = -1;
1204 const char *mod_name, *name;
1205 const struct lys_module *mod = NULL;
1206 const struct lys_node *parent = NULL;
1207 char *str;
1208
1209 if (!ctx || !data_path) {
1210 LOGARG;
1211 return NULL;
1212 }
1213
1214 if ((r = parse_schema_nodeid(data_path, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
1215 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, data_path[-r], &data_path[-r]);
1216 return NULL;
1217 }
1218
1219 if (name[0] == '#') {
1220 if (is_relative) {
1221 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1222 return NULL;
1223 }
1224
1225 ++name;
1226 --nam_len;
1227
1228 if (!mod_name) {
1229 str = strndup(data_path, (name + nam_len) - data_path);
1230 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, str);
1231 free(str);
1232 return NULL;
1233 }
1234
1235 str = strndup(mod_name, mod_name_len);
1236 if (!str) {
1237 LOGMEM(ctx);
1238 return NULL;
1239 }
1240 mod = ly_ctx_get_module(ctx, str, NULL, 1);
1241 free(str);
1242 if (!mod) {
1243 str = strndup(data_path, (mod_name + mod_name_len) - data_path);
1244 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1245 free(str);
1246 return NULL;
1247 }
1248
1249 parent = lyp_get_yang_data_template(mod, name, nam_len);
1250 if (!parent) {
1251 str = strndup(data_path, (name + nam_len) - data_path);
1252 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1253 free(str);
1254 return NULL;
1255 }
1256
1257 out_used = (name + nam_len) - data_path + 1;
1258 out = malloc(out_used);
1259 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
1260 memcpy(out, data_path, out_used -1);
1261 data_path += r;
1262 } else {
1263 out_used = 1;
1264 out = malloc(1);
1265 LY_CHECK_ERR_RETURN(!out, LOGMEM(ctx), NULL);
1266 }
1267
1268 exp = lyxp_parse_expr(ctx, data_path);
1269 if (!exp) {
1270 free(out);
1271 return NULL;
1272 }
1273
1274 if (parent) {
1275 if (ly_path_data2schema_subexp(ctx, parent, mod, exp, &cur_exp, &out, &out_used)) {
1276 free(out);
1277 out = NULL;
1278 }
1279 } else {
1280 if (ly_path_data2schema_subexp(ctx, NULL, NULL, exp, &cur_exp, &out, &out_used)) {
1281 free(out);
1282 out = NULL;
1283 }
1284 }
1285
1286 lyxp_expr_free(exp);
1287 return out;
1288 }
1289
1290 int
ly_new_node_validity(const struct lys_node * schema)1291 ly_new_node_validity(const struct lys_node *schema)
1292 {
1293 int validity;
1294
1295 validity = LYD_VAL_OK;
1296
1297 if (schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) {
1298 /* duplicit instance check */
1299 validity |= LYD_VAL_DUP;
1300 }
1301 if ((schema->nodetype == LYS_LIST) && ((struct lys_node_list *)schema)->unique_size) {
1302 /* unique check */
1303 validity |= LYD_VAL_UNIQUE;
1304 }
1305 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION | LYS_ANYDATA)) {
1306 /* mandatory children check */
1307 validity |= LYD_VAL_MAND;
1308 }
1309
1310 return validity;
1311 }
1312
1313 void *
ly_realloc(void * ptr,size_t size)1314 ly_realloc(void *ptr, size_t size)
1315 {
1316 void *new_mem;
1317
1318 new_mem = realloc(ptr, size);
1319 if (!new_mem) {
1320 free(ptr);
1321 }
1322
1323 return new_mem;
1324 }
1325
1326 int
ly_strequal_(const char * s1,const char * s2)1327 ly_strequal_(const char *s1, const char *s2)
1328 {
1329 if (s1 == s2) {
1330 return 1;
1331 } else if (!s1 || !s2) {
1332 return 0;
1333 } else {
1334 for ( ; *s1 == *s2; s1++, s2++) {
1335 if (*s1 == '\0') {
1336 return 1;
1337 }
1338 }
1339 return 0;
1340 }
1341 }
1342
1343 int64_t
dec_pow(uint8_t exp)1344 dec_pow(uint8_t exp)
1345 {
1346 int64_t ret = 1;
1347 uint8_t i;
1348
1349 for (i = 0; i < exp; ++i) {
1350 ret *= 10;
1351 }
1352
1353 return ret;
1354 }
1355
1356 int
dec64cmp(int64_t num1,uint8_t dig1,int64_t num2,uint8_t dig2)1357 dec64cmp(int64_t num1, uint8_t dig1, int64_t num2, uint8_t dig2)
1358 {
1359 if (dig1 < dig2) {
1360 num2 /= dec_pow(dig2 - dig1);
1361 } else if (dig1 > dig2) {
1362 num1 /= dec_pow(dig1 - dig2);
1363 }
1364
1365 if (num1 == num2) {
1366 return 0;
1367 }
1368 return (num1 > num2 ? 1 : -1);
1369 }
1370
1371 #ifdef LY_ENABLED_CACHE
1372 # if defined(__has_feature)
1373 # if __has_feature(thread_sanitizer)
1374 # define LY_HASH_NO_TSAN __attribute__((no_sanitize("thread")))
1375 # endif
1376 # endif
1377 # ifndef LY_HASH_NO_TSAN
1378 # define LY_HASH_NO_TSAN
1379 # endif
1380
lyb_hash_cache_check(const struct lys_node * sibling,const uint8_t collision_id)1381 LY_HASH_NO_TSAN static inline LYB_HASH lyb_hash_cache_check(const struct lys_node *sibling, const uint8_t collision_id)
1382 {
1383 if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
1384 return sibling->hash[collision_id];
1385 }
1386 return 0;
1387 }
1388
lyb_hash_cache_update(struct lys_node * sibling,const uint8_t collision_id,const LYB_HASH hash)1389 LY_HASH_NO_TSAN static inline void lyb_hash_cache_update(struct lys_node *sibling, const uint8_t collision_id, const LYB_HASH hash)
1390 {
1391 if (collision_id < LYS_NODE_HASH_COUNT) {
1392 sibling->hash[collision_id] = hash;
1393 }
1394 }
1395 #endif
1396
1397 LYB_HASH
lyb_hash(struct lys_node * sibling,uint8_t collision_id)1398 lyb_hash(struct lys_node *sibling, uint8_t collision_id)
1399 {
1400 struct lys_module *mod;
1401 int ext_len;
1402 uint32_t full_hash;
1403 LYB_HASH hash;
1404
1405 #ifdef LY_ENABLED_CACHE
1406 if ((hash = lyb_hash_cache_check(sibling, collision_id))) {
1407 return hash;
1408 }
1409 #endif
1410
1411 mod = lys_node_module(sibling);
1412
1413 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
1414 full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
1415 if (collision_id) {
1416 if (collision_id > strlen(mod->name)) {
1417 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
1418 ext_len = strlen(mod->name);
1419 } else {
1420 /* use one more byte from the module name than before */
1421 ext_len = collision_id;
1422 }
1423 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
1424 }
1425 full_hash = dict_hash_multi(full_hash, NULL, 0);
1426
1427 /* use the shortened hash */
1428 hash = full_hash & (LYB_HASH_MASK >> collision_id);
1429 /* add colision identificator */
1430 hash |= LYB_HASH_COLLISION_ID >> collision_id;
1431
1432 /* save this hash */
1433 #ifdef LY_ENABLED_CACHE
1434 lyb_hash_cache_update(sibling, collision_id, hash);
1435 #endif
1436
1437 return hash;
1438 }
1439
1440 int
lyb_has_schema_model(struct lys_node * sibling,const struct lys_module ** models,int mod_count)1441 lyb_has_schema_model(struct lys_node *sibling, const struct lys_module **models, int mod_count)
1442 {
1443 int i;
1444 const struct lys_module *mod = lys_node_module(sibling);
1445
1446 for (i = 0; i < mod_count; ++i) {
1447 if (mod == models[i]) {
1448 return 1;
1449 }
1450 }
1451
1452 return 0;
1453 }
1454
1455 /**
1456 * @brief Static table of the UTF8 characters lengths according to their first byte.
1457 */
1458 static const unsigned char
1459 utf8_char_length_table[] = {
1460 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1461 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1462 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1463 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1464 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1466 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1467 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1468 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1469 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1470 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1471 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1472 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1473 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1474 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1475 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
1476 };
1477
1478 /**
1479 * @brief Use of utf8_char_length_table.
1480 */
1481 #define UTF8LEN(x) utf8_char_length_table[((unsigned char)(x))]
1482
1483 size_t
ly_strlen_utf8(const char * str)1484 ly_strlen_utf8(const char *str)
1485 {
1486 size_t clen, len;
1487 const char *ptr;
1488
1489 for (len = 0, clen = strlen(str), ptr = str; *ptr && len < clen; ++len, ptr += UTF8LEN(*ptr));
1490 return len;
1491 }
1492